diff --git a/src/assets/js/iframe-recaptcha.js b/src/assets/js/iframe-recaptcha.js new file mode 100644 index 000000000..f1ff5e843 --- /dev/null +++ b/src/assets/js/iframe-recaptcha.js @@ -0,0 +1,42 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +(function () { + var url = location.href; + + if (!url.match(/^https?:\/\//i) || !url.match(/\/webservice\/recaptcha\.php/i)) { + // Not the recaptcha script, stop. + return; + } + + // Define recaptcha callbacks. + window.recaptchacallback = function(value) { + window.parent.postMessage({ + environment: 'moodleapp', + context: 'recaptcha', + action: 'callback', + frameUrl: location.href, + value: value, + }, '*'); + }; + + window.recaptchaexpiredcallback = function() { + window.parent.postMessage({ + environment: 'moodleapp', + context: 'recaptcha', + action: 'expired', + frameUrl: location.href, + }, '*'); + }; +})(); \ No newline at end of file diff --git a/src/assets/js/iframe-treat-links.js b/src/assets/js/iframe-treat-links.js new file mode 100644 index 000000000..c585c96fe --- /dev/null +++ b/src/assets/js/iframe-treat-links.js @@ -0,0 +1,210 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +(function () { + var url = location.href; + + if (url.match(/^moodleappfs:\/\/localhost/i) || !url.match(/^[a-z0-9]+:\/\//i)) { + // Same domain as the app, stop. + return; + } + + // Redefine window.open. + window.open = function(url, name, specs) { + if (name == '_self') { + // Link should be loaded in the same frame. + location.href = toAbsolute(url); + + return; + } + + getRootWindow(window).postMessage({ + environment: 'moodleapp', + context: 'iframe', + action: 'window_open', + frameUrl: location.href, + url: url, + name: name, + specs: specs, + }, '*'); + }; + + // Handle link clicks. + document.addEventListener('click', (event) => { + if (event.defaultPrevented) { + // Event already prevented by some other code. + return; + } + + // Find the link being clicked. + var el = event.target; + while (el && (el.tagName !== 'A' && el.tagName !== 'a')) { + el = el.parentElement; + } + + if (!el || el.treated) { + return; + } + + // Add click listener to the link, this way if the iframe has added a listener to the link it will be executed first. + el.treated = true; + el.addEventListener('click', function(event) { + linkClicked(el, event); + }); + }, { + capture: true // Use capture to fix this listener not called if the element clicked is too deep in the DOM. + }); + + + + /** + * Concatenate two paths, adding a slash between them if needed. + * + * @param leftPath Left path. + * @param rightPath Right path. + * @return Concatenated path. + */ + function concatenatePaths(leftPath, rightPath) { + if (!leftPath) { + return rightPath; + } else if (!rightPath) { + return leftPath; + } + + var lastCharLeft = leftPath.slice(-1); + var firstCharRight = rightPath.charAt(0); + + if (lastCharLeft === '/' && firstCharRight === '/') { + return leftPath + rightPath.substr(1); + } else if (lastCharLeft !== '/' && firstCharRight !== '/') { + return leftPath + '/' + rightPath; + } else { + return leftPath + rightPath; + } + } + + /** + * Get the root window. + * + * @param win Current window to check. + * @return Root window. + */ + function getRootWindow(win) { + if (win.parent === win) { + return win; + } + + return getRootWindow(win.parent); + } + + /** + * Get the scheme from a URL. + * + * @param url URL to treat. + * @return Scheme, undefined if no scheme found. + */ + function getUrlScheme(url) { + if (!url) { + return; + } + + var matches = url.match(/^([a-z][a-z0-9+\-.]*):/); + if (matches && matches[1]) { + return matches[1]; + } + } + + /** + * Check if a URL is absolute. + * + * @param url URL to treat. + * @return Whether it's absolute. + */ + function isAbsoluteUrl(url) { + return /^[^:]{2,}:\/\//i.test(url); + } + + /** + * Check whether a URL scheme belongs to a local file. + * + * @param scheme Scheme to check. + * @return Whether the scheme belongs to a local file. + */ + function isLocalFileUrlScheme(scheme) { + if (scheme) { + scheme = scheme.toLowerCase(); + } + + return scheme == 'cdvfile' || + scheme == 'file' || + scheme == 'filesystem' || + scheme == 'moodleappfs'; + } + + /** + * Handle a click on an anchor element. + * + * @param link Anchor element clicked. + * @param event Click event. + */ + function linkClicked(link, event) { + if (event.defaultPrevented) { + // Event already prevented by some other code. + return; + } + + var linkScheme = getUrlScheme(link.href); + var pageScheme = getUrlScheme(location.href); + var isTargetSelf = !link.target || link.target == '_self'; + + if (!link.href || linkScheme == 'javascript') { + // Links with no URL and Javascript links are ignored. + return; + } + + event.preventDefault(); + + if (isTargetSelf && (isLocalFileUrlScheme(linkScheme) || !isLocalFileUrlScheme(pageScheme))) { + // Link should be loaded in the same frame. Don't do it if link is online and frame is local. + location.href = toAbsolute(link.href); + + return; + } + + getRootWindow(window).postMessage({ + environment: 'moodleapp', + context: 'iframe', + action: 'link_clicked', + frameUrl: location.href, + link: {href: link.href, target: link.target}, + }, '*'); + } + + /** + * Convert a URL to an absolute URL if needed using the frame src. + * + * @param url URL to convert. + * @return Absolute URL. + */ + function toAbsolute(url) { + if (isAbsoluteUrl(url)) { + return url; + } + + // It's a relative URL, use the frame src to create the full URL. + var pathToDir = location.href.substring(0, location.href.lastIndexOf('/')); + + return concatenatePaths(pathToDir, url); + } +})(); \ No newline at end of file