[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 /** 17 * Encapsules the behavior for creating a tool type and tool proxy from a 18 * registration url in Moodle. 19 * 20 * Manages the UI while operations are occuring, including rendering external 21 * registration page within the iframe. 22 * 23 * See template: mod_lti/external_registration 24 * 25 * @module mod_lti/external_registration 26 * @class external_registration 27 * @package mod_lti 28 * @copyright 2015 Ryan Wyllie <ryan@moodle.com> 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 * @since 3.1 31 */ 32 define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/events', 33 'mod_lti/tool_proxy', 'mod_lti/tool_type', 'mod_lti/keys', 'core/str'], 34 function($, ajax, notification, templates, ltiEvents, toolProxy, toolType, KEYS, str) { 35 36 var SELECTORS = { 37 EXTERNAL_REGISTRATION_CONTAINER: '#external-registration-page-container', 38 EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER: '#external-registration-template-container', 39 EXTERNAL_REGISTRATION_CANCEL_BUTTON: '#cancel-external-registration', 40 TOOL_TYPE_CAPABILITIES_CONTAINER: '#tool-type-capabilities-container', 41 TOOL_TYPE_CAPABILITIES_TEMPLATE_CONTAINER: '#tool-type-capabilities-template-container', 42 CAPABILITIES_AGREE_CONTAINER: '.capabilities-container', 43 }; 44 45 /** 46 * Return the external registration cancel button element. This button is 47 * the cancel button that appears while the iframe is rendered. 48 * 49 * @method getExternalRegistrationCancelButton 50 * @private 51 * @return {JQuery} jQuery object 52 */ 53 var getExternalRegistrationCancelButton = function() { 54 return $(SELECTORS.EXTERNAL_REGISTRATION_CANCEL_BUTTON); 55 }; 56 57 /** 58 * Return the container that holds all elements for the external registration, including 59 * the cancel button and the iframe. 60 * 61 * @method getExternalRegistrationContainer 62 * @private 63 * @return {JQuery} jQuery object 64 */ 65 var getExternalRegistrationContainer = function() { 66 return $(SELECTORS.EXTERNAL_REGISTRATION_CONTAINER); 67 }; 68 69 /** 70 * Return the container that holds the external registration page template. It should 71 * be the iframe. 72 * 73 * @method getExternalRegistrationTemplateContainer 74 * @private 75 * @return {JQuery} jQuery object 76 */ 77 var getExternalRegistrationTemplateContainer = function() { 78 return $(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER); 79 }; 80 81 /** 82 * Return the container that holds the elements for displaying the list of capabilities 83 * that this tool type requires. This container wraps the loading indicator and the template 84 * container. 85 * 86 * @method getToolTypeCapabilitiesContainer 87 * @private 88 * @return {JQuery} jQuery object 89 */ 90 var getToolTypeCapabilitiesContainer = function() { 91 return $(SELECTORS.TOOL_TYPE_CAPABILITIES_CONTAINER); 92 }; 93 94 /** 95 * Return the container that holds the template that lists the capabilities that the 96 * tool type will require. 97 * 98 * @method getToolTypeCapabilitiesTemplateContainer 99 * @private 100 * @return {JQuery} jQuery object 101 */ 102 var getToolTypeCapabilitiesTemplateContainer = function() { 103 return $(SELECTORS.TOOL_TYPE_CAPABILITIES_TEMPLATE_CONTAINER); 104 }; 105 106 /** 107 * Triggers a visual indicator to show that the capabilities section is loading. 108 * 109 * @method startLoadingCapabilitiesContainer 110 * @private 111 */ 112 var startLoadingCapabilitiesContainer = function() { 113 getToolTypeCapabilitiesContainer().addClass('loading'); 114 }; 115 116 /** 117 * Removes the visual indicator that shows the capabilities section is loading. 118 * 119 * @method stopLoadingCapabilitiesContainer 120 * @private 121 */ 122 var stopLoadingCapabilitiesContainer = function() { 123 getToolTypeCapabilitiesContainer().removeClass('loading'); 124 }; 125 126 /** 127 * Adds a visual indicator that shows the cancel button is loading. 128 * 129 * @method startLoadingCancel 130 * @private 131 */ 132 var startLoadingCancel = function() { 133 getExternalRegistrationCancelButton().addClass('loading'); 134 }; 135 136 /** 137 * Adds a visual indicator that shows the cancel button is loading. 138 * 139 * @method startLoadingCancel 140 * @private 141 */ 142 var stopLoadingCancel = function() { 143 getExternalRegistrationCancelButton().removeClass('loading'); 144 }; 145 146 /** 147 * Stops displaying the tool type capabilities container. 148 * 149 * @method hideToolTypeCapabilitiesContainer 150 * @private 151 */ 152 var hideToolTypeCapabilitiesContainer = function() { 153 getToolTypeCapabilitiesContainer().addClass('hidden'); 154 }; 155 156 /** 157 * Displays the tool type capabilities container. 158 * 159 * @method showToolTypeCapabilitiesContainer 160 * @private 161 */ 162 var showToolTypeCapabilitiesContainer = function() { 163 getToolTypeCapabilitiesContainer().removeClass('hidden'); 164 }; 165 166 /** 167 * Stops displaying the external registration content. 168 * 169 * @method hideExternalRegistrationContent 170 * @private 171 */ 172 var hideExternalRegistrationContent = function() { 173 getExternalRegistrationContainer().addClass('hidden'); 174 }; 175 176 /** 177 * Displays the external registration content. 178 * 179 * @method showExternalRegistrationContent 180 * @private 181 */ 182 var showExternalRegistrationContent = function() { 183 getExternalRegistrationContainer().removeClass('hidden'); 184 }; 185 186 /** 187 * Save the given tool proxy id on the DOM. 188 * 189 * @method setToolProxyId 190 * @private 191 * @param {Integer} id Tool proxy ID 192 */ 193 var setToolProxyId = function(id) { 194 var button = getExternalRegistrationCancelButton(); 195 button.attr('data-tool-proxy-id', id); 196 }; 197 198 /** 199 * Return the saved tool proxy id. 200 * 201 * @method getToolProxyId 202 * @private 203 * @return {String} Tool proxy ID 204 */ 205 var getToolProxyId = function() { 206 var button = getExternalRegistrationCancelButton(); 207 return button.attr('data-tool-proxy-id'); 208 }; 209 210 /** 211 * Remove the saved tool proxy id. 212 * 213 * @method clearToolProxyId 214 * @private 215 */ 216 var clearToolProxyId = function() { 217 var button = getExternalRegistrationCancelButton(); 218 button.removeAttr('data-tool-proxy-id'); 219 }; 220 221 /** 222 * Returns true if a tool proxy id has been recorded. 223 * 224 * @method hasToolProxyId 225 * @private 226 * @return {Boolean} 227 */ 228 var hasToolProxyId = function() { 229 return getToolProxyId() ? true : false; 230 }; 231 232 /** 233 * Checks if this process has created a tool proxy within 234 * Moodle yet. 235 * 236 * @method hasCreatedToolProxy 237 * @private 238 * @return {Boolean} 239 */ 240 var hasCreatedToolProxy = function() { 241 var button = getExternalRegistrationCancelButton(); 242 return button.attr('data-tool-proxy-new') && hasToolProxyId(); 243 }; 244 245 /** 246 * Records that this process has created a tool proxy. 247 * 248 * @method setProxyAsNew 249 * @private 250 * @return {Boolean} 251 */ 252 var setProxyAsNew = function() { 253 var button = getExternalRegistrationCancelButton(); 254 return button.attr('data-tool-proxy-new', "new"); 255 }; 256 257 /** 258 * Records that this process has not created a tool proxy. 259 * 260 * @method setProxyAsOld 261 * @private 262 * @return {Boolean} 263 */ 264 var setProxyAsOld = function() { 265 var button = getExternalRegistrationCancelButton(); 266 return button.removeAttr('data-tool-proxy-new'); 267 }; 268 269 /** 270 * Gets the external registration request required to be sent to the external 271 * registration page using a form. 272 * 273 * See mod_lti/tool_proxy_registration_form template. 274 * 275 * @method getRegistrationRequest 276 * @private 277 * @param {Integer} id Tool Proxy ID 278 * @return {Promise} jQuery Deferred object 279 */ 280 var getRegistrationRequest = function(id) { 281 var request = { 282 methodname: 'mod_lti_get_tool_proxy_registration_request', 283 args: { 284 id: id 285 } 286 }; 287 288 return ajax.call([request])[0]; 289 }; 290 291 /** 292 * Cancel an in progress external registration. This will perform any necessary 293 * clean up of tool proxies and return the page section back to the home section. 294 * 295 * @method cancelRegistration 296 * @private 297 * @return {Promise} jQuery Deferred object 298 */ 299 var cancelRegistration = function() { 300 startLoadingCancel(); 301 var promise = $.Deferred(); 302 303 // If we've created a proxy as part of this process then 304 // we need to delete it to clean up the data in the back end. 305 if (hasCreatedToolProxy()) { 306 var id = getToolProxyId(); 307 toolProxy.delete(id).done(function() { 308 promise.resolve(); 309 }).fail(function(failure) { 310 promise.reject(failure); 311 }); 312 } else { 313 promise.resolve(); 314 } 315 316 promise.done(function() { 317 // Return to the original page. 318 finishExternalRegistration(); 319 stopLoadingCancel(); 320 }).fail(function(failure) { 321 notification.exception(failure); 322 finishExternalRegistration(); 323 stopLoadingCancel(); 324 str.get_string('failedtodeletetoolproxy', 'mod_lti').done(function(s) { 325 var feedback = { 326 message: s, 327 error: true 328 }; 329 $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback); 330 }).fail(notification.exception); 331 }); 332 333 return promise; 334 }; 335 336 /** 337 * Load the external registration template and render it in the DOM and display it. 338 * 339 * @method renderExternalRegistrationWindow 340 * @private 341 * @param {Object} registrationRequest 342 * @return {Promise} jQuery Deferred object 343 */ 344 var renderExternalRegistrationWindow = function(registrationRequest) { 345 var promise = templates.render('mod_lti/tool_proxy_registration_form', registrationRequest); 346 347 promise.done(function(html, js) { 348 // Show the external registration page in an iframe. 349 var container = getExternalRegistrationTemplateContainer(); 350 container.append(html); 351 templates.runTemplateJS(js); 352 353 container.find('form').submit(); 354 showExternalRegistrationContent(); 355 }).fail(notification.exception); 356 357 return promise; 358 }; 359 360 /** 361 * Send a request to Moodle server to set the state of the tool type to configured (active). 362 * 363 * @method setTypeStatusActive 364 * @private 365 * @param {Object} typeData A set of data representing a type, as returned by a request to get a type 366 * from the Moodle server. 367 * @return {Promise} jQuery Deferred object 368 */ 369 var setTypeStatusActive = function(typeData) { 370 return toolType.update({ 371 id: typeData.id, 372 state: toolType.constants.state.configured 373 }); 374 }; 375 376 /** 377 * Render and display an agreement page for the user to acknowledge the list of capabilities 378 * (groups of data) that the external tool requires in order to work. If the user agrees then 379 * we will activate the tool so that it is immediately available. If they don't agree then 380 * the tool remains in a pending state within Moodle until agreement is given. 381 * 382 * @method promptForToolTypeCapabilitiesAgreement 383 * @private 384 * @param {Object} typeData A set of data representing a type, as returned by a request to get a type 385 * from the Moodle server. 386 * @return {Promise} jQuery Deferred object 387 */ 388 var promptForToolTypeCapabilitiesAgreement = function(typeData) { 389 var promise = $.Deferred(); 390 391 templates.render('mod_lti/tool_type_capabilities_agree', typeData).done(function(html, js) { 392 var container = getToolTypeCapabilitiesTemplateContainer(); 393 394 hideExternalRegistrationContent(); 395 showToolTypeCapabilitiesContainer(); 396 397 templates.replaceNodeContents(container, html, js); 398 399 var choiceContainer = container.find(SELECTORS.CAPABILITIES_AGREE_CONTAINER); 400 401 // The user agrees to allow the tool to use the groups of data so we can go 402 // ahead and activate it for them so that it can be used straight away. 403 choiceContainer.on(ltiEvents.CAPABILITIES_AGREE, function() { 404 startLoadingCapabilitiesContainer(); 405 setTypeStatusActive(typeData).always(function() { 406 stopLoadingCapabilitiesContainer(); 407 container.empty(); 408 promise.resolve(); 409 }); 410 }); 411 412 // The user declines to let the tool use the data. In this case we leave 413 // the tool as pending and they can delete it using the main screen if they 414 // wish. 415 choiceContainer.on(ltiEvents.CAPABILITIES_DECLINE, function() { 416 container.empty(); 417 promise.resolve(); 418 }); 419 }).fail(promise.reject); 420 421 promise.done(function() { 422 hideToolTypeCapabilitiesContainer(); 423 }).fail(notification.exception); 424 425 return promise; 426 }; 427 428 /** 429 * Send a request to the Moodle server to create a tool proxy using the registration URL the user 430 * has provided. The proxy is required for the external registration page to work correctly. 431 * 432 * After the proxy is created the external registration page is rendered within an iframe for the user 433 * to complete the registration in the external page. 434 * 435 * If the tool proxy creation fails then we redirect the page section back to the home section and 436 * display the error, rather than rendering the external registration page. 437 * 438 * @method createAndRegisterToolProxy 439 * @private 440 * @param {String} url Tool registration URL to register 441 * @return {Promise} jQuery Deferred object 442 */ 443 var createAndRegisterToolProxy = function(url) { 444 var promise = $.Deferred(); 445 446 if (!url || url === "") { 447 // No URL has been input so do nothing. 448 promise.resolve(); 449 } else { 450 // A tool proxy needs to exist before the external page is rendered because 451 // the external page sends requests back to Moodle for information that is stored 452 // in the proxy. 453 toolProxy.create({regurl: url}) 454 .done(function(result) { 455 // Note that it's a new proxy so we will always clean it up. 456 setProxyAsNew(); 457 promise = registerProxy(result.id); 458 }) 459 .fail(function(exception) { 460 // Clean up. 461 cancelRegistration(); 462 // Let the user know what the error is. 463 var feedback = { 464 message: exception.message, 465 error: true 466 }; 467 $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback); 468 promise.reject(exception); 469 }); 470 } 471 472 return promise; 473 }; 474 475 /** 476 * Loads the window to register a proxy, given an ID. 477 * 478 * @method registerProxy 479 * @private 480 * @param {Integer} id Proxy id to register 481 * @return {Promise} jQuery Deferred object to fail or resolve 482 */ 483 var registerProxy = function(id) { 484 var promise = $.Deferred(); 485 // Save the id on the DOM to cleanup later. 486 setToolProxyId(id); 487 488 // There is a specific set of data needed to send to the external registration page 489 // in a form, so let's get it from our server. 490 getRegistrationRequest(id) 491 .done(function(registrationRequest) { 492 renderExternalRegistrationWindow(registrationRequest) 493 .done(function() { 494 promise.resolve(); 495 }) 496 .fail(promise.fail); 497 }) 498 .fail(promise.fail); 499 500 return promise; 501 }; 502 503 /** 504 * Complete the registration process, clean up any left over data and 505 * trigger the appropriate events. 506 * 507 * @method finishExternalRegistration 508 * @private 509 */ 510 var finishExternalRegistration = function() { 511 if (hasToolProxyId()) { 512 clearToolProxyId(); 513 } 514 setProxyAsOld(false); 515 516 hideExternalRegistrationContent(); 517 var container = getExternalRegistrationTemplateContainer(); 518 container.empty(); 519 520 $(document).trigger(ltiEvents.STOP_EXTERNAL_REGISTRATION); 521 }; 522 523 /** 524 * Sets up the listeners for user interaction on the page. 525 * 526 * @method registerEventListeners 527 * @private 528 */ 529 var registerEventListeners = function() { 530 531 $(document).on(ltiEvents.START_EXTERNAL_REGISTRATION, function(event, data) { 532 if (!data) { 533 return; 534 } 535 if (data.url) { 536 createAndRegisterToolProxy(data.url); 537 } 538 if (data.proxyid) { 539 registerProxy(data.proxyid); 540 } 541 }); 542 543 var cancelExternalRegistrationButton = getExternalRegistrationCancelButton(); 544 cancelExternalRegistrationButton.click(function(e) { 545 e.preventDefault(); 546 cancelRegistration(); 547 }); 548 cancelExternalRegistrationButton.keypress(function(e) { 549 if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { 550 if (e.keyCode == KEYS.ENTER || e.keyCode == KEYS.SPACE) { 551 e.preventDefault(); 552 cancelRegistration(); 553 } 554 } 555 }); 556 557 // This is gross but necessary due to isolated jQuery scopes between 558 // child iframe and parent windows. There is no other way to communicate. 559 // 560 // This function gets called by the moodle page that received the redirect 561 // from the external registration page and handles the external page's returned 562 // parameters. 563 // 564 // See AMD module mod_lti/external_registration_return. 565 window.triggerExternalRegistrationComplete = function(data) { 566 var promise = $.Deferred(); 567 var feedback = { 568 message: "", 569 error: false 570 }; 571 572 if (data.status == "success") { 573 str.get_string('successfullycreatedtooltype', 'mod_lti').done(function(s) { 574 feedback.message = s; 575 }).fail(notification.exception); 576 577 // Trigger appropriate events when we've completed the necessary requests. 578 promise.done(function() { 579 finishExternalRegistration(); 580 $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback); 581 $(document).trigger(ltiEvents.NEW_TOOL_TYPE); 582 }).fail(notification.exception); 583 584 // We should have created a tool proxy by this point. 585 if (hasCreatedToolProxy()) { 586 var proxyId = getToolProxyId(); 587 588 // We need the list of types that are linked to this proxy. We're assuming it'll 589 // only be one because this process creates a one-to-one type->proxy. 590 toolType.getFromToolProxyId(proxyId).done(function(types) { 591 if (types && types.length) { 592 // There should only be one result. 593 var typeData = types[0]; 594 595 // Check if the external tool required access to any Moodle data (users, courses etc). 596 if (typeData.hascapabilitygroups) { 597 // If it did then we ask the user to agree to those groups before the type is 598 // activated (i.e. can be used in Moodle). 599 promptForToolTypeCapabilitiesAgreement(typeData).always(function() { 600 promise.resolve(); 601 }); 602 } else { 603 promise.resolve(); 604 } 605 } else { 606 promise.resolve(); 607 } 608 }).fail(function() { 609 promise.resolve(); 610 }); 611 } 612 } else { 613 // Anything other than success is failure. 614 feedback.message = data.error; 615 feedback.error = true; 616 617 // Cancel registration to clean up any proxies and tools that were 618 // created. 619 promise.done(function() { 620 cancelRegistration().always(function() { 621 $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback); 622 }); 623 }).fail(notification.exception); 624 625 promise.resolve(); 626 } 627 628 return promise; 629 }; 630 }; 631 632 return /** @alias module:mod_lti/external_registration */ { 633 634 /** 635 * Initialise this module. 636 */ 637 init: function() { 638 registerEventListeners(); 639 } 640 }; 641 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |