Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions www/addons/remotestyles/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,35 @@ angular.module('mm.addons.remotestyles', [])

.constant('mmaRemoteStylesComponent', 'mmaRemoteStyles')

.config(function($mmInitDelegateProvider, mmInitDelegateMaxAddonPriority) {
// Addons shouldn't use a priority higher than mmInitDelegateMaxAddonPriority, but this is a special case
// because it needs to be done before the mmLogin process.
$mmInitDelegateProvider.registerProcess('mmaRemoteStylesCurrent',
'$mmaRemoteStyles._preloadCurrentSite', mmInitDelegateMaxAddonPriority + 250, true);
$mmInitDelegateProvider.registerProcess('mmaRemoteStylesPreload', '$mmaRemoteStyles._preloadSites');
})

.run(function($mmEvents, mmCoreEventLogin, mmCoreEventLogout, mmCoreEventSiteAdded, mmCoreEventSiteUpdated, $mmaRemoteStyles,
$mmSite) {
$mmSite, mmCoreEventSiteDeleted) {

$mmEvents.on(mmCoreEventSiteAdded, $mmaRemoteStyles.load);
$mmEvents.on(mmCoreEventSiteUpdated, function(siteid) {
$mmEvents.on(mmCoreEventSiteAdded, function(siteId) {
$mmaRemoteStyles.addSite(siteId);
});
$mmEvents.on(mmCoreEventSiteUpdated, function(siteId) {
// Load only if current site was updated.
if (siteid === $mmSite.getId()) {
$mmaRemoteStyles.load();
if (siteId === $mmSite.getId()) {
$mmaRemoteStyles.load(siteId);
}
});
$mmEvents.on(mmCoreEventLogin, $mmaRemoteStyles.load);

// Remove added styles on logout.
// Enable styles of current site on login.
$mmEvents.on(mmCoreEventLogin, $mmaRemoteStyles.enable);

// Disable added styles on logout.
$mmEvents.on(mmCoreEventLogout, $mmaRemoteStyles.clear);

// Remove site styles on logout.
$mmEvents.on(mmCoreEventSiteDeleted, function(site) {
$mmaRemoteStyles.removeSite(site.id);
});
});
244 changes: 208 additions & 36 deletions www/addons/remotestyles/services/remotestyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,36 @@ angular.module('mm.addons.remotestyles')
* @name $mmaRemoteStyles
*/
.factory('$mmaRemoteStyles', function($log, $q, $mmSite, $mmSitesManager, $mmFilepool, $http, $mmFS, mmaRemoteStylesComponent,
mmCoreNotDownloaded) {
mmCoreNotDownloaded, $mmUtil, md5) {

$log = $log.getInstance('$mmaRemoteStyles');

var self = {},
remoteStylesEl = angular.element(document.querySelector('#mobilecssurl'));
remoteStylesEls = {};

/**
* Add a style element for a site and load the styles for that element. The style will be disabled.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#addSite
* @param {String} siteId Site ID.
* @return {Promise} Promise resolved when added and loaded.
*/
self.addSite = function(siteId) {
if (!siteId || remoteStylesEls[siteId]) {
return $q.when();
}

var el = angular.element('<style id="mobilecssurl-' + siteId + '" disabled="disabled"></style>');
angular.element(document.head).append(el);
remoteStylesEls[siteId] = {
element: el,
hash: ''
};

return self.load(siteId, true);
};

/**
* Clear remote styles added to the DOM.
Expand All @@ -37,7 +61,47 @@ angular.module('mm.addons.remotestyles')
* @name $mmaRemoteStyles#clear
*/
self.clear = function() {
remoteStylesEl.html('');
// Disable all the styles.
angular.element(document.querySelectorAll('style[id*=mobilecssurl]')).attr('disabled', true);
};

/**
* Downloads a CSS file and remove old files if needed.
*
* @param {String} siteId Site ID.
* @param {String} url File URL.
* @return {Promise} Promise resolved when the file is downloaded.
*/
function downloadFileAndRemoveOld(siteId, url) {
return $mmFilepool.getFileStateByUrl(siteId, url).then(function(state) {
return state !== mmCoreNotDownloaded;
}).catch(function() {
return true; // An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
}).then(function(isDownloaded) {
if (!isDownloaded) {
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
return $mmFilepool.removeFilesByComponent(siteId, mmaRemoteStylesComponent, 1);
}
}).then(function() {
return $mmFilepool.downloadUrl(siteId, url, false, mmaRemoteStylesComponent, 1);
});
}

/**
* Enable the styles of a certain site.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#addSite
* @param {String} [siteId] Site ID. If not defined, current site.
* @return {Void}
*/
self.enable = function(siteId) {
siteId = siteId || $mmSite.getId();

if (remoteStylesEls[siteId]) {
remoteStylesEls[siteId].element.attr('disabled', false);
}
};

/**
Expand All @@ -46,47 +110,33 @@ angular.module('mm.addons.remotestyles')
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#get
* @param {String} siteid Site ID.
* @return {Promise} Promise resolved with the styles.
* @param {String} [siteId] Site ID. If not defined, current site.
* @return {Promise} Promise resolved with the styles and the URL of the loaded CSS file (local if downloaded).
*/
self.get = function(siteid) {
var promise;
self.get = function(siteId) {
var fileUrl;

siteid = siteid || $mmSite.getId();
if (!siteid) {
siteId = siteId || $mmSite.getId();
if (!siteId) {
return $q.reject();
}

// Downloads a CSS file and remove old files if needed.
function downloadFileAndRemoveOld(url) {
return $mmFilepool.getFileStateByUrl(siteid, url).then(function(state) {
return state !== mmCoreNotDownloaded;
}).catch(function() {
return true; // An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
}).then(function(isDownloaded) {
if (!isDownloaded) {
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
return $mmFilepool.removeFilesByComponent(siteid, mmaRemoteStylesComponent, 1);
}
}).then(function() {
return $mmFilepool.downloadUrl(siteid, url, false, mmaRemoteStylesComponent, 1);
});
}

return $mmSitesManager.getSite(siteid).then(function(site) {
return $mmSitesManager.getSite(siteId).then(function(site) {
var infos = site.getInfo();
if (infos && infos.mobilecssurl) {
fileUrl = infos.mobilecssurl;

if ($mmFS.isAvailable()) {
// The file system is available. Download the file and remove old CSS files if needed.
return downloadFileAndRemoveOld(infos.mobilecssurl);
return downloadFileAndRemoveOld(siteId, infos.mobilecssurl);
} else {
// We return the online URL. We're probably on browser.
return infos.mobilecssurl;
}
} else {
if (infos.mobilecssurl === '') {
// CSS URL is empty. Delete downloaded files (if any).
$mmFilepool.removeFilesByComponent(siteid, mmaRemoteStylesComponent, 1)
$mmFilepool.removeFilesByComponent(siteId, mmaRemoteStylesComponent, 1);
}
return $q.reject();
}
Expand All @@ -95,30 +145,152 @@ angular.module('mm.addons.remotestyles')
return $http.get(url);
}).then(function(response) {
if (typeof response.data == 'string') {
return response.data;
return {file: fileUrl, styles: response.data};
} else {
return $q.reject();
}
});
};

/**
* Load styles for current site.
* Load styles for a certain site.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#load
* @param {String} [siteId] Site ID. If not defined, current site.
* @param {Boolean} disabled True if loaded styles should be disabled, false if they should be enabled.
* @return {Promise} Promise resolved when styles are loaded.
*/
self.load = function() {
var siteid = $mmSite.getId();
if (siteid) {
self.get(siteid).then(function(styles) {
if (siteid === $mmSite.getId()) { // Make sure it hasn't logout while retrieving styles.
remoteStylesEl.html(styles);
self.load = function(siteId, disabled) {
siteId = siteId || $mmSite.getId();
disabled = !!disabled;

$log.debug('Load site: ', siteId, disabled);
if (siteId && remoteStylesEls[siteId]) {
// Enable or disable the styles.
remoteStylesEls[siteId].element.attr('disabled', disabled);

return self.get(siteId).then(function(data) {
var hash = md5.createHash(data.styles);

// Update the styles only if they have changed.
if (remoteStylesEls[siteId].hash !== hash) {
remoteStylesEls[siteId].element.html(data.styles);
remoteStylesEls[siteId].hash = hash;

// New styles will be applied even if the style is disabled. We'll disable it again if needed.
if (disabled && remoteStylesEls[siteId].element.attr('disabled') == 'disabled') {
remoteStylesEls[siteId].element.attr('disabled', true);
}
}

// Styles have been loaded, now treat the CSS.
treatCSSCode(siteId, data.file, data.styles);
});
}

return $q.reject();
};

/**
* Preload the styles of the current site (stored in DB). Please do not use.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#_preloadCurrentSite
* @return {Promise} Promise resolved when loaded.
* @protected
*/
self._preloadCurrentSite = function() {
return $mmSitesManager.getStoredCurrentSiteId().then(function(siteId) {
return self.addSite(siteId);
});
};

/**
* Preload the styles of all the stored sites. Please do not use.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#_preloadSites
* @return {Promise} Promise resolved when loaded.
* @protected
*/
self._preloadSites = function() {
return $mmSitesManager.getSitesIds().then(function(ids) {
var promises = [];
angular.forEach(ids, function(siteId) {
promises.push(self.addSite(siteId));
});
return $q.all(promises);
});
};

/**
* Remove the styles of a certain site.
*
* @module mm.addons.remotestyles
* @ngdoc method
* @name $mmaRemoteStyles#removeSite
* @param {String} siteId Site ID.
* @return {Void}
*/
self.removeSite = function(siteId) {
if (siteId && remoteStylesEls[siteId]) {
remoteStylesEls[siteId].element.remove();
delete remoteStylesEls[siteId];
}
};

/**
* Search for files in a CSS code and try to download them. Once downloaded, replace their URLs
* and store the result in the CSS file.
*
* @param {String} siteId Site ID.
* @param {String} fileUrl CSS file URL.
* @param {String} cssCode CSS code.
* @return {Promise} Promise resolved with the CSS code.
*/
function treatCSSCode(siteId, fileUrl, cssCode) {
if (!$mmFS.isAvailable()) {
return $q.reject();
}

var urls = $mmUtil.extractUrlsFromCSS(cssCode),
promises = [],
filePath,
updated = false;

// Get the path of the CSS file.
promises.push($mmFilepool.getFilePathByUrl(siteId, fileUrl).then(function(path) {
filePath = path;
}));

angular.forEach(urls, function(url) {
// Download the file only if it's an online URL.
if (url.indexOf('http') == 0) {
promises.push($mmFilepool.downloadUrl(siteId, url, false, mmaRemoteStylesComponent, 2).then(function(fileUrl) {
if (fileUrl != url) {
cssCode = cssCode.replace(new RegExp(url, 'g'), fileUrl);
updated = true;
}
}).catch(function(error) {
// It shouldn't happen. Ignore errors.
$log.warn('MMRMSTYLES Error treating file ', url, error);
}));
}
});

return $q.all(promises).then(function() {
// All files downloaded. Store the result if it has changed.
if (updated) {
return $mmFS.writeFile(filePath, cssCode);
}
}).then(function() {
return cssCode;
});
}

return self;
});
16 changes: 15 additions & 1 deletion www/core/lib/sitesmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ angular.module('mm.core')
currentSite = candidateSite;
// Store session.
self.login(siteid);
$mmEvents.trigger(mmCoreEventSiteAdded);
$mmEvents.trigger(mmCoreEventSiteAdded, siteid);
} else {
return $translate(validation.error, validation.params).then(function(error) {
return $q.reject(error);
Expand Down Expand Up @@ -723,6 +723,20 @@ angular.module('mm.core')
});
};

/**
* Get the site ID stored in DB ad current site.
*
* @module mm.core
* @ngdoc method
* @name $mmSitesManager#getStoredCurrentSiteId
* @return {Promise} Promise resolved with the site ID.
*/
self.getStoredCurrentSiteId = function() {
return $mmApp.getDB().get(mmCoreCurrentSiteStore, 1).then(function(current_site) {
return current_site.siteid;
});
};

return self;

});
Loading