luci-base: luci.js: add ability to add "preload" classes
authorJo-Philipp Wich <jo@mein.io>
Sun, 12 Apr 2020 20:54:02 +0000 (22:54 +0200)
committerJo-Philipp Wich <jo@mein.io>
Sun, 12 Apr 2020 21:55:36 +0000 (23:55 +0200)
Extend the LuCI bootstrap procedure to scan for class files in
/www/luci-static/preload/. Any JavaScript file found there will be
required automatically before setting up the view, allowing to stage
code that should run on every page load.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/luci.js

index e1aa65a34d1afb3bcd31d9df2418a91463354aec..1ed213ebb684e669967328cb5d60d81a95bace2e 100644 (file)
            domParser = null,
            originalCBIInit = null,
            rpcBaseURL = null,
-           sysFeatures = null;
+           sysFeatures = null,
+           preloadClasses = null;
 
        /* "preload" builtin classes to make the available via require */
        var classes = {
                        return Promise.resolve(sysFeatures);
                },
 
+               probePreloadClasses: function() {
+                       var sessionid = classes.rpc.getSessionID();
+
+                       if (preloadClasses == null) {
+                               try {
+                                       var data = JSON.parse(window.sessionStorage.getItem('preloadClasses'));
+
+                                       if (this.isObject(data) && this.isObject(data[sessionid]))
+                                               preloadClasses = data[sessionid];
+                               }
+                               catch (e) {}
+                       }
+
+                       if (!Array.isArray(preloadClasses)) {
+                               preloadClasses = this.resolveDefault(classes.rpc.declare({
+                                       object: 'file',
+                                       method: 'list',
+                                       params: [ 'path' ],
+                                       expect: { 'entries': [] }
+                               })(this.fspath(this.resource('preload'))), []).then(function(entries) {
+                                       var classes = [];
+
+                                       for (var i = 0; i < entries.length; i++) {
+                                               if (entries[i].type != 'file')
+                                                       continue;
+
+                                               var m = entries[i].name.match(/(.+)\.js$/);
+
+                                               if (m)
+                                                       classes.push('preload.%s'.format(m[1]));
+                                       }
+
+                                       try {
+                                               var data = {};
+                                                   data[sessionid] = classes;
+
+                                               window.sessionStorage.setItem('preloadClasses', JSON.stringify(data));
+                                       }
+                                       catch (e) {}
+
+                                       preloadClasses = classes;
+
+                                       return classes;
+                               });
+                       }
+
+                       return Promise.resolve(preloadClasses);
+               },
+
                /**
                 * Test whether a particular system feature is available, such as
                 * hostapd SAE support or an installed firewall. The features are
                                L.notifySessionExpiry();
                        });
 
-                       return this.probeSystemFeatures().finally(this.initDOM);
+                       return Promise.all([
+                               this.probeSystemFeatures(),
+                               this.probePreloadClasses()
+                       ]).finally(L.bind(function() {
+                               var tasks = [];
+
+                               if (Array.isArray(preloadClasses))
+                                       for (var i = 0; i < preloadClasses.length; i++)
+                                               tasks.push(this.require(preloadClasses[i]));
+
+                               return Promise.all(tasks);
+                       }, this)).finally(this.initDOM);
                },
 
                /* private */