Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"external_registration.min.js","sources":["../src/external_registration.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Encapsules the behavior for creating a tool type and tool proxy from a\n * registration url in Moodle.\n *\n * Manages the UI while operations are occuring, including rendering external\n * registration page within the iframe.\n *\n * See template: mod_lti/external_registration\n *\n * @module     mod_lti/external_registration\n * @copyright  2015 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.1\n */\ndefine(['jquery', 'core/ajax', 'core/notification', 'core/templates', 'mod_lti/events',\n        'mod_lti/tool_proxy', 'mod_lti/tool_type', 'mod_lti/keys', 'core/str'],\n        function($, ajax, notification, templates, ltiEvents, toolProxy, toolType, KEYS, str) {\n\n    var SELECTORS = {\n        EXTERNAL_REGISTRATION_CONTAINER: '#external-registration-page-container',\n        EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER: '#external-registration-template-container',\n        EXTERNAL_REGISTRATION_CANCEL_BUTTON: '#cancel-external-registration',\n        TOOL_TYPE_CAPABILITIES_CONTAINER: '#tool-type-capabilities-container',\n        TOOL_TYPE_CAPABILITIES_TEMPLATE_CONTAINER: '#tool-type-capabilities-template-container',\n        CAPABILITIES_AGREE_CONTAINER: '.capabilities-container',\n    };\n\n    /**\n     * Return the external registration cancel button element. This button is\n     * the cancel button that appears while the iframe is rendered.\n     *\n     * @method getExternalRegistrationCancelButton\n     * @private\n     * @return {JQuery} jQuery object\n     */\n    var getExternalRegistrationCancelButton = function() {\n        return $(SELECTORS.EXTERNAL_REGISTRATION_CANCEL_BUTTON);\n    };\n\n    /**\n     * Return the container that holds all elements for the external registration, including\n     * the cancel button and the iframe.\n     *\n     * @method getExternalRegistrationContainer\n     * @private\n     * @return {JQuery} jQuery object\n     */\n    var getExternalRegistrationContainer = function() {\n        return $(SELECTORS.EXTERNAL_REGISTRATION_CONTAINER);\n    };\n\n    /**\n     * Return the container that holds the external registration page template. It should\n     * be the iframe.\n     *\n     * @method getExternalRegistrationTemplateContainer\n     * @private\n     * @return {JQuery} jQuery object\n     */\n    var getExternalRegistrationTemplateContainer = function() {\n        return $(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER);\n    };\n\n    /**\n     * Return the container that holds the elements for displaying the list of capabilities\n     * that this tool type requires. This container wraps the loading indicator and the template\n     * container.\n     *\n     * @method getToolTypeCapabilitiesContainer\n     * @private\n     * @return {JQuery} jQuery object\n     */\n    var getToolTypeCapabilitiesContainer = function() {\n        return $(SELECTORS.TOOL_TYPE_CAPABILITIES_CONTAINER);\n    };\n\n    /**\n     * Return the container that holds the template that lists the capabilities that the\n     * tool type will require.\n     *\n     * @method getToolTypeCapabilitiesTemplateContainer\n     * @private\n     * @return {JQuery} jQuery object\n     */\n    var getToolTypeCapabilitiesTemplateContainer = function() {\n        return $(SELECTORS.TOOL_TYPE_CAPABILITIES_TEMPLATE_CONTAINER);\n    };\n\n    /**\n     * Triggers a visual indicator to show that the capabilities section is loading.\n     *\n     * @method startLoadingCapabilitiesContainer\n     * @private\n     */\n    var startLoadingCapabilitiesContainer = function() {\n        getToolTypeCapabilitiesContainer().addClass('loading');\n    };\n\n    /**\n     * Removes the visual indicator that shows the capabilities section is loading.\n     *\n     * @method stopLoadingCapabilitiesContainer\n     * @private\n     */\n    var stopLoadingCapabilitiesContainer = function() {\n        getToolTypeCapabilitiesContainer().removeClass('loading');\n    };\n\n    /**\n     * Adds a visual indicator that shows the cancel button is loading.\n     *\n     * @method startLoadingCancel\n     * @private\n     */\n    var startLoadingCancel = function() {\n        getExternalRegistrationCancelButton().addClass('loading');\n    };\n\n    /**\n     * Adds a visual indicator that shows the cancel button is loading.\n     *\n     * @method startLoadingCancel\n     * @private\n     */\n    var stopLoadingCancel = function() {\n        getExternalRegistrationCancelButton().removeClass('loading');\n    };\n\n    /**\n     * Stops displaying the tool type capabilities container.\n     *\n     * @method hideToolTypeCapabilitiesContainer\n     * @private\n     */\n    var hideToolTypeCapabilitiesContainer = function() {\n        getToolTypeCapabilitiesContainer().addClass('hidden');\n    };\n\n    /**\n     * Displays the tool type capabilities container.\n     *\n     * @method showToolTypeCapabilitiesContainer\n     * @private\n     */\n    var showToolTypeCapabilitiesContainer = function() {\n        getToolTypeCapabilitiesContainer().removeClass('hidden');\n    };\n\n    /**\n     * Stops displaying the external registration content.\n     *\n     * @method hideExternalRegistrationContent\n     * @private\n     */\n    var hideExternalRegistrationContent = function() {\n        getExternalRegistrationContainer().addClass('hidden');\n    };\n\n    /**\n     * Displays the external registration content.\n     *\n     * @method showExternalRegistrationContent\n     * @private\n     */\n    var showExternalRegistrationContent = function() {\n        getExternalRegistrationContainer().removeClass('hidden');\n    };\n\n    /**\n     * Save the given tool proxy id on the DOM.\n     *\n     * @method setToolProxyId\n     * @private\n     * @param {Integer} id Tool proxy ID\n     */\n    var setToolProxyId = function(id) {\n        var button = getExternalRegistrationCancelButton();\n        button.attr('data-tool-proxy-id', id);\n    };\n\n    /**\n     * Return the saved tool proxy id.\n     *\n     * @method getToolProxyId\n     * @private\n     * @return {String} Tool proxy ID\n     */\n    var getToolProxyId = function() {\n        var button = getExternalRegistrationCancelButton();\n        return button.attr('data-tool-proxy-id');\n    };\n\n    /**\n     * Remove the saved tool proxy id.\n     *\n     * @method clearToolProxyId\n     * @private\n     */\n    var clearToolProxyId = function() {\n        var button = getExternalRegistrationCancelButton();\n        button.removeAttr('data-tool-proxy-id');\n    };\n\n    /**\n     * Returns true if a tool proxy id has been recorded.\n     *\n     * @method hasToolProxyId\n     * @private\n     * @return {Boolean}\n     */\n    var hasToolProxyId = function() {\n        return getToolProxyId() ? true : false;\n    };\n\n    /**\n     * Checks if this process has created a tool proxy within\n     * Moodle yet.\n     *\n     * @method hasCreatedToolProxy\n     * @private\n     * @return {Boolean}\n     */\n    var hasCreatedToolProxy = function() {\n        var button = getExternalRegistrationCancelButton();\n        return button.attr('data-tool-proxy-new') && hasToolProxyId();\n    };\n\n    /**\n     * Records that this process has created a tool proxy.\n     *\n     * @method setProxyAsNew\n     * @private\n     * @return {Boolean}\n     */\n    var setProxyAsNew = function() {\n        var button = getExternalRegistrationCancelButton();\n        return button.attr('data-tool-proxy-new', \"new\");\n    };\n\n    /**\n     * Records that this process has not created a tool proxy.\n     *\n     * @method setProxyAsOld\n     * @private\n     * @return {Boolean}\n     */\n    var setProxyAsOld = function() {\n        var button = getExternalRegistrationCancelButton();\n        return button.removeAttr('data-tool-proxy-new');\n    };\n\n    /**\n     * Gets the external registration request required to be sent to the external\n     * registration page using a form.\n     *\n     * See mod_lti/tool_proxy_registration_form template.\n     *\n     * @method getRegistrationRequest\n     * @private\n     * @param {Integer} id Tool Proxy ID\n     * @return {Promise} jQuery Deferred object\n     */\n    var getRegistrationRequest = function(id) {\n        var request = {\n            methodname: 'mod_lti_get_tool_proxy_registration_request',\n            args: {\n                id: id\n            }\n        };\n\n        return ajax.call([request])[0];\n    };\n\n    /**\n     * Cancel an in progress external registration. This will perform any necessary\n     * clean up of tool proxies and return the page section back to the home section.\n     *\n     * @method cancelRegistration\n     * @private\n     * @return {Promise} jQuery Deferred object\n     */\n    var cancelRegistration = function() {\n        startLoadingCancel();\n        var promise = $.Deferred();\n\n        // If we've created a proxy as part of this process then\n        // we need to delete it to clean up the data in the back end.\n        if (hasCreatedToolProxy()) {\n            var id = getToolProxyId();\n            toolProxy.delete(id).done(function() {\n                promise.resolve();\n            }).fail(function(failure) {\n                promise.reject(failure);\n            });\n        } else {\n            promise.resolve();\n        }\n\n        promise.done(function() {\n            // Return to the original page.\n            finishExternalRegistration();\n            stopLoadingCancel();\n        }).fail(function(failure) {\n            notification.exception(failure);\n            finishExternalRegistration();\n            stopLoadingCancel();\n            str.get_string('failedtodeletetoolproxy', 'mod_lti').done(function(s) {\n                var feedback = {\n                    message: s,\n                    error: true\n                };\n                $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback);\n            }).fail(notification.exception);\n        });\n\n        return promise;\n    };\n\n    /**\n     * Load the external registration template and render it in the DOM and display it.\n     *\n     * @method renderExternalRegistrationWindow\n     * @private\n     * @param {Object} registrationRequest\n     * @return {Promise} jQuery Deferred object\n     */\n    var renderExternalRegistrationWindow = function(registrationRequest) {\n        var promise = templates.render('mod_lti/tool_proxy_registration_form', registrationRequest);\n\n        promise.done(function(html, js) {\n            // Show the external registration page in an iframe.\n            var container = getExternalRegistrationTemplateContainer();\n            container.append(html);\n            templates.runTemplateJS(js);\n\n            container.find('form').submit();\n            showExternalRegistrationContent();\n        }).fail(notification.exception);\n\n        return promise;\n    };\n\n    /**\n     * Send a request to Moodle server to set the state of the tool type to configured (active).\n     *\n     * @method setTypeStatusActive\n     * @private\n     * @param {Object} typeData A set of data representing a type, as returned by a request to get a type\n     *               from the Moodle server.\n     * @return {Promise} jQuery Deferred object\n     */\n    var setTypeStatusActive = function(typeData) {\n        return toolType.update({\n            id: typeData.id,\n            state: toolType.constants.state.configured\n        });\n    };\n\n    /**\n     * Render and display an agreement page for the user to acknowledge the list of capabilities\n     * (groups of data) that the external tool requires in order to work. If the user agrees then\n     * we will activate the tool so that it is immediately available. If they don't agree then\n     * the tool remains in a pending state within Moodle until agreement is given.\n     *\n     * @method promptForToolTypeCapabilitiesAgreement\n     * @private\n     * @param {Object} typeData A set of data representing a type, as returned by a request to get a type\n     *               from the Moodle server.\n     * @return {Promise} jQuery Deferred object\n     */\n    var promptForToolTypeCapabilitiesAgreement = function(typeData) {\n        var promise = $.Deferred();\n\n        templates.render('mod_lti/tool_type_capabilities_agree', typeData).done(function(html, js) {\n            var container = getToolTypeCapabilitiesTemplateContainer();\n\n            hideExternalRegistrationContent();\n            showToolTypeCapabilitiesContainer();\n\n            templates.replaceNodeContents(container, html, js);\n\n            var choiceContainer = container.find(SELECTORS.CAPABILITIES_AGREE_CONTAINER);\n\n            // The user agrees to allow the tool to use the groups of data so we can go\n            // ahead and activate it for them so that it can be used straight away.\n            choiceContainer.on(ltiEvents.CAPABILITIES_AGREE, function() {\n                startLoadingCapabilitiesContainer();\n                setTypeStatusActive(typeData).always(function() {\n                    stopLoadingCapabilitiesContainer();\n                    container.empty();\n                    promise.resolve();\n                });\n            });\n\n            // The user declines to let the tool use the data. In this case we leave\n            // the tool as pending and they can delete it using the main screen if they\n            // wish.\n            choiceContainer.on(ltiEvents.CAPABILITIES_DECLINE, function() {\n                container.empty();\n                promise.resolve();\n            });\n        }).fail(promise.reject);\n\n        promise.done(function() {\n            hideToolTypeCapabilitiesContainer();\n        }).fail(notification.exception);\n\n        return promise;\n    };\n\n    /**\n     * Send a request to the Moodle server to create a tool proxy using the registration URL the user\n     * has provided. The proxy is required for the external registration page to work correctly.\n     *\n     * After the proxy is created the external registration page is rendered within an iframe for the user\n     * to complete the registration in the external page.\n     *\n     * If the tool proxy creation fails then we redirect the page section back to the home section and\n     * display the error, rather than rendering the external registration page.\n     *\n     * @method createAndRegisterToolProxy\n     * @private\n     * @param {String} url Tool registration URL to register\n     * @return {Promise} jQuery Deferred object\n     */\n    var createAndRegisterToolProxy = function(url) {\n        var promise = $.Deferred();\n\n        if (!url || url === \"\") {\n            // No URL has been input so do nothing.\n            promise.resolve();\n        } else {\n            // A tool proxy needs to exist before the external page is rendered because\n            // the external page sends requests back to Moodle for information that is stored\n            // in the proxy.\n            toolProxy.create({regurl: url})\n                .done(function(result) {\n                        // Note that it's a new proxy so we will always clean it up.\n                        setProxyAsNew();\n                        promise = registerProxy(result.id);\n                    })\n                .fail(function(exception) {\n                        // Clean up.\n                        cancelRegistration();\n                        // Let the user know what the error is.\n                        var feedback = {\n                            message: exception.message,\n                            error: true\n                        };\n                        $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback);\n                        promise.reject(exception);\n                    });\n        }\n\n        return promise;\n    };\n\n    /**\n     * Loads the window to register a proxy, given an ID.\n     *\n     * @method registerProxy\n     * @private\n     * @param {Integer} id Proxy id to register\n     * @return {Promise} jQuery Deferred object to fail or resolve\n     */\n    var registerProxy = function(id) {\n        var promise = $.Deferred();\n        // Save the id on the DOM to cleanup later.\n        setToolProxyId(id);\n\n        // There is a specific set of data needed to send to the external registration page\n        // in a form, so let's get it from our server.\n        getRegistrationRequest(id)\n            .done(function(registrationRequest) {\n                    renderExternalRegistrationWindow(registrationRequest)\n                        .done(function() {\n                                promise.resolve();\n                            })\n                        .fail(promise.fail);\n                })\n            .fail(promise.fail);\n\n        return promise;\n    };\n\n    /**\n     * Complete the registration process, clean up any left over data and\n     * trigger the appropriate events.\n     *\n     * @method finishExternalRegistration\n     * @private\n     */\n    var finishExternalRegistration = function() {\n        if (hasToolProxyId()) {\n            clearToolProxyId();\n        }\n        setProxyAsOld(false);\n\n        hideExternalRegistrationContent();\n        var container = getExternalRegistrationTemplateContainer();\n        container.empty();\n\n        $(document).trigger(ltiEvents.STOP_EXTERNAL_REGISTRATION);\n    };\n\n    /**\n     * Sets up the listeners for user interaction on the page.\n     *\n     * @method registerEventListeners\n     * @private\n     */\n    var registerEventListeners = function() {\n\n        $(document).on(ltiEvents.START_EXTERNAL_REGISTRATION, function(event, data) {\n                if (!data) {\n                    return;\n                }\n                if (data.url) {\n                    createAndRegisterToolProxy(data.url);\n                }\n                if (data.proxyid) {\n                    registerProxy(data.proxyid);\n                }\n            });\n\n        var cancelExternalRegistrationButton = getExternalRegistrationCancelButton();\n        cancelExternalRegistrationButton.click(function(e) {\n            e.preventDefault();\n            cancelRegistration();\n        });\n        cancelExternalRegistrationButton.keypress(function(e) {\n            if (!e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey) {\n                if (e.keyCode == KEYS.ENTER || e.keyCode == KEYS.SPACE) {\n                    e.preventDefault();\n                    cancelRegistration();\n                }\n            }\n        });\n\n        // This is gross but necessary due to isolated jQuery scopes between\n        // child iframe and parent windows. There is no other way to communicate.\n        //\n        // This function gets called by the moodle page that received the redirect\n        // from the external registration page and handles the external page's returned\n        // parameters.\n        //\n        // See AMD module mod_lti/external_registration_return.\n        window.triggerExternalRegistrationComplete = function(data) {\n            var promise = $.Deferred();\n            var feedback = {\n                message: \"\",\n                error: false\n            };\n\n            if (data.status == \"success\") {\n                str.get_string('successfullycreatedtooltype', 'mod_lti').done(function(s) {\n                    feedback.message = s;\n                }).fail(notification.exception);\n\n                // Trigger appropriate events when we've completed the necessary requests.\n                promise.done(function() {\n                    finishExternalRegistration();\n                    $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback);\n                    $(document).trigger(ltiEvents.NEW_TOOL_TYPE);\n                }).fail(notification.exception);\n\n                // We should have created a tool proxy by this point.\n                if (hasCreatedToolProxy()) {\n                    var proxyId = getToolProxyId();\n\n                    // We need the list of types that are linked to this proxy. We're assuming it'll\n                    // only be one because this process creates a one-to-one type->proxy.\n                    toolType.getFromToolProxyId(proxyId).done(function(types) {\n                        if (types && types.length) {\n                            // There should only be one result.\n                            var typeData = types[0];\n\n                            // Check if the external tool required access to any Moodle data (users, courses etc).\n                            if (typeData.hascapabilitygroups) {\n                                // If it did then we ask the user to agree to those groups before the type is\n                                // activated (i.e. can be used in Moodle).\n                                promptForToolTypeCapabilitiesAgreement(typeData).always(function() {\n                                    promise.resolve();\n                                });\n                            } else {\n                                promise.resolve();\n                            }\n                        } else {\n                            promise.resolve();\n                        }\n                    }).fail(function() {\n                        promise.resolve();\n                    });\n                }\n            } else {\n                // Anything other than success is failure.\n                feedback.message = data.error;\n                feedback.error = true;\n\n                // Cancel registration to clean up any proxies and tools that were\n                // created.\n                promise.done(function() {\n                    cancelRegistration().always(function() {\n                        $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, feedback);\n                    });\n                }).fail(notification.exception);\n\n                promise.resolve();\n            }\n\n            return promise;\n        };\n    };\n\n    return {\n\n        /**\n         * Initialise this module.\n         */\n        init: function() {\n            registerEventListeners();\n        }\n    };\n});\n"],"names":["define","$","ajax","notification","templates","ltiEvents","toolProxy","toolType","KEYS","str","SELECTORS","getExternalRegistrationCancelButton","getExternalRegistrationContainer","getExternalRegistrationTemplateContainer","getToolTypeCapabilitiesContainer","stopLoadingCancel","removeClass","hideExternalRegistrationContent","addClass","getToolProxyId","attr","hasToolProxyId","hasCreatedToolProxy","cancelRegistration","promise","Deferred","id","delete","done","resolve","fail","failure","reject","finishExternalRegistration","exception","get_string","s","feedback","message","error","document","trigger","REGISTRATION_FEEDBACK","renderExternalRegistrationWindow","registrationRequest","render","html","js","container","append","runTemplateJS","find","submit","promptForToolTypeCapabilitiesAgreement","typeData","replaceNodeContents","choiceContainer","on","CAPABILITIES_AGREE","update","state","constants","configured","setTypeStatusActive","always","empty","CAPABILITIES_DECLINE","createAndRegisterToolProxy","url","create","regurl","result","registerProxy","setToolProxyId","request","methodname","args","call","getRegistrationRequest","removeAttr","STOP_EXTERNAL_REGISTRATION","init","START_EXTERNAL_REGISTRATION","event","data","proxyid","cancelExternalRegistrationButton","click","e","preventDefault","keypress","metaKey","shiftKey","altKey","ctrlKey","keyCode","ENTER","SPACE","window","triggerExternalRegistrationComplete","status","NEW_TOOL_TYPE","proxyId","getFromToolProxyId","types","length","hascapabilitygroups","registerEventListeners"],"mappings":"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"}