diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 88e34860cf492..80f614d6691a3 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -3759,7 +3759,7 @@ public function export_for_template(renderer_base $output) { * @copyright 2013 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class action_menu implements renderable { +class action_menu implements renderable, templatable { /** * Top right alignment. @@ -4108,6 +4108,98 @@ public function set_nowrap_on_items($value = true) { $this->attributes['class'] = $class; } } + + /** + * Export for template. + * + * @param renderer_base $output The renderer. + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + $data = new stdClass(); + $attributes = $this->attributes; + $attributesprimary = $this->attributesprimary; + $attributessecondary = $this->attributessecondary; + + $data->instance = $this->instance; + + $data->classes = isset($attributes['class']) ? $attributes['class'] : ''; + unset($attributes['class']); + + $data->attributes = array_map(function($key, $value) { + return [ 'name' => $key, 'value' => $value ]; + }, array_keys($attributes), $attributes); + + $primary = new stdClass(); + $primary->title = ''; + $primary->prioritise = $this->prioritise; + + $primary->classes = isset($attributesprimary['class']) ? $attributesprimary['class'] : ''; + unset($attributesprimary['class']); + $primary->attributes = array_map(function($key, $value) { + return [ 'name' => $key, 'value' => $value ]; + }, array_keys($attributesprimary), $attributesprimary); + + $actionicon = $this->actionicon; + if (!empty($this->menutrigger)) { + $primary->menutrigger = $this->menutrigger; + } else { + $primary->title = get_string('actions'); + $actionicon = new pix_icon('t/edit_menu', '', 'moodle', ['class' => 'iconsmall actionmenu', 'title' => '']); + } + + if ($actionicon instanceof pix_icon) { + $primary->icon = $actionicon->export_for_template($output); + $primary->title = !empty($actionicon->attributes['alt']) ? $this->actionicon->attributes['alt'] : ''; + } else { + $primary->iconraw = $actionicon ? $output->render($actionicon) : ''; + } + + $primary->actiontext = $this->actiontext ? (string) $this->actiontext : ''; + $primary->items = array_map(function($item) use ($output) { + $data = (object) []; + if ($item instanceof action_menu_link) { + $data->actionmenulink = $item->export_for_template($output); + } else if ($item instanceof action_menu_filler) { + $data->actionmenufiller = $item->export_for_template($output); + } else if ($item instanceof action_link) { + $data->actionlink = $item->export_for_template($output); + } else if ($item instanceof pix_icon) { + $data->pixicon = $item->export_for_template($output); + } else { + $data->rawhtml = ($item instanceof renderable) ? $output->render($item) : $item; + } + return $data; + }, $this->primaryactions); + + $secondary = new stdClass(); + $secondary->classes = isset($attributessecondary['class']) ? $attributessecondary['class'] : ''; + unset($attributessecondary['class']); + $secondary->attributes = array_map(function($key, $value) { + return [ 'name' => $key, 'value' => $value ]; + }, array_keys($attributessecondary), $attributessecondary); + $secondary->items = array_map(function($item) use ($output) { + $data = (object) []; + if ($item instanceof action_menu_link) { + $data->actionmenulink = $item->export_for_template($output); + } else if ($item instanceof action_menu_filler) { + $data->actionmenufiller = $item->export_for_template($output); + } else if ($item instanceof action_link) { + $data->actionlink = $item->export_for_template($output); + } else if ($item instanceof pix_icon) { + $data->pixicon = $item->export_for_template($output); + } else { + $data->rawhtml = ($item instanceof renderable) ? $output->render($item) : $item; + } + return $data; + }, $this->secondaryactions); + + $data->primary = $primary; + $data->secondary = $secondary; + + return $data; + } + } /** @@ -4170,6 +4262,64 @@ public function __construct(moodle_url $url, pix_icon $icon = null, $text, $prim $this->add_class('menu-action'); $this->attributes['role'] = 'menuitem'; } + + /** + * Export for template. + * + * @param renderer_base $output The renderer. + * @return stdClass + */ + public function export_for_template(renderer_base $output) { + static $instance = 1; + + $data = parent::export_for_template($output); + $data->instance = $instance++; + + // Ignore what the parent did with the attributes, except for ID and class. + $data->attributes = []; + $attributes = $this->attributes; + unset($attributes['id']); + unset($attributes['class']); + + // Handle text being a renderable. + $comparetoalt = $this->text; + if ($this->text instanceof renderable) { + $data->text = $this->render($this->text); + $comparetoalt = ''; + } + $comparetoalt = (string) $comparetoalt; + + $data->showtext = (!$this->icon || $this->primary === false); + + $data->icon = null; + if ($this->icon) { + $icon = $this->icon; + if ($this->primary || !$this->actionmenu->will_be_enhanced()) { + $attributes['title'] = $data->text; + } + if (!$this->primary && $this->actionmenu->will_be_enhanced()) { + if ((string) $icon->attributes['alt'] === $comparetoalt) { + $icon->attributes['alt'] = ''; + } + if (isset($icon->attributes['title']) && (string) $icon->attributes['title'] === $comparetoalt) { + unset($icon->attributes['title']); + } + } + $data->icon = $icon ? $icon->export_for_template($output) : null; + } + + $data->disabled = !empty($attributes['disabled']); + unset($attributes['disabled']); + + $data->attributes = array_map(function($key, $value) { + return [ + 'name' => $key, + 'value' => $value + ]; + }, array_keys($attributes), $attributes); + + return $data; + } } /** diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index e4c8392f3acd9..750456b2d7c2c 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -1310,31 +1310,8 @@ public function block_controls($actions, $blockid = null) { * @return string HTML */ public function render_action_menu(action_menu $menu) { - $menu->initialise_js($this->page); - - $output = html_writer::start_tag('div', $menu->attributes); - $output .= html_writer::start_tag('ul', $menu->attributesprimary); - foreach ($menu->get_primary_actions($this) as $action) { - if ($action instanceof renderable) { - $content = $this->render($action); - } else { - $content = $action; - } - $output .= html_writer::tag('li', $content, array('role' => 'presentation')); - } - $output .= html_writer::end_tag('ul'); - $output .= html_writer::start_tag('ul', $menu->attributessecondary); - foreach ($menu->get_secondary_actions() as $action) { - if ($action instanceof renderable) { - $content = $this->render($action); - } else { - $content = $action; - } - $output .= html_writer::tag('li', $content, array('role' => 'presentation')); - } - $output .= html_writer::end_tag('ul'); - $output .= html_writer::end_tag('div'); - return $output; + $context = $menu->export_for_template($this); + return $this->render_from_template('core/action_menu', $context); } /** @@ -1344,53 +1321,7 @@ public function render_action_menu(action_menu $menu) { * @return string HTML fragment */ protected function render_action_menu_link(action_menu_link $action) { - static $actioncount = 0; - $actioncount++; - - $comparetoalt = ''; - $text = ''; - if (!$action->icon || $action->primary === false) { - $text .= html_writer::start_tag('span', array('class'=>'menu-action-text', 'id' => 'actionmenuaction-'.$actioncount)); - if ($action->text instanceof renderable) { - $text .= $this->render($action->text); - } else { - $text .= $action->text; - $comparetoalt = (string)$action->text; - } - $text .= html_writer::end_tag('span'); - } - - $icon = ''; - if ($action->icon) { - $icon = $action->icon; - if ($action->primary || !$action->actionmenu->will_be_enhanced()) { - $action->attributes['title'] = $action->text; - } - if (!$action->primary && $action->actionmenu->will_be_enhanced()) { - if ((string)$icon->attributes['alt'] === $comparetoalt) { - $icon->attributes['alt'] = ''; - } - if (isset($icon->attributes['title']) && (string)$icon->attributes['title'] === $comparetoalt) { - unset($icon->attributes['title']); - } - } - $icon = $this->render($icon); - } - - // A disabled link is rendered as formatted text. - if (!empty($action->attributes['disabled'])) { - // Do not use div here due to nesting restriction in xhtml strict. - return html_writer::tag('span', $icon.$text, array('class'=>'currentlink', 'role' => 'menuitem')); - } - - $attributes = $action->attributes; - unset($action->attributes['disabled']); - $attributes['href'] = $action->url; - if ($text !== '') { - $attributes['aria-labelledby'] = 'actionmenuaction-'.$actioncount; - } - - return html_writer::tag('a', $icon.$text, $attributes); + return $this->render_from_template('core/action_menu_link', $action->export_for_template($this)); } /** @@ -3376,7 +3307,6 @@ public function user_menu($user = null, $withlinks = null) { $divider->primary = false; $am = new action_menu(); - $am->initialise_js($this->page); $am->set_menu_trigger( $returnstr ); diff --git a/lib/templates/action_menu.mustache b/lib/templates/action_menu.mustache new file mode 100644 index 0000000000000..6445e77ee847d --- /dev/null +++ b/lib/templates/action_menu.mustache @@ -0,0 +1,49 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + Action menu. +}} +
+ {{#primary}} + + + + {{/primary}} + + {{#secondary}} + + {{/secondary}} + + +
+{{#js}} +require(['core/yui'], function(Y) { + Y.use('moodle-core-actionmenu', function() { + M.core.actionmenu.init(); + }); +}); +{{/js}} diff --git a/lib/templates/action_menu_item.mustache b/lib/templates/action_menu_item.mustache new file mode 100644 index 0000000000000..d00323a5c480b --- /dev/null +++ b/lib/templates/action_menu_item.mustache @@ -0,0 +1,24 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + Action menu item. +}} +{{#actionmenulink}}{{> core/action_menu_link }}{{/actionmenulink}} +{{#actionmenufiller}} {{/actionmenufiller}} +{{#actionlink}}{{> core/action_link }}{{/actionlink}} +{{#pixicon}}{{> core/pix_icon }}{{/pixicon}} +{{#rawhtml}}{{{.}}}{{/rawhtml}} \ No newline at end of file diff --git a/lib/templates/action_menu_link.mustache b/lib/templates/action_menu_link.mustache new file mode 100644 index 0000000000000..3c41ad8dd7b27 --- /dev/null +++ b/lib/templates/action_menu_link.mustache @@ -0,0 +1,25 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + Action menu link. +}} +{{^disabled}} + {{#icon}}{{>core/pix_icon}}{{/icon}}{{#showtext}}{{{text}}}{{/showtext}} +{{/disabled}} +{{#disabled}} + {{#icon}}{{>core/pix_icon}}{{/icon}}{{{text}}} +{{/disabled}} diff --git a/lib/templates/action_menu_trigger.mustache b/lib/templates/action_menu_trigger.mustache new file mode 100644 index 0000000000000..977d382d232a4 --- /dev/null +++ b/lib/templates/action_menu_trigger.mustache @@ -0,0 +1,20 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + Action menu trigger. +}} +{{{actiontext}}}{{{menutrigger}}}{{#icon}}{{> core/pix_icon}}{{/icon}}{{#rawicon}}{{{.}}}{{/rawicon}}{{#menutrigger}}{{/menutrigger}} \ No newline at end of file diff --git a/lib/templates/pix_icon.mustache b/lib/templates/pix_icon.mustache index 63cedac297f51..e98675765710c 100644 --- a/lib/templates/pix_icon.mustache +++ b/lib/templates/pix_icon.mustache @@ -39,4 +39,4 @@ } }} - + \ No newline at end of file