diff --git a/www/core/directives/external_content.js b/www/core/directives/external_content.js index 6dfeab8ec62..e805a247c63 100644 --- a/www/core/directives/external_content.js +++ b/www/core/directives/external_content.js @@ -31,34 +31,71 @@ angular.module('mm.core') * Attributes accepted: * - siteid: Reference to the site ID if different than the site the user is connected to. */ -.directive('mmExternalContent', function($log, $mmFilepool, $mmSite, $mmSitesManager, $mmUtil) { +.directive('mmExternalContent', function($log, $mmFilepool, $mmSite, $mmSitesManager, $mmUtil, $q) { $log = $log.getInstance('mmExternalContent'); + /** + * Add a new source with a certain URL. + * + * @param {Object} dom Current source element. The new source will be a sibling of this element. + * @param {String} url URL to use in the source. + */ + function addSource(dom, url) { + if (dom.tagName !== 'SOURCE') { + return; + } + + var e = document.createElement('source'); + e.setAttribute('src', url); + e.setAttribute('type', dom.getAttribute('type')); + dom.parentNode.insertBefore(e, dom); + } + + /** + * Handle external content, setting the right URL. + * + * @param {String} siteId Site ID. + * @param {Object} dom DOM element. + * @param {String} targetAttr Attribute to modify. + * @param {String} url Original URL to treat. + * @param {String} [component] Component + * @param {Number} [componentId] Component ID. + * @return {Promise} Promise resolved if the element is successfully treated. + */ function handleExternalContent(siteId, dom, targetAttr, url, component, componentId) { if (!url || !$mmUtil.isDownloadableUrl(url)) { $log.debug('Ignoring non-downloadable URL: ' + url); - return; + if (dom.tagName === 'SOURCE') { + // Restoring original src. + addSource(dom, url); + } + return $q.reject(); } // Get the webservice pluginfile URL, we ignore failures here. - $mmSitesManager.getSite(siteId).then(function(site) { + return $mmSitesManager.getSite(siteId).then(function(site) { if (!site.canDownloadFiles() && $mmUtil.isPluginFileUrl(url)) { dom.remove(); // Remove element since it'll be broken. - return; + return $q.reject(); } var fn; - if (targetAttr === 'src') { + if (targetAttr === 'src' && dom.tagName !== 'SOURCE') { fn = $mmFilepool.getSrcByUrl; } else { fn = $mmFilepool.getUrlByUrl; } - fn(siteId, url, component, componentId).then(function(finalUrl) { + return fn(siteId, url, component, componentId).then(function(finalUrl) { $log.debug('Using URL ' + finalUrl + ' for ' + url); - dom.setAttribute(targetAttr, finalUrl); + if (dom.tagName === 'SOURCE') { + // The browser does not catch changes in SRC, we need to add a new source. + addSource(dom, finalUrl); + } else { + dom.setAttribute(targetAttr, finalUrl); + } }); }); } @@ -70,20 +107,30 @@ angular.module('mm.core') }, link: function(scope, element, attrs) { var dom = element[0], + siteid = scope.siteid || $mmSite.getId(), component = attrs.component, componentId = attrs.componentId, targetAttr, - observe = false, - url; + sourceAttr, + observe = false; if (dom.tagName === 'A') { targetAttr = 'href'; + sourceAttr = 'href'; if (attrs.hasOwnProperty('ngHref')) { observe = true; } } else if (dom.tagName === 'IMG') { targetAttr = 'src'; + sourceAttr = 'src'; + if (attrs.hasOwnProperty('ngSrc')) { + observe = true; + } + + } else if (dom.tagName === 'AUDIO' || dom.tagName === 'VIDEO' || dom.tagName === 'SOURCE') { + targetAttr = 'src'; + sourceAttr = 'targetSrc'; if (attrs.hasOwnProperty('ngSrc')) { observe = true; } @@ -99,10 +146,10 @@ angular.module('mm.core') if (!url) { return; } - handleExternalContent(scope.siteid || $mmSite.getId(), dom, targetAttr, url, component, componentId); + handleExternalContent(siteid, dom, targetAttr, url, component, componentId); }); } else { - handleExternalContent(scope.siteid || $mmSite.getId(), dom, targetAttr, attrs[targetAttr], component, componentId); + handleExternalContent(siteid, dom, targetAttr, attrs[sourceAttr] || attrs[targetAttr], component, componentId); } } diff --git a/www/core/directives/formattext.js b/www/core/directives/formattext.js index 15409597b3f..cb410cb2c11 100644 --- a/www/core/directives/formattext.js +++ b/www/core/directives/formattext.js @@ -42,6 +42,27 @@ angular.module('mm.core') var extractVariableRegex = new RegExp('{{([^|]+)(|.*)?}}', 'i'), tagsToIgnore = ['AUDIO', 'VIDEO', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'A']; + /** + * Add mm-external-content and its extra attributes to a certain element. + * + * @param {Object} el DOM element to add the attributes to. + * @param {String} [component] Component. + * @param {Number} [componentId] Component ID. + * @param {String} [siteId] Site ID. + */ + function addExternalContent(el, component, componentId, siteId) { + el.setAttribute('mm-external-content', ''); + if (component) { + el.setAttribute('component', component); + if (componentId) { + el.setAttribute('component-id', componentId); + } + } + if (siteId) { + el.setAttribute('siteid', siteId); + } + } + /** * Returns the number of characters to shorten the text. If the text shouldn't be shortened, returns undefined. * @@ -80,6 +101,15 @@ angular.module('mm.core') } } + /** + * Add class to adapt media to a certain element. + * + * @param {Object} el Dom element to add the class to. + */ + function addMediaAdaptClass(el) { + angular.element(el).addClass('mm-media-adapt-width'); + } + /** * Format contents and render. * @@ -175,44 +205,21 @@ angular.module('mm.core') return $mmText.formatText(text, attrs.clean, attrs.singleline, shorten).then(function(formatted) { var el = element[0], - elWidth = el.offsetWidth || el.width || el.clientWidth; - - function addMediaAdaptClass(el) { - angular.element(el).addClass('mm-media-adapt-width'); - } - - // Convert the content into DOM. - var dom = angular.element('