PageSourceSearch

https://www.tulsastatefair.com/js/angular/app.js?sv=8.6.3.9.0

js tulsastatefair.com collected 2026-09-24 20:17:13 UTC 47,362 bytes, 1,597 lines download raw bytes

1
2
3/**************************************/
4/*Application                         */
5/**************************************/
6
7extend(saffire, {
8
9    angular: {
10
11        //shared angular application
12        app: angular.module("SaffireAngularApp", ['ngAnimate', 'ngTouch', 'ngSanitize', 'ngCookies', 'ngMask'])
13
14
15    }
16
17}
18);
19
20saffire.angular.app.config(['$compileProvider', function ($compileProvider) {
21    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|file|javascript):/);
22}])
23
24saffire.angular.app.run(function ($rootScope) {
25    $rootScope.siteBaseURL = SITEBASEURL;
26    $rootScope.fileServerUploadURL = FILESERVERUPLOADURL;
27    $rootScope.fileServerImagesURL = FILESERVERIMAGESURL;
28    $rootScope.fileServerFilesURL = FILESERVERFILESURL;
29
30    if (PAGESSL != undefined && PAGESSL) {
31        $rootScope.siteBaseURL == SITEBASEURL.replace("http://","https://")
32    }
33});
34
35saffire.angular.app.filter("sanitize", ['$sce', function ($sce) {
36    return function (htmlCode) {
37        return $sce.trustAsHtml(htmlCode);
38    }
39}]);
40
41/**************************************/
42/*Services                            */
43/**************************************/
44
45saffire.angular.app.service('saffire.angular.webServices', ['$http', function webServices($http) {
46
47    //Public API
48
49    return ({
50        getWebRequest: getWebRequest
51    });
52
53    //Public Functions
54
55    function getWebRequest(url) {
56
57        var request = $http({
58            method: "get",
59            url: url,
60            contentType: "application/json",
61            dataType: "json",
62            params: {},
63            data: {}
64        })
65
66        return (request.then(handleSuccess, handleError))
67
68    }
69
70    //Private Functions
71
72    function handleSuccess(response) {
73        return response.data;
74    }
75
76    function handleError(response) {
77        return response.data;
78    }
79
80}]);
81
82saffire.angular.app.service('saffire.angular.webPoster', ['$http', function webPoster($http) {
83
84    //Public API
85
86    return ({
87        postWebRequest: postWebRequest
88    });
89
90    //Public Functions
91
92    function postWebRequest(url, postJsonString) {
93
94        var request = $http({
95            method: "post",
96            url: url,
97            params: {},
98            data: postJsonString
99        })
100
101        return (request.then(handleSuccess, handleError))
102
103    }
104
105    //Private Functions
106
107    function handleSuccess(response) {
108        return response.data;
109    }
110
111    function handleError(response) {
112        return response.data;
113    }
114
115}]);
116
117saffire.angular.app.service('saffire.angular.navigatorService', ['$window', function navigatorService($window) {
118
119    return ({
120        getMediaDevices: getMediaDevices
121    });
122
123    //Public Functions
124
125    function getMediaDevices() {   
126
127        if (!$window.navigator.mediaDevices || !$window.navigator.mediaDevices.enumerateDevices) {           
128            return new Promise(function (resolve, reject) { });
129        }
130
131        var request = navigator.mediaDevices.enumerateDevices();
132
133        return request.then(handleSuccess, handleError);
134
135    }
136
137    //Private Functions
138
139    function handleSuccess(response) {
140        return response;
141    }
142
143    function handleError(response) {
144        return response;
145    }
146
147}]);
148
149saffire.angular.app.service('saffire.angular.scriptLoaderService', ['$q', function scriptLoaderService($q) {
150
151    //Public API
152
153    return ({
154        loadScript: loadScript
155    })
156
157    //Public Functions
158
159    function loadScript(scriptPath) {
160
161        var deffered = $q.defer();
162
163        var head = document.getElementsByTagName('head')[0];
164        var script = document.createElement('script');
165
166        script.setAttribute('type', 'text/javascript');
167        script.src = scriptPath;
168
169        var onScriptLoaded = function () {
170            deffered.resolve()
171        };
172
173        if (script.addEventListener) { // Standard browsers (including IE9+) 
174            script.addEventListener('load', onScriptLoaded, false);
175        }
176        else { // IE8 and below 
177            script.onreadystatechange = function () {
178                if (script.readyState === 'loaded' || script.readyState === 'complete') {
179                    script.onreadystatechange = null;
180                    onScriptLoaded();
181                }
182            };
183        }
184
185        head.appendChild(script);
186
187        return deffered.promise
188    };
189
190}]);
191
192saffire.angular.app.service('saffire.angular.pdfPrinterService', ['$q', function pdfPrinterService($q) {
193
194    //Public API
195
196    return ({
197        printPDF: printPDF
198    })
199
200    //Public Functions
201
202    function printPDF(pdfURL) {
203
204        var deffered = $q.defer();
205
206        if (document.getElementById("pdfIframe"))
207            document.getElementById("pdfIframe").remove();
208
209        var ifrm = document.createElement("iframe");
210
211        ifrm.setAttribute('id', 'pdfIframe');
212        ifrm.setAttribute("src", pdfURL);
213        ifrm.style.visibility = 'hidden';
214        ifrm.style.width = '1px';
215        ifrm.style.height = '1px';
216
217        document.body.appendChild(ifrm);
218
219        var onIFrameLoaded = function () {
220            var newWin = ifrm.contentWindow;
221            newWin.document.close();
222            newWin.focus(); 
223            newWin.print();
224
225            deffered.resolve();
226        };
227
228        if (ifrm.addEventListener) { // Standard browsers (including IE9+) 
229            ifrm.addEventListener('load', onIFrameLoaded, false);
230        }
231
232        return deffered.promise
233    };
234
235}]);
236
237saffire.angular.app.service('saffire.angular.urlPrinterService', ['$q', function pdfPrinterService($q) {
238
239    //Public API
240
241    return ({
242        printURL: printURL
243    })
244
245    //Public Functions
246
247    function printURL(URL) {
248
249        var deffered = $q.defer();
250
251        if (document.getElementById("printIframe"))
252            document.getElementById("printIframe").remove();
253
254        var ifrm = document.createElement("iframe");
255
256        ifrm.setAttribute('id', 'printIframe');
257        ifrm.setAttribute("src", URL);
258        ifrm.style.visibility = 'hidden';
259        ifrm.style.width = '1px';
260        ifrm.style.height = '1px';
261
262        document.body.appendChild(ifrm);
263
264        var onIFrameLoaded = function () {
265            var newWin = ifrm.contentWindow;
266            newWin.document.close();
267            newWin.focus();
268            newWin.print();
269
270            deffered.resolve();
271        };
272
273        if (ifrm.addEventListener) { // Standard browsers (including IE9+) 
274            ifrm.addEventListener('load', onIFrameLoaded, false);
275        }
276
277        return deffered.promise
278    };
279
280}]);
281
282saffire.angular.app.service('saffire.angular.fileService', [function fileService() {
283
284    //Public API
285
286    return ({
287        getFileExtension: getFileExtension,
288    });
289
290    //Public Functions
291
292    function getFileExtension(fileName) {
293
294        if (fileName) {
295            if (fileName.indexOf('.') > -1) {
296                return '.' + fileName.split('.').pop()
297            }
298        }
299
300        return ''
301    }
302
303}]);
304
305saffire.angular.app.service('saffire.angular.fileServerService', ['$http', '$rootScope', 'saffire.angular.fileService', function fileServerService($http, $rootScope, fileService) {
306
307    //Public API
308
309    return ({
310        uploadFile: uploadFile,
311        getFileAbsolutePath: getFileAbsolutePath
312    });
313
314    //Public Functions
315
316    function getFileAbsolutePath(fileName, isImage) {
317
318        if (isImage) {
319            return $rootScope.fileServerImagesURL + '&i=' + fileName
320        }
321        else {
322            return $rootScope.fileServerFilesURL + '&f=' + fileName
323        }
324
325    }
326
327    function uploadFile(fileName, fileData, mimeType, isImage) {
328
329        var url = $rootScope.fileServerUploadURL
330        var queryParams = [];
331
332        //change url to https if needed
333        if (document.location.protocol == 'https:' && url.indexOf('https:') < 0) {
334            url = url.replace('http:', 'https:')
335        }
336
337        //fileName
338        //remove illegal characters
339        fileName = fileName.replace(/[^\w\)\(\.]/gi, '')
340        fileExtension = fileService.getFileExtension(fileName);
341
342        //give a static filename just in case it was all illegal chars
343        if (fileName.replace(fileExtension, '') == '') {
344            fileName = 'file' + fileExtension
345        }
346
347        queryParams.push('filename=' + fileName)
348
349        //pathKey
350        var pathKey = 'ig';
351        if (!isImage) {
352            pathKey = 'fg';
353        }
354
355        queryParams.push('t=' + pathKey)
356
357        if (queryParams.length) {
358            url = url + '&' + queryParams.join('&')
359        }
360
361        var request = $http({
362            method: "post",
363            url: url,
364            params: {},
365            data: fileData,
366            transformRequest: []
367        })
368
369        return request
370
371    }
372
373}]);
374
375saffire.angular.app.factory('dialogService', ['$q', '$window', '$timeout', function ($q, $window, $timeout) {
376
377    var openDialog = function (scope, dialogOptions) {
378
379        var modalPromise = $q.defer();
380
381        var defaultOptions = {
382            OnCloseCallbackFunction: function (args) {
383                scope.$apply(
384                    modalPromise.resolve({ args: args })
385                )
386            },
387            Parent: window,
388            ScrollFrame: true,
389            OnCloseTargetID: '',
390            OnCloseEventArg: '',
391
392        }
393
394        angular.extend(defaultOptions, dialogOptions);
395
396        $OpenModal(defaultOptions)
397
398        return modalPromise.promise;
399
400    }
401
402    var closeDialog = function (element) {
403
404        $timeout(function () {
405
406            var dialog = null;
407            if (jQuery.type(element) === "string") {
408                dialog = $('#' + element);
409            } else {
410                dialog = element;
411            }
412            $HideModal(dialog);
413        })
414
415    }
416
417    return ({
418        openDialog: openDialog,
419        closeDialog: closeDialog
420    })
421}])
422
423saffire.angular.app.factory('saffire.angular.scannerService', ['saffire.angular.scriptLoaderService', '$q', function (scriptLoaderService,$q) {
424
425    scriptLoaderService.loadScript(SITEBASEURL + 'JS/html5-qrcode.min.js?sv=' + SITEVERSION);
426
427    var permissionDenied = false;
428    var couldNotInitializeStream = false;
429    var hasAccess = false;
430    var myCamera = null;
431    var devices = [];
432    var cameraOn = false;
433
434    var getCameras = function () {
435
436        var getCamerasPromise = $q.defer();
437
438        Html5Qrcode.getCameras()
439            .then(function (devices) {
440                hasAccess = true;
441                getCamerasPromise.resolve(devices)
442            })
443            .catch(function (e) {
444
445                switch (e) {
446                    case 'NotAllowedError : Permission denied':
447                        permissionDenied = true;
448                        break;
449                    case 'NotReadableError : Could not start video source':
450                        couldNotInitializeStream = true
451                        break;
452                }
453
454                getCamerasPromise.resolve(devices)
455            })
456            .then(function (devices) {
457                
458        })
459
460        return getCamerasPromise.promise
461        
462    }
463
464    var start = function (scope,elementID,cameraID,onScanSucces,onScanFailed,config) {
465
466        myCamera = new Html5Qrcode(elementID);
467
468        var startPromise = $q.defer();
469
470        var defaultConfig = {
471            fps: 10,// Optional, frame per seconds for qr code scanning
472            // qrbox: { width: 250, height: 250 }  // Optional, if you want bounded box UI
473        };
474
475        angular.extend(defaultConfig, config);
476
477        myCamera.start(cameraID, defaultConfig,
478            function (decodedText, decodedResult) { //successCallback
479
480                scope.$apply(function () {
481                    onScanSucces(decodedText, decodedResult);
482                });
483
484            }, onScanFailed).then(function () {
485                cameraOn = true;
486                startPromise.resolve()
487            });
488
489        return startPromise.promise
490
491    }
492
493    var stop = function (scope) {
494
495        var stopPromise = $q.defer();
496
497        if (myCamera) {
498            myCamera.stop().then(function () {
499                cameraOn = false;
500                stopPromise.resolve()
501            });
502        }
503        else {
504            cameraOn = false;
505            stopPromise.resolve()
506        }
507
508        
509
510        return stopPromise.promise
511
512    }
513
514    return ({
515        getCameras: getCameras,
516        permissionDenied: function () { return permissionDenied; },
517        couldNotInitializeStream: function () { return couldNotInitializeStream; },
518        hasAccess: function () { return hasAccess },
519        start: start,
520        stop: stop,
521        isScanning: function () { return cameraOn; }
522    })
523}])
524
525saffire.angular.app.factory('saffire.angular.editorService', ['$interval', function ($interval) {
526
527    var enabled = false;
528    var debug = false;
529    var showMessageFunction = null;
530    var closeMessageFunction = null;
531    var broadcastFunction = null;
532    var userIsSuperAdmin = false;
533    var hasChanges = false;
534
535    var setHasChanges = function (hasChangesFlag) {
536        hasChanges = hasChangesFlag;
537    }
538
539    var getHasChanges = function () {
540        return hasChanges;
541    }
542
543    var setShowMessageFunction = function (func) {
544        showMessageFunction = func;
545    }
546
547    var setCloseMessageFunction = function (func) {
548        closeMessageFunction = func
549    }
550
551    var showMessage = function (message) {
552        showMessageFunction(message);
553    }
554
555    var closeMessage = function () {
556        closeMessageFunction();
557    }
558
559    var setBroadcastFunction = function (func) {
560        broadcastFunction = func
561    }
562
563    var broadcast = function (name, args) {
564        broadcastFunction(name, args);
565    }
566
567    var createValidationObject = function () {
568        return {
569            isValid: true,
570            messages: [],
571            flags: [],
572        }
573    }
574
575    var sumValidationObjects = function (validationObjects) {
576
577        var isValid = true;
578        var messages = [];
579        var flags = [];
580
581        if (validationObjects) {
582            $.each(validationObjects, function (voi) {
583                var vo = validationObjects[voi];
584                if (!vo.isValid) {
585                    isValid = false;
586                    messages = messages.concat(vo.messages);
587                    flags = flags.concat(vo.flags);
588                }
589            })
590        }
591
592        var validationObject = createValidationObject()
593        validationObject.isValid = isValid;
594        validationObject.messages = messages;
595        validationObject.flags = flags;
596
597        return validationObject;
598    }
599
600    var sumValidationObjectsWithObject = function (validationObject, validationObjects) {
601
602        var tmp = sumValidationObjects(validationObjects);
603
604        validationObject.isValid = validationObject.isValid && tmp.isValid;
605        validationObject.messages = validationObject.messages.concat(tmp.messages);
606        validationObject.flags = validationObject.flags.concat(tmp.flags);
607
608    }
609
610    return ({
611        enabled: enabled,
612        debug: debug,
613        showMessage: showMessage,
614        setShowMessageFunction: setShowMessageFunction,
615        closeMessage: closeMessage,
616        setCloseMessageFunction: setCloseMessageFunction,
617        setBroadcastFunction: setBroadcastFunction,
618        broadcast: broadcast,
619        createValidationObject: createValidationObject,
620        sumValidationObjects: sumValidationObjects,
621        sumValidationObjectsWithObject: sumValidationObjectsWithObject,
622        userIsSuperAdmin: userIsSuperAdmin,
623        setHasChanges: setHasChanges,
624        getHasChanges: getHasChanges,
625    })
626}])
627
628/**************************************/
629/*directives                          */
630/**************************************/
631
632saffire.angular.app.directive('sfLoadingMask', ['$interval', function ($interval) {
633
634  
635  function link(scope, element, attrs) {
636    
637        if (!scope.loadingText) {
638          scope.loadingText = 'Please Wait...';
639        }
640
641        scope.container = element.closest('.AngularAppContainer')
642
643        scope.$watch('appEnabled', function (newValue, oldValue) {
644
645            if (scope.container) {
646                if (!scope.appEnabled) {
647                    scope.container.addClass('loading');
648                }
649                else {
650                    scope.container.removeClass('loading');
651                }
652            }
653
654        }, true);
655
656        scope.$watch('suppressLoading', function (newValue, oldValue) {
657
658            if (scope.container) {
659
660                if (scope.suppressLoading) {
661                    scope.container.addClass('loading-silent');
662                }
663                else {
664                    scope.container.removeClass('loading-silent');
665                }
666
667            }
668
669        }, true);
670    };
671
672    return {
673        restrict: 'E',
674        scope: {
675            appEnabled: '=',
676            suppressLoading: '=',
677            loadingText: '=?',
678        },
679        templateUrl: SITEBASEURL + 'core/content/angular/loadingMask.html?sv=' + SITEVERSION,
680        link: link
681
682    }
683
684}]);
685
686saffire.angular.app.directive('sfMessenger', ['$interval', '$timeout', function ($interval, $timeout) {
687
688    function link(scope, element, attrs) {
689
690        scope.container = element.closest('.AngularAppContainer')
691
692        var lastActiveElement = null;
693        
694        scope.showMessage = function (settings) {     
695
696            var isShowMessage = true;
697            lastActiveElement = document.activeElement;  
698
699            if (scope.messengerActive) {
700                if (settings.message.indexOf('Still here') != -1) {
701                    scope.previousMessengerSettings = scope.messenger;
702                }
703                else if (scope.messenger.message.indexOf('Still here') != -1) {
704                    isShowMessage = false;
705                    scope.previousMessengerSettings = settings;
706                }
707                else {
708                    scope.previousMessengerSettings = scope.messenger;
709                }                
710            }
711            else {
712                scope.previousMessengerSettings = undefined;
713            }
714
715            if (isShowMessage) {
716                var messageSettings = {
717                    message: '',
718                    buttons: [],
719                    autoHide: false,
720                    timeoutInterval: 1000,
721                }
722
723                messageSettings = $.extend(messageSettings, settings);
724
725                scope.messenger = messageSettings;
726                scope.messengerActive = true;
727
728                if (scope.messenger.message.indexOf('Still here') != -1) {                    
729                    scope.isInactivityTimerActive = true;
730                }
731
732                if (messageSettings.autoHide) {
733
734                    if (scope.autoHideTimeOut) {
735                        $timeout.cancel(scope.autoHideTimeOut);
736                    }
737
738                    scope.autoHideTimeOut = $timeout(function () {
739                        scope.closeMessage(true);
740
741                        if (scope.messenger.beforeClose) {
742                            scope.messenger.beforeClose();
743                        }
744
745                    }, messageSettings.timeoutInterval)
746                }
747
748                scope.container.addClass('messengerActive');          
749                
750                (function() {
751                    let fdelay = 200;
752                    const isSeatSelector = $('#reservations').length > 0;
753                    if (isSeatSelector) {
754                        fdelay = 500;
755                    }
756                    setTimeout(() => {
757                        setFocusInModal('.messenger');
758                    }, fdelay);   
759                })();              
760            }
761        }
762
763        scope.closeMessage = function (isAutoHideTimeOut) {
764
765            if (scope.messenger) {
766                scope.messengerActive = false;
767                scope.messenger.countdown = 0;
768
769                if (scope.autoHideTimeOut) {
770                    $timeout.cancel(scope.autoHideTimeOut);
771                }
772                
773                if (scope.messenger.message.indexOf('Still here') != -1)
774                    scope.isInactivityTimerActive = false;
775                
776                scope.container.removeClass('messengerActive');
777
778                // Return focus to last focused element or top of content
779                setTimeout(() => {
780                    if (lastActiveElement && $(lastActiveElement).is(':visible')) {
781                        lastActiveElement.focus();
782                    } else {
783                        $('main').first().attr('tabindex', '-1').focus();
784                    }
785                }, 100);
786
787                if (isAutoHideTimeOut) {
788                    scope.previousMessengerSettings = undefined;
789                }
790                else {
791                    if (scope.previousMessengerSettings != undefined && scope.messenger.message != scope.previousMessengerSettings.message) {
792                        scope.showMessage(scope.previousMessengerSettings);
793                        scope.previousMessengerSettings = undefined;
794                    }
795                }
796            }
797        }
798    };
799
800    return {
801        restrict: 'E',
802        templateUrl: SITEBASEURL + 'core/content/angular/messenger.html?sv=' + SITEVERSION,
803        link: link
804
805    }
806
807}]);
808
809saffire.angular.app.directive('sfCountdown', ['$interval', '$timeout', function ($interval, $timeout) {
810
811    function link(scope, element, attrs) {
812
813        scope.$watch('startFrom', function (newValue, oldValue) {
814
815            if (scope.startFrom) {
816
817                scope.countdown = scope.startFrom;
818
819                scope.countdownTimeout = $interval(function () {
820                    scope.countdown = scope.countdown - 1;
821                }, 1000, scope.startFrom);
822            }
823
824        }, true);
825    };
826
827    return {
828        restrict: 'E',
829        scope: {
830            startFrom: '='
831        },
832        templateUrl: SITEBASEURL + 'core/content/angular/countdown.html?sv=' + SITEVERSION,
833        link: link
834
835    }
836
837}]);
838
839saffire.angular.app.directive('sfDetailsPanel', ['$timeout', function ($timeout) {
840
841    function link(scope, element, attrs) {
842
843        scope.hideShowDetails = function () {
844            scope.show = !scope.show;
845
846            $timeout(function () {
847                scope.onHideShowClick();
848            }, 100);
849        }
850    };
851
852    return {
853        restrict: 'E',
854        scope: {
855            onHideShowClick: '='
856        },
857        transclude: true,
858        templateUrl: SITEBASEURL + 'core/content/angular/detailsPanel.html',
859        link: link,
860    }
861}]);
862
863saffire.angular.app.directive('sfEnter', function () {
864    return function (scope, element, attrs) {
865        element.bind("keydown keypress", function (event) {
866            if (event.which === 13) {
867                scope.$apply(function () {
868                    scope.$eval(attrs.sfEnter);
869                });
870
871                event.preventDefault();
872            }
873        });
874    };
875});
876
877saffire.angular.app.directive('sfFileUpload', ['saffire.angular.fileServerService', 'saffire.angular.fileService', function (fileServerService, fileService) {
878
879    function link(scope, element, attrs) {
880
881        scope.fileUploadControl = element.find('#file')[0]
882
883        scope.fileName = ''
884        scope.mimeType = ''
885
886        if (scope.buttonText == '' || scope.buttonText == undefined) {
887            scope.buttonText = "Browse...";
888        }
889
890        scope.clickUpload = function () {
891            scope.fileUploadControl.click();
892        }
893
894        scope.fileUploadControl.onchange = function () {
895            var f = scope.fileUploadControl.files[0];
896            var r = new FileReader();
897
898            scope.fileName = scope.fileUploadControl.files[0].name;
899            scope.mimeType = scope.fileUploadControl.files[0].type;
900
901            r.onloadstart = function (e) {
902
903                //Check File Size
904                if (e.lengthComputable && scope.maxFileSize) {
905                    if (e.total > scope.maxFileSize * 1000000) {
906                        this.abort()
907                        scope.fileUploadControl.value = ''
908                        scope.$apply(function () {
909                            scope.onValidationError({ validationMessage: 'File size is too large. File must be less than ' + scope.maxFileSize.toString() + 'MB' })
910                        })
911                        return;
912                    }
913                }
914
915                //Check mime types
916                if (scope.allowFileTypes) {
917                    var allowedTypes = scope.allowFileTypes.split(',')
918                    var fileExtension = fileService.getFileExtension(scope.fileName);
919                    var isValid = false;
920
921                    if (allowedTypes.indexOf('audio') > -1) {
922                        var mimeTypes = ["audio/basic", "audio/mpeg", "audio/mpeg", "audio/x-aiff", "audio/xwav", "audio/x-m4a"]
923                        var fileExtensions = [".au", ".mp3", ".aif", ".m3u", ".wav", ".m4a"]
924
925                        if (mimeTypes.indexOf(scope.mimeType.toLowerCase()) > -1 || fileExtensions.indexOf(fileExtension.toLowerCase()) > -1) {
926                            isValid = true;
927                        }
928                    }
929
930                    if (allowedTypes.indexOf('image') > -1) {
931                        var mimeTypes = ["image/jpg", "image/jpeg", "image/gif", "image/png", "image/bmp"]
932                        var fileExtensions = [".jpg", ".jpeg", ".gif", ".png", ".bmp", ".tiff", ".tif"]
933
934                        if (mimeTypes.indexOf(scope.mimeType.toLowerCase()) > -1 || fileExtensions.indexOf(fileExtension.toLowerCase()) > -1) {
935                            isValid = true;
936                        }
937                    }
938
939                    if (allowedTypes.indexOf('pdf') > -1) {
940                        var mimeTypes = ["application/pdf"]
941                        var fileExtensions = [".pdf"]
942
943                        if (mimeTypes.indexOf(scope.mimeType.toLowerCase()) > -1 || fileExtensions.indexOf(fileExtension.toLowerCase()) > -1) {
944                            isValid = true;
945                        }
946                    }
947
948                    if (!isValid) {
949                        this.abort()
950                        scope.fileUploadControl.value = ''
951                        scope.$apply(function () {
952                            scope.onValidationError({ validationMessage: 'Invalid file type selected' })
953                        })
954                        return;
955                    }
956                }
957
958
959                scope.$apply(function () {
960                    scope.onUploadStart();
961                })
962
963            }
964
965            r.onprogress = function (e) {
966
967            }
968
969            r.onloadend = function (e) {
970                if (e.total > 0 && e.total == e.loaded) {
971                    var data = new Uint8Array(e.target.result)
972                    scope.fileUploadControl.value = ''
973                    scope.$apply(function () {
974                        scope.onFileUpload({
975                            fileName: scope.fileName,
976                            mimeType: scope.mimeType,
977                            data: data
978                        })
979                    })
980
981                }
982
983            }
984            r.readAsArrayBuffer(f);
985        }
986
987
988    }
989
990    return {
991        restrict: 'E',
992        scope: {
993            onFileUpload: '&',
994            onUploadStart: '&',
995            onValidationError: '&',
996            maxFileSize: '@',
997            allowFileTypes: '@',
998            buttonClass: '@',
999            buttonText: '@',
1000            showMessage: '=',
1001            closeMessage: '='
1002        },
1003        templateUrl: SITEBASEURL + 'core/content/angular/templates/fileUpload.html',
1004        link: link
1005    };
1006
1007}]);
1008
1009saffire.angular.app.directive('sfWebCamImageUpload', ['$interval', 'saffire.angular.navigatorService', function ($interval, navigatorService) {
1010
1011    function link(scope, element, attrs) {
1012
1013        if (valueIsNullOrUndefinedOrEmpty(scope.buttonText)) {
1014            scope.buttonText = "Take Picture";
1015        }
1016
1017        scope.openCamera = function () {
1018
1019            //navigatorService.getMediaDevices().then(function (response) {
1020            //    if (response.length > 0) {
1021            //        scope.showSwitchCamera = $.grep(response, function (md) {
1022            //            return md.kind == "videoinput"
1023            //        }).length > 1
1024            //    }
1025            //})
1026
1027            scope.camOptions.constraints = { facingMode: scope.cameraSettings.facingMode };
1028
1029            if (Webcam.live) {
1030                scope.showMessage({
1031                    message: "Camera is already active",
1032                    buttons: [{
1033                        text: 'Ok',
1034                        onClick: function () {
1035                            scope.closeMessage();
1036                        }
1037                    }],
1038                })
1039            } else {
1040                Webcam.set(scope.camOptions);
1041                Webcam.attach(element.find("#camera")[0]);
1042
1043                if (Webcam.userMedia) {
1044                    scope.cameraLoadedInterval = $interval(function () {
1045                        if (Webcam.loaded) {
1046                            $interval.cancel(scope.cameraLoadedInterval);
1047                            scope.cameraOpened = true;
1048                        }
1049                    }, 500)
1050                }
1051            }
1052        }
1053
1054        scope.switchCamera = function () {
1055            if (scope.cameraSettings.facingMode == "environment") {
1056                scope.cameraSettings.facingMode = "user";
1057
1058            } else if (scope.cameraSettings.facingMode == "user") {
1059                scope.cameraSettings.facingMode = "environment";
1060            }
1061
1062            if (Webcam.live) {
1063                Webcam.reset();
1064            }
1065
1066            scope.openCamera();
1067        }        
1068
1069        scope.takeSnapshot = function () {
1070            Webcam.snap(function (dataURI) {
1071
1072                var data = convertDataURIToBinary(dataURI);
1073
1074                var now = new Date();
1075                scope.fileName = (now.getFullYear().toString() + (now.getMonth() + 1).toString() + now.getDate().toString() + now.getHours().toString() + now.getMinutes().toString() + now.getSeconds().toString() + now.getMilliseconds().toString() + ".jpg").toString();            
1076
1077                scope.takePicture({
1078                    fileName: scope.fileName,
1079                    mimeType: "image/jpeg",
1080                    data: data
1081                });   
1082
1083                scope.closeCamera();
1084            });
1085        }
1086
1087        scope.closeCamera = function () {
1088            scope.cameraOpened = false;
1089            Webcam.reset();
1090        }
1091    }
1092
1093    return {
1094        restrict: 'E',
1095        scope: {
1096            camOptions: '=',
1097            takePicture: '&',
1098            buttonClass: '@',
1099            buttonText: '@',
1100            showMessage: '=',
1101            closeMessage: '=',
1102            cameraSettings: '='
1103        },
1104        templateUrl: SITEBASEURL + 'core/content/angular/templates/webCamImageUpload.html',
1105        link: link
1106    };
1107}]);
1108
1109saffire.angular.app.directive('sfGoogleRecaptcha', ['$interval', 'saffire.angular.scriptLoaderService', function ($interval, scriptLoaderService) {
1110
1111    //This is currently written for a single use on a page
1112    //could be expanded to allow mutliple
1113    //The response token needs to be validated server side as well
1114
1115    function link(scope, element, attrs) {
1116
1117        scope.recaptchaContainer = element.find("#div_recaptcha");
1118        scope.initialized = false;
1119
1120        scope.verifyCallback = function (response) {
1121
1122            scope.validation.submitRecaptchaValidationToken = response;
1123
1124            scope.$apply(function () {
1125                scope.validation.isValid = true;
1126
1127            });
1128
1129        }
1130
1131        scope.expiredCallback = function () {
1132
1133            scope.$apply(function () {
1134                scope.validation.submitRecaptchaValidationToken = '';
1135                scope.validation.isValid = false;
1136            })
1137
1138        }
1139
1140        window.recaptchaCallBack = function () {
1141
1142            scope.recaptcha = grecaptcha.render(scope.recaptchaContainer[0],
1143                {
1144                    sitekey: scope.siteKey,
1145                    callback: scope.verifyCallback,
1146                    'expired-callback': scope.expiredCallback,
1147                })
1148
1149        }
1150
1151        scope.$watch('enabled', function (newVal, oldVal) {
1152
1153            if (scope.enabled && !scope.initialized) {
1154
1155                scope.initialized = true;
1156                scriptLoaderService.loadScript('https://www.google.com/recaptcha/api.js?onload=recaptchaCallBack&render=explicit');
1157
1158            }
1159
1160        }, true)
1161
1162        scope.$watch('resetCounter', function (newVal, oldVal) {
1163
1164            if (scope.resetCounter && scope.resetCounter > 0 && scope.enabled && scope.initialized) {
1165
1166                grecaptcha.reset();
1167                scope.validation.submitRecaptchaValidationToken = null;
1168
1169            }
1170
1171        }, true)
1172
1173    };
1174
1175    return {
1176        restrict: 'E',
1177        scope: {
1178            siteKey: '@',
1179            validation: '=',
1180            enabled: '=',
1181            resetCounter: '=?',
1182        },
1183        templateUrl: SITEBASEURL + 'core/content/angular/recaptcha/recaptcha.html?sv=' + SITEVERSION,
1184        link: link
1185
1186    }
1187
1188}]);
1189
1190saffire.angular.app.directive('sfPromptOnExit', [function () {
1191
1192    function link(scope, element, attrs) {
1193
1194        window.onbeforeunload = function () {
1195            if (scope.promptOnExit) {
1196               return  "You have pending items in your cart, are you sure you want to leave this screen?";
1197            }
1198        }
1199
1200    }
1201
1202    return {
1203        restrict: 'E',
1204        scope: {
1205            promptOnExit: '=',
1206        },
1207        link: link
1208    };
1209
1210}]);
1211
1212saffire.angular.app.directive('sfTicketItemInputText', function () {
1213
1214    function link(scope, element, attrs) {
1215
1216        scope.$watch('[value,isRequired,originalValue,validationObject]', function (newVal, oldVal) {
1217
1218            var isValid = true;
1219            var messages = [];
1220
1221            if (scope.isRequired && (valueIsNullOrUndefinedOrEmpty(scope.value))) {
1222                isValid = false;
1223
1224                if (scope.showLabelTextInValidationMessage) {
1225                    messages.push((scope.labelText ? scope.labelText + ' is ' : '') + 'required');
1226                }
1227                else {
1228                    messages.push('required');
1229                }
1230            }
1231
1232            //validation
1233
1234            if (scope.validationObject) {
1235                scope.validationObject.isValid = isValid;
1236                scope.validationObject.messages = messages;
1237                scope.validationObject.isValidated = true;
1238            }
1239
1240        }, true)
1241
1242        scope.$watch('autoComplete', function (newVal, oldVal) {
1243            if (scope.autoComplete && scope.autoComplete !== '') {
1244                element.find('input[type="text"]').attr('autocomplete', scope.autoComplete);
1245            } else {
1246                element.find('input[type="text"]').removeAttr('autocomplete');
1247            }
1248        }, true)
1249    };
1250
1251    return {
1252        scope: {
1253            value: '=',
1254            description: '=',
1255            isRequired: '=',
1256            validationObject: '=',
1257            labelText: '@',
1258            labelCssClass: '@',
1259            cssClass: '@',
1260            isCritical: '=',
1261            maxLen: '=',
1262            showValidationLabel: '=',
1263            showLabelTextInValidationMessage: '=',
1264            autoComplete: '@'
1265        },
1266        templateUrl: SITEBASEURL + 'core/content/angular/Templates/ticketItemInputText.html',
1267        link: link
1268    }
1269});
1270
1271saffire.angular.app.directive('sfTicketDetailsInputValidationLabel', function () {
1272
1273    function link(scope, element, attrs) {
1274
1275    };
1276
1277    return {
1278        scope: {
1279            validationObject: '='
1280        },
1281        templateUrl: SITEBASEURL + 'core/content/angular/Templates/ticketsDetailsInputValidationLabel.html',
1282        link: link
1283    }
1284});
1285
1286saffire.angular.app.directive('sfInputPhone', function () {
1287
1288    function link(scope, element, attrs) {
1289
1290        scope.$watch('[value,isRequired,validationObject]', function (newVal, oldVal) {
1291
1292            var isValid = true;
1293            var messages = [];
1294
1295            if (scope.isRequired && (valueIsNullOrUndefinedOrEmpty(scope.value))) {
1296                isValid = false;
1297                messages.push(scope.labelText + ' is required');
1298            }
1299
1300            var rePhoneNumber = /^[0-9]{3}[0-9]{3}[0-9]{4}$/;
1301
1302            if (!stringIsNullOrEmpty(scope.value && scope.value.toString()) && !(rePhoneNumber.test(scope.value))) {
1303                isValid = false;
1304                messages.push(scope.labelText + ' is invalid');
1305            }
1306
1307            if (scope.validationObject) {
1308                scope.validationObject.isValid = isValid;
1309                scope.validationObject.messages = messages;
1310            }
1311
1312        }, true)
1313    };
1314
1315    return {
1316        scope: {
1317            value: '=',
1318            description: '=',
1319            isRequired: '=',
1320            readonly: '=?',
1321            validationObject: '=',
1322            validationEnabled: '=?',
1323            labelText: '@',
1324            cssClass: '@',
1325            placeholder: '@',
1326            isCritical: '=',
1327            maxLen: '=?',
1328            mask: '@'
1329        },
1330        templateUrl: SITEBASEURL + 'core/content/angular/templates/inputPhone.html',
1331        link: link
1332    }
1333});
1334
1335saffire.angular.app.directive('sfInputNumberKeypad', ['$rootScope', function ($rootScope) {
1336
1337    function link(scope, element, attrs) {
1338        scope.keyPressed = function (key) {
1339
1340            if (key == "Clear") {
1341                scope.input = "";
1342
1343            } else if (key == "Clear Last") {
1344                scope.input = scope.input.slice(0, -1);
1345
1346            } else {
1347                if (scope.input.length < scope.maxLen) {
1348                    scope.input += key;
1349                }
1350            }
1351
1352            $rootScope.$broadcast("sfInputNumberKeypadKeyPressed", key);
1353        }
1354    };
1355
1356    return {
1357        scope: {
1358            input: '=',
1359            maxLen: '='
1360        },
1361        templateUrl: SITEBASEURL + 'core/content/angular/templates/inputNumberKeypad.html',
1362        link: link
1363    }
1364}]);
1365
1366saffire.angular.app.directive('sfValidationInputDropDown', function () {
1367
1368    function link(scope, element, attrs) {
1369
1370        scope.isInitialized = false;
1371
1372        if (!scope.selectLabel)
1373            scope.selectLabel = "Select";
1374
1375        scope.getDisplayName = function (recordData) {
1376            if (scope.displayNameFunc) {
1377                return scope.displayNameFunc({ entity: recordData });
1378            }
1379
1380            return recordData.Name;
1381        }
1382
1383        scope.getDisplayNameWithHTMLStripped = function (recordData) {
1384
1385            var displayName = scope.getDisplayName(recordData);
1386
1387            return displayName.replace(/<\/?[^>]+(>|$)/g, "")
1388        }
1389
1390        scope.isDisabled = function (recordData) {
1391            if (scope.isDisabledFunc) {
1392                return scope.isDisabledFunc({ entity: recordData });
1393            }
1394
1395            return false;
1396        }
1397
1398        scope.$watch('[recordId, recordName, ddDataSource]', function (newVal, oldVal) {
1399
1400            if (scope.ddDataSource) {
1401                var template = [];
1402
1403                if (scope.nameSelection) {
1404                    template = $.grep(scope.ddDataSource, function (tt) {
1405                        return tt.Name == scope.recordId
1406                    })
1407                } else {
1408                    template = $.grep(scope.ddDataSource, function (tt) {
1409                        return tt.ID == scope.recordId
1410                    })
1411                }
1412
1413                if (template.length) {
1414                    scope.selectedRecord = template[0];
1415                }
1416                else
1417                    scope.selectedRecord = null;
1418
1419                scope.isInitialized = true;
1420            }
1421
1422        }, true)
1423
1424        scope.$watch('selectedRecord', function (newVal, oldVal) {
1425
1426            if (scope.isInitialized) {
1427
1428                if (scope.nameSelection)
1429                    scope.recordId = newVal ? scope.selectedRecord.Name : '';
1430                else
1431                    scope.recordId = newVal ? scope.selectedRecord.ID : null;
1432
1433                scope.selectedName = newVal ? scope.selectedRecord.Name : '';
1434            }
1435
1436        }, true)
1437
1438        scope.$watch('[recordId,isRequired,validationObject,ids]', function (newVal, oldVal) {
1439
1440            var isValid = true;
1441            var messages = [];
1442
1443            if (scope.isRequired && valueIsNullOrUndefinedOrEmpty(scope.recordId)) {
1444                isValid = false;
1445                messages.push(scope.labelText + ' is required')
1446            }
1447
1448            if (scope.ids && scope.recordId) {
1449                var isDuplicate = $.grep(scope.ids, function (id) {
1450                    return id == scope.recordId;
1451                }).length > 1;
1452
1453                if (isDuplicate) {
1454                    isValid = false;
1455                    messages.push('Duplicate ' + scope.labelText + ' selected')
1456                }
1457            }
1458
1459            if (scope.validationObject) {
1460                scope.validationObject.isValid = isValid;
1461                scope.validationObject.messages = messages;
1462            }
1463        }, true)
1464    };
1465
1466    return {
1467        scope: {
1468            recordId: '=',
1469            selectedRecord: '=?',
1470            selectedName: '=?',
1471            nameSelection: '=?',
1472            ddDataSource: '=',
1473            showSelectLabel: '=',
1474            isRequired: '=',
1475            validationObject: '=',
1476            showValidationIcon: '=',
1477            selectLabel: '@',
1478            labelText: '@',
1479            disabled: '=',
1480            showLabelText: '=',
1481            ids: '=',
1482            displayNameFunc: '&?',
1483            isDisabledFunc: '&?'
1484        },
1485        templateUrl: SITEBASEURL + 'core/content/angular/Templates/validationInputDropDown.html',
1486        link: link
1487
1488    }
1489});
1490saffire.angular.app.directive('sfValidationInputNumber', function () {
1491
1492    function link(scope, element, attrs, ctrl) {
1493
1494        scope.numberIsValid = true;
1495
1496        scope.$watch('[value, isRequired, numberIsValid, groupVar, min, max, validationEnabled]', function (newVal, oldVal) {
1497
1498            var isValid = true;
1499            var messages = [];
1500            var validationEnabled = scope.validationEnabled == undefined ? true : scope.validationEnabled;
1501
1502            if (scope.allowZero == undefined) {
1503                scope.allowZero = false;
1504            }
1505
1506            if (scope.allowNegative == undefined) {
1507                scope.allowNegative = false;
1508            }
1509
1510            if (validationEnabled) {
1511                scope.isValid = scope.numberIsValid;
1512
1513                if (scope.isRequired && valueIsNullOrUndefinedOrEmpty(scope.value)) {
1514                    isValid = false;
1515                    messages.push(scope.labelText + " is required")
1516                }
1517                else if (!valueIsNullOrUndefinedOrEmpty(scope.value) && scope.numberIsValid) {
1518                    if (scope.min && scope.value < scope.min) {
1519                        isValid = false;
1520
1521                        if (scope.minValidationMessage) {
1522                            messages.push(scope.minValidationMessage);
1523
1524                        } else {
1525                            messages.push("Please input a number greater than " + scope.min);
1526                        }
1527                    }
1528
1529                    if (scope.max && scope.value > scope.max) {
1530                        isValid = false;
1531
1532                        if (scope.maxValidationMessage) {
1533                            messages.push(scope.maxValidationMessage);
1534
1535                        } else {
1536                            messages.push("Please input a number no greater than " + scope.max);
1537                        }
1538                    }
1539                }
1540                else if (!scope.numberIsValid) {
1541                    isValid = false;
1542                    messages.push(scope.labelText + " is invalid");
1543                }
1544
1545                if (scope.customValidateFunc) {
1546
1547                    var customValidationObject = scope.customValidateFunc();
1548
1549                    if (!customValidationObject.isValid) {
1550                        isValid = customValidationObject.isValid;
1551
1552                        angular.forEach(customValidationObject.messages, function (m) {
1553                            messages.push(m);
1554                        })
1555                    }
1556                }
1557            }
1558
1559            if (scope.validationObject) {
1560                scope.validationObject.isValid = isValid;
1561                scope.validationObject.messages = messages;
1562            }
1563        }, true)
1564    };
1565
1566    return {
1567        scope: {
1568            value: '=',
1569            isRequired: '=',
1570            validationObject: '=',
1571            validationEnabled: '=',
1572            showValidationIcon: '=',
1573            labelText: '@',
1574            showLabelText: '=',
1575            cssClass: '@',
1576            maxLen: '=',
1577            minLen: '=',
1578            min: '=?',
1579            minValidationMessage: '@',
1580            max: '=?',
1581            maxValidationMessage: '@',
1582            disabled: '=',
1583            placeholder: '@',
1584            integerOnly: '=?',
1585            allowZero: '=?',
1586            allowNegative: '=?',
1587            isValid: '=?',
1588            customValidateFunc: '=',
1589            groupVar: '=',
1590            width: '@',
1591            display: '@',
1592            isCvv: '='
1593        },
1594        templateUrl: SITEBASEURL + 'core/content/angular/Templates/validationInputNumber.html',
1595        link: link
1596    }
1597});

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.