blocks/navigation/amd/src/ajax_response_renderer.js

  1. // This file is part of Moodle - http://moodle.org/
  2. //
  3. // Moodle is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // Moodle is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * Parse the response from the navblock ajax page and render the correct DOM
  17. * structure for the tree from it.
  18. *
  19. * @module block_navigation/ajax_response_renderer
  20. * @copyright 2015 John Okely <john@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. define([
  24. 'jquery',
  25. 'core/templates',
  26. 'core/notification',
  27. 'core/url',
  28. 'core/aria',
  29. ], function(
  30. $,
  31. Templates,
  32. Notification,
  33. Url,
  34. Aria
  35. ) {
  36. // Mappings for the different types of nodes coming from the navigation.
  37. // Copied from lib/navigationlib.php navigation_node constants.
  38. var NODETYPE = {
  39. // @type int Activity (course module) = 40.
  40. ACTIVITY: 40,
  41. // @type int Resource (course module = 50.
  42. RESOURCE: 50,
  43. };
  44. /**
  45. * Build DOM.
  46. *
  47. * @method buildDOM
  48. * @param {Object} rootElement the root element of DOM.
  49. * @param {object} nodes jquery object representing the nodes to be build.
  50. */
  51. function buildDOM(rootElement, nodes) {
  52. var ul = $('<ul></ul>');
  53. ul.attr('role', 'group');
  54. Aria.hide(ul);
  55. $.each(nodes, function(index, node) {
  56. if (typeof node !== 'object') {
  57. return;
  58. }
  59. var li = $('<li></li>');
  60. var p = $('<p></p>');
  61. var id = node.id || node.key + '_tree_item';
  62. var icon = null;
  63. var isBranch = (node.expandable || node.haschildren) ? true : false;
  64. li.attr('role', 'treeitem');
  65. p.addClass('tree_item');
  66. p.attr('id', id);
  67. // Negative tab index to allow it to receive focus.
  68. p.attr('tabindex', '-1');
  69. if (node.requiresajaxloading) {
  70. li.attr('data-requires-ajax', true);
  71. li.attr('data-node-id', node.id);
  72. li.attr('data-node-key', node.key);
  73. li.attr('data-node-type', node.type);
  74. }
  75. if (isBranch) {
  76. li.addClass('collapsed contains_branch');
  77. li.attr('aria-expanded', false);
  78. p.addClass('branch');
  79. }
  80. var eleToAddIcon = null;
  81. if (node.link) {
  82. var link = $('<a title="' + node.title + '" href="' + node.link + '"></a>');
  83. eleToAddIcon = link;
  84. link.append('<span class="item-content-wrap">' + node.name + '</span>');
  85. if (node.hidden) {
  86. link.addClass('dimmed');
  87. }
  88. p.append(link);
  89. } else {
  90. var span = $('<span></span>');
  91. eleToAddIcon = span;
  92. span.append('<span class="item-content-wrap">' + node.name + '</span>');
  93. if (node.hidden) {
  94. span.addClass('dimmed');
  95. }
  96. p.append(span);
  97. }
  98. if (node.icon && (!isBranch || node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE)) {
  99. li.addClass('item_with_icon');
  100. p.addClass('hasicon');
  101. if (node.type === NODETYPE.ACTIVITY || node.type === NODETYPE.RESOURCE) {
  102. icon = $('<img/>');
  103. icon.attr('alt', node.icon.alt);
  104. icon.attr('title', node.icon.title);
  105. icon.attr('src', Url.imageUrl(node.icon.pix, node.icon.component));
  106. $.each(node.icon.classes, function(index, className) {
  107. icon.addClass(className);
  108. });
  109. eleToAddIcon.prepend(icon);
  110. } else {
  111. if (node.icon.component == 'moodle') {
  112. node.icon.component = 'core';
  113. }
  114. Templates.renderPix(node.icon.pix, node.icon.component, node.icon.title).then(function(html) {
  115. // Prepend.
  116. eleToAddIcon.prepend(html);
  117. return;
  118. }).catch(Notification.exception);
  119. }
  120. }
  121. li.append(p);
  122. ul.append(li);
  123. if (node.children && node.children.length) {
  124. buildDOM(li, node.children);
  125. } else if (isBranch && !node.requiresajaxloading) {
  126. li.removeClass('contains_branch');
  127. p.addClass('emptybranch');
  128. }
  129. });
  130. rootElement.append(ul);
  131. var id = rootElement.attr('id') + '_group';
  132. ul.attr('id', id);
  133. rootElement.attr('aria-owns', id);
  134. rootElement.attr('role', 'treeitem');
  135. }
  136. return {
  137. render: function(element, nodes) {
  138. // The first element of the response is the existing node so we start with processing the children.
  139. if (nodes.children && nodes.children.length) {
  140. buildDOM(element, nodes.children);
  141. var item = element.children("[role='treeitem']").first();
  142. var group = element.find('#' + item.attr('aria-owns'));
  143. item.attr('aria-expanded', true);
  144. Aria.unhide(group);
  145. } else {
  146. if (element.hasClass('contains_branch')) {
  147. element.removeClass('contains_branch');
  148. element.addClass('emptybranch');
  149. }
  150. }
  151. }
  152. };
  153. });