[ 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 * Controls all of the behaviour and interaction with a tool type card. These are 18 * listed on the LTI tool type management page. 19 * 20 * See template: mod_lti/tool_card 21 * 22 * @module mod_lti/tool_card_controller 23 * @class tool_card_controller 24 * @package mod_lti 25 * @copyright 2015 Ryan Wyllie <ryan@moodle.com> 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 * @since 3.1 28 */ 29 define(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/tool_type', 'mod_lti/events', 'mod_lti/keys', 30 'core/str'], 31 function($, ajax, notification, templates, toolType, ltiEvents, KEYS, str) { 32 33 var SELECTORS = { 34 DELETE_BUTTON: '.delete', 35 NAME_ELEMENT: '.name', 36 DESCRIPTION_ELEMENT: '.description', 37 CAPABILITIES_CONTAINER: '.capabilities-container', 38 ACTIVATE_BUTTON: '.tool-card-footer a.activate', 39 }; 40 41 // Timeout in seconds. 42 var ANNOUNCEMENT_TIMEOUT = 2000; 43 44 /** 45 * Return the delete button element. 46 * 47 * @method getDeleteButton 48 * @private 49 * @param {JQuery} element jQuery object representing the tool card. 50 * @return {JQuery} jQuery object 51 */ 52 var getDeleteButton = function(element) { 53 return element.find(SELECTORS.DELETE_BUTTON); 54 }; 55 56 /** 57 * Return the element representing the tool type name. 58 * 59 * @method getNameElement 60 * @private 61 * @param {JQuery} element jQuery object representing the tool card. 62 * @return {JQuery} jQuery object 63 */ 64 var getNameElement = function(element) { 65 return element.find(SELECTORS.NAME_ELEMENT); 66 }; 67 68 /** 69 * Return the element representing the tool type description. 70 * 71 * @method getDescriptionElement 72 * @private 73 * @param {JQuery} element jQuery object representing the tool card. 74 * @return {JQuery} jQuery object 75 */ 76 var getDescriptionElement = function(element) { 77 return element.find(SELECTORS.DESCRIPTION_ELEMENT); 78 }; 79 80 /** 81 * Return the activate button for the type. 82 * 83 * @method getActivateButton 84 * @private 85 * @param {Object} element jQuery object representing the tool card. 86 * @return {Object} jQuery object 87 */ 88 var getActivateButton = function(element) { 89 return element.find(SELECTORS.ACTIVATE_BUTTON); 90 }; 91 92 /** 93 * Checks if the type card has an activate button. 94 * 95 * @method hasActivateButton 96 * @private 97 * @param {JQuery} element jQuery object representing the tool card. 98 * @return {Boolean} true if has active buton 99 */ 100 var hasActivateButton = function(element) { 101 return getActivateButton(element).length ? true : false; 102 }; 103 104 /** 105 * Return the element that contains the capabilities approval for 106 * the user. 107 * 108 * @method getCapabilitiesContainer 109 * @private 110 * @param {Object} element jQuery object representing the tool card. 111 * @return {Object} The element 112 */ 113 var getCapabilitiesContainer = function(element) { 114 return element.find(SELECTORS.CAPABILITIES_CONTAINER); 115 }; 116 117 /** 118 * Checks if the tool type has capabilities that need approval. If it 119 * does then the container will be present. 120 * 121 * @method hasCapabilitiesContainer 122 * @private 123 * @param {JQuery} element jQuery object representing the tool card. 124 * @return {Boolean} true if has capbilities. 125 */ 126 var hasCapabilitiesContainer = function(element) { 127 return getCapabilitiesContainer(element).length ? true : false; 128 }; 129 130 /** 131 * Get the type id. 132 * 133 * @method getTypeId 134 * @private 135 * @param {Object} element jQuery object representing the tool card. 136 * @return {String} Type ID 137 */ 138 var getTypeId = function(element) { 139 return element.attr('data-type-id'); 140 }; 141 142 /** 143 * Stop any announcement currently visible on the card. 144 * 145 * @method clearAllAnnouncements 146 * @private 147 * @param {JQuery} element jQuery object representing the tool card. 148 */ 149 var clearAllAnnouncements = function(element) { 150 element.removeClass('announcement loading success fail capabilities'); 151 }; 152 153 /** 154 * Show the loading announcement. 155 * 156 * @method startLoading 157 * @private 158 * @param {JQuery} element jQuery object representing the tool card. 159 */ 160 var startLoading = function(element) { 161 clearAllAnnouncements(element); 162 element.addClass('announcement loading'); 163 }; 164 165 /** 166 * Hide the loading announcement. 167 * 168 * @method stopLoading 169 * @private 170 * @param {JQuery} element jQuery object representing the tool card. 171 */ 172 var stopLoading = function(element) { 173 element.removeClass('announcement loading'); 174 }; 175 176 /** 177 * Show the success announcement. The announcement is only 178 * visible for 2 seconds. 179 * 180 * @method announceSuccess 181 * @private 182 * @param {JQuery} element jQuery object representing the tool card. 183 * @return {Promise} jQuery Deferred object 184 */ 185 var announceSuccess = function(element) { 186 var promise = $.Deferred(); 187 188 clearAllAnnouncements(element); 189 element.addClass('announcement success'); 190 setTimeout(function() { 191 element.removeClass('announcement success'); 192 promise.resolve(); 193 }, ANNOUNCEMENT_TIMEOUT); 194 195 return promise; 196 }; 197 198 /** 199 * Show the failure announcement. The announcement is only 200 * visible for 2 seconds. 201 * 202 * @method announceFailure 203 * @private 204 * @param {JQuery} element jQuery object representing the tool card. 205 * @return {Promise} jQuery Deferred object 206 */ 207 var announceFailure = function(element) { 208 var promise = $.Deferred(); 209 210 clearAllAnnouncements(element); 211 element.addClass('announcement fail'); 212 setTimeout(function() { 213 element.removeClass('announcement fail'); 214 promise.resolve(); 215 }, ANNOUNCEMENT_TIMEOUT); 216 217 return promise; 218 }; 219 220 /** 221 * Delete the tool type from the Moodle server. Triggers a success 222 * or failure announcement depending on the result. 223 * 224 * @method deleteType 225 * @private 226 * @param {JQuery} element jQuery object representing the tool card. 227 * @return {Promise} jQuery Deferred object 228 */ 229 var deleteType = function(element) { 230 var promise = $.Deferred(); 231 var typeId = getTypeId(element); 232 startLoading(element); 233 234 if (typeId === "") { 235 return $.Deferred().resolve(); 236 } 237 238 str.get_strings([ 239 { 240 key: 'delete', 241 component: 'mod_lti' 242 }, 243 { 244 key: 'delete_confirmation', 245 component: 'mod_lti' 246 }, 247 { 248 key: 'delete', 249 component: 'mod_lti' 250 }, 251 { 252 key: 'cancel', 253 component: 'core' 254 }, 255 ]) 256 .done(function(strs) { 257 notification.confirm(strs[0], strs[1], strs[2], strs[3], function() { 258 toolType.delete(typeId) 259 .done(function() { 260 stopLoading(element); 261 announceSuccess(element) 262 .done(function() { 263 element.remove(); 264 }) 265 .fail(notification.exception) 266 .always(function() { 267 // Always resolve because even if the announcement fails the type was deleted. 268 promise.resolve(); 269 }); 270 }) 271 .fail(function(error) { 272 announceFailure(element); 273 promise.reject(error); 274 }); 275 }, function() { 276 stopLoading(element); 277 promise.resolve(); 278 }); 279 }) 280 .fail(function(error) { 281 stopLoading(element); 282 notification.exception(error); 283 promise.reject(error); 284 }); 285 286 return promise; 287 }; 288 289 /** 290 * Save a given value in a data attribute on the element. 291 * 292 * @method setValueSnapshot 293 * @private 294 * @param {JQuery} element jQuery object representing the element. 295 * @param {String} value to be saved. 296 */ 297 var setValueSnapshot = function(element, value) { 298 element.attr('data-val-snapshot', value); 299 }; 300 301 /** 302 * Return the saved value from the element. 303 * 304 * @method getValueSnapshot 305 * @private 306 * @param {JQuery} element jQuery object representing the element. 307 * @return {String} the saved value. 308 */ 309 var getValueSnapshot = function(element) { 310 return element.attr('data-val-snapshot'); 311 }; 312 313 /** 314 * Save the current value of the tool description. 315 * 316 * @method snapshotDescription 317 * @private 318 * @param {JQuery} element jQuery object representing the tool card. 319 */ 320 var snapshotDescription = function(element) { 321 var descriptionElement = getDescriptionElement(element); 322 323 if (descriptionElement.hasClass('loading')) { 324 return; 325 } 326 327 var description = descriptionElement.text().trim(); 328 setValueSnapshot(descriptionElement, description); 329 }; 330 331 /** 332 * Send a request to update the description value for this tool 333 * in the Moodle server. 334 * 335 * @method updateDescription 336 * @private 337 * @param {JQuery} element jQuery object representing the tool card. 338 * @return {Promise} jQuery Deferred object 339 */ 340 var updateDescription = function(element) { 341 var typeId = getTypeId(element); 342 343 // Return early if we don't have an id because it's 344 // required to save the changes. 345 if (typeId === "") { 346 return $.Deferred().resolve(); 347 } 348 349 var descriptionElement = getDescriptionElement(element); 350 351 // Return early if we're already saving a value. 352 if (descriptionElement.hasClass('loading')) { 353 return $.Deferred().resolve(); 354 } 355 356 var description = descriptionElement.text().trim(); 357 var snapshotVal = getValueSnapshot(descriptionElement); 358 359 // If the value hasn't change then don't bother sending the 360 // update request. 361 if (snapshotVal == description) { 362 return $.Deferred().resolve(); 363 } 364 365 descriptionElement.addClass('loading'); 366 367 var promise = toolType.update({id: typeId, description: description}); 368 369 promise.done(function(type) { 370 descriptionElement.removeClass('loading'); 371 // Make sure the text is updated with the description from the 372 // server, just in case the update didn't work. 373 descriptionElement.text(type.description); 374 }).fail(notification.exception); 375 376 // Probably need to handle failures better so that we can revert 377 // the value in the input for the user. 378 promise.fail(function() { 379 descriptionElement.removeClass('loading'); 380 }); 381 382 return promise; 383 }; 384 385 /** 386 * Save the current value of the tool name. 387 * 388 * @method snapshotName 389 * @private 390 * @param {JQuery} element jQuery object representing the tool card. 391 */ 392 var snapshotName = function(element) { 393 var nameElement = getNameElement(element); 394 395 if (nameElement.hasClass('loading')) { 396 return; 397 } 398 399 var name = nameElement.text().trim(); 400 setValueSnapshot(nameElement, name); 401 }; 402 403 /** 404 * Send a request to update the name value for this tool 405 * in the Moodle server. 406 * 407 * @method updateName 408 * @private 409 * @param {JQuery} element jQuery object representing the tool card. 410 * @return {Promise} jQuery Deferred object 411 */ 412 var updateName = function(element) { 413 var typeId = getTypeId(element); 414 415 // Return if we don't have an id. 416 if (typeId === "") { 417 return $.Deferred().resolve(); 418 } 419 420 var nameElement = getNameElement(element); 421 422 // Return if we're already saving. 423 if (nameElement.hasClass('loading')) { 424 return $.Deferred().resolve(); 425 } 426 427 var name = nameElement.text().trim(); 428 var snapshotVal = getValueSnapshot(nameElement); 429 430 // If the value hasn't change then don't bother sending the 431 // update request. 432 if (snapshotVal == name) { 433 return $.Deferred().resolve(); 434 } 435 436 nameElement.addClass('loading'); 437 var promise = toolType.update({id: typeId, name: name}); 438 439 promise.done(function(type) { 440 nameElement.removeClass('loading'); 441 // Make sure the text is updated with the name from the 442 // server, just in case the update didn't work. 443 nameElement.text(type.name); 444 }); 445 446 // Probably need to handle failures better so that we can revert 447 // the value in the input for the user. 448 promise.fail(function() { 449 nameElement.removeClass('loading'); 450 }); 451 452 return promise; 453 }; 454 455 /** 456 * Send a request to update the state for this tool to be configured (active) 457 * in the Moodle server. A success or failure announcement is triggered depending 458 * on the result. 459 * 460 * @method setStatusActive 461 * @private 462 * @param {JQuery} element jQuery object representing the tool card. 463 * @return {Promise} jQuery Deferred object 464 */ 465 var setStatusActive = function(element) { 466 var id = getTypeId(element); 467 468 // Return if we don't have an id. 469 if (id === "") { 470 return $.Deferred().resolve(); 471 } 472 473 startLoading(element); 474 475 var promise = toolType.update({ 476 id: id, 477 state: toolType.constants.state.configured 478 }); 479 480 promise.done(function(toolTypeData) { 481 stopLoading(element); 482 483 var announcePromise = announceSuccess(element); 484 var renderPromise = templates.render('mod_lti/tool_card', toolTypeData); 485 486 $.when(renderPromise, announcePromise).then(function(renderResult) { 487 var html = renderResult[0]; 488 var js = renderResult[1]; 489 490 templates.replaceNode(element, html, js); 491 }); 492 }); 493 494 promise.fail(function() { 495 stopLoading(element); 496 announceFailure(element); 497 }); 498 499 return promise; 500 }; 501 502 /** 503 * Show the capabilities approval screen to show which groups of data this 504 * type requires access to in Moodle (if any). 505 * 506 * @method displayCapabilitiesApproval 507 * @private 508 * @param {JQuery} element jQuery object representing the tool card. 509 */ 510 var displayCapabilitiesApproval = function(element) { 511 element.addClass('announcement capabilities'); 512 }; 513 514 /** 515 * Hide the capabilities approval screen. 516 * 517 * @method hideCapabilitiesApproval 518 * @private 519 * @param {JQuery} element jQuery object representing the tool card. 520 */ 521 var hideCapabilitiesApproval = function(element) { 522 element.removeClass('announcement capabilities'); 523 }; 524 525 /** 526 * The user wishes to activate this tool so show them the capabilities that 527 * they need to agree to or if there are none then set the tool type's state 528 * to active. 529 * 530 * @method activateToolType 531 * @private 532 * @param {JQuery} element jQuery object representing the tool card. 533 */ 534 var activateToolType = function(element) { 535 if (hasCapabilitiesContainer(element)) { 536 displayCapabilitiesApproval(element); 537 } else { 538 setStatusActive(element); 539 } 540 }; 541 542 /** 543 * Sets up the listeners for user interaction on this tool type card. 544 * 545 * @method registerEventListeners 546 * @private 547 * @param {JQuery} element jQuery object representing the tool card. 548 */ 549 var registerEventListeners = function(element) { 550 var deleteButton = getDeleteButton(element); 551 deleteButton.click(function(e) { 552 e.preventDefault(); 553 deleteType(element); 554 }); 555 deleteButton.keypress(function(e) { 556 if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { 557 if (e.keyCode == KEYS.ENTER || e.keyCode == KEYS.SPACE) { 558 e.preventDefault(); 559 deleteButton.click(); 560 } 561 } 562 }); 563 564 var descriptionElement = getDescriptionElement(element); 565 descriptionElement.focus(function(e) { 566 e.preventDefault(); 567 // Save a copy of the current value for the description so that 568 // we can check if the user has changed it before sending a request to 569 // the server. 570 snapshotDescription(element); 571 }); 572 descriptionElement.blur(function(e) { 573 e.preventDefault(); 574 updateDescription(element); 575 }); 576 descriptionElement.keypress(function(e) { 577 if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { 578 if (e.keyCode == KEYS.ENTER) { 579 e.preventDefault(); 580 descriptionElement.blur(); 581 } 582 } 583 }); 584 585 var nameElement = getNameElement(element); 586 nameElement.focus(function(e) { 587 e.preventDefault(); 588 // Save a copy of the current value for the name so that 589 // we can check if the user has changed it before sending a request to 590 // the server. 591 snapshotName(element); 592 }); 593 nameElement.blur(function(e) { 594 e.preventDefault(); 595 updateName(element); 596 }); 597 nameElement.keypress(function(e) { 598 if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { 599 if (e.keyCode == KEYS.ENTER) { 600 e.preventDefault(); 601 nameElement.blur(); 602 } 603 } 604 }); 605 606 // Only pending tool type cards have an activate button. 607 if (hasActivateButton(element)) { 608 var activateButton = getActivateButton(element); 609 activateButton.click(function(e) { 610 e.preventDefault(); 611 activateToolType(element); 612 }); 613 activateButton.keypress(function(e) { 614 if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) { 615 if (e.keyCode == KEYS.ENTER || e.keyCode == KEYS.SPACE) { 616 e.preventDefault(); 617 activateButton.click(); 618 } 619 } 620 }); 621 } 622 623 if (hasCapabilitiesContainer(element)) { 624 var capabilitiesContainer = getCapabilitiesContainer(element); 625 626 capabilitiesContainer.on(ltiEvents.CAPABILITIES_AGREE, function() { 627 setStatusActive(element); 628 }); 629 630 capabilitiesContainer.on(ltiEvents.CAPABILITIES_DECLINE, function() { 631 hideCapabilitiesApproval(element); 632 }); 633 } 634 }; 635 636 return /** @alias module:mod_lti/tool_card_controller */ { 637 638 /** 639 * Initialise this module. 640 * 641 * @param {JQuery} element jQuery object representing the tool card. 642 */ 643 init: function(element) { 644 registerEventListeners(element); 645 } 646 }; 647 });
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 |