OSDN Git Service

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