OSDN Git Service

[更新]:セッションストレージからローカルストレージに変更
[alterlinux/lightdm-webkit2-theme-alter.git] / js / splashscreen.js
1
2 /**
3 * Creates a splash screen with custom generated content,
4 * diplays when the user inactive.
5 *
6 * A Plugin for the LoginManager class
7 *
8 * EVENTS:
9 * -----------------------------------------------------------------------------
10 * Listens:
11 * 'load' signifies that SplashScreen has finished asyncrhonously
12 * loading its config files.
13 *
14 * 'ready' emitted once the SplashScreen has finished creating its content
15 *
16 * Triggers:
17 * 'init' causes the SplashScreen content to be generated
18 *
19 */
20 text=[]
21 if (window.navigator.language === "en" || window.navigator.language === "en-US" ||window.navigator.language === "fr"  ||window.navigator.language === "es-ES" ) {
22   text[0]="Press any key to login"
23   text[1]="Welcome Back"
24   text[2]="Select Session"
25   text[3]="User"
26   text[4]="Password"
27 }
28 else {
29   text[0]="任意のキーを押すとログインできます。"
30   text[1]="ようこそ"
31   text[2]="セレクトセッション"
32   text[3]="ユーザー"
33   text[4]="パスワード"
34 }
35 document.onkeydown = function (e){
36   document.getElementById("inputPassword").focus();
37 };
38 selectSession = LocalStorage.getItem('access_count');
39 selectSession = window.LocalStorage.getItem('access_count');
40 selectSession = LocalStorage.access_count
41
42 class SplashScreen {
43   constructor() {
44     /* Speed of SplashScreen transitions */
45     this._ANIMATION_DUR = 300;
46
47     /* Default options for the  splash screen */
48     this._DEF_OPT = {
49       "fit": true,
50       "filter": false,
51       "vignette": true,
52       "active-timeout": 15,
53       "transition": "fade",
54       "img": false,
55       "content": {
56         "clock": [{
57         //   "format": "dddd, MMMM Do",
58         //   "css": {
59         //     "color": "white"
60         //   },
61         //   "parent-css": {
62         //     "margin-top": "calc(20vh - 70pt)",
63         //     "text-align": "center",
64         //     "font-size": "70pt",
65         //     "font-family": "Noto Sans",
66         //     "font-weight": "lighter",
67         //     "text-shadow": "rgba(0, 0, 0, 0.25) 0px 3px 3px",
68         //   }
69         // },{
70           "format": ["h:mm", "A"],
71           "css": [
72             {"font-size": "65pt", "font-weight": 200 },
73             {"font-size": "30pt", "font-weight": "lighter", "margin-left": "10pt"}
74           ],
75           "parent-css": {
76             "margin-top": "40vh",
77             "color": "white",
78             "font-family": "MyFont",
79             "text-align": "center",
80             "text-shadow": "rgba(0, 0, 0, 0.25) 0px 3px 3px",
81           }
82         }],
83
84         "html": [{
85           "html":"<text style='display: none' class='active-appear'>"+text[0]+"</text>",
86           "css": {
87             "margin-top": "5vh",
88             "font-weight": "200",
89             "font-size": "23pt",
90             "text-align": "center",
91             "color": "rgba(255, 255, 255, 0.8)"
92           }
93         }]
94       }
95     };
96     this.template = `<!-- Autogenerated SplashScreen -->
97     <div id="splash-screen">
98     <div class="vignette"></div>
99     <div id="splash-screen-content"></div>
100     </div>
101     <!-- End Autogenerated SplashScreen -->`;
102     this.$el = $(this.template);
103     $("body").prepend(this.$el);
104
105     this._loadConfig();
106     // listen to the init event
107     $(this).on("init", () => this._init());
108   }
109
110   /**
111   * Generates the content specified by the user config.
112   * Should be called after the load event has been triggered.
113   */
114   _init() {
115     this.$content = $("#splash-screen-content");
116     this._state = "closed";
117     this._last_active = 0;
118     this._active_timeout = 15;
119
120     let options = this._options; // shorthand
121     if (typeof options == "object") {
122
123       // initilize global values if specfied in the config
124       if (typeof options.img == "string") {
125         this.$img = $(`<img class="splash-screen-img" src="${options.img}">`);
126
127         this.$el.prepend(this.$img);
128         this.$img.one("load", () => {
129           // fit background image to sreen size and center
130           adjustBackground($(".splash-screen-img"))
131         })
132       }
133
134       if (typeof options["active-timeout"] == "number")
135       this._active_timeout = options["active-timeout"];
136
137       if (options.filter == true)
138       this.$img.addClass("filter");
139
140       if (options.vignette == true) {
141         this.$vignette = $("#vignette");
142         this.$vignette.show();
143       }
144
145       if (typeof options.transition == "string")
146       this.transition = options.transition;
147
148       if (typeof options.content == "object")
149       this._initContent(options.content);
150
151       $(this).trigger("ready");
152     }
153
154     /******************** Event Listeners ********************/
155     this.clock = setInterval(() => {
156       $(this).trigger("tick");
157
158       if (!this._isActive())
159       $(this).trigger("inactive");
160     }, 500);
161
162     // update last active time
163     $(this).on("active", () => this._last_active = moment());
164
165     $(document).keyup((e) => {
166       // handle events in seperate method
167       this._keyHandler.call(this, e);
168     }).keypress((e) => this._keyHandler.call(this, e));
169
170     /* Bind event listners to trigger activity event. This can be used on the
171     front end to implement spcific behaivours while the user is active */
172     this.$el.click(() => {
173       this._open();
174     }).mousemove((e) => {
175       if (!this._isActive())
176       $(this).trigger("active", e)
177     });
178     setTimeout(() => $(this).trigger("active"), 1);
179   }
180
181   /**
182   * Loops through the user specified content and appends them to the DOM
183   * in the order specified by the user config
184   */
185   _initContent(content) {
186     for (let content_type in content) {
187       if (content_type == "clock")
188       this._initClock(content[content_type]);
189       else if (content_type == "html")
190       this._initHTML(content[content_type]);
191       else
192       log.warn("Specified content " + content_type + " is not valid.");
193     }
194   }
195
196   /**
197   * Asyncrhonously reads JSON config file from json/SplashScreen.json
198   * and overwrites the default options with those specified by the config.
199   *
200   * Triggers: 'load' on completion. Caller (LoginManager) must listen for this
201   *     event to then trigger 'init'
202   */
203   _loadConfig() {
204     let options = {};
205     $.extend(true, options, this._DEF_OPT);
206
207     $.getJSON("json/SplashScreen.json", (data) => {
208       $.extend(true, options, data);
209       this._options = options;
210       $(this).trigger("load");
211     }).fail(() => {
212       $.extend(true, options, {});
213       this._options = options;
214       $(this).trigger("load");
215     });
216   }
217
218   /**
219   * Closes the splash screen if there has been no user activity
220   */
221   _reset() {
222     if (this._state == "open") {
223       this._close();
224       $(this).trigger("timeout");
225     }
226   }
227
228   /**
229   * Determines if there was user acitivty within in a given amount
230   * of time.
231   * Returns 1 if splash screen is active, else 0
232   */
233   _isActive() {
234     if (moment().diff(this._last_active, "seconds", true) > 30) {
235       return 0;
236     }
237     return 1;
238   }
239
240   /**
241   * Creates clock elements based on the usr config.
242   * Appends each clock to the DOM and binds update events using _startClock
243   */
244   _initClock(opts) {
245     if (typeof opts != "object") {
246       log.error("Unable to initialize clock thats not an object");
247       return -1;
248     }
249     // handle arrays and a single clock object
250     if (!Array.isArray(opts))
251     opts = [opts];
252
253     /* loop through each clock in the config and add it to the dom,
254     then initialize an update event using start clock */
255     for (let i in opts) {
256       this.$clock = $("<div id='clock-" + i + "' class='clock'></div>");
257       this.$content.append(this.$clock);
258       this._startClock(this.$clock, opts[i]);
259     }
260   }
261
262   /**
263   * Applys the css specfied in the argument opts to the jQuery oboject $clock.
264   * Subscribes the clock to a tick event
265   */
266   _startClock($clock, opts) {
267     if (typeof opts != "object") {
268       log.error("Clock opts is not a valid object");
269       return -1;
270     }
271     // handle multiple formats for multiple clocks on the same line
272     if(typeof opts.format == "string")
273     opts.format = [opts.format];
274
275     // ensure the format is now an array
276     if(!Array.isArray(opts.format)) {
277       log.error(`Specfied clock format is not a valid type.
278         Type can be a single string or Array.`);
279         return -1;
280       }
281
282       if(!Array.isArray(opts.css))
283       opts.css = [opts.css];
284
285       for (let i in opts.format) {
286
287         let $format = $("<sub></sub>");
288         // create text field in clock
289         $clock.append($format);
290         // apply css styles
291         if (i < opts.css.length && typeof opts.css[i] == "object")
292         $format.css(opts.css[i]);
293
294         // start clock
295         $format.text(moment().format(opts.format[i]));
296         $(this).on("tick", () => {
297           $format.text(moment().format(opts.format[i]));
298         });
299       }
300
301       if (typeof opts["parent-css"] == "object")
302       $clock.css(opts["parent-css"]);
303
304       $clock.show();
305     }
306
307     /**
308     * Inserts HTML specified in the user config into the splash screen
309     * accepts plain strings and objects. String literals are interpreted as
310     * normal text element. Objects are set using the jQuery API
311     */
312     _initHTML(opts) {
313       // handle single objects and strings
314       if (!Array.isArray(opts)) {
315         opts = [opts];
316       }
317
318       for (let el of opts) {
319         if (typeof el == "string") {
320           let $el = $("<text>");
321           $el.text(el);
322           // create simple text element
323           this.$content.append($el);
324         } else if (typeof el == "object") {
325           // let user specify element properites in object el.
326           let $el = $("<div>");
327           for (let prop in el) {
328             $el[prop](el[prop]);
329           }
330           this.$content.append($el);
331
332         } else {
333           log.warn("Splash screen html element is invalid type");
334         }
335       }
336
337     }
338
339     /**
340     * Handles the key events for the SplachScreen and active-inactive events
341     */
342     _keyHandler(e) {
343       switch (e.keyCode) {
344         case 32:
345         case 13: // Enter key
346         if (this._state == "closed")
347         this._open();
348         break;
349         case 27: // ESC key
350         if (this._state == "open")
351         this._close();
352         else if (this._state == "closed")
353         this._open();
354         break;
355         default:
356         if (this._state == "closed")
357         this._open();
358         break;
359       }
360
361       // stop reset timeout since there has been user activity
362       if (this._state == "open")
363       clearTimeout(this.resetTimeout);
364
365       // trigger active event if the user has been inactive long enough
366       if (!this._isActive())
367       $(this).trigger("active", e);
368     }
369
370     /**
371     * _open and _close will toggle the screen and animate it opening and closing
372     * adds a resetTimeout function to automatically close after a period of user
373     * inactivity
374     *
375     * Uses a _state machine consisting of {'open', 'closed', 'moving'}.
376     * Transitions are not possible while the _state == moving. This prevents
377     * fillUserSelect from trigger concurrernt transitions which would lead to
378     * undefined behaivour.
379     */
380     _close()  {
381       if (this._state != "open") {
382         log.warn("Cannot close splash screen when _state is: " + this._state);
383         return;
384       }
385
386       this._state = "moving";
387       if (this.transition == "fade") {
388         this.$el.fadeIn("slow", () => {
389           this._state = "closed";
390           this.$content.fadeIn("slow");
391           clearTimeout(this.resetTimeout);
392         });
393       } else if (this.transition == "slide") {
394         this.$el.animate({
395           top: "0"
396         },"slow", "easeOutQuint", () => {
397           this._state = "closed";
398           clearTimeout(this.resetTimeout);
399         });
400       }
401
402
403     }
404     _open() {
405       if (this._state != "closed") {
406         log.warn("Cannot open splash screen when _state is: " + this._state);
407         return;
408       }
409       clearTimeout(this.resetTimeout);
410       let reset_duration = 60*1000;
411
412       if (this._state == "open" || this._state == "moving") {
413         this.resetTimeout = setTimeout(this.reset, reset_duration);
414         return;
415       }
416       this._state = "moving";
417
418       if (this.transition == "fade") {
419         this.$content.fadeOut("fast", () => {
420           this.$el.fadeOut(this._ANIMATION_DUR, () => {
421             this._state = "open";
422           });
423         });
424
425       } else if (this.transition == "slide") {
426         this.$el.animate({
427           top: "-100%"
428         }, "slow", "easeInCubic", () => {
429           this._state = "open";
430         });
431       }
432
433
434     }
435
436   }