PageSourceSearch

https://aurora.hwg-lu.de/pwm/public/resources/nonce-m1b96f/js/main.js

js hwg-lu.de collected 2026-10-02 16:47:29 UTC 79,927 bytes, 2,185 lines download raw bytes

1/*
2 * Password Management Servlets (PWM)
3 * http://www.pwm-project.org
4 *
5 * Copyright (c) 2006-2009 Novell, Inc.
6 * Copyright (c) 2009-2023 The PWM Project
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21"use strict";
22
23var PWM_GLOBAL = PWM_GLOBAL || {};
24var PWM_MAIN = PWM_MAIN || {};
25var PWM_VAR = PWM_VAR || {};
26var PWM_API = PWM_API || {};
27
28PWM_API.formatDate = function(dateObj) {
29    return PWM_MAIN.TimestampHandler.formatDate(dateObj);
30};
31
32PWM_MAIN.ajaxTimeout = 60 * 1000;
33
34PWM_MAIN.pageLoadHandler = function() {
35    PWM_GLOBAL['localeBundle'] = PWM_GLOBAL['localeBundle'] || [];
36    PWM_GLOBAL['url-context'] = PWM_MAIN.getObject('application-info').getAttribute('data-url-context');
37    PWM_GLOBAL['pwmFormID'] = PWM_MAIN.getObject('application-info').getAttribute('data-pwmFormID');
38    PWM_GLOBAL['clientEtag'] = PWM_MAIN.getObject('application-info').getAttribute('data-clientEtag');
39
40    var finishInitCounter = 0;
41    var initFunctions = [];
42
43    var completeFunction = function () {
44        finishInitCounter++;
45        if ( finishInitCounter === initFunctions.length ) {
46            PWM_MAIN.initPage();
47        }
48    };
49
50    initFunctions.push(function () {
51        PWM_MAIN.loadClientData(completeFunction);
52    });
53    if (typeof PWM_CONFIG !== 'undefined') {
54        PWM_GLOBAL['localeBundle'].push('Config');
55    }
56    if (typeof PWM_SETTINGS !== 'undefined' && typeof PWM_CFGEDIT !== 'undefined') {
57        initFunctions.push(function () {
58            PWM_CFGEDIT.initConfigSettingsDefinition(completeFunction);
59        });
60    }
61    if (typeof PWM_ADMIN !== 'undefined') {
62        PWM_GLOBAL['localeBundle'].push('Admin');
63
64        initFunctions.push(function () {
65            PWM_ADMIN.initAdminPage(completeFunction);
66        });
67    }
68    {
69        var seenBundles = [];
70        PWM_GLOBAL['localeBundle'].push('Display');
71        PWM_MAIN.JSLibrary.forEachInArray(PWM_GLOBAL['localeBundle'], function (bundleName) {
72            if (!PWM_MAIN.JSLibrary.arrayContains(seenBundles, bundleName)) {
73                initFunctions.push(function () {
74                    PWM_MAIN.loadLocaleBundle(bundleName, completeFunction);
75                });
76            }
77        });
78    }
79
80    PWM_MAIN.JSLibrary.forEachInArray(initFunctions,function(initFunction){
81        initFunction();
82    });
83};
84
85PWM_MAIN.loadClientData=function(completeFunction) {
86    PWM_GLOBAL['app-data-client-retry-count'] = PWM_GLOBAL['app-data-client-retry-count'] + 1;
87    var url = PWM_GLOBAL['url-context'] + "/public/api?processAction=clientData&etag=" + PWM_GLOBAL['clientEtag'];
88    url = PWM_MAIN.addParamToUrl(url,'pageUrl',window.location.href);
89    var loadFunction = function(data) {
90        PWM_MAIN.JSLibrary.forEachInObject(data['data']['PWM_GLOBAL'],function(key,value){
91            PWM_GLOBAL[key] = value;
92        })
93        PWM_MAIN.log('loaded client data');
94        if (completeFunction) completeFunction();
95    };
96    var errorFunction = function(error) {
97        var errorMsg = 'unable to read app-data: ' + error;;
98        PWM_MAIN.log(errorMsg);
99        if (!PWM_VAR['initError']) PWM_VAR['initError'] = errorMsg;
100        if (completeFunction) completeFunction();
101    };
102    PWM_MAIN.ajaxRequest(url, loadFunction, {errorFunction:errorFunction,method:'GET',preventCache:false,addPwmFormID:false});
103};
104
105PWM_MAIN.loadLocaleBundle = function(bundleName, completeFunction) {
106    var clientConfigUrl = PWM_GLOBAL['url-context'] + "/public/api?processAction=strings&bundle=" + bundleName;
107    clientConfigUrl = PWM_MAIN.addParamToUrl(clientConfigUrl,'etag',PWM_GLOBAL['clientEtag']);
108    var loadFunction = function(data){
109        if (data['error'] === true) {
110            console.error('unable to load locale bundle from ' + clientConfigUrl + ', error: ' + data['errorDetail'])
111        } else {
112            PWM_GLOBAL['localeStrings'] = PWM_GLOBAL['localeStrings'] || {};
113            PWM_GLOBAL['localeStrings'][bundleName] = {};
114            for (var settingKey in data['data']) {
115                PWM_GLOBAL['localeStrings'][bundleName][settingKey] = data['data'][settingKey];
116            }
117        }
118        PWM_MAIN.log('loaded locale bundle data for ' + bundleName);
119        if (completeFunction) completeFunction();
120    };
121    var errorFunction = function(){
122        var errorMsg = 'unable to load locale bundle from , please reload page (' + error + ')';
123        PWM_MAIN.log(errorMsg);
124        if (!PWM_VAR['initError']) PWM_VAR['initError'] = errorMsg;
125        if (completeFunction) completeFunction();
126    };
127    PWM_MAIN.ajaxRequest(clientConfigUrl,loadFunction,{errorFunction:errorFunction,method:'GET',preventCache:false,addPwmFormID:false});
128};
129
130PWM_MAIN.initPage = function() {
131    PWM_MAIN.applyFormAttributes();
132    PWM_MAIN.initDisplayTabPreferences();
133
134    document.body.setAttribute( 'data-browserType', PWM_GLOBAL['browserType']);
135
136    PWM_MAIN.addEventHandler(document, "keypress", function (event) {
137        PWM_MAIN.checkForCapsLock(event);
138    });
139
140    PWM_MAIN.doQuery('.pwm-link-print',function(element){
141        PWM_MAIN.addEventHandler(element, "click", function(){ window.print(); });
142    });
143
144    if (PWM_MAIN.getObject('ldapProfile')) {
145        PWM_MAIN.addEventHandler('ldapProfile', 'click', function () {
146            PWM_MAIN.updateLoginContexts()
147        });
148    }
149
150    PWM_MAIN.addEventHandler('icon-configModeHelp','click',function(){
151        PWM_MAIN.showDialog({title:'Notice - Configuration Mode',text:PWM_MAIN.showString('Display_ConfigOpenInfo',{bundle:'Config'})});
152    });
153
154    if (PWM_GLOBAL['applicationMode'] === 'CONFIGURATION') {
155        var configModeNoticeSeen = PWM_MAIN.Preferences.readSessionStorage('configModeNoticeSeen');
156        if (!configModeNoticeSeen) {
157            PWM_MAIN.Preferences.writeSessionStorage('configModeNoticeSeen',true);
158            PWM_MAIN.showDialog({title:'Notice - Configuration Mode',text:PWM_MAIN.showString('Display_ConfigOpenInfo',{bundle:'Config'})});
159        }
160    }
161
162    if (PWM_GLOBAL['pageLeaveNotice'] > 0) {
163        PWM_MAIN.addEventHandler(document, "beforeunload", function(){
164            var url = PWM_GLOBAL['url-command'] + "?processAction=pageLeaveNotice&pwmFormID=" + PWM_GLOBAL['pwmFormID'];
165            PWM_MAIN.ajaxRequest(url,function(){},{preventCache:true});
166        });
167    }
168
169    if (PWM_MAIN.getObject('message')) {
170        PWM_GLOBAL['message_originalStyle'] = PWM_MAIN.getObject('message').style;
171        PWM_MAIN.addEventHandler(window, "resize", function(){ PWM_MAIN.messageDivFloatHandler() });
172        PWM_MAIN.addEventHandler(window, "scroll", function(){ PWM_MAIN.messageDivFloatHandler() });
173    }
174
175    if (PWM_GLOBAL['enableIdleTimeout']) {
176        PWM_MAIN.IdleTimeoutHandler.initCountDownTimer(PWM_GLOBAL['MaxInactiveInterval']);
177    }
178    PWM_MAIN.initLocaleSelectorMenu('localeSelectionMenu');
179
180    if (PWM_MAIN.getObject('LogoutButton')) {
181        PWM_MAIN.showTooltip({
182            id: 'LogoutButton',
183            position: ['below', 'above'],
184            text: PWM_MAIN.showString("Long_Title_Logout"),
185            width: 500
186        });
187    }
188
189    PWM_MAIN.JSLibrary.onPageLoad(function(){
190        PWM_MAIN.JSLibrary.forEachInArray(PWM_GLOBAL['startupFunctions'],function(startupFunction){
191            try {
192                startupFunction();
193            } catch(e) {
194                console.error('error executing startup function: ' + e);
195            }
196        })
197    });
198
199    PWM_MAIN.TimestampHandler.initAllElements();
200
201    ShowHidePasswordHandler.initAllForms();
202    PWM_MAIN.log('initPage completed');
203};
204
205PWM_MAIN.initDisplayTabPreferences = function() {
206    var storageName = 'lastTabState-' + window.location.pathname + '-';
207    var knownTabNames = [];
208    PWM_MAIN.doQuery('div.tab-container>input[type="radio"]',function(formElement) {
209        var name = formElement.name;
210        var id = formElement.id;
211        if (!PWM_MAIN.JSLibrary.arrayContains(knownTabNames,name)) {
212            knownTabNames.push(name);
213        }
214        PWM_MAIN.addEventHandler(formElement, 'click', function(){
215            PWM_MAIN.Preferences.writeSessionStorage(storageName + name, id);
216        });
217
218    });
219
220    knownTabNames.forEach(function(name){
221        var value = PWM_MAIN.Preferences.readSessionStorage(storageName + name);
222        if (value) {
223            var selector = "input[name='" + name + "'][type='radio'][id='" + value + "']";
224            PWM_MAIN.doQuery(selector,function(formElement){
225                formElement.checked = true;
226            });
227        }
228    });
229};
230
231
232PWM_MAIN.applyFormAttributes = function() {
233    PWM_MAIN.doQuery('form',function(formElement) {
234        formElement.setAttribute('autocomplete', 'off');
235
236        //ios/webkit
237        formElement.setAttribute('autocapitalize', 'none');
238        formElement.setAttribute('autocorrect', 'off');
239    });
240
241    PWM_MAIN.doQuery('.pwm-form:not(.pwm-form-captcha)',function(formElement) {
242        PWM_MAIN.addEventHandler(formElement, "submit", function(event){
243            PWM_MAIN.handleFormSubmit(formElement, event);
244        });
245    });
246
247    PWM_MAIN.doQuery('a:not([target])',function(linkElement) {
248        try {
249            if (linkElement.classList.contains('pwm-basic-link')) {
250                return;
251            }
252        } catch (e) { /* ignore for browsers that don't support classList */ }
253        var hrefValue = linkElement.getAttribute('href');
254        if (hrefValue && hrefValue.charAt(0) !== '#') {
255            PWM_MAIN.addEventHandler(linkElement, "click", function (event) {
256                console.log('intercepted anchor click event');
257                event.preventDefault();
258                PWM_MAIN.showWaitDialog({loadFunction: function () {
259                        PWM_MAIN.gotoUrl(hrefValue);
260                    }});
261            });
262            linkElement.removeAttribute('href');
263        }
264    });
265
266    // handle html5 form attribute in JS in case browser (IE) doesn't support it.
267    if(PWM_MAIN.isIE()){
268        PWM_MAIN.doQuery("button[type=submit][form]",function(element){
269            PWM_MAIN.log('added IE event handler for submit button with form attribute ' + element.i
269d);
270            PWM_MAIN.addEventHandler(element,'click',function(e){
271                e.preventDefault();
272                PWM_MAIN.log('IE event handler intercepted submit for referenced form attribute ' + element.id);
273                var formID = element.getAttribute('form');
274                PWM_MAIN.handleFormSubmit(PWM_MAIN.getObject(formID));
275            });
276        });
277    }
278};
279
280PWM_MAIN.isIE = function() {
281    var browserType = document.body.getAttribute('data-browserType');
282    return browserType && "ie" === browserType.toLowerCase();
283}
284
285PWM_MAIN.preloadAll = function(nextFunction) {
286    if (!PWM_MAIN.html5DialogSupport()) {
287        if (!PWM_MAIN.getObject('css-nihilo')) {
288            PWM_MAIN.log('adding nihilo to body class css');
289            document.body.classList.add("nihilo");
290            PWM_MAIN.addCssClass()
291            var link = document.createElement('link');
292            link.rel = 'stylesheet';
293            link.type = 'text/css';
294            link.href = PWM_GLOBAL['url-context'] + '/public/resources/webjars/dijit/themes/nihilo/nihilo.css';
295            link.id = 'css-nihilo'
296            document.getElementsByTagName('HEAD')[0].appendChild(link);
297        }
298
299        require(["dijit/Dialog"], function () {
300            if (nextFunction) { nextFunction(); }
301        });
302    } else {
303        if (nextFunction) { nextFunction(); }
304    }
305};
306
307PWM_MAIN.showString = function (key, options) {
308    options = options === undefined ? {} : options;
309    var bundle = ('bundle' in options) ? options['bundle'] : 'Display';
310    PWM_GLOBAL['localeStrings'] = PWM_GLOBAL['localeStrings'] || {};
311    if (!PWM_GLOBAL['localeStrings'][bundle]) {
312        return "UNDEFINED BUNDLE: " + bundle;
313    }
314    if (PWM_GLOBAL['localeStrings'][bundle][key]) {
315        var returnStr = PWM_GLOBAL['localeStrings'][bundle][key];
316        for (var i = 0; i < 10; i++) {
317            if (options['value' + i]) {
318                returnStr = returnStr.replace('%' + i + '%',options['value' + i]);
319            }
320        }
321        return returnStr;
322    } else {
323        return "UNDEFINED STRING-" + key;
324    }
325};
326
327PWM_MAIN.addEventHandler = function(nodeId,events,theFunction) {
328    var element = PWM_MAIN.getObject(nodeId);
329    if (element && events) {
330        var eventArray = Array.isArray(events) ? events : events.split(',');
331        PWM_MAIN.JSLibrary.forEachInArray(eventArray,function(event){
332            if (element.addEventListener){
333                element.addEventListener(event, theFunction, false);
334            } else if (element.attachEvent){
335                element.attachEvent('on'+event, theFunction);
336            }
337        });
338    }
339};
340
341PWM_MAIN.addOneTimeEventHandler = function(nodeId,events,theFunctions) {
342    var oneTimeFunction = function() {
343        element.removeEventListener(events, oneTimeFunction);
344        theFunctions();
345    }
346    PWM_MAIN.addEventHandler(nodeId,events,oneTimeFunction)
347};
348
349
350PWM_MAIN.gotoUrl = function(url, options) {
351    options = options === undefined ? {} : options;
352    if (!('noContext' in options) && url.indexOf(PWM_GLOBAL['url-context']) !== 0) {
353        if (url.substring(0,1) === '/') {
354            url = PWM_GLOBAL['url-context'] + url;
355        }
356    }
357
358    if ('addFormID' in options) {
359        if (url.indexOf('pwmFormID') === -1) {
360            url = PWM_MAIN.addPwmFormIDtoURL(url);
361        }
362    }
363
364    var executeGoto = function() {
365        if (options['delay']) {
366            setTimeout(function () {
367                PWM_MAIN.log('redirecting to new url: ' + url);
368                window.location = url;
369            }, options['delay']);
370        } else {
371            PWM_MAIN.log('redirecting to new url: ' + url);
372            window.location = url;
373        }
374    };
375
376    var hideDialog = options['hideDialog'] = true;
377    if (hideDialog) {
378        executeGoto();
379    } else {
380        PWM_MAIN.showWaitDialog({loadFunction:function () {
381                executeGoto();
382            }});
383    }
384};
385
386
387PWM_MAIN.handleLoginFormSubmit = function(form, event) {
388    PWM_MAIN.log('entering handleLoginFormSubmit');
389    PWM_MAIN.cancelEvent(event);
390
391    PWM_MAIN.showWaitDialog({loadFunction: function () {
392            var options = {};
393            options['content'] = PWM_MAIN.JSLibrary.formToValueMap(form);
394            delete options['content']['processAction'];
395            delete options['content']['pwmFormID'];
396            var url = 'login?processAction=restLogin';
397            if (options['content']['skipCaptcha'])
398            {
399                PWM_MAIN.addParamToUrl( url, 'skipCaptcha', options['content']['skipCaptcha']);
400            }
401            var loadFunction = function(data) {
402                if (data['error'] === true) {
403                    PWM_MAIN.getObject('password').value = '';
404                    PWM_MAIN.showErrorDialog(data,{
405                        okAction:function(){
406                            setTimeout(function(){
407                                PWM_MAIN.getObject('password').focus();
408                            },50);
409                        }
410                    });
411                    return;
412                }
413                PWM_MAIN.log('authentication success');
414                var nextURL = data['data']['nextURL'];
415                if (nextURL) {
416                    PWM_MAIN.gotoUrl(nextURL, {noContext: true});
417                }
418            };
419            PWM_MAIN.ajaxRequest(url,loadFunction,options);
420            if(typeof grecaptcha !== 'undefined'){
421                try {
422                    grecaptcha.reset(); // reset the
423                } catch (e) {
424                    PWM_MAIN.log("error resetting the captcha: " + e)
425                }
426            }
427        }});
428};
429
430PWM_MAIN.log = function(text) {
431    console.log(text);
432};
433
434
435PWM_MAIN.handleFormSubmit = function(form, event) {
436    PWM_MAIN.log('entering handleFormSubmit');
437    PWM_MAIN.cancelEvent(event);
438
439    PWM_GLOBAL['idle_suspendTimeout'] = true;
440    if ( form.elements ) {
441        var formElements = form.elements;
442        for (var i = 0; i < formElements.length; i++) {
443            formElements[i].readOnly = true;
444            if (formElements[i].type === 'button' || formElements[i].type === 'submit') {
445                formElements[i].disabled = true;
446            }
447        }
448    }
449
450    PWM_MAIN.showWaitDialog({loadFunction:function(){
451            form.submit();
452        }});
453    return false;
454};
455
456
457PWM_MAIN.checkForCapsLock = function(e) {
458    var capsLockWarningElement = PWM_MAIN.getObject('capslockwarning');
459    if (capsLockWarningElement === null || capsLockWarningElement === undefined) {
460        return;
461    }
462
463    var capsLockKeyDetected = false;
464    {
465        var elementTarget = null;
466        if (e.target) {
467            elementTarget = e.target;
468        } else if (e.srcElement) {
469            elementTarget = e.srcElement;
470        }
471        if (elementTarget) {
472            if (elementTarget.nodeName === 'input' || elementTarget.nodeName === 'INPUT') {
473                var kc = e.keyCode ? e.keyCode : e.which;
474                var sk = e.shiftKey ? e.shiftKey : ((kc === 16));
475                if (((kc >= 65 && kc <= 90) && !sk) || ((kc >= 97 && kc <= 122) && sk)) {
476                    capsLockKeyDetected = true;
477                }
478            }
479        }
480    }
481
482    var displayDuration = 5 * 1000;
483    if (capsLockKeyDetected) {
484        PWM_MAIN.removeCssClass('capslockwarning','display-none');
485        PWM_GLOBAL['lastCapsLockErrorTime'] = (new Date().getTime());
486        setTimeout(function(){
487            if ((new Date().getTime() - PWM_GLOBAL['lastCapsLockErrorTime'] > displayDuration)) {
488                PWM_MAIN.addCssClass('capslockwarning','display-none');
489            }
490        },displayDuration + 500);
491    } else {
492        PWM_MAIN.addCssClass('capslockwarning','display-none');
493    }
494};
495
496PWM_MAIN.getObject = function(name) {
497    if (name === null || name === undefined) {
498        return null;
499    }
500
501    if (name.tagName) {  // argument is already a dom element
502        return name;
503    }
504
505    if (name === document || name === window) {
506        return name;
507    }
508
509    var ns4 = document.layers;
510    var w3c = document.getElementById;
511    var ie4 = document.all;
512
513    if (ns4) {
514        return eval('document.' + name);
515    }
516    if (w3c) {
517        return document.getElementById(name);
518    }
519    if (ie4) {
520        return eval('document.all.' + name);
521    }
522    return false;
523};
524
525PWM_MAIN.trimString = function(sInString) {
526    sInString = sInString.replace(/^\s+/g, "");
527    // strip leading
528    return sInString.replace(/\s+$/g, "");
529    // strip trailing
530};
531
532PWM_MAIN.showDijitTooltip = function(options){
533    options = options === undefined ? {} : options;
534
535    if (!options['id']) {
536        return;
537    }
538
539    var id = options['id'] instanceof Array ? options['id'] : [options['id']];
540    var position = options['position'] instanceof Array ? options['position'] : null;
541
542    var dojoOptions = {};
543    dojoOptions['connectId'] = id;
544    dojoOptions['id'] = id[0];
545    dojoOptions['label'] = 'text' in options ? options['text'] : "missing text option";
546
547    if (position) {
548        dojoOptions['position'] = position;
549    }
550
551    if (options['width']) {
552        dojoOptions['label'] = '<div style="max-width:' + options['width'] + 'px">' + dojoOptions['label'] + '</div>'
553    }
554
555    require(["dijit/Tooltip","dijit/registry"],function(Tooltip){
556        PWM_MAIN.clearDijitWidget(id[0]);
557        new Tooltip(dojoOptions);
558    });
559};
560
561PWM_MAIN.showTooltip = function(options){
562    options = options === undefined ? {} : options;
563
564    if (!options['id']) {
565        return;
566    }
567
568    var id = options['id'] instanceof Array ? options['id'] : [options['id']];
569
570    var dojoOptions = {};
571    dojoOptions['connectId'] = id;
572    dojoOptions['id'] = id[0];
573
574    var label = 'text' in options ? options['text'] : "missing text option for id " + id;
575
576    var element = PWM_MAIN.getObject(id);
577    if (element) {
578        element.setAttribute('title',label);
579    }
580};
581
582
583
584PWM_MAIN.clearDijitWidget = function (widgetName) {
585    require(["dojo","dijit/registry"],function(dojo, registry){
586
587        var oldDijitNode = registry.byId(widgetName);
588        if (oldDijitNode) {
589            try {
590                oldDijitNode.destroyRecursive();
591            } catch (error) {
592                PWM_MAIN.log('error destroying old widget: ' + error);
593            }
594
595            try {
596                oldDijitNode.destroy();
597            } catch (error) {
598                PWM_MAIN.log('error destroying old widget: ' + error);
599            }
600        }
601    });
602};
603
604PWM_MAIN.showLocaleSelectionMenu = function(nextFunction, options) {
605    options = options === undefined ? {} : options;
606    var excludeLocales = 'excludeLocales' in options ? options['excludeLocales'] : [];
607
608    var localeData = PWM_GLOBAL['localeInfo'];
609
610    var bodyHtml = '<table class="noborder" style="width:auto;margin-right:auto;margin-left:auto;overflow-x:scroll">';
611    PWM_MAIN.JSLibrary.forEachInObject(localeData, function (localeKey, loopDisplayName) {
612        if (!PWM_MAIN.JSLibrary.arrayContains(excludeLocales, localeKey)) {
613            var flagCode = PWM_GLOBAL['localeFlags'][localeKey];
614            var flagUrl = PWM_GLOBAL['url-resources'] + '/webjars/famfamfam-flags/dist/png/' + flagCode + '.png';
615            bodyHtml += '<tr style="cursor:pointer" id="locale-row-' + localeKey + '">';
616            bodyHtml += '<td><img alt="Flag Image" src="' + flagUrl + '"/></td>';
617            bodyHtml += '<td>' + loopDisplayName + '</td>';
618            bodyHtml += '</tr>';
619        }
620    });
621    bodyHtml += '</table>';
622
623    PWM_MAIN.showDialog({
624        showClose: true,
625        showOk: false,
626        text: bodyHtml,
627        title: PWM_MAIN.showString('Title_LocaleSelect'),
628        loadFunction: function () {
629            PWM_MAIN.JSLibrary.forEachInObject(localeData, function (localeKey, loopDisplayName) {
630                PWM_MAIN.addEventHandler('locale-row-' + localeKey, 'click', function () {
631                    PWM_MAIN.closeWaitDialog();
632                    nextFunction(localeKey);
633                });
634            });
635        }
636    });
637};
638
639PWM_MAIN.initLocaleSelectorMenu = function(attachNode) {
640    PWM_MAIN.addEventHandler(attachNode,'click',function(){
641        PWM_MAIN.showLocaleSelectionMenu(function(localeKey){
642            PWM_MAIN.showWaitDialog({loadFunction:function(){
643                    var url = PWM_GLOBAL['url-context'] + '/public/api?locale=' + localeKey;
644                    PWM_MAIN.ajaxRequest(url, function(){
645                        try {
646                            var newLocation = window.location;
647                            var searchParams = new URLSearchParams(newLocation.search);
648                            if ( searchParams.has('locale')) {
649                                searchParams.set('locale', localeKey);
650                                newLocation.search = searchParams.toString();
651                                window.location = newLocation;
652                                return;
653                            }
654                        } catch (e) {
655                            PWM_MAIN.log('error replacing locale parameter on existing url: ' + e);
656                        }
657
658                        window.location.reload(true);
659                    });
660                }
661            });
662        });
663    });
664};
665
666
667
668PWM_MAIN.showErrorDialog = function(error, options) {
669    options = options === undefined ? {} : options;
670    var forceReload = false;
671    var body = '';
672    var logMsg = '';
673    var titleMsg = PWM_MAIN.showString('Title_Error');
674    if ('text' in options) {
675        body += options['text'];
676        body += '<br/><br/>';
677        logMsg += options['text'];
678    }
679    if (error && error['error']) {
680        var code = error['errorCode'];
681        if (code === 5028 || code === 5034 || code === 5035) {
682            forceReload = true;
683        }
684        titleMsg += ' ' + error['errorCode'];
685        body += error['errorMessage'];
686        logMsg += error['errorCode'] + "," + error['errorMessage'];
687        if (error['errorDetail']) {
688            body += "<br/><br/><div class='errorDetail' style='max-height: 250px; overflow-y: auto'>" + error['errorDetail'] + '</div>';
689            logMsg += ", detail: " + error['errorDetail'];
690        }
691    } else {
692        body += error;
693        logMsg += error;
694    }
695
696    if (forceReload) {
697        logMsg += 'due to error code type, reloading page.';
698    }
699
700    PWM_MAIN.log('displaying error message: ' + logMsg);
701    options['title'] = titleMsg;
702    options['text'] = body;
703    var previousOkAction = 'okAction' in options ? options['okAction'] : function() {};
704    options['okAction'] =  function() {
705        if (forceReload) { // incorrect page sequence;
706            var newURL = window.location.pathname;
707            PWM_MAIN.gotoUrl(newURL);
708            PWM_MAIN.showWaitDialog();
709        } else {
710            previousOkAction();
711        }
712    };
713    PWM_MAIN.showDialog(options);
714};
715
716PWM_MAIN.showWaitDialog = function(options) {
717    PWM_MAIN.closeWaitDialog();
718
719    options = options || {};
720    options['title'] = options['title'] || '';
721
722    var waitOverlayDiv = document.createElement('div');
723    waitOverlayDiv.setAttribute('id','wait-overlay');
724    document.body.appendChild(waitOverlayDiv);
725
726    var waitOverlayMessage = document.createElement('div');
727    waitOverlayMessage.setAttribute('id','wait-overlay-message');
728    waitOverlayMessage.innerHTML = '<span>' + options['title'] + '</span><div id="wait-overlay-inner"></div>';
729    document.body.appendChild(waitOverlayMessage);
730
731    if ('loadFunction' in options) {
732        options.loadFunction();
733    }
734};
735
736PWM_MAIN.closeWaitDialog = function(idName) {
737
738    var html5Mode = PWM_MAIN.html5DialogSupport();
739    if (html5Mode) {
740        if (PWM_MAIN.getObject('html5Dialog')) {
741            PWM_MAIN.getObject('html5Dialog').parentNode.removeChild(PWM_MAIN.getObject('html5Dialog'));
742        }
743    } else {
744        idName = idName === undefined ? 'dialogPopup' : idName;
745        PWM_MAIN.clearDijitWidget(idName);
746    }
747
748    PWM_MAIN.JSLibrary.removeElementFromDom('wait-overlay');
749    PWM_MAIN.JSLibrary.removeElementFromDom('wait-overlay-message');
750};
751
752PWM_MAIN.html5DialogSupport = function() {
753    if (PWM_GLOBAL['client.js.enableHtml5Dialog']) {
754        var testdialog = document.createElement("dialog");
755        testdialog.setAttribute("open", "");
756        return (testdialog.open === true);
757    }
758    return false;
759};
760
761PWM_MAIN.showDialog = function(options) {
762    PWM_MAIN.closeWaitDialog();
763    var html5Dialog = PWM_MAIN.html5DialogSupport();
764
765    options = options === undefined ? {} : options;
766    var title = options['title'] || 'DialogTitle';
767    var text = 'text' in options ? options['text'] : 'DialogBody';
768    var closeOnOk = 'closeOnOk' in options ? options['closeOnOk'] : true;
769    var showOk = 'showOk' in options ? options['showOk'] : true;
770    var showCancel = 'showCancel' in options ? options['showCancel'] : false;
771    var showClose = 'showClose' in options ? options['showClose'] : false;
772    var allowMove = 'allowMove' in options ? options['allowMove'] : false;
773    var idName = 'id' in options ? options['id'] : 'dialogPopup';
774    var dialogClass = 'dialogClass' in options ? options['dialogClass'] : null;
775    var dojoStyle = 'dojoStyle' in options ? options['dojoStyle'] : null;
776    var okLabel = 'okLabel' in options ? options['okLabel'] : PWM_MAIN.showString('Button_OK');
777    var buttonHtml = 'buttonHtml' in options ? options['buttonHtml'] : '';
778    var href = 'href' in options ? options['href'] : null;
779
780    var okAction = function(){
781        if (closeOnOk) {
782            PWM_MAIN.closeWaitDialog(idName);
783        }
784        if ('okAction' in options) {
785            options['okAction']();
786        } else {
787            PWM_MAIN.log('dialog okAction is empty')
788        }
789    };
790    var cancelAction = 'cancelAction' in options ? options['cancelAction'] : function(){
791        PWM_MAIN.closeWaitDialog(idName);
792        PWM_MAIN.log('no-dialog-cancelaction')
793    };
794    var loadFunction = 'loadFunction' in options ? options['loadFunction'] : function(){
795        PWM_MAIN.log('no-dialog-loadfunction')
796    };
797
798    PWM_VAR['dialog_loadFunction'] = loadFunction;
799
800    var bodyText = '';
801    bodyText += text;
802
803    if (showOk || showCancel || buttonHtml.length > 0) {
804        bodyText += '<div class="buttonbar">';
805        if (showOk) {
806            bodyText += '<button class="btn" id="dialog_ok_button">'
807                + '<span class="btn-icon pwm-icon pwm-icon-check-square-o"></span>'
808                + okLabel + '</button>  ';
809        }
810        if (showCancel) {
811            bodyText += '<button class="btn" id="dialog_cancel_button">'
812                + '<span class="btn-icon pwm-icon pwm-icon-times"></span>'
813                + PWM_MAIN.showString('Button_Cancel') + '</button>  ';
814        }
815        bodyText += buttonHtml;
816        bodyText += '</div>';
817    }
818
819    var dialogClassText = 'dialogBody';
820    if (dialogClass) {
821        dialogClassText += ' ' + dialogClass;
822    }
823    bodyText = '<div class="' + dialogClassText + '">
823' + bodyText + '</div>';
824
825    if (html5Dialog) {
826        var doDialogDisplay = function(){
827            PWM_MAIN.closeWaitDialog();
828            var dialogElement = document.createElement("dialog");
829            dialogElement.setAttribute("id", 'html5Dialog');
830            var html5DialogHtml = '<div class="titleBar">' + title;
831            if (showClose) {
832                html5DialogHtml += '<div id="icon-closeDialog" class="closeIcon pwm-icon pwm-icon-times"></div>'
833            }
834            html5DialogHtml += '</div><div class="body">' + bodyText + '</div>';
835            dialogElement.innerHTML = html5DialogHtml;
836            document.body.appendChild(dialogElement);
837            dialogElement.showModal();
838
839            setTimeout(function () {
840                if (showOk) {
841                    PWM_MAIN.addEventHandler('dialog_ok_button', 'click', function () {
842                        okAction()
843                    });
844                }
845                if (showClose) {
846                    PWM_MAIN.addEventHandler('icon-closeDialog', 'click', function () {
847                        PWM_MAIN.closeWaitDialog();
848                    });
849                }
850
851                if (showCancel) {
852                    PWM_MAIN.addEventHandler('dialog_cancel_button', 'click', function () {
853                        cancelAction()
854                    });
855                }
856                setTimeout(loadFunction, 100);
857            }, 100);
858        }
859
860        if (href) {
861            var hrefContentHandler = function( value ) {
862                bodyText = '<div class="' + dialogClassText + '">' + value + '</div>';
863                doDialogDisplay();
864            };
865            PWM_MAIN.showWaitDialog({loadFunction:function(){
866                    PWM_MAIN.ajaxRequest(href,hrefContentHandler,{method:'GET',responseMimeType:'text/html',handleAs:'html'});
867                }});
868        } else {
869            doDialogDisplay();
870        }
871    } else {
872        PWM_MAIN.preloadAll();
873        require(["dojo", "dijit/Dialog"], function (dojo, Dialog) {
874            PWM_MAIN.clearDijitWidget(idName);
875            var theDialog = new Dialog({
876                id: idName,
877                closable: showClose,
878                draggable: allowMove,
879                title: title,
880                style: dojoStyle,
881                content: bodyText,
882                href: href
883            });
884            if (!showClose) {
885                dojo.style(theDialog.closeButtonNode, "display", "none");
886            }
887            dojo.connect(theDialog, "onShow", null, function () {
888                if (showOk) {
889                    PWM_MAIN.addEventHandler('dialog_ok_button', 'click', function () {
890                        okAction()
891                    });
892                }
893                if (showCancel) {
894                    PWM_MAIN.addEventHandler('dialog_cancel_button', 'click', function () {
895                        cancelAction()
896                    });
897                }
898                setTimeout(loadFunction, 100);
899            });
900            theDialog.show();
901        });
902    }
903};
904
905PWM_MAIN.showEula = function(requireAgreement, agreeFunction) {
906    if (agreeFunction && PWM_GLOBAL['eulaAgreed']) {
907        agreeFunction();
908        return;
909    }
910
911    var displayEula = function (data) {
912        PWM_GLOBAL['dialog_agreeAction'] = agreeFunction ? agreeFunction : function(){};
913
914        var bodyText = '<div style="height: 400px; overflow: auto" class="eulaText">' + data + '</div>';
915
916        var dialogOptions = {};
917        dialogOptions['text'] = bodyText;
918        dialogOptions['title'] = 'End User License Agreement';
919
920        if (requireAgreement) {
921            dialogOptions['showCancel'] = true;
922            dialogOptions['okLabel'] = PWM_MAIN.showString('Button_Agree');
923            dialogOptions['okAction'] = function() {
924                PWM_GLOBAL['eulaAgreed']=true;
925                agreeFunction();
926            };
927        }
928
929        PWM_MAIN.showDialog(dialogOptions);
930    };
931
932    var eulaLocation = PWM_GLOBAL['url-resources'] + '/text/eula.txt';
933
934    var options = {};
935    options['method'] = 'GET';
936    options['handleAs'] = 'text';
937    var loadFunction = function (data) {
938        displayEula(data);
939    };
940    PWM_MAIN.ajaxRequest(eulaLocation, loadFunction, options);
941};
942
943PWM_MAIN.showConfirmDialog = function(options) {
944    options = options === undefined ? {} : options;
945    options['showCancel'] = true;
946    options['title'] = 'title' in options ? options['title'] : PWM_MAIN.showString('Button_Confirm');
947    options['text'] = 'text' in options ? options['text'] : PWM_MAIN.showString('Confirm');
948    PWM_MAIN.showDialog(options);
949};
950
951PWM_MAIN.clearError=function() {
952    PWM_GLOBAL['messageStatus'] = '';
953    PWM_MAIN.doShow('messageStatus','\u00a0');
954};
955
956PWM_MAIN.showInfo=function(infoMsg) {
957    PWM_GLOBAL['messageStatus'] = 'message-info';
958    PWM_MAIN.doShow('message-info',infoMsg);
959};
960
961PWM_MAIN.showError=function(errorMsg) {
962    PWM_GLOBAL['messageStatus'] = 'message-error';
963    PWM_MAIN.doShow('message-error',errorMsg);
964};
965
966PWM_MAIN.showSuccess=function(successMsg) {
967    PWM_GLOBAL['messageStatus'] = 'message-success';
968    PWM_MAIN.doShow('message-success',successMsg);
969};
970
971PWM_MAIN.doShow = function(destClass, message, fromFloatHandler) {
972    var messageElement = PWM_MAIN.getObject("message");
973    if (messageElement === null || messageElement.firstChild === null || messageElement.firstChild.nodeValue === null) {
974        return;
975    }
976
977    // clear existing status
978    PWM_MAIN.removeCssClass(messageElement,'message-info');
979    PWM_MAIN.removeCssClass(messageElement,'message-error');
980    PWM_MAIN.removeCssClass(messageElement,'message-success');
981
982    if (destClass === '') {
983        PWM_MAIN.addCssClass(messageElement, "nodisplay")
984        return;
985    } else {
986        PWM_MAIN.removeCssClass(messageElement, "nodisplay")
987    }
988
989    messageElement.firstChild.nodeValue = message;
990
991    PWM_MAIN.addCssClass(messageElement,destClass);
992
993    if (!fromFloatHandler) {
994        PWM_MAIN.messageDivFloatHandler();
995    }
996};
997
998PWM_MAIN.createCSSClass = function(selector, style) {
999    // using information found at: http://www.quirksmode.org/dom/w3c_css.html
1000    // doesn't work in older versions of Opera (< 9) due to lack of styleSheets support
1001    if(!document.styleSheets) return;
1002    if(document.getElementsByTagName("head").length === 0) return;
1003    var styleSheet;
1004    var mediaType;
1005    if(document.styleSheets.length > 0)
1006    {
1007        for(var i = 0; i<document.styleSheets.length; i++)
1008        {
1009            if(document.styleSheets[i].disabled) continue;
1010            var media = document.styleSheets[i].media;
1011            mediaType = typeof media;
1012            // IE
1013            if(mediaType === "string")
1014            {
1015                if(media === "" || media.indexOf("screen") !== -1)
1016                {
1017                    styleSheet = document.styleSheets[i];
1018                }
1019            }
1020            else if(mediaType === "object")
1021            {
1022                try {
1023                    if(media.mediaText === "" || media.mediaText.indexOf("screen") !== -1)
1024                    {
1025                        styleSheet = document.styleSheets[i];
1026                    }
1027                } catch (e) { /* noop */ }
1028            }
1029            // stylesheet found, so break out of loop
1030            if(typeof styleSheet !== "undefined") break;
1031        }
1032    }
1033    // if no style sheet is found
1034    if(typeof styleSheet === "undefined")
1035    {
1036        // create a new style sheet
1037        var styleSheetElement = document.createElement("style");
1038        styleSheetElement.type = "text/css";
1039        // add to <head>
1040        document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
1041        // select it
1042        for(i = 0; i<document.styleSheets.length; i++)
1043        {
1044            if(document.styleSheets[i].disabled) continue;
1045            styleSheet = document.styleSheets[i];
1046        }
1047        // read media type
1048        var media = styleSheet.media;
1049        mediaType = typeof media;
1050    }
1051    // IE
1052    if(mediaType === "string")
1053    {
1054        for(i = 0;i<styleSheet.rules.length;i++)
1055        {
1056            // if there is an existing rule set up, replace it
1057            try {
1058                if(styleSheet.cssRules[i].selectorText && styleSheet.rules[i].selectorText.toLowerCase() === selector.toLowerCase())
1059                {
1060                    styleSheet.rules[i].style.cssText = style;
1061                    return;
1062                }
1063            } catch (e) {
1064                PWM_MAIN.log('error while checking existing rules during cssCreate:' + e);
1065            }
1066        }
1067        // or add a new rule
1068        styleSheet.addRule(selector,style);
1069    }
1070    else if(mediaType === "object")
1071    {
1072        for(i = 0;i<styleSheet.cssRules.length;i++)
1073        {
1074            // if there is an existing rule set up, replace it
1075            if(styleSheet.cssRules[i].selectorText && styleSheet.cssRules[i].selectorText.toLowerCase() === selector.toLowerCase())
1076            {
1077                styleSheet.cssRules[i].style.cssText = style;
1078                return;
1079            }
1080        }
1081        // or insert new rule
1082        styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
1083    }
1084};
1085
1086PWM_MAIN.flashDomElement = function(flashColor,elementName,durationMS) {
1087    var element = PWM_MAIN.getObject(elementName);
1088    if ( element ) {
1089        PWM_MAIN.addCssClass(element,'background-alert-flash');
1090        setTimeout(function(){
1091            //      PWM_MAIN.removeCssClass(element, 'background-alert-flash');
1092        },5000)
1093    }
1094    /*
1095
1096    if (!PWM_MAIN.getObject(elementName)) {
1097        PWM_MAIN.log('cant flash non-existing element id ' + elementName);
1098        return;
1099    }
1100    PWM_MAIN.log('will flash element id ' + elementName);
1101    require(["dojo","dojo/window","dojo/domReady!"],function(dojo) {
1102        var originalBGColor = PWM_MAIN.getRenderedStyle(elementName,'background-color');
1103        PWM_MAIN.getObject(elementName).style.backgroundColor = flashColor;
1104        dojo.animateProperty({
1105            node:elementName,
1106            duration: durationMS,
1107            properties: { backgroundColor: originalBGColor}
1108        }).play();
1109    });
1110     */
1111};
1112
1113PWM_MAIN.getRenderedStyle = function(el,styleProp) {
1114    var x = document.getElementById(el);
1115    if (x.currentStyle) {
1116        return x.currentStyle[styleProp];
1117    }
1118
1119    if (window.getComputedStyle) {
1120        return document.defaultView.getComputedStyle(x,null).getPropertyValue(styleProp);
1121    }
1122
1123    return null;
1124};
1125
1126PWM_MAIN.elementInViewport = function(el, includeWidth) {
1127    var top = el.offsetTop;
1128    var left = el.offsetLeft;
1129    var width = el.offsetWidth;
1130    var height = el.offsetHeight;
1131
1132    while(el.offsetParent) {
1133        el = el.offsetParent;
1134        top += el.offsetTop;
1135        left += el.offsetLeft;
1136    }
1137
1138    var pageY = (typeof(window.pageYOffset)=='number') ? window.pageYOffset : document.documentElement.scrollTop;
1139    var pageX = (typeof(window.pageXOffset)=='number') ? window.pageXOffset : document.documentElement.scrollLeft;
1140
1141    return includeWidth ? (
1142        top >= pageY && (top + height) <= (pageY + window.innerHeight) &&
1143        left >= pageX &&
1144        (left + width) <= (pageX + window.innerWidth)
1145    ) : (
1146        top >= pageY && (top + height) <= (pageY + window.innerHeight)
1147    );
1148};
1149
1150PWM_MAIN.messageDivFloatHandler = function() {
1151    var messageObj = PWM_MAIN.getObject('message');
1152    var messageWrapperObj = PWM_MAIN.getObject('message_wrapper');
1153    if (!messageObj || !messageWrapperObj) {
1154        return;
1155    }
1156
1157    if (PWM_MAIN.hasCssClass('message','nodisplay')) {
1158        return;
1159    }
1160
1161    var doFloatDisplay = !(PWM_MAIN.elementInViewport(messageWrapperObj,false) || PWM_GLOBAL['messageStatus'] === '');
1162
1163    if (PWM_GLOBAL['message_scrollToggle'] !== doFloatDisplay) {
1164        PWM_GLOBAL['message_scrollToggle'] = doFloatDisplay;
1165
1166        if (doFloatDisplay) {
1167            PWM_MAIN.addCssClass(messageObj,'message-scrollFloat');
1168            PWM_MAIN.doShow(PWM_GLOBAL['messageStatus'],messageObj.innerHTML,true);
1169        } else {
1170            PWM_MAIN.removeCssClass(messageObj,'message-scrollFloat');
1171            PWM_MAIN.doShow(PWM_GLOBAL['messageStatus'],messageObj.innerHTML,true);
1172        }
1173    }
1174};
1175
1176PWM_MAIN.pwmFormValidator = function(validationProps, reentrant) {
1177    var CONSOLE_DEBUG = false;
1178
1179    var serviceURL = validationProps['serviceURL'];
1180    var readDataFunction = validationProps['readDataFunction'];
1181    var processResultsFunction = validationProps['processResultsFunction'];
1182    var messageWorking = validationProps['messageWorking'] ? validationProps['messageWorking'] : PWM_MAIN.showString('Display_PleaseWait');
1183    var typeWaitTimeMs = validationProps['typeWaitTimeMs'] ? validationProps['typeWaitTimeMs'] : PWM_GLOBAL['client.ajaxTypingWait'];
1184    var ajaxTimeout = validationProps['ajaxTimeout'] ? validationProps['ajaxTimeout'] : PWM_GLOBAL['client.ajaxTypingTimeout'];
1185    var showMessage = 'showMessage' in validationProps ? validationProps['showMessage'] : true;
1186    var completeFunction = 'completeFunction' in validationProps ? validationProps['completeFunction'] : function(){};
1187
1188
1189    if (CONSOLE_DEBUG) PWM_MAIN.log("pwmFormValidator: beginning...");
1190
1191    //init vars;
1192    if (!PWM_VAR['validationCache']) {
1193        PWM_VAR['validationCache'] = {};
1194    }
1195
1196    // check if data is in cache, if it is just process it.
1197    var formData = readDataFunction();
1198    var formKey = "";
1199    for (var key in formData) {formKey += formData[key] + "-";}
1200
1201    {
1202        var cachedResult = PWM_VAR['validationCache'][formKey];
1203        if (cachedResult) {
1204            processResultsFunction(cachedResult);
1205            if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: processed cached data, exiting');
1206            completeFunction(cachedResult);
1207            return;
1208        }
1209    }
1210
1211    if (!reentrant) {
1212        PWM_VAR['validationLastType'] = new Date().getTime();
1213    }
1214
1215    // check to see if user is still typing.  if yes, then come back later.
1216    if (new Date().getTime() - PWM_VAR['validationLastType'] < typeWaitTimeMs) {
1217        if (showMessage) {
1218            PWM_MAIN.showInfo(PWM_MAIN.showString('Display_TypingWait'));
1219        }
1220        setTimeout(function(){PWM_MAIN.pwmFormValidator(validationProps, true)}, typeWaitTimeMs + 1);
1221        if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: sleeping while waiting for typing to finish, will retry...');
1222        return;
1223    }
1224    if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: user no longer typing, continuing..');
1225
1226    //check to see if a validation is already in progress, if it is then ignore keypress.
1227    if (PWM_VAR['validationInProgress'] === true) {
1228        setTimeout(function(){PWM_MAIN.pwmFormValidator(validationProps, true)}, typeWaitTimeMs + 1);
1229        if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: waiting for a previous validation to complete, exiting...');
1230        return;
1231    }
1232    PWM_VAR['validationInProgress'] = true;
1233
1234    // show in-progress message if load takes too long.
1235    if (showMessage) {
1236        setTimeout(function () {
1237            if (PWM_VAR['validationInProgress'] === true) {
1238                PWM_MAIN.showInfo(messageWorking);
1239            }
1240        }, 5);
1241    }
1242
1243    var formDataString = JSON.stringify(formData) ;
1244
1245    if (CONSOLE_DEBUG) PWM_MAIN.log('FormValidator: sending form data to server... ' + formDataString);
1246    var loadFunction = function(data) {
1247        PWM_VAR['validationInProgress'] = false;
1248        delete PWM_VAR['validationLastType'];
1249        PWM_VAR['validationCache'][formKey] = data;
1250        if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: successful read, data added to cache');
1251        PWM_MAIN.pwmFormValidator(validationProps, true);
1252    };
1253    var options = {};
1254    options['content'] = formData;
1255    options['ajaxTimeout'] = ajaxTimeout;
1256    options['errorFunction'] = function(error) {
1257        PWM_VAR['validationInProgress'] = false;
1258        if (showMessage) {
1259            PWM_MAIN.showInfo(PWM_MAIN.showString('Display_CommunicationError'));
1260        }
1261        if (CONSOLE_DEBUG) PWM_MAIN.log('pwmFormValidator: error connecting to service: ' + error);
1262        processResultsFunction(null);
1263        completeFunction(null);
1264    };
1265    PWM_MAIN.ajaxRequest(serviceURL,loadFunction,options);
1266};
1267
1268PWM_MAIN.preloadImages = function(imgArray){
1269    var newimages=[];
1270    var arr=(typeof imgArray!="object")? [imgArray] : imgArray; //force arr parameter to always be an array
1271    for (var i=0; i<arr.length; i++){
1272        newimages[i]=new Image();
1273        newimages[i].src=arr[i];
1274    }
1275};
1276
1277PWM_MAIN.JSLibrary = {};
1278PWM_MAIN.JSLibrary.isEmpty = function(o) {
1279    return PWM_MAIN.JSLibrary.itemCount(o) < 1;
1280};
1281
1282PWM_MAIN.JSLibrary.itemCount = function(o) {
1283    var i = 0;
1284    for (var key in o) if (o.hasOwnProperty(key)) i++;
1285    return i;
1286};
1287
1288PWM_MAIN.JSLibrary.arrayContains = function(array,element) {
1289    if (!array) {
1290        return false;
1291    }
1292
1293    return array.indexOf(element) > -1;
1294};
1295
1296PWM_MAIN.JSLibrary.getAttribute = function(element,attribute) {
1297    return PWM_MAIN.getObject(element).getAttribute(attribute);
1298};
1299
1300PWM_MAIN.JSLibrary.setAttribute = function(element,attribute,value) {
1301    PWM_MAIN.getObject(element).setAttribute(attribute,value);
1302}
1303
1304PWM_MAIN.JSLibrary.removeFromArray = function(array,element) {
1305    for(var i = array.length - 1; i >= 0; i--) {
1306        if(array[i] === element) {
1307            array.splice(i, 1);
1308        }
1309    }
1310};
1311
1312PWM_MAIN.JSLibrary.readValueOfSelectElement = function(nodeID) {
1313    var element = PWM_MAIN.getObject(nodeID);
1314    if (element && element.options && element.selectedIndex >= 0) {
1315        return element.options[element.selectedIndex].value;
1316    }
1317    return "";
1318};
1319
1320PWM_MAIN.JSLibrary.setValueOfSelectElement = function(nodeID, value) {
1321    var element = PWM_MAIN.getObject(nodeID);
1322    for(var i=0; i < element.options.length; i++) {
1323        if (element.options[i].value === value) {
1324            element.selectedIndex = i;
1325            break;
1326        }
1327    }
1328};
1329
1330PWM_MAIN.JSLibrary.readValueOfRadioFormInput = function(name){
1331    var value = '';
1332    var query = "input[name='" + name + "'"
1333    PWM_MAIN.doQuery(query, function(element){
1334        if( element.checked ) {
1335            value = element.value;
1336        }
1337    });
1338    console.log('radioRead name=' + name + ' value=' + value);
1339    return value;
1340};
1341
1342PWM_MAIN.JSLibrary.formToValueMap = function(formElement) {
1343    formElement = PWM_MAIN.getObject(formElement);
1344    var returnData = {};
1345    if ( formElement.elements ) {
1346        var formElements = formElement.elements;
1347        for (var i = 0; i < formElements.length; i++) {
1348            var field = formElements[i];
1349            if (field.disabled !== true) {
1350                var name = field.name;
1351                var value = field.value;
1352                if (field.tagName && field.tagName.toLowerCase() === 'input' && field.type === 'radio' ) {
1353                    value = PWM_MAIN.JSLibrary.readValueOfRadioFormInput(name);
1354                } else if (field.tagName && field.tagName.toLowerCase() === 'select') {
1355                    value = PWM_MAIN.JSLibrary.readValueOfSelectElement(field);
1356                } else if (field.type === "checkbox") {
1357                    value = field.checked.toString();
1358                }
1359                if ( name && value ) {
1360                    returnData[name] = value;
1361                }
1362            }
1363        }
1364    }
1365
1366    return returnData;
1367};
1368
1369PWM_MAIN.JSLibrary.forEachInArray = function(array,forEachFunction) {
1370    for (var i=0, l=array.length; i<l; i++) {
1371        forEachFunction(array[i]);
1372    }
1373}
1374
1375PWM_MAIN.JSLibrary.forEachInObject = function(object,forEachFunction) {
1376    for (var key in object) {
1377        if (object.hasOwnProperty(key)) {
1378            forEachFunction(key,object[key]);
1379        }
1380    }
1381}
1382
1383PWM_MAIN.JSLibrary.removeElementFromDom = function(elementID) {
1384    var element = PWM_MAIN.getObject(elementID);
1385    if (element) {
1386        element.parentNode.removeChild(element);
1387    }
1388};
1389
1390PWM_MAIN.JSLibrary.onPageLoad = function(callback) {
1391    if (document.readyState === "complete") {
1392        callback();
1393    } else {
1394        window.addEventListener("load",function(event) {
1395            callback();
1396        }, false);
1397    }
1398};
1399
1400PWM_MAIN.toggleFullscreen = function(iconObj,divName) {
1401    var obj = PWM_MAIN.getObject(divName);
1402
1403    var storedStyleName = 'fullscreen-style-' + divName;
1404    if (PWM_GLOBAL[storedStyleName]) {
1405        iconObj.className = "icon-fullscreen";
1406        obj.style = PWM_GLOBAL[storedStyleName];
1407        delete PWM_GLOBAL[storedStyleName];
1408    } else {
1409        PWM_GLOBAL[storedStyleName] = obj.style;
1410        iconObj.className = "icon-resize-full";
1411        obj.style.position = 'fixed';
1412        obj.style.top = '0';
1413        obj.style.left = '0';
1414        obj.style.bottom = '0';
1415        obj.style.right = '0';
1416        obj.style.zIndex = '100';
1417        obj.style.background = 'white';
1418    }
1419    if (PWM_GLOBAL['displayGrid']) {
1420        PWM_GLOBAL['displayGrid'].resize();
1421    }
1422};
1423
1424PWM_MAIN.updateLoginContexts = function() {
1425    var ldapProfileElement = PWM_MAIN.getObject('ldapProfile');
1426    var contextElement = PWM_MAIN.getObject('context');
1427    if (contextElement && ldapProfileElement) {
1428        var selectedProfile = ldapProfileElement.options[ldapProfileElement.selectedIndex].value;
1429        var contextList = PWM_GLOBAL['ldapProfiles'][selectedProfile];
1430        if (PWM_MAIN.JSLibrary.isEmpty(contextList)) {
1431            PWM_MAIN.addCssClass( 'contentSelectorWrapper', 'display-none' );
1432        } else {
1433            contextElement.innerHTML = '';
1434            PWM_MAIN.removeCssClass( 'contentSelectorWrapper', 'display-none' );
1435            for (var iter in contextList) {
1436                (function (key) {
1437                    var display = contextList[key];
1438                    var optionElement = document.createElement('option');
1439                    optionElement.setAttribute('value', key);
1440                    optionElement.appendChild(document.createTextNode(display));
1441                    contextElement.appendChild(optionElement);
1442                }(iter));
1443            }
1444        }
1445    }
1446};
1447
1448//---------- show/hide password handler
1449
1450var ShowHidePasswordHandler = {};
1451
1452ShowHidePasswordHandler.idSuffix = '-eye-icon';
1453ShowHidePasswordHandler.state = {};
1454ShowHidePasswordHandler.toggleRevertTimeout = 30 * 1000; //default value, overridden by settings.
1455ShowHidePasswordHandler.debugOutput = false;
1456
1457ShowHidePasswordHandler.initAllForms = function() {
1458    if (!PWM_GLOBAL['setting-showHidePasswordFields']) {
1459        return;
1460    }
1461
1462    PWM_MAIN.doQuery('.passwordfield',function(field){
1463        if (field.id) {
1464            if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log('adding show/hide option on fieldID=' + field.id);
1465            ShowHidePasswordHandler.init(field.id);
1466        }
1467    });
1468};
1469
1470ShowHidePasswordHandler.init = function(nodeName) {
1471    if (!PWM_GLOBAL['setting-showHidePasswordFields']) {
1472        return;
1473    }
1474
1475    var node = PWM_MAIN.getObject(nodeName);
1476    if (!node) {
1477        return;
1478    }
1479
1480    ShowHidePasswordHandler.toggleRevertTimeout = PWM_GLOBAL['client.pwShowRevertTimeout'] || ShowHidePasswordHandler.toggleRevertTimeout;
1481    var eyeId = nodeName + ShowHidePasswordHandler.idSuffix;
1482    if (PWM_MAIN.getObject(eyeId)) {
1483        return;
1484    }
1485
1486    var defaultType = PWM_MAIN.JSLibrary.getAttribute(node, "type");
1487    PWM_MAIN.JSLibrary.setAttribute(node, "data-originalType", defaultType);
1488    PWM_MAIN.JSLibrary.setAttribute(node, "data-managedByShowHidePasswordHandler","true");
1489
1490    var divElement = document.createElement('div');
1491    divElement.id = eyeId;
1492    divElement.onclick = function(){ShowHidePasswordHandler.toggle(nodeName)};
1493    divElement.style.cursor = 'pointer';
1494    divElement.style.visibility = 'hidden';
1495    divElement.setAttribute('class','pwm-icon icon-showhidepassword');
1496    node.parentNode.insertBefore(divElement, node.nextSibling);
1497
1498    ShowHidePasswordHandler.state[nodeName] = (defaultType === "password");
1499    ShowHidePasswordHandler.setupTooltip(nodeName, false);
1500    ShowHidePasswordHandler.addInputEvents(nodeName);
1501};
1502
1503ShowHidePasswordHandler.renderIcon = function(nodeName) {
1504    if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log("calling renderIcon on node " + nodeName);
1505    var node = PWM_MAIN.getObject(nodeName);
1506    var eyeId = nodeName + ShowHidePasswordHandler.idSuffix;
1507    var eyeNode = PWM_MAIN.getObject(eyeId);
1508    if (node && node.value && node.value.length > 0) {
1509        eyeNode.style.visibility = 'visible';
1510    } else {
1511        eyeNode.style.visibility = 'hidden';
1512    }
1513    eyeNode.className = eyeNode.className; //ie8 force-rendering hack
1514};
1515
1516ShowHidePasswordHandler.toggle = function(nodeName) {
1517    if (ShowHidePasswordHandler.state[nodeName]) {
1518        ShowHidePasswordHandler.show(nodeName);
1519    } else {
1520        ShowHidePasswordHandler.hide(nodeName);
1521    }
1522};
1523
1524ShowHidePasswordHandler.hide = function(nodeName) {
1525    ShowHidePasswordHandler.state[nodeName] = true;
1526    ShowHidePasswordHandler.changeInputTypeField(PWM_MAIN.getObject(nodeName),'password');
1527    ShowHidePasswordHandler.setupTooltip(nodeName);
1528    ShowHidePasswordHandler.renderIcon(nodeName);
1529    var node = PWM_MAIN.getObject(nodeName);
1530    node.focus();
1531};
1532
1533ShowHidePasswordHandler.show = function(nodeName) {
1534    ShowHidePasswordHandler.state[nodeName] = false;
1535    ShowHidePasswordHandler.changeInputTypeField(PWM_MAIN.getObject(nodeName),'text');
1536    ShowHidePasswordHandler.setupTooltip(nodeName);
1537    ShowHidePasswordHandler.renderIcon(nodeName);
1538
1539    var node = PWM_MAIN.getObject(nodeName);
1540    node.focus();
1541    require(["dojo/dom-construct", "dojo/dom-attr"], function(domConstruct, attr) {
1542        var defaultType = attr.get(nodeName, "data-originalType");
1543        if (defaultType === 'password') {
1544            setTimeout(function () {
1545                if (!ShowHidePasswordHandler.state[nodeName]) {
1546                    ShowHidePasswordHandler.toggle(nodeName);
1547                }
1548            }, ShowHidePasswordHandler.toggleRevertTimeout);
1549        }
1550    });
1551};
1552
1553ShowHidePasswordHandler.addInputEvents = function(nodeName) {
1554    PWM_MAIN.addEventHandler(nodeName, "keyup, input", function(){
1555        if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log("keypress event on node " + nodeName);
1556        ShowHidePasswordHandler.renderIcon(nodeName);
1557        ShowHidePasswordHandler.setupTooltip(nodeName);
1558    });
1559
1560};
1561
1562ShowHidePasswordHandler.changeInputTypeField = function(object, type) {
1563    require(["dojo","dojo/_base/lang", "dojo/dom", "dojo/dom-attr"], function(dojo, lang, dom, attr){
1564        var newObject = null;
1565        if(dojo.isIE <= 8){ // IE doesn't support simply changing the type of object
1566            newObject = document.createElement(object.nodeName);
1567            newObject.type = type;
1568            if (object.size) newObject.size = object.size;
1569            if (object.value) newObject.value = object.value;
1570            if (object.name) newObject.name = object.name;
1571            if (object.id) newObject.id = object.id;
1572            if (object.className) newObject.className = object.className;
1573            if (object.disabled) newObject.disabled = object.disabled;
1574            if (object.readonly) newObject.readonly = object.readonly;
1575            if (object.data) newObject.data = object.data;
1576        } else {
1577            newObject = object;
1578            attr.set(newObject, "type", type);
1579        }
1580
1581        object.parentNode.replaceChild(newObject, object);
1582        ShowHidePasswordHandler.addInputEvents(object.id);
1583        return newObject;
1584    });
1585};
1586
1587ShowHidePasswordHandler.setupTooltip = function(nodeName) {
1588    if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log('begin setupTooltip');
1589    var state = ShowHidePasswordHandler.state[nodeName];
1590    var eyeNodeId = nodeName + ShowHidePasswordHandler.idSuffix;
1591
1592    if (state) {
1593        PWM_MAIN.showTooltip({id:eyeNodeId,text:PWM_MAIN.showString('Button_Show')});
1594        PWM_MAIN.removeCssClass(eyeNodeId,"pwm-icon-eye-slash");
1595        PWM_MAIN.addCssClass(eyeNodeId,"pwm-icon-eye");
1596        if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log('set class to pwm-icon-eye');
1597    } else {
1598        PWM_MAIN.showTooltip({id:eyeNodeId,text:PWM_MAIN.showString('Button_Hide')});
1599        PWM_MAIN.removeCssClass(eyeNodeId,"pwm-icon-eye");
1600        PWM_MAIN.addCssClass(eyeNodeId,"pwm-icon-eye-slash");
1601        if (ShowHidePasswordHandler.debugOutput) PWM_MAIN.log('set class to pwm-icon-slash');
1602    }
1603};
1604
1605//---------- idle timeout handler
1606
1607PWM_MAIN.IdleTimeoutHandler = {};
1608
1609PWM_MAIN.IdleTimeoutHandler.SETTING_LOOP_FREQUENCY = 1000;   // milliseconds
1610PWM_MAIN.IdleTimeoutHandler.SETTING_WARN_SECONDS = 30;       // seconds
1611PWM_MAIN.IdleTimeoutHandler.SETTING_POLL_SERVER_SECONDS = 10; //
1612PWM_MAIN.IdleTimeoutHandler.timeoutSeconds = 0; // idle timeout time permitted
1613PWM_MAIN.IdleTimeoutHandler.lastActivityTime = new Date(); // time at which we are "idled out"
1614PWM_MAIN.IdleTimeoutHandler.lastPingTime = new Date(); // date at which the last ping occured
1615PWM_MAIN.IdleTimeoutHandler.realWindowTitle = "";
1616PWM_MAIN.IdleTimeoutHandler.warningDisplayed = false;
1617
1618PWM_MAIN.IdleTimeoutHandler.initCountDownTimer = function(secondsRemaining) {
1619    PWM_MAIN.IdleTimeoutHandler.timeoutSeconds = secondsRemaining;
1620    PWM_MAIN.IdleTimeoutHandler.lastPingTime = new Date();
1621    PWM_MAIN.IdleTimeoutHandler.realWindowTitle = document.title;
1622    PWM_MAIN.IdleTimeoutHandler.resetIdleCounter();
1623    setInterval(function(){PWM_MAIN.IdleTimeoutHandler.pollActivity()}, PWM_MAIN.IdleTimeoutHandler.SETTING_LOOP_FREQUENCY); //poll scrolling
1624    PWM_MAIN.addEventHandler(document, "click", function(){PWM_MAIN.IdleTimeoutHandler.resetIdleCounter()});
1625    PWM_MAIN.addEventHandler(document, "keypress", function(){PWM_MAIN.IdleTimeoutHandler.resetIdleCounter()});
1626    PWM_MAIN.addEventHandler(document, "scroll", function(){PWM_MAIN.IdleTimeoutHandler.resetIdleCounter()});
1627};
1628
1629PWM_MAIN.IdleTimeoutHandler.cancelCountDownTimer = function() {
1630    PWM_GLOBAL['idle_suspendTimeout'] = true;
1631};
1632
1633PWM_MAIN.IdleTimeoutHandler.resetIdleCounter = function() {
1634    PWM_MAIN.IdleTimeoutHandler.lastActivityTime = new Date();
1635    PWM_MAIN.IdleTimeoutHandler.closeIdleWarning();
1636    PWM_MAIN.IdleTimeoutHandler.pollActivity();
1637};
1638
1639PWM_MAIN.IdleTimeoutHandler.pollActivity = function() {
1640    var secondsRemaining = PWM_MAIN.IdleTimeoutHandler.calcSecondsRemaining();
1641    var idleDisplayString = PWM_MAIN.IdleTimeoutHandler.makeIdleDisplayString(secondsRemaining);
1642    var idleStatusFooter = PWM_MAIN.getObject("idle_status");
1643    if (idleStatusFooter) {
1644        idleStatusFooter.firstChild.nodeValue = idleDisplayString;
1645    }
1646
1647    var warningDialogText = PWM_MAIN.getObject("IdleDialogWindowIdleText");
1648    if (warningDialogText) {
1649        warningDialogText.firstChild.nodeValue = idleDisplayString;
1650    }
1651
1652    if (secondsRemaining < 0) {
1653        if (!PWM_GLOBAL['idle_suspendTimeout']) {
1654            PWM_GLOBAL['idle_suspendTimeout'] = true;
1655            var url = PWM_GLOBAL['url-logout'] + '?idle=true&url=' + encodeURIComponent(window.location.pathname);
1656            PWM_MAIN.gotoUrl(url);
1657        } else {
1658            try { PWM_MAIN.getObject('idle_wrapper').style.visibility = 'none'; } catch(e) { /* noop */ }
1659        }
1660        return;
1661    }
1662
1663    var pingAgoMs = (new Date()).getTime() - PWM_MAIN.IdleTimeoutHandler.lastPingTime.getTime();
1664    if (pingAgoMs > (PWM_MAIN.IdleTimeoutHandler.timeoutSeconds - PWM_MAIN.IdleTimeoutHandler.SETTING_POLL_SERVER_SECONDS) * 1000) {
1665        PWM_MAIN.IdleTimeoutHandler.pingServer();
1666    }
1667
1668    if (secondsRemaining < PWM_MAIN.IdleTimeoutHandler.SETTING_WARN_SECONDS) {
1669        if (!PWM_GLOBAL['idle_suspendTimeout']) {
1670            PWM_MAIN.IdleTimeoutHandler.showIdleWarning();
1671            if (secondsRemaining % 2 === 0) {
1672                document.title = PWM_MAIN.IdleTimeoutHandler.realWindowTitle;
1673            } else {
1674                document.title = idleDisplayString;
1675            }
1676        }
1677    }
1678};
1679
1680PWM_MAIN.IdleTimeoutHandler.pingServer = function() {
1681    PWM_MAIN.IdleTimeoutHandler.lastPingTime = new Date();
1682    console.log("idle timeout ping at " + PWM_MAIN.IdleTimeoutHandler.lastPingTime.toISOString());
1683    var pingURL = PWM_GLOBAL['url-command'] + "?processAction=idleUpdate&j=1";
1684    PWM_MAIN.ajaxRequest(pingURL, function(){},{method:'POST',preventCache:true});
1685};
1686
1687PWM_MAIN.IdleTimeoutHandler.calcSecondsRemaining = function() {
1688    var timeoutTime = PWM_MAIN.IdleTimeoutHandler.lastActivityTime.getTime() + (PWM_MAIN.IdleTimeoutHandler.timeoutSeconds * 1000)
1689    var amount = timeoutTime - (new Date()).getTime();
1690    amount = Math.floor(amount / 1000);
1691    return amount;
1692};
1693
1694PWM_MAIN.IdleTimeoutHandler.makeIdleDisplayString = function(amount) {
1695    var output = PWM_MAIN.convertSecondsToDisplayTimeDuration(amount);
1696    output = PWM_MAIN.showString('Display_IdleTimeout') + " " + output;
1697    return output;
1698};
1699
1700PWM_MAIN.IdleTimeoutHandler.showIdleWarning = function() {
1701    if (!PWM_MAIN.IdleTimeoutHandler.warningDisplayed) {
1702        PWM_MAIN.IdleTimeoutHandler.warningDisplayed = true;
1703
1704        var idleOverlayDiv = document.createElement('div');
1705        idleOverlayDiv.setAttribute('id','idle-overlay');
1706        document.body.appendChild(idleOverlayDiv);
1707
1708        var idleMsgDiv = document.createElement('div');
1709        idleMsgDiv.setAttribute('id','idle-overlay-message');
1710        idleMsgDiv.innerHTML = '<p>' + PWM_MAIN.showString('Display_IdleWarningMessage') + '</p><p><span id="IdleDialogWindowIdleText">&nbsp;</span></p>';
1711        document.body.appendChild(idleMsgDiv);
1712
1713        PWM_MAIN.addEventHandler('idle-overlay','click',function(){
1714            idleOverlayDiv.parentNode.removeChild(idleOverlayDiv);
1715            idleMsgDiv.parentNode.removeChild(idleMsgDiv);
1716        })
1717    }
1718};
1719
1720PWM_MAIN.IdleTimeoutHandler.closeIdleWarning = function() {
1721    document.title = PWM_MAIN.IdleTimeoutHandler.realWindowTitle;
1722    PWM_MAIN.IdleTimeoutHandler.warningDisplayed = false;
1723};
1724
1725PWM_MAIN.TimestampHandler = PWM_MAIN.TimestampHandler || {};
1726PWM_MAIN.TimestampHandler.PreferencesKey = 'timestampLocalized';
1727PWM_MAIN.TimestampHandler.ElementList = [];
1728
1729PWM_MAIN.TimestampHandler.initAllElements = function() {
1730    PWM_MAIN.doQuery(".timestamp",function(node){
1731        PWM_MAIN.TimestampHandler.initElement(node);
1732    });
1733};
1734
1735PWM_MAIN.TimestampHandler.testIfStringIsTimestamp = function(input, trueFunction) {
1736    if (input && input.length > 0) {
1737        input = input.trim();
1738        var timestamp = Date.parse(input);
1739        if (isNaN(timestamp) === false) {
1740            trueFunction(new Date(timestamp));
1741        }
1742    }
1743};
1744
1745PWM_MAIN.TimestampHandler.initElement = function(element) {
1746    if (!element) {
1747        return
1748    }
1749
1750    if (element.getAttribute('data-timestamp-init') === 'true') {
1751        return;
1752    }
1753
1754    require(["dojo"], function(dojo) {
1755        var innerText = dojo.attr(element, 'innerHTML');
1756        innerText = innerText.trim(innerText);
1757        PWM_MAIN.TimestampHandler.testIfStringIsTimestamp(innerText, function () {
1758            element.setAttribute('data-timestamp-original', innerText);
1759            PWM_MAIN.addEventHandler(element, 'click', function(){
1760                var LocalizedState = !PWM_MAIN.Preferences.readSessionStorage(PWM_MAIN.TimestampHandler.PreferencesKey,true);
1761                PWM_MAIN.Preferences.writeSessionStorage(PWM_MAIN.TimestampHandler.PreferencesKey, LocalizedState);
1762                PWM_MAIN.TimestampHandler.updateAllElements();
1763            });
1764            if (!dojo.hasClass(element,"timestamp")) {
1765                dojo.addClass(element,"timestamp");
1766            }
1767
1768            element.setAttribute('data-timestamp-init', 'true');
1769            PWM_MAIN.TimestampHandler.ElementList.push(element);
1770            PWM_MAIN.TimestampHandler.updateElement(element);
1771        });
1772    });
1773};
1774
1775PWM_MAIN.TimestampHandler.updateAllElements = function() {
1776    PWM_MAIN.JSLibrary.forEachInArray(PWM_MAIN.TimestampHandler.ElementList,function(element){
1777        if (document.body.contains(element)) {
1778            PWM_MAIN.TimestampHandler.updateElement(element);
1779        } else {
1780            PWM_MAIN.JSLibrary.removeFromArray(PWM_MAIN.TimestampHandler.ElementList,element);
1781        }
1782    });
1783};
1784
1785PWM_MAIN.TimestampHandler.updateElement = function(element) {
1786    require(["dojo"], function(dojo) {
1787        var localized = PWM_MAIN.Preferences.readSessionStorage(PWM_MAIN.TimestampHandler.PreferencesKey,true);
1788        if (localized) {
1789            var isoDateStr = element.getAttribute('data-timestamp-original');
1790            var date = new Date(Date.parse(isoDateStr));
1791            var localizedStr = PWM_MAIN.TimestampHandler.formatDate(date);
1792
1793            dojo.attr(element,'innerHTML',localizedStr);
1794        } else {
1795            dojo.attr(element,'innerHTML',element.getAttribute('data-timestamp-original'));
1796        }
1797    })
1798};
1799
1800PWM_MAIN.TimestampHandler.formatDate = function(dateObj) {
1801    var options = {timeZoneName:'short', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'};
1802    var locale = PWM_GLOBAL['client.locale'];
1803    return dateObj.toLocaleString(locale, options);
1804};
1805
1806PWM_MAIN.addPwmFormIDtoURL = function(url) {
1807    return PWM_MAIN.addParamToUrl(url,'pwmFormID',PWM_GLOBAL['pwmFormID']);
1808};
1809
1810PWM_MAIN.addParamToUrl = function(url,paramName,paramValue) {
1811    if (!url || url.length < 1) {
1812        return url;
1813    }
1814
1815    if (
1816        url.indexOf('?' + paramName + '=') > -1
1817        || url.indexOf('&' + paramName + '=') > -1)
1818    {
1819        console.warn('ignoring request to append duplicate param "' + paramName + '" to url ' + url);
1820        return url;
1821    }
1822
1823    var encodedName = encodeURIComponent(paramName);
1824    var encodedValue = encodeURIComponent(paramValue);
1825
1826    url += url.indexOf('?') > 0 ? '&' : '?';
1827    url += encodedName + "=" + encodedValue;
1828    return url;
1829};
1830
1831PWM_MAIN.ajaxRequest = function(url,loadFunction,options) {
1832    options = options === undefined ? {} : options;
1833    var content = 'content' in options ? options['content'] : null;
1834    var method = 'method' in options ? options['method'] : 'POST';
1835    var responseMimeType = 'responseMimeType' in options ? options['responseMimeType'] : 'application/json';
1836    var handleAs = 'handleAs' in options ? options['handleAs'] : 'json';
1837    var errorFunction = 'errorFunction' in options ? options['errorFunction'] : function(error){
1838        var status = error['response']['status'];
1839        if (status === 0 || status < 200 || status >= 300) {
1840            var msg = PWM_MAIN.showString("Display_ClientDisconnect") + "  (" + status + ")";
1841            PWM_MAIN.log(msg);
1842            PWM_MAIN.showErrorDialog(msg);
1843        } else {
1844            PWM_MAIN.showErrorDialog(error);
1845        }
1846    };
1847    var hasContent = options['content'] !== null && options['content'] !== undefined;
1848    var preventCache = 'preventCache' in options ? options['preventCache'] : true;
1849    var addPwmFormID = 'addPwmFormID' in options ? options['addPwmFormID'] : true;
1850    var ajaxTimeout = options['ajaxTimeout'] ? options['ajaxTimeout'] : PWM_MAIN.ajaxTimeout;
1851    var requestHeaders = {};
1852    requestHeaders['Accept'] = responseMimeType;
1853    if (hasContent) {
1854        requestHeaders['Content-Type'] = responseMimeType;
1855    }
1856
1857    if (addPwmFormID) {
1858        url = PWM_MAIN.addPwmFormIDtoURL(url);
1859    }
1860    if (preventCache) {
1861        url = PWM_MAIN.addParamToUrl(url, 'preventCache', (new Date).valueOf());
1862    }
1863
1864    var xhr = new XMLHttpRequest();
1865    xhr.onload = function() {
1866        if ( loadFunction === undefined ) {
1867            alert('missing load function, return results:' + xhr.response)
1868        } else {
1869            var response = xhr.response;
1870            // run parser for IE
1871            if ( typeof response === "string" && handleAs === "json") {
1872                response = JSON.parse( response );
1873            }
1874            loadFunction(response);
1875        }
1876    };
1877    xhr.onerror = errorFunction;
1878    xhr.ontimeout = errorFunction;
1879    xhr.open(method, url);
1880    xhr.responseType = handleAs;
1881    xhr.timeout = ajaxTimeout;
1882
1883    for (var headerKey in requestHeaders) {
1884        xhr.setRequestHeader( headerKey, requestHeaders[headerKey]);
1885    }
1886
1887    if ( hasContent ) {
1888        xhr.send( JSON.stringify( content ) );
1889    } else {
1890        xhr.send();
1891    }
1892};
1893
1894PWM_MAIN.convertSecondsToDisplayTimeDuration = function(amount, fullLength) {
1895    if (amount < 1) {
1896        return "";
1897    }
1898
1899    var output = "";
1900
1901    var days = Math.floor(amount / 86400);
1902
1903    amount = amount % 86400;
1904    var hours = Math.floor(amount / 3600);
1905
1906    amount = amount % 3600;
1907    var mins = Math.floor(amount / 60);
1908
1909    amount = amount % 60;
1910    var secs = Math.floor(amount);
1911
1912    // write number of days
1913    var positions = 0;
1914    if (days !== 0) {
1915        output += days + " ";
1916        if (days !== 1) {
1917            output += PWM_MAIN.showString('Display_Days');
1918        } else {
1919            output += PWM_MAIN.showString('Display_Day');
1920        }
1921        positions++;
1922    }
1923
1924    // write number of hours
1925    if (days !== 0 || hours !== 0) {
1926        if (output.length > 0) {
1927            output += ", ";
1928        }
1929
1930        output += hours + " ";
1931        if (hours !== 1) {
1932            output += PWM_MAIN.showString('Display_Hours');
1933        } else {
1934            output += PWM_MAIN.showString('Display_Hour');
1935        }
1936        positions ++;
1937    }
1938
1939    // write number of minutes
1940    if (positions < 2 || fullLength) {
1941        if (days !== 0 || hours !== 0 || mins !== 0 || fullLength) {
1942            if (output.length > 0) {
1943                output += ", ";
1944            }
1945            output += mins + " ";
1946            if (mins !== 1) {
1947                output += PWM_MAIN.showString('Display_Minutes');
1948            } else {
1949                output += PWM_MAIN.showString('Display_Minute');
1950            }
1951            positions++;
1952        }
1953    }
1954
1955    // write number of seconds
1956    if (positions < 2 || fullLength) {
1957        if (mins < 4 || fullLength) {
1958            if (output.length > 0) {
1959                output += ", ";
1960            }
1961
1962            output += secs + " ";
1963
1964            if (secs !== 1) {
1965                output += PWM_MAIN.showString('Display_Seconds');
1966            } else {
1967                output += PWM_MAIN.showString('Display_Second');
1968            }
1969        }
1970    }
1971
1972    return output;
1973};
1974
1975PWM_MAIN.setStyle = function(elementID, property, value) {
1976
1977    require(["dojo"],function(dojo) {
1978        if (dojo.isIE <= 8) { // IE8 and below cant handle the css associated with the locale select menu
1979            try {
1980                var element = PWM_MAIN.getObject(elementID);
1981                if (element) {
1982                    element.style[property] = value;
1983                }
1984            } catch (e) {
1985                console.error('error while setting ie8 style, elementID=' + elementID + ", property=" + property + ", value=" + value + ", error: " + e);
1986            }
1987        } else {
1988            try {
1989                var element = PWM_MAIN.getObject(elementID);
1990                if (element) {
1991                    element.style.setProperty(property, value, null);
1992                }
1993            } catch (e) {
1994                console.error('error while setting style, elementID=' + elementID + ", property=" + property + ", value=" + value + ", error: " + e);
1995            }
1996        }
1997    });
1998};
1999
2000PWM_MAIN.addCssClass = function(elementID, className) {
2001    var element = PWM_MAIN.getObject(elementID);
2002    if (element) {
2003        element.classList.add(className);
2004    }
2005};
2006
2007PWM_MAIN.removeCssClass = function(elementID, className) {
2008    var element = PWM_MAIN.getObject(elementID);
2009    if (element) {
2010        element.classList.remove(className);
2011    }
2012};
2013
2014PWM_MAIN.hasCssClass = function(elementID, className) {
2015    var element = PWM_MAIN.getObject(elementID);
2016    return element && element.classList.contains(className);
2017};
2018
2019PWM_MAIN.newWindowOpen=function(windowUrl,windowName) {
2020    var windowParams = 'status=0,toolbar=0,location=0,menubar=0,scrollbars=1,resizable=1';
2021    var viewLog = window.open(windowUrl,windowName,windowParams).focus();
2022};
2023
2024PWM_MAIN.cancelEvent = function(event) {
2025    if (event) {
2026        if (event.preventDefault) {
2027            event.preventDefault();
2028        } else if (event.returnValue) {
2029            event.returnValue = false;
2030        }
2031    }
2032};
2033
2034PWM_MAIN.submitPostAction = function(actionUrl,actionValue,additionalValues) {
2035    var fields = {};
2036    fields['processAction'] = actionValue;
2037    fields['pwmFormID'] = PWM_GLOBAL['pwmFormID'];
2038    if (additionalValues) {
2039        var addValueFunction = function(key) {
2040            fields[key] = additionalValues[key];
2041        };
2042        for (var key in additionalValues) {
2043            addValueFunction(key);
2044        }
2045    }
2046    var makeFieldHtml = function() {
2047        var text = '';
2048        var addField = function(key) {
2049            return '<input type="hidden" name="' + key + '" value="' + fields[key] + '"></input>';
2050        };
2051        for (var key in fields) {
2052            text += addField(key);
2053        }
2054        return text;
2055    };
2056    var formElement = document.createElement('form');
2057    formElement.setAttribute('id','form-jsSendAction');
2058    formElement.setAttribute('action',actionUrl);
2059    formElement.setAttribute('method','post');
2060    formElement.setAttribute('style','display:none');
2061    formElement.innerHTML = makeFieldHtml();
2062    document.body.appendChild(formElement);
2063    PWM_MAIN.handleFormSubmit(formElement);
2064};
2065
2066PWM_MAIN.doQuery = function(queryString, resultFunction) {
2067    var results = document.querySelectorAll(queryString);
2068    PWM_MAIN.JSLibrary.forEachInArray(results,resultFunction);
2069};
2070
2071PWM_MAIN.doIfQueryHasResults = function(queryString, trueFunction) {
2072    if (document.querySelector(queryString)) trueFunction();
2073};
2074
2075PWM_MAIN.stopEvent = function(e) {
2076    if (!e) var e = window.event;
2077    e.cancelBubble = true;
2078    if (e.stopPropagation) e.stopPropagation();
2079};
2080
2081PWM_MAIN.clearFocus = function() {
2082    document.activeElement.blur();
2083};
2084
2085PWM_MAIN.Preferences = {};
2086PWM_MAIN.Preferences.StorageKeyName = 'preferences';
2087PWM_MAIN.Preferences.Key_Timestamp = 'timestamp';
2088PWM_MAIN.Preferences.Key_ExpireSeconds = 'expireSeconds';
2089PWM_MAIN.Preferences.Key_Value = 'value';
2090PWM_MAIN.Preferences.readLocalStorage = function(key,valueIfMissing) {
2091    if(typeof(Storage) !== "undefined") {
2092        try {
2093            var baseObjStr = localStorage.getItem(PWM_MAIN.Preferences.StorageKeyName);
2094            if (baseObjStr) {
2095                var baseJson = JSON.parse(baseObjStr);
2096                var wrappedValue = baseJson[key];
2097                if (wrappedValue !== null) {
2098                    var timestamp = new Date(Date.parse(wrappedValue[PWM_MAIN.Preferences.Key_Timestamp]));
2099                    var expireSeconds = parseInt(wrappedValue[PWM_MAIN.Preferences.Key_ExpireSeconds]);
2100                    var valueAgeSeconds = (new Date().getTime()) - timestamp.getTime();
2101                    if (valueAgeSeconds > (expireSeconds * 1000)) {
2102                        delete baseJson[key];
2103                        localStorage.setItem(PWM_MAIN.Preferences.StorageKeyName,JSON.stringify(baseJson));
2104                        return valueIfMissing;
2105                    }
2106
2107                    return wrappedValue[PWM_MAIN.Preferences.Key_Value];
2108                }
2109            }
2110        } catch (e) {
2111            PWM_MAIN.log("error reading locale storage preferences: " + e);
2112        }
2113    } else {
2114        PWM_MAIN.log("browser doesn't support local storage");
2115    }
2116    return valueIfMissing;
2117};
2118
2119PWM_MAIN.Preferences.writeLocalStorage = function(key, value, lifetimeSeconds) {
2120    if(typeof(Storage) !== "undefined") {
2121        try {
2122            var baseObjStr = localStorage.getItem(PWM_MAIN.Preferences.StorageKeyName);
2123            var baseJson = baseObjStr !== null ? JSON.parse(baseObjStr) : {};
2124            var wrapperValue = {};
2125            wrapperValue[PWM_MAIN.Preferences.Key_Timestamp] = new Date().toISOString();
2126            wrapperValue[PWM_MAIN.Preferences.Key_ExpireSeconds] = lifetimeSeconds;
2127            wrapperValue[PWM_MAIN.Preferences.Key_Value] = value;
2128            baseJson[key] = wrapperValue;
2129            localStorage.setItem(PWM_MAIN.Preferences.StorageKeyName,JSON.stringify(baseJson));
2130        } catch (e) {
2131            PWM_MAIN.log("error writing locale storage preferences: " + e);
2132        }
2133    } else {
2134        PWM_MAIN.log("browser doesn't support local storage");
2135    }
2136};
2137
2138PWM_MAIN.Preferences.readSessionStorage = function(key,valueIfMissing) {
2139    if(typeof(Storage) !== "undefined") {
2140        try {
2141            var baseObjStr = sessionStorage.getItem(PWM_MAIN.Preferences.StorageKeyName);
2142            if (baseObjStr !== null) {
2143                var baseJson = JSON.parse(baseObjStr);
2144                return key in baseJson ? baseJson[key] : valueIfMissing;
2145            }
2146        } catch (e) {
2147            PWM_MAIN.log("error reading session storage preferences: " + e);
2148        }
2149    } else {
2150        PWM_MAIN.log("browser doesn't support session storage");
2151    }
2152    return valueIfMissing;
2153};
2154
2155PWM_MAIN.Preferences.writeSessionStorage = function(key, value) {
2156    if(typeof(Storage) !== "undefined") {
2157        try {
2158            var baseObjStr = sessionStorage.getItem(PWM_MAIN.Preferences.StorageKeyName);
2159            var baseJson = baseObjStr !== null ? JSON.parse(baseObjStr) : {};
2160            baseJson[key] = value;
2161            sessionStorage.setItem(PWM_MAIN.Preferences.StorageKeyName,JSON.stringify(baseJson));
2162        } catch (e) {
2163            PWM_MAIN.log("error writing session storage preferences: " + e);
2164        }
2165    } else {
2166        PWM_MAIN.log("browser doesn't support session storage");
2167    }
2168};
2169
2170PWM_MAIN.copyObject = function(input) {
2171    return JSON.parse(JSON.stringify(input));
2172};
2173
2174PWM_MAIN.numberFormat = function (number) {
2175    try {
2176        return new Number(number).toLocaleString();
2177    } catch (t) {
2178        PWM_MAIN.log('error localizing number value "' + number + '", error: ' + t);
2179    }
2180
2181    return number;
2182};
2183
2184PWM_MAIN.pageLoadHandler();
2185

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.