Skip to content

Commit 0752e80

Browse files
committed
Merge pull request #461 from dpalou/MOBILE-1531
Mobile 1531
2 parents 86e81e4 + 98973e1 commit 0752e80

File tree

5 files changed

+273
-45
lines changed

5 files changed

+273
-45
lines changed

www/addons/remotestyles/main.js

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,35 @@ angular.module('mm.addons.remotestyles', [])
1616

1717
.constant('mmaRemoteStylesComponent', 'mmaRemoteStyles')
1818

19+
.config(function($mmInitDelegateProvider, mmInitDelegateMaxAddonPriority) {
20+
// Addons shouldn't use a priority higher than mmInitDelegateMaxAddonPriority, but this is a special case
21+
// because it needs to be done before the mmLogin process.
22+
$mmInitDelegateProvider.registerProcess('mmaRemoteStylesCurrent',
23+
'$mmaRemoteStyles._preloadCurrentSite', mmInitDelegateMaxAddonPriority + 250, true);
24+
$mmInitDelegateProvider.registerProcess('mmaRemoteStylesPreload', '$mmaRemoteStyles._preloadSites');
25+
})
26+
1927
.run(function($mmEvents, mmCoreEventLogin, mmCoreEventLogout, mmCoreEventSiteAdded, mmCoreEventSiteUpdated, $mmaRemoteStyles,
20-
$mmSite) {
28+
$mmSite, mmCoreEventSiteDeleted) {
2129

22-
$mmEvents.on(mmCoreEventSiteAdded, $mmaRemoteStyles.load);
23-
$mmEvents.on(mmCoreEventSiteUpdated, function(siteid) {
30+
$mmEvents.on(mmCoreEventSiteAdded, function(siteId) {
31+
$mmaRemoteStyles.addSite(siteId);
32+
});
33+
$mmEvents.on(mmCoreEventSiteUpdated, function(siteId) {
2434
// Load only if current site was updated.
25-
if (siteid === $mmSite.getId()) {
26-
$mmaRemoteStyles.load();
35+
if (siteId === $mmSite.getId()) {
36+
$mmaRemoteStyles.load(siteId);
2737
}
2838
});
29-
$mmEvents.on(mmCoreEventLogin, $mmaRemoteStyles.load);
3039

31-
// Remove added styles on logout.
40+
// Enable styles of current site on login.
41+
$mmEvents.on(mmCoreEventLogin, $mmaRemoteStyles.enable);
42+
43+
// Disable added styles on logout.
3244
$mmEvents.on(mmCoreEventLogout, $mmaRemoteStyles.clear);
45+
46+
// Remove site styles on logout.
47+
$mmEvents.on(mmCoreEventSiteDeleted, function(site) {
48+
$mmaRemoteStyles.removeSite(site.id);
49+
});
3350
});

www/addons/remotestyles/services/remotestyles.js

Lines changed: 208 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,36 @@ angular.module('mm.addons.remotestyles')
2222
* @name $mmaRemoteStyles
2323
*/
2424
.factory('$mmaRemoteStyles', function($log, $q, $mmSite, $mmSitesManager, $mmFilepool, $http, $mmFS, mmaRemoteStylesComponent,
25-
mmCoreNotDownloaded) {
25+
mmCoreNotDownloaded, $mmUtil, md5) {
2626

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

2929
var self = {},
30-
remoteStylesEl = angular.element(document.querySelector('#mobilecssurl'));
30+
remoteStylesEls = {};
31+
32+
/**
33+
* Add a style element for a site and load the styles for that element. The style will be disabled.
34+
*
35+
* @module mm.addons.remotestyles
36+
* @ngdoc method
37+
* @name $mmaRemoteStyles#addSite
38+
* @param {String} siteId Site ID.
39+
* @return {Promise} Promise resolved when added and loaded.
40+
*/
41+
self.addSite = function(siteId) {
42+
if (!siteId || remoteStylesEls[siteId]) {
43+
return $q.when();
44+
}
45+
46+
var el = angular.element('<style id="mobilecssurl-' + siteId + '" disabled="disabled"></style>');
47+
angular.element(document.head).append(el);
48+
remoteStylesEls[siteId] = {
49+
element: el,
50+
hash: ''
51+
};
52+
53+
return self.load(siteId, true);
54+
};
3155

3256
/**
3357
* Clear remote styles added to the DOM.
@@ -37,7 +61,47 @@ angular.module('mm.addons.remotestyles')
3761
* @name $mmaRemoteStyles#clear
3862
*/
3963
self.clear = function() {
40-
remoteStylesEl.html('');
64+
// Disable all the styles.
65+
angular.element(document.querySelectorAll('style[id*=mobilecssurl]')).attr('disabled', true);
66+
};
67+
68+
/**
69+
* Downloads a CSS file and remove old files if needed.
70+
*
71+
* @param {String} siteId Site ID.
72+
* @param {String} url File URL.
73+
* @return {Promise} Promise resolved when the file is downloaded.
74+
*/
75+
function downloadFileAndRemoveOld(siteId, url) {
76+
return $mmFilepool.getFileStateByUrl(siteId, url).then(function(state) {
77+
return state !== mmCoreNotDownloaded;
78+
}).catch(function() {
79+
return true; // An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
80+
}).then(function(isDownloaded) {
81+
if (!isDownloaded) {
82+
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
83+
return $mmFilepool.removeFilesByComponent(siteId, mmaRemoteStylesComponent, 1);
84+
}
85+
}).then(function() {
86+
return $mmFilepool.downloadUrl(siteId, url, false, mmaRemoteStylesComponent, 1);
87+
});
88+
}
89+
90+
/**
91+
* Enable the styles of a certain site.
92+
*
93+
* @module mm.addons.remotestyles
94+
* @ngdoc method
95+
* @name $mmaRemoteStyles#addSite
96+
* @param {String} [siteId] Site ID. If not defined, current site.
97+
* @return {Void}
98+
*/
99+
self.enable = function(siteId) {
100+
siteId = siteId || $mmSite.getId();
101+
102+
if (remoteStylesEls[siteId]) {
103+
remoteStylesEls[siteId].element.attr('disabled', false);
104+
}
41105
};
42106

43107
/**
@@ -46,47 +110,33 @@ angular.module('mm.addons.remotestyles')
46110
* @module mm.addons.remotestyles
47111
* @ngdoc method
48112
* @name $mmaRemoteStyles#get
49-
* @param {String} siteid Site ID.
50-
* @return {Promise} Promise resolved with the styles.
113+
* @param {String} [siteId] Site ID. If not defined, current site.
114+
* @return {Promise} Promise resolved with the styles and the URL of the loaded CSS file (local if downloaded).
51115
*/
52-
self.get = function(siteid) {
53-
var promise;
116+
self.get = function(siteId) {
117+
var fileUrl;
54118

55-
siteid = siteid || $mmSite.getId();
56-
if (!siteid) {
119+
siteId = siteId || $mmSite.getId();
120+
if (!siteId) {
57121
return $q.reject();
58122
}
59123

60-
// Downloads a CSS file and remove old files if needed.
61-
function downloadFileAndRemoveOld(url) {
62-
return $mmFilepool.getFileStateByUrl(siteid, url).then(function(state) {
63-
return state !== mmCoreNotDownloaded;
64-
}).catch(function() {
65-
return true; // An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
66-
}).then(function(isDownloaded) {
67-
if (!isDownloaded) {
68-
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
69-
return $mmFilepool.removeFilesByComponent(siteid, mmaRemoteStylesComponent, 1);
70-
}
71-
}).then(function() {
72-
return $mmFilepool.downloadUrl(siteid, url, false, mmaRemoteStylesComponent, 1);
73-
});
74-
}
75-
76-
return $mmSitesManager.getSite(siteid).then(function(site) {
124+
return $mmSitesManager.getSite(siteId).then(function(site) {
77125
var infos = site.getInfo();
78126
if (infos && infos.mobilecssurl) {
127+
fileUrl = infos.mobilecssurl;
128+
79129
if ($mmFS.isAvailable()) {
80130
// The file system is available. Download the file and remove old CSS files if needed.
81-
return downloadFileAndRemoveOld(infos.mobilecssurl);
131+
return downloadFileAndRemoveOld(siteId, infos.mobilecssurl);
82132
} else {
83133
// We return the online URL. We're probably on browser.
84134
return infos.mobilecssurl;
85135
}
86136
} else {
87137
if (infos.mobilecssurl === '') {
88138
// CSS URL is empty. Delete downloaded files (if any).
89-
$mmFilepool.removeFilesByComponent(siteid, mmaRemoteStylesComponent, 1)
139+
$mmFilepool.removeFilesByComponent(siteId, mmaRemoteStylesComponent, 1);
90140
}
91141
return $q.reject();
92142
}
@@ -95,30 +145,152 @@ angular.module('mm.addons.remotestyles')
95145
return $http.get(url);
96146
}).then(function(response) {
97147
if (typeof response.data == 'string') {
98-
return response.data;
148+
return {file: fileUrl, styles: response.data};
99149
} else {
100150
return $q.reject();
101151
}
102152
});
103153
};
104154

105155
/**
106-
* Load styles for current site.
156+
* Load styles for a certain site.
107157
*
108158
* @module mm.addons.remotestyles
109159
* @ngdoc method
110160
* @name $mmaRemoteStyles#load
161+
* @param {String} [siteId] Site ID. If not defined, current site.
162+
* @param {Boolean} disabled True if loaded styles should be disabled, false if they should be enabled.
163+
* @return {Promise} Promise resolved when styles are loaded.
111164
*/
112-
self.load = function() {
113-
var siteid = $mmSite.getId();
114-
if (siteid) {
115-
self.get(siteid).then(function(styles) {
116-
if (siteid === $mmSite.getId()) { // Make sure it hasn't logout while retrieving styles.
117-
remoteStylesEl.html(styles);
165+
self.load = function(siteId, disabled) {
166+
siteId = siteId || $mmSite.getId();
167+
disabled = !!disabled;
168+
169+
$log.debug('Load site: ', siteId, disabled);
170+
if (siteId && remoteStylesEls[siteId]) {
171+
// Enable or disable the styles.
172+
remoteStylesEls[siteId].element.attr('disabled', disabled);
173+
174+
return self.get(siteId).then(function(data) {
175+
var hash = md5.createHash(data.styles);
176+
177+
// Update the styles only if they have changed.
178+
if (remoteStylesEls[siteId].hash !== hash) {
179+
remoteStylesEls[siteId].element.html(data.styles);
180+
remoteStylesEls[siteId].hash = hash;
181+
182+
// New styles will be applied even if the style is disabled. We'll disable it again if needed.
183+
if (disabled && remoteStylesEls[siteId].element.attr('disabled') == 'disabled') {
184+
remoteStylesEls[siteId].element.attr('disabled', true);
185+
}
118186
}
187+
188+
// Styles have been loaded, now treat the CSS.
189+
treatCSSCode(siteId, data.file, data.styles);
119190
});
120191
}
192+
193+
return $q.reject();
121194
};
122195

196+
/**
197+
* Preload the styles of the current site (stored in DB). Please do not use.
198+
*
199+
* @module mm.addons.remotestyles
200+
* @ngdoc method
201+
* @name $mmaRemoteStyles#_preloadCurrentSite
202+
* @return {Promise} Promise resolved when loaded.
203+
* @protected
204+
*/
205+
self._preloadCurrentSite = function() {
206+
return $mmSitesManager.getStoredCurrentSiteId().then(function(siteId) {
207+
return self.addSite(siteId);
208+
});
209+
};
210+
211+
/**
212+
* Preload the styles of all the stored sites. Please do not use.
213+
*
214+
* @module mm.addons.remotestyles
215+
* @ngdoc method
216+
* @name $mmaRemoteStyles#_preloadSites
217+
* @return {Promise} Promise resolved when loaded.
218+
* @protected
219+
*/
220+
self._preloadSites = function() {
221+
return $mmSitesManager.getSitesIds().then(function(ids) {
222+
var promises = [];
223+
angular.forEach(ids, function(siteId) {
224+
promises.push(self.addSite(siteId));
225+
});
226+
return $q.all(promises);
227+
});
228+
};
229+
230+
/**
231+
* Remove the styles of a certain site.
232+
*
233+
* @module mm.addons.remotestyles
234+
* @ngdoc method
235+
* @name $mmaRemoteStyles#removeSite
236+
* @param {String} siteId Site ID.
237+
* @return {Void}
238+
*/
239+
self.removeSite = function(siteId) {
240+
if (siteId && remoteStylesEls[siteId]) {
241+
remoteStylesEls[siteId].element.remove();
242+
delete remoteStylesEls[siteId];
243+
}
244+
};
245+
246+
/**
247+
* Search for files in a CSS code and try to download them. Once downloaded, replace their URLs
248+
* and store the result in the CSS file.
249+
*
250+
* @param {String} siteId Site ID.
251+
* @param {String} fileUrl CSS file URL.
252+
* @param {String} cssCode CSS code.
253+
* @return {Promise} Promise resolved with the CSS code.
254+
*/
255+
function treatCSSCode(siteId, fileUrl, cssCode) {
256+
if (!$mmFS.isAvailable()) {
257+
return $q.reject();
258+
}
259+
260+
var urls = $mmUtil.extractUrlsFromCSS(cssCode),
261+
promises = [],
262+
filePath,
263+
updated = false;
264+
265+
// Get the path of the CSS file.
266+
promises.push($mmFilepool.getFilePathByUrl(siteId, fileUrl).then(function(path) {
267+
filePath = path;
268+
}));
269+
270+
angular.forEach(urls, function(url) {
271+
// Download the file only if it's an online URL.
272+
if (url.indexOf('http') == 0) {
273+
promises.push($mmFilepool.downloadUrl(siteId, url, false, mmaRemoteStylesComponent, 2).then(function(fileUrl) {
274+
if (fileUrl != url) {
275+
cssCode = cssCode.replace(new RegExp(url, 'g'), fileUrl);
276+
updated = true;
277+
}
278+
}).catch(function(error) {
279+
// It shouldn't happen. Ignore errors.
280+
$log.warn('MMRMSTYLES Error treating file ', url, error);
281+
}));
282+
}
283+
});
284+
285+
return $q.all(promises).then(function() {
286+
// All files downloaded. Store the result if it has changed.
287+
if (updated) {
288+
return $mmFS.writeFile(filePath, cssCode);
289+
}
290+
}).then(function() {
291+
return cssCode;
292+
});
293+
}
294+
123295
return self;
124296
});

www/core/lib/sitesmanager.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ angular.module('mm.core')
222222
currentSite = candidateSite;
223223
// Store session.
224224
self.login(siteid);
225-
$mmEvents.trigger(mmCoreEventSiteAdded);
225+
$mmEvents.trigger(mmCoreEventSiteAdded, siteid);
226226
} else {
227227
return $translate(validation.error, validation.params).then(function(error) {
228228
return $q.reject(error);
@@ -723,6 +723,20 @@ angular.module('mm.core')
723723
});
724724
};
725725

726+
/**
727+
* Get the site ID stored in DB ad current site.
728+
*
729+
* @module mm.core
730+
* @ngdoc method
731+
* @name $mmSitesManager#getStoredCurrentSiteId
732+
* @return {Promise} Promise resolved with the site ID.
733+
*/
734+
self.getStoredCurrentSiteId = function() {
735+
return $mmApp.getDB().get(mmCoreCurrentSiteStore, 1).then(function(current_site) {
736+
return current_site.siteid;
737+
});
738+
};
739+
726740
return self;
727741

728742
});

0 commit comments

Comments
 (0)