lib/amd/src/fragment.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. * A way to call HTML fragments to be inserted as required via JavaScript.
  17. *
  18. * @module core/fragment
  19. * @copyright 2016 Adrian Greeve <adrian@moodle.com>
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. * @since 3.1
  22. */
  23. define(['jquery', 'core/ajax'], function($, ajax) {
  24. /**
  25. * Loads an HTML fragment through a callback.
  26. *
  27. * @method loadFragment
  28. * @param {string} component Component where callback is located.
  29. * @param {string} callback Callback function name.
  30. * @param {integer} contextid Context ID of the fragment.
  31. * @param {object} params Parameters for the callback.
  32. * @return {Promise} JQuery promise object resolved when the fragment has been loaded.
  33. */
  34. var loadFragment = function(component, callback, contextid, params) {
  35. // Change params into required webservice format.
  36. var formattedparams = [];
  37. for (var index in params) {
  38. formattedparams.push({
  39. name: index,
  40. value: params[index]
  41. });
  42. }
  43. return ajax.call([{
  44. methodname: 'core_get_fragment',
  45. args: {
  46. component: component,
  47. callback: callback,
  48. contextid: contextid,
  49. args: formattedparams
  50. }
  51. }])[0];
  52. };
  53. /**
  54. * Converts the JS that was received from collecting JS requirements on the $PAGE so it can be added to the existing page
  55. *
  56. * @param {string} js
  57. * @return {string}
  58. */
  59. var processCollectedJavascript = function(js) {
  60. var jsNodes = $(js);
  61. var allScript = '';
  62. jsNodes.each(function(index, scriptNode) {
  63. scriptNode = $(scriptNode);
  64. var tagName = scriptNode.prop('tagName');
  65. if (tagName && (tagName.toLowerCase() == 'script')) {
  66. if (scriptNode.attr('src')) {
  67. // We only reload the script if it was not loaded already.
  68. var exists = false;
  69. $('script').each(function(index, s) {
  70. if ($(s).attr('src') == scriptNode.attr('src')) {
  71. exists = true;
  72. }
  73. return !exists;
  74. });
  75. if (!exists) {
  76. allScript += ' { ';
  77. allScript += ' node = document.createElement("script"); ';
  78. allScript += ' node.type = "text/javascript"; ';
  79. allScript += ' node.src = decodeURI("' + encodeURI(scriptNode.attr('src')) + '"); ';
  80. allScript += ' document.getElementsByTagName("head")[0].appendChild(node); ';
  81. allScript += ' } ';
  82. }
  83. } else {
  84. allScript += ' ' + scriptNode.text();
  85. }
  86. }
  87. });
  88. return allScript;
  89. };
  90. return {
  91. /**
  92. * Appends HTML and JavaScript fragments to specified nodes.
  93. * Callbacks called by this AMD module are responsible for doing the appropriate security checks
  94. * to access the information that is returned. This only does minimal validation on the context.
  95. *
  96. * @method fragmentAppend
  97. * @param {string} component Component where callback is located.
  98. * @param {string} callback Callback function name.
  99. * @param {integer} contextid Context ID of the fragment.
  100. * @param {object} params Parameters for the callback.
  101. * @return {Deferred} new promise that is resolved with the html and js.
  102. */
  103. loadFragment: function(component, callback, contextid, params) {
  104. var promise = $.Deferred();
  105. loadFragment(component, callback, contextid, params).then(function(data) {
  106. promise.resolve(data.html, processCollectedJavascript(data.javascript));
  107. }).fail(function(ex) {
  108. promise.reject(ex);
  109. });
  110. return promise.promise();
  111. },
  112. /**
  113. * Converts the JS that was received from collecting JS requirements on the $PAGE so it can be added to the existing page
  114. *
  115. * @param {string} js
  116. * @return {string}
  117. */
  118. processCollectedJavascript: function(js) {
  119. return processCollectedJavascript(js);
  120. }
  121. };
  122. });