3 * Creates a splash screen with custom generated content,
4 * diplays when the user inactive.
6 * A Plugin for the LoginManager class
9 * -----------------------------------------------------------------------------
11 * 'load' signifies that SplashScreen has finished asyncrhonously
12 * loading its config files.
14 * 'ready' emitted once the SplashScreen has finished creating its content
17 * 'init' causes the SplashScreen content to be generated
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"
29 text[0]="任意のキーを押すとログインできます。"
37 /* Speed of SplashScreen transitions */
38 this._ANIMATION_DUR = 300;
40 /* Default options for the splash screen */
50 // "format": "dddd, MMMM Do",
55 // "margin-top": "calc(20vh - 70pt)",
56 // "text-align": "center",
57 // "font-size": "70pt",
58 // "font-family": "Noto Sans",
59 // "font-weight": "lighter",
60 // "text-shadow": "rgba(0, 0, 0, 0.25) 0px 3px 3px",
63 "format": ["h:mm", "A"],
65 {"font-size": "65pt", "font-weight": 200 },
66 {"font-size": "30pt", "font-weight": "lighter", "margin-left": "10pt"}
71 "font-family": "MyFont",
72 "text-align": "center",
73 "text-shadow": "rgba(0, 0, 0, 0.25) 0px 3px 3px",
78 "html":"<text style='display: none' class='active-appear'>"+text[0]+"</text>",
83 "text-align": "center",
84 "color": "rgba(255, 255, 255, 0.8)"
89 this.template = `<!-- Autogenerated SplashScreen -->
90 <div id="splash-screen">
91 <div class="vignette"></div>
92 <div id="splash-screen-content"></div>
94 <!-- End Autogenerated SplashScreen -->`;
95 this.$el = $(this.template);
96 $("body").prepend(this.$el);
99 // listen to the init event
100 $(this).on("init", () => this._init());
104 * Generates the content specified by the user config.
105 * Should be called after the load event has been triggered.
108 this.$content = $("#splash-screen-content");
109 this._state = "closed";
110 this._last_active = 0;
111 this._active_timeout = 15;
113 let options = this._options; // shorthand
114 if (typeof options == "object") {
116 // initilize global values if specfied in the config
117 if (typeof options.img == "string") {
118 this.$img = $(`<img class="splash-screen-img" src="${options.img}">`);
120 this.$el.prepend(this.$img);
121 this.$img.one("load", () => {
122 // fit background image to sreen size and center
123 adjustBackground($(".splash-screen-img"))
127 if (typeof options["active-timeout"] == "number")
128 this._active_timeout = options["active-timeout"];
130 if (options.filter == true)
131 this.$img.addClass("filter");
133 if (options.vignette == true) {
134 this.$vignette = $("#vignette");
135 this.$vignette.show();
138 if (typeof options.transition == "string")
139 this.transition = options.transition;
141 if (typeof options.content == "object")
142 this._initContent(options.content);
144 $(this).trigger("ready");
147 /******************** Event Listeners ********************/
148 this.clock = setInterval(() => {
149 $(this).trigger("tick");
151 if (!this._isActive())
152 $(this).trigger("inactive");
155 // update last active time
156 $(this).on("active", () => this._last_active = moment());
158 $(document).keyup((e) => {
159 // handle events in seperate method
160 this._keyHandler.call(this, e);
161 }).keypress((e) => this._keyHandler.call(this, e));
163 /* Bind event listners to trigger activity event. This can be used on the
164 front end to implement spcific behaivours while the user is active */
165 this.$el.click(() => {
167 }).mousemove((e) => {
168 if (!this._isActive())
169 $(this).trigger("active", e)
171 setTimeout(() => $(this).trigger("active"), 1);
175 * Loops through the user specified content and appends them to the DOM
176 * in the order specified by the user config
178 _initContent(content) {
179 for (let content_type in content) {
180 if (content_type == "clock")
181 this._initClock(content[content_type]);
182 else if (content_type == "html")
183 this._initHTML(content[content_type]);
185 log.warn("Specified content " + content_type + " is not valid.");
190 * Asyncrhonously reads JSON config file from json/SplashScreen.json
191 * and overwrites the default options with those specified by the config.
193 * Triggers: 'load' on completion. Caller (LoginManager) must listen for this
194 * event to then trigger 'init'
198 $.extend(true, options, this._DEF_OPT);
200 $.getJSON("json/SplashScreen.json", (data) => {
201 $.extend(true, options, data);
202 this._options = options;
203 $(this).trigger("load");
205 $.extend(true, options, {});
206 this._options = options;
207 $(this).trigger("load");
212 * Closes the splash screen if there has been no user activity
215 if (this._state == "open") {
217 $(this).trigger("timeout");
222 * Determines if there was user acitivty within in a given amount
224 * Returns 1 if splash screen is active, else 0
227 if (moment().diff(this._last_active, "seconds", true) > 30) {
234 * Creates clock elements based on the usr config.
235 * Appends each clock to the DOM and binds update events using _startClock
238 if (typeof opts != "object") {
239 log.error("Unable to initialize clock thats not an object");
242 // handle arrays and a single clock object
243 if (!Array.isArray(opts))
246 /* loop through each clock in the config and add it to the dom,
247 then initialize an update event using start clock */
248 for (let i in opts) {
249 this.$clock = $("<div id='clock-" + i + "' class='clock'></div>");
250 this.$content.append(this.$clock);
251 this._startClock(this.$clock, opts[i]);
256 * Applys the css specfied in the argument opts to the jQuery oboject $clock.
257 * Subscribes the clock to a tick event
259 _startClock($clock, opts) {
260 if (typeof opts != "object") {
261 log.error("Clock opts is not a valid object");
264 // handle multiple formats for multiple clocks on the same line
265 if(typeof opts.format == "string")
266 opts.format = [opts.format];
268 // ensure the format is now an array
269 if(!Array.isArray(opts.format)) {
270 log.error(`Specfied clock format is not a valid type.
271 Type can be a single string or Array.`);
275 if(!Array.isArray(opts.css))
276 opts.css = [opts.css];
278 for (let i in opts.format) {
280 let $format = $("<sub></sub>");
281 // create text field in clock
282 $clock.append($format);
284 if (i < opts.css.length && typeof opts.css[i] == "object")
285 $format.css(opts.css[i]);
288 $format.text(moment().format(opts.format[i]));
289 $(this).on("tick", () => {
290 $format.text(moment().format(opts.format[i]));
294 if (typeof opts["parent-css"] == "object")
295 $clock.css(opts["parent-css"]);
301 * Inserts HTML specified in the user config into the splash screen
302 * accepts plain strings and objects. String literals are interpreted as
303 * normal text element. Objects are set using the jQuery API
306 // handle single objects and strings
307 if (!Array.isArray(opts)) {
311 for (let el of opts) {
312 if (typeof el == "string") {
313 let $el = $("<text>");
315 // create simple text element
316 this.$content.append($el);
317 } else if (typeof el == "object") {
318 // let user specify element properites in object el.
319 let $el = $("<div>");
320 for (let prop in el) {
323 this.$content.append($el);
326 log.warn("Splash screen html element is invalid type");
333 * Handles the key events for the SplachScreen and active-inactive events
338 case 13: // Enter key
339 if (this._state == "closed")
343 if (this._state == "open")
345 else if (this._state == "closed")
349 if (this._state == "closed")
354 // stop reset timeout since there has been user activity
355 if (this._state == "open")
356 clearTimeout(this.resetTimeout);
358 // trigger active event if the user has been inactive long enough
359 if (!this._isActive())
360 $(this).trigger("active", e);
364 * _open and _close will toggle the screen and animate it opening and closing
365 * adds a resetTimeout function to automatically close after a period of user
368 * Uses a _state machine consisting of {'open', 'closed', 'moving'}.
369 * Transitions are not possible while the _state == moving. This prevents
370 * fillUserSelect from trigger concurrernt transitions which would lead to
371 * undefined behaivour.
374 if (this._state != "open") {
375 log.warn("Cannot close splash screen when _state is: " + this._state);
379 this._state = "moving";
380 if (this.transition == "fade") {
381 this.$el.fadeIn("slow", () => {
382 this._state = "closed";
383 this.$content.fadeIn("slow");
384 clearTimeout(this.resetTimeout);
386 } else if (this.transition == "slide") {
389 },"slow", "easeOutQuint", () => {
390 this._state = "closed";
391 clearTimeout(this.resetTimeout);
398 if (this._state != "closed") {
399 log.warn("Cannot open splash screen when _state is: " + this._state);
402 clearTimeout(this.resetTimeout);
403 let reset_duration = 60*1000;
405 if (this._state == "open" || this._state == "moving") {
406 this.resetTimeout = setTimeout(this.reset, reset_duration);
409 this._state = "moving";
411 if (this.transition == "fade") {
412 this.$content.fadeOut("fast", () => {
413 this.$el.fadeOut(this._ANIMATION_DUR, () => {
414 this._state = "open";
418 } else if (this.transition == "slide") {
421 }, "slow", "easeInCubic", () => {
422 this._state = "open";