OSDN Git Service

decoupled SplashScreen from login manager
[alterlinux/lightdm-webkit2-theme-alter.git] / js / theme.js
1
2 const  DEF_OPT = 
3 {
4         "fit": true,
5         "filter": true,
6         "vignette": true,
7         "clock": [{
8                 "format": ["h:mm", "A"],
9                 "css": [{
10                                 "font-size": "60pt",
11                         },{
12                                 "font-size": "30pt"
13                         }
14         ],                      
15         "parent-css": {
16                 "color": "white",
17                 "font-family": "Noto Sans",
18                 "text-align": "center",
19                 "margin-top": "calc(50vh - 90pt)",
20                 "text-shadow": "rgba(0, 0, 0, 0.8) 0px 7px 10px",
21         }
22         }]
23 };
24
25 /**
26  * Scale an image up or down until it's larger than or equal to the viewport 
27  * and then center it.
28  */
29 var adjustBackground = function ($img) {
30         var viewportWidth = screen.width;
31         var viewportHeight = screen.height;
32         var viewportAspect = viewportWidth/viewportHeight;
33         var imgWidth = $img.width();
34         var imgHeight = $img.height();
35         var imgAspect = imgWidth/imgHeight; 
36         
37         /* First determine what is 
38            the limiting factor (ie. if the image is wider, then the height is
39            is the limiting factor and needs to be adjustested */
40         if (imgAspect < viewportAspect) {
41                 /* The view port is wider compared to its height than
42                    the image is compared to the image height  meaning
43                    the width is the limiting dimension. Therefore we
44                    set image width = view ports width use the aspect
45                    ratio to set the correct height */
46                 $img.width(viewportWidth);
47                 $img.height(viewportWidth/imgAspect);
48         } else {
49                 /* The image is wider than it is tall compared to the
50                    viewport so we adjust the to fit */
51                 $img.height(viewportHeight);
52                 $img.width(viewportHeight*imgAspect);
53         }
54         this.centerImage($img);
55 }
56
57 var centerImage =  function($img) {
58         var overlapWidth = $img.width() - screen.width;
59         var overlapHeight = $img.height() - screen.height;
60
61         console.log("overlapwidth: " + overlapWidth + " overlapHeight " + overlapHeight);
62         // image overlaps viewport, move the image back 
63         // half the length of the overlap
64         $img.css({
65                 position: "relative",
66                 right: overlapWidth/2,
67                 bottom: overlapHeight/2 
68         }); 
69 }
70
71 class LoginManager {
72         constructor() {
73                 this.use_splash = true;
74                 $(document).ready(() => {
75                         this.init();
76                 });             
77         }
78
79         init() {
80                 if (this.use_splash) {
81                         this.splash = new SplashScreen();
82                 }
83                 $(this).trigger("ready");
84         }
85
86
87         login(username, password, callback) {
88                 // set default values
89                 if (typeof lightdm == 'undefined') {
90                         console.warn("Cannot attempt login without lightdm");
91                         // call async so that events can be binded in cascade
92                         setTimeout(() => $(this).trigger("access-deny"));
93                         return;
94                 }
95                 username = username || lightdm.select_user; 
96                 password = password || "";
97                 //  session_key = session_key || lightdm.sessions[0].key;
98
99                 let auth_cb = () =>  {
100                     lightdm.respond(password);
101                 }
102                 let auth_complete_cb = () => {
103                         if (typeof callback == "function")
104                                 callback(lightdm.is_authenticated); 
105
106                         $(this).trigger(lightdm.is_authenticated ? "access-grant" : "access-deny");
107                 }
108                 window.show_prompt = auth_cb; 
109                 window.authentication_complete = auth_complete_cb; 
110                 lightdm.authenticate(username);
111     }
112 }
113
114 class SplashScreen {
115         constructor() {
116                 this.$el = $("#splash-screen");
117                 this.$content = $("#splash-screen-content");
118                 this.options = this.getUserOptions();
119                 this.is_open = false;   
120
121                 if (!this.$el.length)
122                         console.error("Missing-screen element.");
123
124                 // fit background image to sreen size and center
125                 this.$img = $(".splash-screen-img");
126                 if (!this.$img.length) 
127                         console.warn("No background images supplied for splash screen.");
128                 this.$img.each((i, v) => adjustBackground($(v)));
129
130                 let options = this.options; // shorthand
131                 if (typeof options == "object") {
132                         this.is_open = false;
133                         // initilize global values if specfied in the config
134                         if (options.filter == true) {
135                                 this.$img.addClass("filter");   
136                         }
137                         if (options.vignette == true) {
138                                 this.$vignette = $("#vignette");
139                                 this.$vignette.show();
140                         }
141                         if (typeof options.clock == "object") {
142                                 this.initClock(options.clock);
143                         }
144         
145                 }
146
147                 /******************** Event Listeners ********************/ 
148                 this.clock = setInterval(() => {
149                         $(this).trigger("tick");                
150                 }, 500);
151
152                 $(document).keyup((e) => {
153                         // handle events in seperate method 
154                         this.keyHandler.call(this, e);
155                 }).keypress((e) => this.keyHandler.call(this, e));
156
157                 $(this).click(() => {
158                 
159                 });
160         }
161
162         getUserOptions() {
163                 let options = {};
164                 $.extend(true, options, DEF_OPT);
165                 $.extend(true, options, {});
166                 return options;
167         }
168         /**
169          * open and close will toggle the screen and animate it opening and closing
170          * adds a resetTimeout function to automatically close after a period of user
171          * inactivity */
172         close(time=450)  {
173                 if (!this.is_open) 
174                         return
175                 this.$el.animate({
176                         top: "0"
177                 }, time, "easeInCubic", () => {
178                         this.is_open = false
179                         clearTimeout(this.resetTimeout);
180                 });
181         }
182         open(time=400) {
183                 clearTimeout(this.resetTimeout);
184                 let reset_duration = 60*1000;
185
186
187                 if (this.is_open) {
188                         this.resetTimeout = setTimeout(this.reset, reset_duration); 
189                         return;
190                 }
191                 this.$el.animate({
192                         top: "-100%"
193                 }, time, "easeInCubic", () => {
194                         this.is_open = true;
195                         // close the screen after 1 minute of inactivty
196                         this.resetTimeout = setTimeout(() => this.reset, reset_duration); 
197                 });                     
198         }
199         reset() {
200                 if (this.is_open == true) {
201                         this.close();
202                         $(this).trigger("timeout");
203                 }
204         }
205
206         /**
207          * handles the key events for the splash
208          */ 
209         keyHandler(e) {
210                 switch (e.keyCode) {
211                         case 32:
212                         case 13:
213                                 this.open();
214                                 break;
215                         case 27:
216                                 if (this.is_open) this.close();
217                                 else this.open();
218                                 break;
219
220                 }
221         
222                 // stop reset timeout since there has been user activity
223                 if (this.is_open)
224                         clearTimeout(this.resetTimeout);
225                 
226         }
227
228         /**
229          *  Creates clock elements based on the usr config
230          */
231         initClock(opts) {
232                 if (typeof opts != "object")
233                         return -1;
234                 // handle arrays and a single clock object
235                 if (!Array.isArray(opts))
236                         opts = [opts];
237
238                 for (let i in opts) {
239                         this.$clock = $("<div class='clock'></div>");
240                         this.$content.append(this.$clock);
241                         this.startClock(this.$clock, opts[i]);
242                 }
243         }
244
245         /**
246          * Applys the css specfied in the argument opts to the jQuery oboject $clock.
247          * Subscribes the clock to a tick event 
248          */
249         startClock($clock, opts) {
250                 if (typeof opts != "object") {
251                         console.error("Clock opts is not a valid object");
252                         return -1;
253                 }                       
254                 // handle multiple formats for multiple clocks on the same line
255                 if(typeof opts.format == "string")
256                         opts.format = [opts.format];
257
258                 // ensure the format is now an array
259                 if(!Array.isArray(opts.format)) {
260                         console.error(`Specfied clock format is not a valid type.
261                                 Type can be a single string or Array.`);
262                         return -1;              
263                 }
264                         
265                 if(!Array.isArray(opts.css))
266                         opts.css = [opts.css];
267                 
268                 for (let i in opts.format) {
269
270                         let $format = $("<sub></sub>");
271                         // create text field in clock
272                         $clock.append($format);
273
274                         // apply css styles
275                         if (i < opts.css.length && typeof opts.css[i] == "object")
276                                 $format.css(opts.css[i]);
277
278                         // start clock
279                         $format.text(moment().format(opts.format[i]));
280                         $(this).on("tick", () => {
281                                 $format.text(moment().format(opts.format[i]));
282                         });
283                 }
284
285                 if (typeof opts["parent-css"] == "object")
286                         $clock.css(opts["parent-css"]);
287                 console.debug($clock);
288                 $clock.show();
289         }
290
291
292 }
293 // create singleton 
294 const greeter = new LoginManager();
295 $(greeter).ready(function() {
296         greeter.login("jay", "");
297         $(greeter).on("access-grant", () => {
298              lightdm.start_session_sync("i3");
299         }).on("access-deny", () => console.log("denied!"));
300 });
301