PageSourceSearch

https://www.toyota.ee/etc.clientlibs/fd/af/runtime/clientlibs/guid…ime.min.36daeaae17184d2a32bd90ef2aa8a117.js

js toyota.ee collected 2026-09-25 06:38:42 UTC 1,571,883 bytes, 39,008 lines download raw bytes

vendor: 2,088 bytes, lines 1-58
1/*
2 * ***********************************************************************
3 * ADOBE CONFIDENTIAL
4 * __________________
5 *
6 * Copyright 2015 Adobe Systems Incorporated
7 * All Rights Reserved.
8 *
9 * NOTICE:  All information contained herein is, and remains
10 * the property of Adobe Systems Incorporated and its suppliers,
11 * if any.  The intellectual and technical concepts contained
12 * herein are proprietary to Adobe Systems Incorporated and its
13 * suppliers and may be covered by U.S. and Foreign Patents,
14 * patents in process, and are protected by trade secret or copyright law.
15 * Dissemination of this information or reproduction of this material
16 * is strictly forbidden unless prior written permission is obtained
17 * from Adobe Systems Incorporated.
18 * ***********************************************************************
19 */
20
21(function ($) {
22    $.uaMatch = function( ua ) {
23        ua = ua.toLowerCase();
24        var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
25            /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
26            /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
27            /(msie) ([\w.]+)/.exec( ua ) ||
28            ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || [];
29        return {
30            browser: match[ 1 ] || "",
31            version: match[ 2 ] || "0"
32        };
33    };
34    // Not clobbering any existing $.browser
35    if ( !$.browser ) {
36        var
37            matched = $.uaMatch( navigator.userAgent ),
38            browser = {};
39        if ( matched.browser ) {
40            browser[ matched.browser ] = true;
41            browser.version = matched.version;
42        }
43        // Chrome is Webkit, but Webkit is also Safari.
44        if ( browser.chrome ) {
45            browser.webkit = true;
46        } else if ( browser.webkit ) {
47            browser.safari = true;
48        }
49        $.browser = browser;
50    }
51})($);
52/*************************************************************************
53 * ADOBE CONFIDENTIAL
54 * ___________________
55 *
56 *  Copyright 2013 Adobe Systems Incorporated
57 *  All Rights Reserved.
58 *
59 * NOTICE:  All information contained herein is, and remains
60 * the property of Adobe Systems Incorporated and its suppliers,
61 * if any.  The intellectual and technical concepts contained
62 * herein are proprietary to Adobe Systems Incorporated and its
63 * suppliers and are protected by all applicable intellectual property
64 * laws, including trade secret and copyright laws.
65 * Dissemination of this information or reproduction of this material
66 * is strictly forbidden unless prior written permission is obtained
67 * from Adobe Systems Incorporated.
68 **************************************************************************/
69
70
71/**
72 * @package xfalib.ut.Class
73 */
74(function(_, xfalib){
75
76    xfalib.ns = xfalib.ns || function (namespaceString) {
77        var parts = namespaceString.split('.'),
78            parent = window,
79            currentPart = '';
80
81        for(var i = 0, length = parts.length; i < length; i++) {
82            currentPart = parts[i];
83            parent[currentPart] = parent[currentPart] || {};
84            parent = parent[currentPart];
85        }
86
87        return parent;
88    };
89
90    var Class = xfalib.ut.Class = function(options) {
91        this.options = _.extend({}, this.options, options);
92        if(!this.options.jsonModel)
93            this.options.jsonModel = {};
94        //For perf reason, we are setting jsonModel as direct property instead of using property descriptor
95        this.jsonModel = this.options.jsonModel;
96        this.initialize.apply(this, arguments);
97    };
98
99    _.extend(Class.prototype, {
100        initialize : function(){
101        },
102
103        xfaUtil :function(){
104          return xfalib.ut.XfaUtil.prototype;
105        },
106
107        copyArray : function(src,dst,options) {
108            var keepReference = this.getOrElse(options, "keepReference", true);
109            if(src instanceof Array)
110            {
111                for (var i = 0;i<src.length;i++)
112                {
113                    var obj;
114                    if(src[i] instanceof Array)
115                    {
116                        obj = this._createDestination(dst, i, keepReference, []);
117                        this.copyArray(src[i],obj,options);
118                    }
119                    else if(typeof src[i] == "object")
120                    {
121                        obj = this._createDestination(dst, i, keepReference, {});
122                        this.copyObject(src[i],obj,options);
123                    } else {
124                        obj = src[i];
125                    }
126                    dst[i] = obj;
127                }
128                if(dst.length > src.length){
129                    dst.splice(src.length, (dst.length - src.length));  //Remove ths rest of the extra destination items
130                }
131            }
132        },
133
134        /**
135         *
136         * @param src
137         * @param dst
138         * @param options e.g. {keepReference: true, exceptions:["htmlId"], transformMaps: {"dataId", function(src, options){ return src "33"+src; }}}
139         */
140        copyObject : function(src,dst,options) {
141            var keepReference = this.getOrElse(options, "keepReference", true);
142            var exceptions = this.getOrElse(options, "exceptions", []);
143            var transformMaps = this.getOrElse(options, "transformMaps", {});
144            if(typeof src == "object") {
145                for (var child in src) {
146                    if(exceptions.indexOf(child) == -1) {
147                        if(src[child] instanceof Array) {
148                            dst[child] = this._createDestination(dst, child, keepReference, []);
149                            this.copyArray(src[child],dst[child],options);
150                        }
151                        else if(typeof src[child] == "object" && src[child] != null) {
152                            dst[child] = this._createDestination(dst, child, keepReference, {});
153                            this.copyObject(src[child],dst[child],options);
154                        }
155                        else{
156                            if(!_.isUndefined(transformMaps[child])){
157                                dst[child] = transformMaps[child](src[child], options, src);
158                            }
159                            else
160                                dst[child] = src[child];
161                        }
162                    }
163                }
164            }
165        },
166
167        _createDestination : function(obj, property, keepReference, defaultValue) {
168            if(!keepReference)
169                return defaultValue;
170            else if(_.isObject(obj) && !obj.hasOwnProperty(property))
171                return defaultValue;
172            else
173                return obj[property] || defaultValue ;  //Would handle both, Array and objects
174        },
175
176        /**
177         * will replace functions in the object with noop function based on a predicate function's result.
178         * If no predicate is passed all functions will be disabled.
179         * Warning once disabled object cant be re-enabled.
180         *
181         * sample predicate to disable all 'public' functions : function (funcName) { return funcName[0] != '_'}
182         *
183         * @param predicate
184         * @private
185         */
186        _disableFunctions: function (predicate) {
187            var noop = function () {},
188                disableAll = !_.isFunction(predicate);
189
190            _.each(_.functions(this), function (funcName) {
191                if (disableAll || predicate(funcName)) {
192                    this[funcName] = noop;
193                }
194            }, this);
195        },
196
197        /**
198         * getOrElse can take multiple arguments.
199         * arg1(obj): base Object
200         * arg2: string representing property chain where properties are concatenated via dot
201         * arg3: default value
202         **/
203
204        getOrElse : function(obj){
205            var currObject = obj;
206            if(arguments.length < 2)
207                return currObject;
208            else if(arguments.length == 2) {
209                if(!_.isUndefined(currObject)){
210                    return currObject;
211                } else {
212                    return _.clone(arguments[1]);
213                }
214            }
215            else {
216                var propChain = (arguments[1] || "").split(".");
217                var defaultValue = arguments[2];
218                _.each(propChain, function(prop){
219                    if(_.isObject(currObject))
220                        currObject = currObject[prop];
221                    else
222                        currObject = undefined;
223                }, this);
224
225                if(!_.isUndefined(currObject))
226                    return currObject;
227                else {
228                    return _.clone(defaultValue) ; //May have to do deep clone in future. TODO: support for conditional clone
229                }
230            }
231        },
232
233        jqId: function (id) {
234            return xfalib.ut.XfaUtil.prototype.jqId(id);
235        },
236
237        logger : function(){
238            return this.xfaUtil().getLogger();
239        },
240
241        validateInput : function(param, dataType,fallback){
242        	if(typeof param !== "undefined" && param !== null) {
243        		switch(dataType) {
244        		case "string":
245        			param = param+"";
246        			break;
247        		case "object":
248        			if(typeof param !== "object")
249        				param = fallback;
250        			break;
251        	    case "integer":
252                    param = parseInt(param);
253                    if(isNaN(param))
254                        param = fallback;
255                    break;
256               case "measurement":
257                     break;
258        		default:
259        			if(dataType instanceof Array) {
260                        if(!~dataType.indexOf(param))
261                            param = fallback
262                    }
263        		}
264        	}
265        	return param;
266        }
267
268    });
269
270    _.extend(Class, {
271        defineProps : function(propsMap){
272            _.each(propsMap, function(propDesc, propName){
273                //Check property can be resolved using resolveNode
274                if(propDesc.resolve) {
275                    //Check whether prototype owns the object resolveProperties
276                    if(!this.prototype.hasOwnProperty("resolveProperties")) {
277                        //check whether prototype inherits the object resolveProperties
278                        if(this.prototype.resolveProperties) {
279                            //clone the object since we do not want to modify parent's prototype
280                            this.prototype.resolveProperties = _.clone(this.prototype.resolveProperties);
281                        }
282                        else
283                            this.prototype.resolveProperties = [];
284                    }
285                    this.prototype.resolveProperties.push(propName)
286                }
287                Object.defineProperty(this.prototype, propName, propDesc);
288
289            }, this);
290        },
291        extend : function(props){
292            var child = inherits(this, props);
293            child.extend = this.extend;
294            return child;
295        },
296        addMixins : function(mixinBakers){
297            if(!_.isArray(mixinBakers)){
298                mixinBakers = [mixinBakers];
299            }
300            _.each(mixinBakers, function(mixinBaker){
301                if(mixinBaker.normalProperties){
302                    _.extend(this.prototype, mixinBaker.normalProperties);
303                }
304                if(mixinBaker.propertyDescriptors){
305                    this.defineProps(mixinBaker.propertyDescriptors);
306                }
307            }, this);
308        }
309    });
310
311    // Shared empty constructor function to aid in prototype-chain creation.
312    var ctor = function(){};
313
314    // Helper function to correctly set up the prototype chain, for subclasses.
315    // Similar to `goog.inherits`, but uses a hash of prototype properties and
316    // class properties to be extended.
317    function inherits(parent, protoProps, staticProps) {
318        var child;
319        var _super = parent.prototype;
320        // The constructor function for the new subclass is either defined by you
321        // (the "constructor" property in your `extend` definition), or defaulted
322        // by us to simply call the parent's constructor.
323        if (protoProps && protoProps.hasOwnProperty('constructor')) {
324            child = protoProps.constructor;
325        } else {
326            child = function(){ parent.apply(this, arguments); };
327        }
328
329        // Inherit class (static) properties from parent.
330        _.extend(child, parent);
331
332        // Set the prototype chain to inherit from `parent`, without calling
333        // `parent`'s constructor function.
334        ctor.prototype = parent.prototype;
335        child.prototype = new ctor();
336        child._super = parent.prototype;
337        child._superClass = parent;
338
339        // Add prototype properties (instance properties) to the subclass,
340        // if supplied.
341        if (protoProps) { //_.extend(child.prototype, protoProps);
342            // Copy the properties over onto the new prototype
343            for (var name in protoProps) {
344                if(name == "_defaults"){
345                    protoProps[name] = _.extend({}, _super[name], protoProps[name]);
346                }
347                child.prototype[name] = protoProps[name];
348            }
349        }
350
351
352        // Add static properties to the constructor function, if supplied.
353        if (staticProps) _.extend(child, staticProps);
354
355        // Correctly set child's `prototype.constructor`.
356        child.prototype.constructor = child;
357
358        // Set a convenience property in case the parent's prototype is needed later.
359        child.__super__ = parent.prototype;
360
361        return child;
362    };
363})(_, window.xfalib);
364/**
365 * Created by vdua on 2/18/2015.
366 */
367(function (_, xfalib) {
368    var XMLUtils = {
369        dataSom2xpath: function (dataSom) {
370            var xpath = "";
371
372            if (!_.isEmpty(dataSom)) {
373                // any dot preceded by ], takes care of dot-s in name,
374                // and remove constant prefix "xfa[0].datasets[0].data[0]" and form root name, then join using '/'
375                _.each(dataSom.split(/\]\./).slice(4),
376                    function (part) {
377                        var openBracketPos = part.lastIndexOf('[');
378                        xpath += part.substring(0, openBracketPos + 1) +
379                            (parseInt(part.substring(openBracketPos + 1)) + 1) + // increment index by 1 for xpath query
380                            "]/";
381                    });
382
383                if (_.isEmpty(xpath)) {
384                    xpath = dataSom;
385                } else if (xpath[xpath.length - 1] === '/') {
386                    xpath = xpath.slice(0, -1);
387                }
388            }
389
390            return xpath;
391        },
392
393        /**
394         * Converts an xPathResult of type iterator to an array
395         * @param xPathResult
396         * @returns {Array}
397         */
398        iteratorToArray: function (xPathResult) {
399            var result = [];
400            // in some browsers, if xpath is invalid xPath result is null whereas some browsers return XpathResult with empty iterator
401            var node = xPathResult ? xPathResult.iterateNext() : null;
402            while (node != null) {
403                result.push(node);
404                node = xPathResult.iterateNext();
405            }
406            return result;
407        },
408        /**
409         * Wrapper API for document.evaluate to provide cross-browser support.
410         * @param xpath
411         * @param node
412         * @param nsResolver
413         * @param resultType
414         * @param result
415         * @returns {Object|*}
416         */
417        evaluateXPath: function (xpath, node, nsResolver, resultType, result) {
418            try {
419                if(_.isEmpty(xpath) || !_.isString(xpath) || !(node instanceof Node)) {
420                    return null;
421                }
422
423                // Determine the appropriate document context for searching.
424                var searchContext = node instanceof Document ? node : node.ownerDocument;
425                // Check if the document.evaluate function is undefined or if we're in a server-side context.
426                var isEvaluateUndefined = typeof searchContext.evaluate === 'undefined';
427                var isServerSide = window.guideBridge && window.guideBridge.hostName === "server";
428                var needsXPathPolyfill = isEvaluateUndefined || isServerSide;
429                if (needsXPathPolyfill) {
430                    // Install the wgxpath polyfill to provide evaluate functionality.
431                    wgxpath.install(window, true);
432                    // Assign the newly installed evaluate function to the search context.
433                    searchContext.evaluate = window.document.evaluate;
434                }
435
436                var documentToEval = searchContext.evaluate ? searchContext : document;
437                xpath = this.sanitizeXPath(xpath);
438
439                return documentToEval.evaluate(xpath, node, nsResolver, resultType, result);
440
441            } catch (exception) {
442                xfalib.ut.XfaUtil.prototype.getLogger().error("Could not evaluate xpath: " + xpath  + exception);
443
444            }
445
446        },
447         /**
448         *Removes all [*] other than ['numeric'] from xpath
449         *@param xpath
450         *@returns xpath after removing "[*]"
451         */
452         sanitizeXPath: function(xpath) {
453             var xpathArray=xpath.split("/"),
454                 resultXpath = _.map(xpathArray, function (path) {
455                 return path.replace(/\[(.*\D+.*)\]|\[\]/g,"");
456             }).join("/");
457             return resultXpath;
458         },
459
460        /**
461         * Creates all the Elements (if they don't exist) in the xpath leading to the node being searched for in the
462         * xpath relative to the element. Optionally creates the node as well if bParentsOnly is false
463         * @param xpath
464         * @param element
465         * @param bParentsOnly whether to create only the parents or the node as well
466         * @returns node that is being represented by the xpath relative to the element.
467         */
468        createElementsFromXPath: function (xpath, element, bParentsOnly) {
469            if (xpath != null || element != null) {
470                var parts = xpath.split("/"),
471                    actualParts = bParentsOnly ? _.initial(parts) : parts,
472                    el = element;
473                _.each(actualParts, function (part, index) {
474                    var som = part.match(/^([^[]+)(\[(\d+)\])?/),
475                        childEl;
476                    if (som == null) {
477                        xfalib.ut.XfaUtil.prototype.getLogger().error("Unsupported expression in Bindref " + part);
478                        return null;
479                    }
480                    //only the last element can be attribute
481                    childEl = this.findOrCreateElement(part, el, index === actualParts.length - 1);
482                    el = childEl;
483                }, this);
484                return el;
485            }
486            return null;
487        },
488
489        /**
490         * Form an xpath part returns the index as well as the tagName. Index can be * as well
491         * @param xpathName
492         * @returns {*}
493         * @private
494         */
495        _getElementNameAndIndexFromXPathPart: function (xpathName) {
496            var som  =  xpathName.match(/^([^[]+)(?:\[(\d+|\*)\])?/);
497            if (som !== null) {
498                return {
499                    name: som[1],
500                    index: som[2] || 0
501                };
502            }
503            return null;
504        },
505
506        /**
507         * create an element with the tagName elementName for the ownerDocument of element.
508         * @param elementName
509         * @param element
510         * @returns {HTMLElement}
511         */
512        createElement: function (elementName, element) {
513            var el = element.ownerDocument.createElement(elementName);
514            return el;
515        },
516
517        /**
518         * Searches for the nodeXpath relative to element. If it doesn't exists creates it and returns the node
519         * @param element
520         * @param nodeXpath
521         * @param bAttribute if true then check for attribute otherwise not.
522         * @returns {Node|*}
523         */
524        findOrCreateElement: function (nodeXpath, element, bAttribute) {
525            try {
526                if (element == null) {
527                    return null;
528                }
529                var result = this.evaluateXPath(nodeXpath, element, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
530                    el = result.iterateNext(),
531                    res;
532                if (el == null) {
533                    res = this._getElementNameAndIndexFromXPathPart(nodeXpath);
534                    if (res != null) {
535                        if (bAttribute && res.name.match(/^@/)) {
536                            var attrName = res.name.replace(/^@/, "");
537                            el = element.ownerDocument.createAttribute(attrName);
538                            element.setAttributeNode(el);
539                        } else {
540                            el = element.ownerDocument.createElement(res.name);
541                            element.appendChild(el);
542                        }
543                    }
544                }
545                return el;
546
547            } catch (exception) {
548                xfalib.ut.XfaUtil.prototype.getLogger().error("Following exception "
549                    +  "occurred while executing findOrCreateElement " + exception);
550            }
551
552        },
553
554        /**
555         * Returns the Root Form Elment from the xmlDocumentElement
556         * @param xmlDocumentElement It can be a document or Element. If the root element is xdp element, it returns
557         *        the grand grand child of that element. otherwise the root element is returned. The root
558         *        Element can be either the element itself or documentElement of the element.
559         */
560        getXFARootFormElementFromXML: function (xmlDocumentElement) {
561            if(_.isUndefined(document.evaluate)) {
562                wgxpath.install();
563            }
564            var isElement = xmlDocumentElement instanceof Element,
565                docElemName = isElement ? xmlDocumentElement.nodeName : xmlDocumentElement.documentElement.nodeName,
566                rootElement = isElement ? xmlDocumentElement : xmlDocumentElement.documentElement,
567                nodeList;
568
569            if ("xdp:xdp" === docElemName || "xdp" === docElemName) {
570                if (xfalib.ut.XfaUtil.prototype.isIE()) {
571                    //IE doesn't support evaluating namespace elements
572                    var datasets = rootElement.firstElementChild,
573                        data = datasets.firstElementChild;
574                    rootElement = data.firstElementChild;
575                } else {
576                    // assumption is that the xml will be of format <xdp><datasets><data><form1>
577                    // TODO: change first * to xfa:datasets
578                    nodeList = this.evaluateXPath("*/xfa:data/*", rootElement, formBridge.nsResolver,
579                                            XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
580                    rootElement = nodeList.iterateNext();
581                }
582            }
583            return rootElement;
584        },
585
586        /**
587         * Returns an object containing the prefix and namespaces present in the rootElement. For default namespace the
588         * prefix is "_default"
589         * @param rootElement {Element} xml element which has to be looked for namespaces
590         * @returns {object} object whose keys are the prefix and values are the namespace
591         */
592        getNamespaces: function (rootElement) {
593            var namespaces = {
594                "_default" : null
595            };
596            _.each(rootElement.attributes, function (attr) {
597                var name = attr.name,
598                    parsedAttrName = name.match(/^xmlns(?:\:(.*))?/),
599                    isNamespace = parsedAttrName != null,
600                    namespaceName = isNamespace ? parsedAttrName[1] || "_default" : null;
601                if (namespaceName) {
602                    namespaces[namespaceName] = attr.value;
603                }
604            });
605            return namespaces;
606        },
607
608        /**
609         * Returns a namespace resolver given a element. The nsResolver returns the namespace given a prefix by
610         * using the namespaces mentioned in the element.
611         * @param rootElement element from which to create the nsResolver
612         * @returns {function} the function returns the namespace given a prefix.
613         */
614        getNsResolver: function (rootElement) {
615            var namespaces = this.getNamespaces(rootElement),
616                nsResolver = (function (namespaces) {
617                    return function (nsPrefix) {
618                        var namespace = formBridge.nsResolver(nsPrefix) || namespaces[nsPrefix];
619                        return namespace;
620                    };
621                }(namespaces));
622            return nsResolver;
623        },
624
625        /**
626         * Removes default namespaces from xml, basically the namespace defined as xmlns="some namespace". The
627         * side-effect of the API is it removes the string "xmlns='some namespace'" from any attribute value as well.
628         * @param xml {string}
629         * @returns {string}
630         */
631        removeDefaultNamespace: function (xml) {
632            var stringRegex = "(\\s+)" + // any number of spaces
633                             "(xmlns=" + // then xmlns=
634                            "('[^']*'|\"[^\"]*\"))" + // then value in single quotes ('[^']') or
635                                                    //                 double quotes ("[^"]")
636                            "(?=[^<>]*>)",  // followed by closing tag (implies attribute) and before another
637                                           // opening tag(implies text)
638                regex = new RegExp(stringRegex, "g");
639            return xml.replace(regex, "$1");
640        }
641    };
642    xfalib.ut.XMLUtils = XMLUtils;
643}(_, xfalib));
644/**
645 * @package xfalib.ut.Logger
646 * @import xfalib.ut.Class
647 */
648
649(function(_, xfalib, $){
650    var categoryAcronyms = {
651                            "a": "xfa",
652                            "b": "xfaView",
653                            "c": "xfaPerf"
654        },
655        loggerTypes = ["off", "console", "server", "consoleServer"];
656    var Logger = xfalib.ut.Logger = xfalib.ut.Class.extend({
657
658//      Count of log messages so far.
659        LOG_COUNT : {
660            level : {
661                "FATAL" : 0,
662                "ERROR" : 0,
663                "WARN" : 0,
664                "INFO" : 0,
665                "DEBUG" : 0,
666                "TRACE" : 0,
667                "ALL" : 0
668            },
669            category : {
670                "xfa" : 0,
671                "xfaView" : 0,
672                "xfaPerf" : 0,
673                "Unknown" : 0
674           }
675        },
676
677        /**
678         * Log level to turn logging off (default).
679         * @static
680         * @final
681         * @type Number
682         */
683        OFF : 0,
684
685        /**
686         * Log level for fatal error messages.
687         * @static
688         * @final
689         * @type Number
690         */
691        FATAL : 1,
692
693        /**
694         * Log level for error messages.
695         * @static
696         * @type Number
697         * @final
698         */
699        ERROR : 2,
700
701        /**
702         * Log level for warning messages.
703         * @static
704         * @type Number
705         * @final
706         */
707        WARN : 3,
708
709        /**
710         * Log level for info messages.
711         * @static
712         * @type Number
713         * @final
714         */
715        INFO : 4,
716
717        /**
718         * Log level for debug messages.
719         * @static
720         * @type Number
721         * @final
722         */
723        DEBUG : 5,
724
725        /**
726         * Log level for trace messages.
727         * @static
728         * @type Number
729         * @final
730         */
731        TRACE : 6,
732
733        /**
734         * Log level for all messages.
735         * @static
736         * @type Number
737         * @final
738         */
739        ALL : 7,
740
741
742        logLevelNames : ["OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "ALL"],
743
744        initialize : function(){
745            var str = "",
746                that =this;
747            Logger._super.initialize.call(this);
748            this.logs = {};
749            this.logMessages = "";
750            this.logServiceProxy = this.options.logServiceProxy;
751            this.contextPath = this.options.contextPath;
752            this.renderContext =  this.options.renderContext;
753            if(this.jsonModel.logConfigString) {
754                _.extend(this.jsonModel, this.parse(this.jsonModel.logConfigString));
755            }
756            _.each(this.jsonModel.category, function(category) {
757                that.LOG_COUNT.category[category] = 0;
758            })
759        },
760
761        /**
762         * parses a log config string of the form <0,1,2,3>-<category string><level integer>-<category string><level integer>..
763         * and returns an a config object that logger uses. The function is a private and not to be called outside
764         * this function
765         *
766         * category can not contain numbers and only valid characters are a-zA-Z
767         * level can be any integer.
768         *
769         * category string is converted into actual category for the logger by using default categoryAcronyms
770         * [a : xfa, b: xfaView, c: xfaPerf} and the categoryAcronyms passed to the options while instantiating the
771         * object. If not found in both the acronyms then the value category string is used as actual category
772         *
773         * For example for the input string 1-a9-b9-c9 return object is
774         * {on: true, category: [xfa,xfaView, xfaPerf], level: [9, 9, 9], type: console}
775         *
776         * For the input string 1-a9-b9-c9-d9-e11 with options.categoryAcronyms {a:a, d:AF} return object is
777         * {on: true, category: [xfa,xfaView, xfaPerf, AF, e], level: [9, 9, 9, 9, 11], type: console}
778         */
779        parse : function(configString) {
780            var arr = configString.split("-"),
781                logType = _.first(arr),
782                logConfig = _.rest(arr),
783                res = {
784                    on: logType === "0" ? "false": "true",
785                    category: [],
786                    level:[],
787                    type:loggerTypes[parseInt(logType)]
788                };
789           _.each(logConfig, function(item, index) {
790                var config = item.match(/^([A-Za-z]+)(\d+)$/),
791                    category;
792                if (config && config.length === 3) {
793                    category = this.getOrElse(categoryAcronyms, config[1],
794                                    this.getOrElse(this.jsonModel, "categoryAcronyms." + config[1], config[1]));
795                    res.category.push(category);
796                    res.level.push(parseInt(config[2]));
797                } else {
798                    //calling this because logger is not initialized as of now
799                    this.consoleHandler(this.resolveMessage(xfalib.locale.LogMessages["ALC-FRM-901-020"],
800                                                    [item, configString]))
801                }
802            }, this);
803            return res;
804        },
805
806        /*
807         *
808         */
809        resolveMessage : function(message, snippets) {
810            snippets = snippets || [];
811            return message.replace(/{(\d+)}/g, function(match, number) {
812                return typeof snippets[number] != 'undefined'
813                    ? snippets[number]
814                    : match
815                    ;
816            });
817        },
818
819        /**
820         * Writes a message to the console.
821         * @private
822         * @param {Number} level The log level
823         * @param {String} message The log message
824         * @param {String/String[]} snippets (optional) The texts replacing
825         *        <code>{n}</code>
826         * @return The log message
827         * @type String
828         */
829        log : function(category, level, message, snippets) {
830            var d= new Date();
831            var day = d.getDate();
832            var month = d.getMonth() + 1;
833            var year = d.getFullYear();
834            var mili = d.getMilliseconds();
835            var sec = d.getSeconds();
836            var min = d.getMinutes();
837            var hour = d.getHours();
838            var date = day + "." + month + "." + year +" " + hour + ":" + min + ":" + sec + ":" + mili;
839            if(this.jsonModel && this.jsonModel.category) {
840                for(var i = 0; i<this.jsonModel.category.length; i++) {
841                    if (level != 0 && this.jsonModel.level[i] >= level && this.jsonModel.category[i] == category && this.jsonModel.on == "true") {
842
843                        var resolvedMessage = message;
844                        if(snippets){
845                            //resolve message with snippet
846                            resolvedMessage = this.resolveMessage(message, snippets);
847                        }
848
849                        var text = "";
850                        text += date ;
851                        text += " *" + this.logLevelNames[level] + "*";
852                        text += " [" +  category + "]" ;
853                        text += "  " + resolvedMessage + "\r\n" ;
854                        this.logMessages += text ;
855                        if(this.jsonModel.type == "console" || this.jsonModel.type == "consoleServer" ) {
856                            ++this.LOG_COUNT.category[category || 'Unknown'];
857                            ++this.LOG_COUNT.level[this.logLevelNames[parseInt(level) < 8? level:7]];
858                            this.consoleHandler(text, level);
859                        }
860                    }
861                }
862            }
863        },
864
865        consoleHandler : function(text, level){
866            if(typeof console != "undefined") {
867                var levelName = typeof this.logLevelNames[level] === "string"
868                    ? this.logLevelNames[level].toLowerCase()
869                    : "log",
870                    logFunction = console.log;
871                if (typeof console[levelName] === "function") {
872                    logFunction = console[levelName]
873                }
874                logFunction.call(console, "\n\n\n" + text);
875                //Error log already shows the call stack for debugging.
876                if(levelName !== "error") {
877                    try {
878                        n.test
879                    } catch (exception) {
880                        if (exception.stack) {
881                            logFunction.call(console, exception.stack.replace("ReferenceError: n is not defined", ""));
882                        }
883                    }
884                }
885            }
886
887        },
888
889        /*
890         *  Helper function to ger submit service proxy url
891         */
892        _getLogServiceProxyUrl: function() {
893            var logServiceProxyUrl = "";
894            if(this.logServiceProxy)
895                logServiceProxyUrl += this.logServiceProxy;
896            else //finally hard code it
897                logServiceProxyUrl += ((this.contextPath && this.contextPath != "/") ? this.contextPath : "") + "/content/xfaforms/profiles/default.log.html";
898            return logServiceProxyUrl;
899        },
900
901        _invokeAtServer: function(options) {
902            var localSubmitUrl =  this._getLogServiceProxyUrl();
903            var params = {
904                    async: true,
905                    url: localSubmitUrl,
906                    type: 'POST',
907                    contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
908                    data: options
909                };
910            $.ajax(params);
911        },
912
913        isServerLoggingEnabled : function(){
914            if((this.jsonModel.on == "true") && (this.jsonModel.type == "server" || this.jsonModel.type == "consoleServer"))
915                return true;
916            else
917                return false;
918        },
919
920        serverHandler :function() {
921            var options = {'logMessages' : this.logMessages, 'renderContext' : this.renderContext};
922            this._invokeAtServer(options);
923            this.logMessages = "" ;
924        },
925
926        /**
927         * Writes a message to the console if log level is set to
928         * {@link #FATAL} or higher.
929         * @static
930         * @param {String} message The log message
931         * @param {String/String[]} snippets (optional) The texts replacing
932         *        <code>{n}</code>
933         */
934        fatal : function(category, message, snippets) {
935            this.log(category, this.FATAL, message, snippets);
936        },
937
938        /**
939         * Writes a message to the console if log level is set to
940         * {@link #ERROR} or higher.
941         * @static
942         * @param {String} message The log message
943         * @param {String/String[]} snippets (optional) The texts replacing
944         *        <code>{n}</code>
945         */
946        error : function(category, message, snippets) {
947            this.log(category, this.ERROR, message, snippets);
948        },
949
950        /**
951         * Writes a message to the console if log level is set to
952         * {@link #WARN} or higher.
953         * @static
954         * @param {String} message The log message
955         * @param {String/String[]} snippets (optional) The texts replacing
956         *        <code>{n}</code>
957         */
958        warn : function(category, message, snippets) {
959            this.log(category, this.WARN, message, snippets);
960        },
961
962        /**
963         * Writes a message to the console if log level is set to
964         * {@link #INFO} or higher.
965         * @static
966         * @param {String} message The log message
967         * @param {String/String[]} snippets (optional) The texts replacing
968         *        <code>{n}</code>
969         */
970        info : function(category, message, snippets) {
971            this.log(category, this.INFO, message, snippets);
972        },
973
974        /**
975         * Writes a message to the console if log level is set to
976         * {@link #DEBUG} or higher.
977         * @static
978         * @param {String} message The log message
979         * @param {String/String[]} snippets (optional) The texts replacing
980         *        <code>{n}</code>
981         */
982        debug : function(category, message, snippets) {
983            this.log(category, this.DEBUG, message, snippets);
984        },
985
986        /**
987         * Writes a message to the console if log level is set to
988         * {@link #TRACE} or higher.
989         * @static
990         * @param {String} message The log message
991         * @param {String/String[]} snippets (optional) The texts replacing
992         *        <code>{n}</code>
993         */
994        trace :  function(category, message, snippets) {
995            this.log(category, this.TRACE, message, snippets);
996        },
997
998        isLogEnabled : function(category, level) {
999            if(this.jsonModel.on == "true") {
1000                var pos = this.jsonModel.category.indexOf(category) ;
1001                if(this.jsonModel.level[pos] >= level)
1002                    return true;
1003            }
1004            return false;
1005        }
1006
1007    });
1008})(_, xfalib, $);
1009/**
1010 * @package xfalib.ut.EventClass
1011 * @import xfalib.ut.Class
1012 */
1013(function(_, xfalib){
1014    // Regular expression used to split event strings
1015    // Regular expression used to split event strings
1016    var eventSplitter = /\s+/;
1017
1018    // A module that can be mixed in to *any object* in order to provide it with
1019    // custom events. You may bind with `on` or remove with `off` callback functions
1020    // to an event; trigger`-ing an event fires all callbacks in succession.
1021    //
1022    var EventClass = xfalib.ut.EventClass =  xfalib.ut.Class.extend({
1023
1024        // Bind one or more space separated events, `events`, to a `listener`
1025        // object. The object should implement `handleEvent` function which will be
1026        // called on event dispatch
1027        on: function(event, listener, context) {
1028
1029            var calls, list,retVal = true;
1030            var fnCallback = _.isFunction(listener) ? listener : null;
1031            if (!listener || (!listener["handleEvent"] && !fnCallback)) return false;
1032
1033            calls = this._callbacks || (this._callbacks = {});
1034
1035            list = calls[event] || (calls[event] = []);
1036            if(fnCallback){
1037                context = context || this;
1038                var found = _.find(list, function(callback){
1039                    return (callback.fn == fnCallback && callback.context == context);
1040                }, this);
1041                if(found)
1042                    return false;
1043                else {
1044                    list.push({"fn" : fnCallback, "context": context});
1045                }
1046            }
1047            else{
1048                if(~list.indexOf(listener))
1049                    return false;
1050                else
1051                    list.push(listener);
1052            }
1053
1054            return  true;
1055        },
1056
1057        // Remove one or many callbacks. If `listener` is null, removes all listener for the
1058        // event. If `events` is null, removes all bound callbacks for all events.
1059        off: function(events, listener, context) {
1060            var event, calls, node;
1061
1062            // No events, or removing *all* events.
1063            if (!(calls = this._callbacks)) return;
1064            if (!(events || listener)) {
1065                delete this._callbacks;
1066                return this;
1067            }
1068
1069            var fnCallback = _.isFunction(listener) ? listener : null;
1070            // Loop through the listed events and contexts and remove the required ones.
1071            events = events ? events.split(eventSplitter) : _.keys(calls);
1072            while (event = events.shift()) {
1073                node = calls[event];
1074                calls[event] = _.filter(calls[event],function(elem) {
1075                    if(typeof(listener) !== "undefined"){
1076                        if(fnCallback && elem.fn == fnCallback && elem.context == context)
1077                            return false;
1078                        else if(!fnCallback && listener === elem)
1079                            return false;
1080                    }
1081                    else{
1082                        return false;
1083                    }
1084                    return true;
1085                });
1086                if(!calls[event].length)
1087                    delete calls[event];
1088            }
1089
1090            return this;
1091        },
1092
1093        // Trigger one or many events, firing all bound callbacks. Callbacks are
1094        // passed the same arguments as `trigger` except the first
1095        trigger: function(events) {
1096            var event, calls, rest;
1097            if (!(calls = this._callbacks)) return this;
1098            events = events.split(eventSplitter);
1099            var payLoad = _.rest(arguments);
1100            while (event = events.shift()) {
1101                _.each(calls[event],function(callback) {
1102                    if(callback.fn && callback.context){
1103                        callback.fn.apply(callback.context, payLoad);
1104                    }
1105                    else if (_.isFunction(callback.handleEvent)){
1106                        callback.handleEvent.apply(callback, payLoad);
1107                    }
1108                });
1109            }
1110
1111            return this;
1112        }
1113
1114    });
1115
1116
1117})(_, xfalib);
1118
1119
1120(function (_, $, xfalib) {
1121    var XfaUtil = xfalib.ut.XfaUtil = function () {
1122        },
1123        registeredLocaleProperties = null,
1124        timeoutListenerAttached = false,
1125        timeouts = [],
1126        attachClearTimeoutListener = function (timeout) {
1127            timeouts.push(timeout);
1128            if (timeoutListenerAttached === false) {
1129                $(window).one("destroy.xfa", function () {
1130                    _.each(timeouts, function (_timeout) {
1131                        clearTimeout(_timeout);
1132                    });
1133                    timeouts = [];
1134                    timeoutListenerAttached = false;
1135                });
1136                timeoutListenerAttached = true;
1137            }
1138        };
1139    _.extend(XfaUtil.prototype, {
1140        _globalUniqueId: (new Date()).getTime(),
1141        logger: null,
1142
1143        formScaleFactor: 1,      // used to appropriately scale the form when contained inside an iframe
1144
1145        getOrElse: xfalib.ut.Class.prototype.getOrElse,
1146        //map of event names between XTG and Mobile Form
1147        //Mobile Form uses different names for some the event and let's fix those names before sending them to XTG.
1148        _xtgEventName: {
1149            "$formready": "ready",
1150            "$layoutready": "ready"
1151        },
1152
1153        generateUID: function () {
1154            return "UID" + (++XfaUtil.prototype._globalUniqueId);
1155        },
1156
1157        matchJsonType: function (jsonModel, _class) {   //TODO: handle getOrElse
1158            return (jsonModel && _class && XfaUtil.prototype.getOrElse(jsonModel._class, "").toLowerCase() == ("" + _class).toLowerCase());
1159        },
1160
1161        $data: function (elem, name, data) {
1162            if (!$.data(elem, "_xfaInitialized")) {
1163                //Initialized data- attributes parse for once using this call.
1164                // Next onward don't use this. Instead use $.data which is cheap/
1165                $(elem).data();
1166                $.data(elem, "_xfaInitialized", true); //Mark the element to say that data has been initialized.
1167            }
1168            return $.data(elem, name, data);
1169        },
1170
1171        /*
1172         * alternative to jQuery.css which sets style properties directly through element.style. This is much faster then
1173         * corresponding jQuery.css alternative.
1174         *
1175         * Warning: this only supports standard css property names and does not do any pre-processing of name and value.
1176         * So calling this, make sure the style names are compatible.
1177         */
1178        $css: function (elem, stylesObj) {
1179            // Exclude the following css properties to add px. copied from jquery.cssNumber to add hyphenated style names
1180            var cssNumber = {
1181                "fillOpacity": true,
1182                "fill-opacity": true,
1183                "fontWeight": true,
1184                "font-weight": true,
1185                "lineHeight": true,
1186                "line-height": true,
1187                "zIndex": true,
1188                "z-index": true,
1189                "opacity": true,
1190                "orphans": true,
1191                "widows": true,
1192                "zoom": true
1193            };
1194
1195            for (var prop in stylesObj) {
1196                var value = stylesObj[prop];
1197                // If a number was passed in, add 'px' to the (except for certain CSS properties)
1198                if (_.isNumber(value) && !cssNumber[ prop ]) {
1199                    value += "px";
1200                }
1201                elem.style[prop] = value;
1202            }
1203        },
1204
1205        isTableHF: function (iChildNode) {
1206            //model can be a Node object or simply a json
1207            var assistJson = _.find(iChildNode.children, function (jChild) {
1208                return jChild._class == "assist";
1209            }, this);
1210            var childRole = (assistJson || {}).role;
1211            if (childRole == "TH" || childRole == "TF")
1212                return true;
1213            else
1214                return false;
1215        },
1216
1217        getUiOneOfChildTag: function (uiParent) {
1218            var uiEl = _.find(uiParent.children, function (child) {
1219                return child._class == "ui";
1220            });
1221            if (!uiEl)
1222                return undefined;
1223            var uiOneOfChildMap = xfalib.runtime.xfa._templateSchema._getOneOfChild("ui");
1224            var uiOneOfChild = _.find(uiEl.children, function (child) {
1225                return uiOneOfChildMap[child._class] == true;
1226            });
1227            if (!uiOneOfChild)
1228                return undefined;
1229            return uiOneOfChild._class;
1230        },
1231
1232        //TODO: this should be removed. One of the worst function.
1233        dIndexOf: function (searchArray, item2Find) {
1234            var ind = -1;
1235            _.find(searchArray, function (item, index) {
1236                return item == item2Find && (ind = index)
1237            });
1238            return ind;
1239        },
1240
1241        splitStringByWidth: function (value, width, refEl) {
1242            var i = value.length , expectedWidth;
1243            do {
1244                expectedWidth = xfalib.view.util.TextMetrics.measureExtent(value.slice(0, i), {"refEl": refEl, maxWidth: -1}).width;
1245                i--;
1246            } while (expectedWidth > width)
1247            if (i != value.length - 1)
1248                return value.slice(0, i + 1);
1249            return value;
1250        },
1251
1252        isRepeatabeEl: function (elTag) {
1253            if (elTag == "subform" || elTag == "subformSet")
1254                return true;
1255            else
1256                return false;
1257        },
1258
1259        /**
1260         * @function
1261         * stripOrCall(toStrip, diffFunc, fArgs)
1262         * @description
1263         * common utility function to handle final submission payload stripping
1264         * @param {bool} toStrip : flag to signify whether to optimize jsonModelDiff size, by stripping off unnecessary properties
1265         * @param {function} diffFunc : callback func. call in case submit is not on
1266         * @param {Array} fArgs : arguments to be passed to the diff func.
1267         * @returns {object} object containing the jsonDiff
1268         */
1269        // should ALWAYS be called with a flag signifying if a submission is in progress,
1270        // and a callback function to compute the json to be sent back during submission, usually an apt '_computeJsonDiff'
1271        stripOrCall: function (toStrip, diffFunc, fArgs) {
1272            if (toStrip) {
1273                return {
1274                    "changed": false,
1275                    "jsonDifference": {}
1276                };
1277            }
1278            else if (_.isFunction(diffFunc)) {
1279                return diffFunc.apply(this, fArgs);
1280            }
1281        },
1282
1283        /**
1284         * @function
1285         * partialStripOrCall(stripLvl, diffFunc, fArgs)
1286         * @description
1287         * common utility function to handle final submission payload stripping or for output of getFormState.
1288         * @param {int} diff_level : flag to signify whether to optimize jsonModelDiff size, by stripping off unnecessary properties
1289         *                        must be 0,1, or 2, as with "diff_level" param of _computeJsonDiff.
1290         * @param {function} diffFunc : callback func. call in case submit is not on
1291         * @returns {object}
1291 object containing the jsonDiff
1292         */
1293        partialStripOrCall: function (diff_level, diffFunc) {
1294            var diffObj = diffFunc.call(this, diff_level);
1295
1296            if (!diffObj.changed) {
1297                if(diff_level === 1) {
1298                    diffObj = {
1299                        "changed": true,
1300                        "jsonDifference": {
1301                            "_class": this.jsonModel._class,
1302                            "name": this.jsonModel.name
1303                        }
1304                    };
1305                } else {
1306                    diffObj.jsonDifference = {};  // don't need stuff for other cases
1307                }
1308            }
1309
1310            return diffObj;
1311        },
1312
1313        /**
1314         * @function
1315         * stripObject(obj, exceptionNames)
1316         * @description
1317         * Utility function to strip unnecessary properties from an object
1318         * @param {object} obj : the object to strip
1319         * @param {Array} exceptionNames : array holding names of important properties to preserve
1320         * @returns {boolean} : true if this obj, or any of it's descendant is returned un-stripped
1321         */
1322        stripObject: function (obj, exceptionNames) {
1323            if (_.isEmpty(obj) || !_.isObject(obj)) {
1324                return true;
1325            } else {
1326                var dontStrip = false;
1327                _.each(_.keys(obj), function (propName) {
1328                    var keepProp = false;
1329                    if (!_.contains(exceptionNames, propName)) {
1330                        if (_.isArray(obj[propName])) {
1331                            _.each(obj[propName], function (arrElem) {
1332                                var isUnStripped = XfaUtil.prototype.stripObject(arrElem, exceptionNames);
1333                                keepProp = keepProp || isUnStripped;
1334                            });
1335                        } else if (_.isObject(obj[propName])) {
1336                            keepProp = XfaUtil.prototype.stripObject(obj[propName], exceptionNames);
1337                        }
1338
1339                        if (!keepProp) {
1340                            delete obj[propName];
1341                        } else {
1342                            dontStrip = true;
1343                        }
1344                    } else {
1345                        dontStrip = true;
1346                    }
1347                });
1348                return dontStrip;
1349            }
1350        },
1351
1352        computeDomJsonDiff: function (domNode, diff_level) {
1353            var changed = true;
1354            if (domNode.hasOwnProperty("_modelChanged")) {
1355                changed = domNode._modelChanged;
1356            }
1357            var jsonDiff = {};
1358            if (changed) {
1359                this.copyObject(domNode.jsonModel, jsonDiff, {"exceptions": ["children", "{default}", "extras"]});
1360            } else {
1361                jsonDiff = {_class: domNode.className};
1362            }
1363            if (!changed && domNode.jsonModel.hasOwnProperty("name")) {
1364                jsonDiff.name = domNode.jsonModel.name;
1365            }
1366            if (domNode.name === "FS_EXTRAS" && diff_level === 3) {
1367                domNode._childModified = true;
1368            }
1369            return {
1370                "changed": changed,
1371                jsonDifference: jsonDiff
1372            };
1373        },
1374
1375        getLogger: function () {
1376            return XfaUtil.prototype.logger || XfaUtil.prototype.getOrElse(xfalib, "runtime.xfa.Logger", null);
1377        },
1378
1379        getErrorManager: function () {
1380            return XfaUtil.prototype.getOrElse(xfalib, "runtime.xfa.ErrorManager", null);
1381        },
1382
1383        XFA_CLICK_EVENT: "xfaclick",
1384        XFA_EXIT_EVENT: "xfaexit",
1385        XFA_ENTER_EVENT: "xfaenter",
1386        XFA_CHANGE_EVENT: "xfachange",
1387        XFA_PREOPEN_EVENT: "xfapreopen",
1388
1389        btwn: function (val, a, b) {
1390            return val > a && val < b;
1391        },
1392
1393        // function to detect if Browser is chrome / safari (webkit)
1394        isWebkit: function () {
1395            return  !!$.browser.webkit || /webkit/.test(navigator.userAgent.toLowerCase()) || !!window.chrome || !!$.browser.chrome || /chrom(e|ium)/.test(navigator.userAgent.toLowerCase()) || !!$.browser.safari || !!window.webkitURL ||
1396                ( /safari/.test(navigator.userAgent.toLowerCase()) &&
1397                    /apple computer/.test(navigator.vendor.toLowerCase()) );
1398
1399            // TODO : find a better way to do this as $.browser is deprecated and
1400            // userAgent may be spoofed
1401        },
1402
1403        clearTimeoutOnDestroy: function (timeout) {
1404            attachClearTimeoutListener(timeout);
1405        },
1406
1407        // function to detect if Browser is  safari
1408        isSafari: function () {
1409            return ( /safari/.test(navigator.userAgent.toLowerCase()) &&
1410                    /apple computer/.test(navigator.vendor.toLowerCase()) );
1411        },
1412
1413        getLocaleStrings: function () {
1414            return xfalib.locale.Strings;
1415        },
1416
1417        getLogMessages: function () {
1418            return xfalib.locale.LogMessages;
1419        },
1420
1421        /*
1422         * This function should not be added in the prototype of any Object
1423         * as in the case of other functions
1424         */
1425        registerLocaleProperties: function (props) {
1426            registeredLocaleProperties = props;
1427        },
1428
1429        /*
1430         * This function should not be added in the prototype of any Object
1431         * as in the case of other functions
1432         */
1433        getDefaultLocaleProperty: function (property) {
1434            var localeProps = registeredLocaleProperties || this.getOrElse(xfalib, "script.Xfa._defaultLocale", null);
1435            return this.getOrElse(localeProps, property, null);
1436        },
1437
1438        /**
1439         * Encodes <script> and </script> with &lt;script&gt; and &lt;/script&gt;
1440         * Does same with img, video and audio tags also.
1441         * These tags are being removed since scripts can be run through
1442         * <img onerror="script" /> (same for audio and video).
1443         */
1444        encodeScriptableTags: function (str) {
1445            var index;
1446            if (_.isString(str)) {
1447                return str.replace(/<(\/?)(script[^<>]*)>/gi, '&lt;$1$2&gt;')
1448                    .replace(/<(\/?)(img[^<>]*)>/gi, '&lt;$1$2&gt;')
1449                    .replace(/<(\/?)(video[^<>]*)>/gi, '&lt;$1$2&gt;')
1450                    .replace(/<(\/?)(audio[^<>]*)>/gi, '&lt;$1$2&gt;')
1451            }
1452        },
1453
1454        /**
1455         *
1456         * @param id : a string representing an HTML element id.
1457         *
1458         * return after applying an escaping '\' before each # . : [ ]
1459         */
1460        jqId: function(id) {
1461            return "#" + id.replace(/(#|:|\.|\[|\])/g, "\\$1");
1462        },
1463
1464        _triggerOnBridge: function (eventName, target, property, oldVal, newVal) {
1465            var evnt = xfalib.script.XfaModelEvent.createEvent(eventName, target,
1466                property, oldVal, newVal);
1467            if(formBridge){
1468                window.formBridge.trigger(eventName, evnt);
1469            }
1470        },
1471
1472        /*
1473         * pads the passed in String str by pre-pending padChars to convert it to a string of given width.
1474         * If string length is already greater that equal to given width, original string is returned.
1475         */
1476        padString : function (str, width, padChar) {
1477            padChar = padChar || '0';
1478            str = str + '';
1479            return str.length >= width ? str : new Array(width - str.length + 1).join(padChar) + str;
1480        },
1481
1482        /**
1483         * returns true if the browser is IE otherwise false
1484         * @returns {boolean}
1485         */
1486        isIE: function () {
1487            return $.browser.msie || (navigator.appName === "Netscape" && navigator.userAgent.match(/Trident\//))
1488        },
1489
1490        /**
1491         * returns false if other browser
1492         * if ie tries to return browser version (non falsy)
1493         * @returns {*}
1494         */
1495
1496        detectIE: function () {
1497            // 1st try jq
1498            if($.browser.msie) {
1499                if($.browser.version && parseInt($.browser.version, 10)) {
1500                    return parseInt($.browser.version, 10);
1501                }
1502            }
1503
1504            var ua = window.navigator.userAgent;
1505
1506            // IE 10
1507            // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
1508
1509            // IE 11
1510            // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';
1511
1512            // IE 12 / Spartan
1513            // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';
1514
1515            // Edge (IE 12+)
1516            // ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
1517
1518            var msie = ua.indexOf('MSIE ');
1519            if (msie > 0) {
1520                // IE 10 or older => return version number
1521                return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
1522            }
1523
1524            var trident = ua.indexOf('Trident/');
1525            if (trident > 0) {
1526                // IE 11 => return version number
1527                var rv = ua.indexOf('rv:');
1528                return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
1529            }
1530
1531            var edge = ua.indexOf('Edge/');
1532            if (edge > 0) {
1533                // Edge (IE 12+) => return version number
1534                return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
1535            }
1536
1537            // other browser
1538            return false;
1539        },
1540        /**
1541         * returns true if the browser is chrome otherwise false
1542         * @returns {boolean}
1543         */
1544        detectChrome : function () {
1545            return (!!window.chrome || !!$.browser.chrome || /chrom(e|ium)/.test(navigator.userAgent.toLowerCase()));
1546        },
1547
1548        /**
1549        * @param {String} val: value to be verified
1550        * @returns {boolean}
1551        * returns true if the provided string contains DOM element
1552        */
1553        isHTML: function(val) {
1554            //check whether string contains tags, so that $val does not contain result of the val used as selector
1555            // eg: val = "a" will return result for $(val) which is not required
1556            if(val && /<[a-z][\s\S]*>/.test(val)) {
1557                try {
1558                    var $val = $(val);
1559                    return $val.length > 0;
1560                } catch (exception) {
1561                    // if jquery throws exception that means string is not a proper HTML
1562                    return false;
1563                }
1564            } else {
1565                return false;
1566            }
1567        },
1568
1569        /**
1570         * returns true if passed key is non printable, false otherwise.
1571         * @param {String} key event.key property of a Keyboard event
1572         */
1573        isNonPrintableKey : function (key) {
1574            return (key   // In IE, event.key returns words instead of actual characters for some keys.
1575               && !_.contains(['MozPrintableKey','Divide','Multiply','Subtract','Add','Enter','Decimal','Spacebar','Del'],key)
1576               && key.length != 1 )
1577        },
1578
1579        /**
1580        * returns true for ipad
1581        * @returns {boolean}
1582        */
1583        _isIpad : function () {
1584            return navigator.userAgent.match(/iPad/i) != null;
1585        },
1586
1587        /**
1588        * returns true if the subform is table or having role table else false
1589        * @param {Object} view
1590        */
1591        _tableCheckForAccessibility : function (view) {
1592            var assist = view.model.getElement("assist", 0, true);
1593            return this.getOrElse(view, "layoutModel.layout", null) == xfalib.view.LayoutConst.LAYOUT_TABLE
1594                || this.getOrElse(assist, "role", null) == "Table";
1595        },
1596
1597        /**
1598        * returns value of tooltip to be assigned as title based on values provided in accessibility
1599        * @param {Object} model
1600        * @returns toolTipText
1601        */
1602        _getToolTipText : function (model) {
1603            var assist = model.getElement("assist", 0, true),
1604                toolTipText = "";
1605            // going against xfa spec, on hover show tooltip or speak text or element name, don't show caption as it's already visible
1606            // assist priority doesn't matter, but selecting none will disable tooltip on hover
1607            if (this.getOrElse(assist, "speak.disable", 0) != 1) { // loose compare str
1607ing value
1608                toolTipText = this.getOrElse(assist, "toolTip.value", "") ||
1609                    this.getOrElse(assist, "speak.value", "")   ||
1610                    this.getOrElse(model, "jsonModel.name", "");
1611            }
1612            return toolTipText;
1613        },
1614
1615        /**
1616        * returns value of mandatory message
1617        * @param {Object} model
1618        * @returns mandatoryMessage
1619        */
1620        _getMandatoryMessage : function (model) {
1621            var defaultMessage = model._defaults.validate.message.defaultMessage,
1622                msg = this.getOrElse(model, "validate.message.nullTest", defaultMessage);
1623            return (msg && msg.value) ? msg.value : defaultMessage.value;
1624        },
1625        /**
1626        * returns boolean based on val1, val2, checkEqual
1627        * For comparing date, use date object
1628        */
1629        _compareVal : function (val1, val2, checkEqual) {
1630            if(!val1 || !val2) {
1631                return false;
1632            }
1633
1634            if(checkEqual) {
1635                return val1 >= val2;
1636            } else {
1637                return val1 > val2;
1638            }
1639        }
1640    });
1641
1642    //Special handling for IE.
1643    if ($.browser.msie || $.browser.mozilla) {
1644        XfaUtil.prototype.$css = function (elem, stylesObj) {
1645            $(elem).css(stylesObj);
1646        }
1647    }
1648})(_, $, xfalib);
1649/*************************************************************************
1650 *
1651 * ADOBE CONFIDENTIAL
1652 * ___________________
1653 *
1654 *  Copyright 2013 Adobe Systems Incorporated
1655 *  All Rights Reserved.
1656 *
1657 * NOTICE:  All information contained herein is, and remains
1658 * the property of Adobe Systems Incorporated and its suppliers,
1659 * if any.  The intellectual and technical concepts contained
1660 * herein are proprietary to Adobe Systems Incorporated and its
1661 * suppliers and are protected by trade secret or copyright law.
1662 * Dissemination of this information or reproduction of this material
1663 * is strictly forbidden unless prior written permission is obtained
1664 * from Adobe Systems Incorporated.
1665 **************************************************************************/
1666
1667
1668
1669(function (_, $, xfalib) {
1670    xfalib.ut.Utilities = {
1671
1672        isIE11: function () {
1673            return !!navigator.userAgent.match(/Trident.*rv\:11\./);
1674        },
1675
1676        checkMinMozillaVersion: function (version) {
1677            return (!this.isIE11() && $.browser.mozilla && parseInt($.browser.version) >= version);
1678        },
1679
1680        getObjectFromKeyValueStringList: function (list) {
1681            var key, value, object = {}, tempArray;
1682            _.each(list, function (keyValuePair, index) {
1683                tempArray = keyValuePair.split("=");
1684                if (tempArray && tempArray.length > 1) {
1685                    object[tempArray[0]] = tempArray[1];
1686                }
1687            });
1688            return object;
1689        },
1690
1691        _getNameWithoutMarker: function (fileName) {
1692            var markerIndex = fileName.indexOf("__afAttachment__");
1693            if (markerIndex !== -1) {
1694                fileName = fileName.substring(markerIndex + "__afAttachment__".length, fileName.length);
1695            }
1696            return fileName;
1697        },
1698
1699        /*
1700         * This is to check support of multiple files selection in one add new dialog
1701         */
1702        _isDataContainerSupported : function () {
1703            try {
1704                var dataContainer = new DataTransfer() || (new ClipboardEvent("")).clipboardData;
1705                if (dataContainer && dataContainer.items) {
1706                    return true;
1707                }
1708            } catch(err) {
1709                // if err comes then dataContainer is not supported
1710            }
1711            return false;
1712        }
1713    };
1714})(_, $, xfalib);
1715/**
1716 * @package xfalib.ut.Scanner
1717 * @fileOverview helper class to scan over a string.
1718 * @version 0.0.1
1719 */
1720
1721/**
1722 * @constructor
1723 * @param Object {jsonModel:{_str: String}}
1724 */
1725
1726(function(_,xfalib){
1727    var Scanner = xfalib.ut.Scanner = xfalib.ut.Class.extend({
1728
1729        initialize: function() {
1730            this._pos = 0;
1731        },
1732
1733        isEOF : function(){
1734            return (this.jsonModel._str.length <= this._pos);
1735        },
1736
1737        peek : function(){
1738            return (this.isEOF()) ? null : this.jsonModel._str.charAt(this._pos);
1739        },
1740
1741        optionalConsumeChar : function(aChar){
1742            if(this.jsonModel._str.charAt(this._pos) == aChar){
1743                this._pos++;
1744                return aChar;
1745            }else{
1746                return null;
1747            }
1748        },
1749
1750        /**
1751         * Gets next char ignore quoted string.
1752         *    |
1753         *   abc returns c.
1754         *     |
1755         *   abc'de'f returns f.
1756         * @param aChar
1757         */
1758        getNCharIQS : function(){
1759            this._pos++;
1760            if(this.jsonModel._str.length <= this._pos){
1761                var current = this.jsonModel._str.charAt(this._pos);
1762                if(current != '\''){
1763                    return current;
1764                }else{
1765                    if(moveNextExpectedChar('\'')){
1766                        return this.jsonModel._str.charAt(this._pos);
1767                    }
1768                }
1769            }
1770            return null;
1771        },
1772
1773        moveNextExpectedChar : function(aChar){
1774            this._pos++;// currently point to '
1775            while(this._pos< this.jsonModel._str.length && this.jsonModel._str.charAt(this._pos) != aChar){
1776                this._pos++;
1777            }
1778            return this._pos < this.jsonModel._str.length;
1779        },
1780
1781        readInteger : function(len){
1782            if(this.pos+len >this.jsonModel._str.length){
1783                return null;
1784            }
1785            var integer = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._str,this._pos,len);
1786            this._pos+=len;
1787            return integer;
1788        }
1789    });
1790
1791    Scanner.lookupNext = function(pat, patPos, filter){
1792        var patLen = pat.length;
1793        if(patPos >= patLen){
1794            return null;
1795        }
1796
1797        var token = {};
1798        token.startPos = patPos;
1799
1800        var firstChar = pat.charAt(patPos);
1801        var patValid = false;
1802        //
1803        if (firstChar == '\''){
1804            for (var i = patPos+1; i < patLen;i++ ){
1805                var chr = pat.charAt(i);
1806                if(chr =='\''){
1807                    token.type=1;
1808                    token.len = i - patPos + 1;
1809                    patValid = true;
1810                    break;
1811                }
1812            }
1813
1814        }else if( ('a' <= firstChar && firstChar <= 'z' || 'A' <= firstChar && firstChar <= 'Z') || filter.call(null, firstChar)){
1815            var endPos = patLen;//end is exclusive
1816            for (var i = 1; patPos+i < patLen;i++ ){
1817                if(pat.charAt(patPos+i)!=firstChar){
1818                    endPos = patPos+i;
1819                    break;
1820                }
1821            }
1822            token.type=2;
1823            token.len = endPos - patPos;
1824            token.patChar = firstChar;
1825            token.patPos = patPos;
1826            patValid = true;
1827        }else{
1828            if (firstChar == '?' || firstChar == '+' || firstChar == '*') {
1829                token.type=3;
1830                token.len = 1;
1831            }else{
1832                token.type=4;
1833                token.len = 1;
1834            }
1835            patValid = true;
1836        }
1837        if(patValid){
1838            return token;
1839        }else{
1840            throw "Picture is invalid.";
1841        }
1842    }
1843})(_,xfalib);
1844
1845
1846/**
1847 * @package xfalib.ut.PictureFmt
1848 * @fileOverview The file defines methods to parse and format data
1849 * according to XFA picture patterns.
1850 * @version 0.0.1
1851 */
1852(function(_,xfalib) {
1853
1854    var PictureFmt = xfalib.ut.PictureFmt = function() {};
1855    PictureFmt.DatePicturePattern =  /^date(?:\([a-zA-Z]*_[a-zA-Z]*\))?\{([\w\W]*?)\}$/;
1856    PictureFmt.TimePicturePattern =  /^time(?:\([a-zA-Z]*_[a-zA-Z]*\))?\{([\w\W]*?)\}$/;
1857    PictureFmt.TextPicturePattern =  /^text\{([\w\W]*?)\}$/;
1858    PictureFmt.NumPicturePattern =  /^num\{([\w\W]*?)\}$/;
1859
1860    /**
1861     * Parses a given data source according to the given picture.
1862     * @param sSource {string}
1863     * @param sPicture {string}
1864     * @param sLocale {string}
1865     * @returns {object}
1866     */
1867    PictureFmt.parse  = function(sSource, sPicture,sLocale){
1868        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
1869
1870        var match = PictureFmt.DatePicturePattern.exec(sPicture);
1871        if(match && match[1]){
1872            return PictureEngine.parseDate(sSource, match[1]);
1873        }
1874        match = PictureFmt.TimePicturePattern.exec(sPicture);
1875        if(match && match[1]){
1876            return PictureEngine.parseTime(sSource, match[1]);
1877        }
1878        match = PictureFmt.TextPicturePattern.exec(sPicture);
1879        if(match && match[1]){
1880            return PictureEngine.parseText(sSource, match[1]);
1881        }
1882        match = PictureFmt.NumPicturePattern.exec(sPicture);
1883        if(match && match[1]){
1884            return PictureEngine.parseNumeric(sSource, match[1]);
1885        }
1886        throw "Invalid picture clause "+sPicture;
1887    };
1888
1889    /**
1890     * Formats a given data source according to the given picture.
1891     * @param date {object}
1892     * @param sPicture {string}
1893     * @param sLocale {string}
1894     * @returns {string}
1895     */
1896    PictureFmt.format  = function(sSource, sPicture, sLocale,bRelaxed,bFormatNumberFromasDefaultPC){
1897        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
1898
1899        var match = PictureFmt.DatePicturePattern.exec(sPicture);
1900        if(match && match[1]){
1901            return PictureEngine.formatDate(sSource, match[1]);
1902        }
1903        match = PictureFmt.TimePicturePattern.exec(sPicture);
1904        if(match && match[1]){
1905            return PictureEngine.formatTime(sSource, match[1]);
1906        }
1907        match = PictureFmt.TextPicturePattern.exec(sPicture);
1908        if(match && match[1]){
1909            return PictureEngine.formatText(sSource, match[1],bRelaxed);
1910        }
1911        match = PictureFmt.NumPicturePattern.exec(sPicture);
1912        if(match && match[1]){
1913            return PictureEngine.formatNumeric(sSource, match[1],sLocale,bRelaxed,bFormatNumberFromasDefaultPC);
1914        }
1915            throw "Invalid picture clause "+sPicture;
1916    };
1917
1918    /**
1919     * Checks if a given data source is formatted according to the given picture.
1920     * @param date {object}
1921     * @param sPicture {string}
1922     * @param sLocale {string}
1923     * @returns {boolean}
1924     */
1925    PictureFmt.formatTest = function (sSource, sPicture, sLocale, bRelaxed, bFormatNumberFromasDefaultPC) {
1926        var formattedData;
1927        try {
1928            formattedData = PictureFmt.format(sSource, sPicture, sLocale, bRelaxed, bFormatNumberFromasDefaultPC);
1929        }catch(e) {
1930            return false;
1931        }
1932
1933        if(!_.isString(formattedData)) {
1934            return false;
1935        } else {
1936            var parsedData;
1937            try {
1938                parsedData = PictureFmt.parse(formattedData, sPicture, sLocale);
1939            } catch (e) {
1940                return false;
1941            }
1942            if(!_.isString(parsedData) && parsedData !== formattedData) {
1943                return false;
1944            }
1945        }
1946        return true;
1947    };
1948
1949    /**
1950     * Parses a given data source according to the given date picture
1951     * under the given sLocale.
1952     * @param sSource {string}
1953     * @param sPicture {string}
1954     * @param sLocale {string}
1955     * @returns {string}
1956     */
1957    PictureFmt.parseDate  = function(sSource, sPicture,sLocale){
1958        var picRegexp = PictureFmt.DatePicturePattern;
1959        var match = picRegexp.exec(sPicture);
1960        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
1961        if(match && match[1]){
1962            return PictureEngine.parseDate(sSource, match[1]);
1963        }else{
1964            return PictureEngine.parseDate(sSource, sPicture);
1965        }
1966    };
1967
1968
1969    /**
1970     * Formats a given data source according to the given date picture
1971     * * under the given sLocale.
1972     * @param date {string}
1973     * @param sPicture {string}
1974     * @param sLocale {string}
1975     * @returns {string}
1976     */
1977    PictureFmt.formatDate  = function(date, sPicture, sLocale){
1978        var picRegexp =  PictureFmt.DatePicturePattern;
1979        var match = picRegexp.exec(sPicture);
1980        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
1981        if(match && match[1]){
1982            return PictureEngine.formatDate(date, match[1]);
1983        }else{
1984            return PictureEngine.formatDate(date, sPicture);
1985        }
1986    };
1987
1988    /**
1989     * Parses a given data source according to the given date picture
1990     * under the given sLocale.
1991     * @param sSource {string}
1992     * @param sPicture {string}
1993     * @param sLocale {string}
1994     * @returns {date}
1995     */
1996    PictureFmt.parseTime  = function(sSource, sPicture,sLocale){
1997        var picRegexp = PictureFmt.TimePicturePattern;
1998        var match = picRegexp.exec(sPicture);
1999        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2000        if(match && match[1]){
2001            return PictureEngine.parseTime(sSource, match[1]);
2002        }else{
2003            return PictureEngine.parseTime(sSource, sPicture);
2004        }
2005        return null;
2006    };
2007
2008
2009    /**
2010     * Formats a given data source according to the given date picture
2011     * * under the given sLocale.
2012     * @param date {string}
2013     * @param sPicture {string}
2014     * @param sLocale {string}
2015     * @returns {string}
2016     */
2017    PictureFmt.formatTime  = function(date, sPicture, sLocale){
2018        var picRegexp =  PictureFmt.TimePicturePattern;
2019        var match = picRegexp.exec(sPicture);
2020        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2021        if(match && match[1]){
2022            return PictureEngine.formatTime(date, match[1]);
2023        }else{
2024            return PictureEngine.formatTime(date, sPicture);
2025        }
2026    };
2027
2028    /**
2029     * Parses a given data source according to the given text picture
2030     * under the given sLocale.
2031     * @param sSource {string}
2032     * @param sPicture {string}
2033     * @param sLocale {string}
2034     * @returns {string}
2035     */
2036    PictureFmt.parseText  = function(sSource, sPicture,sLocale){
2037        var picRegexp = PictureFmt.TextPicturePattern;
2038        var match = picRegexp.exec(sPicture);
2039        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2040        if(match && match[1]){
2041            return PictureEngine.parseText(sSource, match[1]);
2042        }else{
2043            return PictureEngine.parseText(sSource, sPicture);
2044        }
2045    };
2046
2047    /**
2048     * Formats a given data source according to the given text picture
2049     *  under the given sLocale.
2050     * @param sSource {string}
2051     * @param sPicture {string}
2052     * @param sLocale {string}
2053     * @returns {string}
2054     */
2055    PictureFmt.formatText  = function(sSource, sPicture, sLocale,bRelaxed){
2056        var picRegexp =  PictureFmt.TextPicturePattern;
2057        var match = picRegexp.exec(sPicture);
2058        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2059        if(match && match[1]){
2060            return PictureEngine.formatText(sSource, match[1],bRelaxed);
2061        }else{
2062            return PictureEngine.formatText(sSource, sPicture,bRelaxed);
2063        }
2064        return null;
2065    };
2066
2067    /**
2068     * Parses a given data source according to the given numeric picture
2069     * under the given sLocale.
2070     * @param sSource {string}
2071     * @param sPicture {string}
2072     * @param sLocale {string}
2073     * @returns {string}
2074     */
2075    PictureFmt.parseNumeric  = function(sSource, sPicture,sLocale){
2076        var picRegexp = PictureFmt.NumPicturePattern;
2077        var match = picRegexp.exec(sPicture);
2078        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2079        if(match && match[1]){
2080            return PictureEngine.parseNumeric(sSource, match[1]);
2081        }else{
2082            return PictureEngine.parseNumeric(sSource, sPicture);
2083        }
2084        return null;
2085    };
2086
2087    /**
2088     * Formats a given data source according to the given numeric picture
2089     *  under the given sLocale.
2090     * @param sSource {string}
2091     * @param sPicture {string}
2092     * @param sLocale {string}
2093     * @returns {string}
2094     */
2095    PictureFmt.formatNumeric  = function(sSource, sPicture, sLocale){
2096        var picRegexp =  PictureFmt.NumPicturePattern;
2097        var match = picRegexp.exec(sPicture);
2098        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2099        if(match && match[1]){
2100            return PictureEngine.formatNumeric(sSource, match[1]);
2101        }else{
2102            return PictureEngine.formatNumeric(sSource, sPicture);
2103        }
2104    };
2105
2106
2107
2108
2109    /**
2110     * Parses a given data source according to the given datetime picture
2111     * under the given sLocale.
2112     * @param sSource {string}
2113     *            the source data.
2114     * @param sPicture {string}
2115     *            the datetime picture.
2116     * @param sDateMask {string}
2117     *            the date sub-picture.
2118     * @param sTimeMask {string}
2119     *            the time sub-picture.
2120     * @param sLocale
2121     *            the locale name.
2122     *
2123     */
2124    PictureFmt.parseDateTime  = function(sSource, sPicture, sDateMask, sTimeMask, sLocale){
2125
2126    };
2127    /**
2128     * Formats a given data source according to the given datetime picture
2129     * under the given locale.
2130     *
2131     * @param sSource {string}
2132     *            the source data.
2133     * @param sPicture {string}
2134     *            the datetime picture.
2135     * @param sDateMask {string}
2136     *            the date sub-picture.
2137     * @param sTimeMask {string}
2138     *            the time sub-picture.
2139     * @param sLocale {string}
2140     *            the locale name.
2141     */
2142    PictureFmt.formatDateTime  = function(sSource, sPicture, sDateMask, sTimeMask, sLocale){
2143
2144    };
2145
2146})(_,xfalib);
2147/**
2148 * @package xfalib.ut.PictureUtils
2149 * @fileOverview The file defines static utilities methods.
2150 * @version 0.0.1
2151 */
2152
2153(function(_,xfalib){
2154    var PictureUtils = xfalib.ut.PictureUtils = function() {}
2155
2156    PictureUtils.padding = function(number, digits, isFw, zero){
2157        var leading = ["0","00","000","0000"];
2158        var numStr = leading[digits-1] + number;
2159        return numStr.slice(- digits);
2160    };
2161
2162    PictureUtils.parseIntAggressive = function(dateString, startPos,len){
2163        var result = new Object();
2164        var parsedNum = 0; //The number value parsed from dateString
2165        var parsedLen = -1; //How many chars parsed according to this pattern;
2166        for(var idx=0; idx<len && (startPos + idx) < dateString.length; idx++){
2167            var chr = dateString.charAt(startPos + idx);
2168            if(chr >='0' && chr <='9'){
2169                parsedNum = parsedNum *10 + (chr- '0');
2170            }else{
2171                parsedLen = idx;
2172                break;
2173            }
2174        }
2175        if(parsedLen == -1) {
2176            parsedLen = len;
2177        }
2178        result.value = parsedNum;
2179        result.len = parsedLen;
2180        return result;
2181    };
2182
2183    PictureUtils.parseIntExact = function(dateString, startPos,len){
2184        var result = 0;
2185        PictureUtils.assert(startPos+ len <= dateString.length, "mismatch");
2186        for(var idx=0; idx<len ; idx++){
2187            var chr = dateString.charAt(startPos + idx);
2188            if(chr >='0' && chr <='9'){
2189                result = result *10 + (chr- '0');
2190            }else{
2191                throw "unexpected currentChar in PictureUtils.parseInt";
2192            }
2193        }
2194        return result;
2195    };
2196
2197    PictureUtils.isDigit = function(chr){
2198        return /[0-9]/.test(chr) ;
2199    };
2200
2201    PictureUtils.inString = function(chr,aString){
2202        return (aString.indexOf(chr) >=0) ;
2203    };
2204
2205
2206    var regExpIsLetter = /[\u0041-\u005a\u0061-\u007a\u00aa-\u00aa\u00b5-\u00b5\u00ba-\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u0236\u0250-\u02
2206c1\u02c6-\u02d1\u02e0-\u02e4\u02ee-\u02ee\u037a-\u037a\u0386-\u0386\u0388-\u038a\u038c-\u038c\u038e-\u03a1\u03a3-\u03ce\u03d0-\u03f5\u03f7-\u03fb\u0400-\u0481\u048a-\u04ce\u04d0-\u04f5\u04f8-\u04f9\u0500-\u050f\u0531-\u0556\u0559-\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0621-\u063a\u0640-\u064a\u066e-\u066f\u0671-\u06d3\u06d5-\u06d5\u06e5-\u06e6\u06ee-\u06ef\u06fa-\u06fc\u06ff-\u06ff\u0710-\u0710\u0712-\u072f\u074d-\u074f\u0780-\u07a5\u07b1-\u07b1\u0904-\u0939\u093d-\u093d\u0950-\u0950\u0958-\u0961\u0985-\u098c\u098f-\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2-\u09b2\u09b6-\u09b9\u09bd-\u09bd\u09dc-\u09dd\u09df-\u09e1\u09f0-\u09f1\u0a05-\u0a0a\u0a0f-\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32-\u0a33\u0a35-\u0a36\u0a38-\u0a39\u0a59-\u0a5c\u0a5e-\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2-\u0ab3\u0ab5-\u0ab9\u0abd-\u0abd\u0ad0-\u0ad0\u0ae0-\u0ae1\u0b05-\u0b0c\u0b0f-\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32-\u0b33\u0b35-\u0b39\u0b3d-\u0b3d\u0b5c-\u0b5d\u0b5f-\u0b61\u0b71-\u0b71\u0b83-\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99-\u0b9a\u0b9c-\u0b9c\u0b9e-\u0b9f\u0ba3-\u0ba4\u0ba8-\u0baa\u0bae-\u0bb5\u0bb7-\u0bb9\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c60-\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cbd\u0cde-\u0cde\u0ce0-\u0ce1\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d28\u0d2a-\u0d39\u0d60-\u0d61\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd-\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32-\u0e33\u0e40-\u0e46\u0e81-\u0e82\u0e84-\u0e84\u0e87-\u0e88\u0e8a-\u0e8a\u0e8d-\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5-\u0ea5\u0ea7-\u0ea7\u0eaa-\u0eab\u0ead-\u0eb0\u0eb2-\u0eb3\u0ebd-\u0ebd\u0ec0-\u0ec4\u0ec6-\u0ec6\u0edc-\u0edd\u0f00-\u0f00\u0f40-\u0f47\u0f49-\u0f6a\u0f88-\u0f8b\u1000-\u1021\u1023-\u1027\u1029-\u102a\u1050-\u1055\u10a0-\u10c5\u10d0-\u10f8\u1100-\u1159\u115f-\u11a2\u11a8-\u11f9\u1200-\u1206\u1208-\u1246\u1248-\u1248\u124a-\u124d\u1250-\u1256\u1258-\u1258\u125a-\u125d\u1260-\u1286\u1288-\u1288\u128a-\u128d\u1290-\u12ae\u12b0-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0-\u12c0\u12c2-\u12c5\u12c8-\u12ce\u12d0-\u12d6\u12d8-\u12ee\u12f0-\u130e\u1310-\u1310\u1312-\u1315\u1318-\u131e\u1320-\u1346\u1348-\u135a\u13a0-\u13f4\u1401-\u166c\u166f-\u1676\u1681-\u169a\u16a0-\u16ea\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7-\u17d7\u17dc-\u17dc\u1820-\u1877\u1880-\u18a8\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1d00-\u1d6b\u1e00-\u1e9b\u1ea0-\u1ef9\u1f00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59-\u1f59\u1f5b-\u1f5b\u1f5d-\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe-\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071-\u2071\u207f-\u207f\u2102-\u2102\u2107-\u2107\u210a-\u2113\u2115-\u2115\u2119-\u211d\u2124-\u2124\u2126-\u2126\u2128-\u2128\u212a-\u212d\u212f-\u2131\u2133-\u2139\u213d-\u213f\u2145-\u2149\u3005-\u3006\u3031-\u3035\u303b-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312c\u3131-\u318e\u31a0-\u31b7\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fa5\ua000-\ua48c\uac00-\ud7a3\uf900-\ufa2d\ufa30-\ufa6a\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e-\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]/
2207
2208    /**
2209     * TODO Implement method equivalent to Character.isLetter.
2210     */
2211    PictureUtils.isLetter = function(chr){
2212        return regExpIsLetter.test(chr);
2213    };
2214
2215    PictureUtils.isLetterOrDigit = function(chr){
2216        return this.isLetter(chr) || this.isDigit(chr);
2217    };
2218
2219    /**
2220     * Scan this string for the first character in the given set. Similar to
2221     * strcspn().
2222     *
2223     * @param src{String}
2224     *            the string to scan
2225     * @param sSkip{String}
2226     *            the characters to scan for
2227     * @param nOffset{number}
2228     *            the position where to start the scan. Default = 0.
2229     * @return The position, relative to nOffset, for the first character found
2230     *         in the given set
2231     */
2232    PictureUtils.skipUntil = function(srcStr, sSkip, nOffset) {
2233        var nCharsSkipped = nOffset;
2234
2235        // starting at the offset position, scan the characters in this string
2236        // until it matches one of the characters in the given set.
2237        while (nCharsSkipped < srcStr.length) {
2238            var i = nCharsSkipped;
2239            if (sSkip.indexOf(srcStr.charAt(i++)) >= 0)
2240                break;
2241            nCharsSkipped = i;
2242        }
2243
2244        return nCharsSkipped - nOffset;
2245    };
2246
2247    PictureUtils.matchString = function(str, startPos, target){
2248        if(startPos + target.length > str.length){
2249            return false;
2250        }else{
2251            for(var idx = 0; idx<target.length; idx++){
2252                if(target.charAt(idx) != str.charAt(startPos + idx)) return false;
2253            }
2254            return true;
2255        }
2256    };
2257
2258    PictureUtils.assert = function(condition, message){
2259        if(!condition){
2260            throw message;
2261        }
2262    };
2263
2264    PictureUtils.getLocaleObject = function(locale,property) {
2265        if(locale !== null && xfalib.runtime.xfa) {
2266            return xfalib.runtime.xfa._getLocaleSymbols(locale, property);
2267        } else {
2268            return xfalib.ut.XfaUtil.prototype.getDefaultLocaleProperty(property)
2269        }
2270    }
2271
2272    PictureUtils.getHashOfLocaleObject = function(locale,property) {
2273          if(!PictureUtils.getHashOfLocaleObject[locale+"_"+property]) {
2274              var hashObj = {};
2275              _.each(PictureUtils.getLocaleObject(locale,property), function(val) {
2276                  var sVal = (val+"").toLowerCase();
2277                  var hash = 0;
2278                  for(var i =0;i<sVal.length;i++) {
2279                      hash+=(i+1)*sVal.charCodeAt(i)
2280                  }
2281                  hashObj[hash] = hashObj[hash] || [];
2282                  hashObj[hash].push(sVal);
2283              })
2284              PictureUtils.getHashOfLocaleObject[locale+"_"+property] = hashObj;
2285          }
2286          return PictureUtils.getHashOfLocaleObject[locale+"_"+property]
2287    }
2288
2289    PictureUtils.convertNumberToLocale = function(locale,number) {
2290        var zero = PictureUtils.getLocaleObject(locale,"numberSymbols.zero");
2291        var zeroCode = zero.charCodeAt(0);
2292        number += "";
2293        var newNumber = [];
2294        for(var i = 0;i < number.length;i++) {
2295            newNumber.push(String.fromCharCode(zeroCode + parseInt(number.charAt(i))));
2296        }
2297        return newNumber.join("");
2298    }
2299
2300    PictureUtils.parsePictureClause = function (clause){
2301        if(clause === null || clause === undefined) {
2302            return [];
2303        }
2304        var insidePattern = false,
2305            insideQuote=false,
2306            insideLocale = false,
2307            locale = "",
2308            type = "",
2309            pattern = "",
2310            flag = false,
2311            currentChar = "",
2312            result = [],
2313            matchType = /^num$|^text$|^date$/,
2314            matchLocale = /^[a-zA-Z]*_[a-zA-Z]*$/,
2315            i = 0,
2316            bracketOpenCount = 0;
2317        for(;i<clause.length;i++) {
2318            currentChar = clause.charAt(i);
2319            if(insideQuote && currentChar !== "'") {
2320                pattern += currentChar;
2321                continue;
2322            }
2323            switch(currentChar) {
2324               case "'":
2325                   if(!insidePattern) {
2326                       // ' is not allowed except insidePattern
2327                       return null;
2328                   }
2329                   insideQuote = !insideQuote;
2330                   pattern += currentChar;
2331                   break;
2332               case "{":
2333                    if(insidePattern || insideLocale || type === "") {
2334                        // { is not allowed insidePattern or insideLocale
2335                        return null;
2336                    }
2337                   insidePattern = true;
2338                    break;
2339                case "}":
2340                    if(!insidePattern || (insideLocale && pattern === "") || type === "") {
2341                        // { is allowed only insidePattern and not insideLocale
2342                        return null;
2343                    } else {
2344                        bracketOpenCount = 0;
2345                        insidePattern = false;
2346                        if(matchType.exec(type) === null) {
2347                            return null;
2348                        }
2349                        if(locale !== "" && matchLocale.exec(locale) === null) {
2350                            return null;
2351                        }
2352                        result.push({
2353                            category: type,
2354                            mask: pattern,
2355                            locale: locale
2356                        })
2357                    }
2358                    break;
2359                case "|":
2360                    if(type === "" || insidePattern || insideLocale) {
2361                        return null;
2362                    } else {
2363                        type = pattern = locale = "";
2364                        insidePattern = insideLocale = false;
2365                    }
2366                    break;
2367                case "(" :
2368                    if(type === "" || bracketOpenCount === 1) {
2369                        // ( is not allowed inside Locale
2370                        return null;
2371                    } else {
2372                        if(!insidePattern) {
2373                            insideLocale = true;
2374                        } else {
2375                            pattern += currentChar;
2376                        }
2377                        bracketOpenCount++;
2378                    }
2379                    break;
2380                case ")" :
2381                    if((!insideLocale && !insidePattern) || bracketOpenCount === 0) {
2382                        return null;
2383                    } else {
2384                        if(insidePattern) {
2385                            pattern += currentChar;
2386                        }
2387                        insideLocale = false;
2388                        bracketOpenCount--;
2389                    }
2390                    break;
2391                default:
2392                    if(insidePattern) {
2393                        pattern += currentChar;
2394                    } else if(insideLocale) {
2395                        locale += currentChar;
2396                    } else if(type !== "" && (pattern !== "" || locale !== "")){
2397                        return null;
2398                    } else {
2399                        type += currentChar;
2400                    }
2401                    break;
2402           }
2403       }
2404       if(insidePattern || insideLocale || insideQuote || bracketOpenCount !== 0) {
2405           return null;
2406       }
2407       return result;
2408    }
2409
2410})(_,xfalib);
2411
2412/**
2413 * @package xfalib.ut.VisitorBase
2414 * @import xfalib.ut.Class
2415 * @fileOverview Base class for visitor
2416 * @version 0.0.1
2417 */
2418
2419/**
2420 * @constructor
2421 * @param Object {jsonModel: {_sPicture: String}}
2422 */
2423
2424(function(_,xfalib) {
2425    var VisitorBase = xfalib.ut.VisitorBase = xfalib.ut.Class.extend({
2426        consume : function(token){
2427            switch (token.type)
2428            {
2429                case 1:
2430                    this.consumeStringLiteral(token);
2431                    break;
2432                case 2:
2433                    this.consumeSubPattern(token);
2434                    break;
2435                case 3:
2436                    this.consumeStringWildCard(token);
2437                    break;
2438                case 4:
2439                    this.consumeCharLiteral(token);
2440                    break;
2441            }
2442        },
2443        acceptPatternChar : function(chr){
2444            return false;
2445        },
2446        getPicture : function(){
2447            return this.jsonModel._sPicture;
2448        },
2449        abstractMethod : function(){
2450            throw "Not implemented";
2451        },
2452        consumeStringWildCard : this.abstractMethod,
2453        consumeStringLiteral: this.abstractMethod,
2454        consumeCharLiteral: this.abstractMethod,
2455        consumeSubPattern: this.abstractMethod,
2456        getResult: this.abstractMethod
2457    });
2458})(_,xfalib);
2459
2460/**
2461 * @package xfalib.ut.NumPictureDesc
2462 * @import xfalib.ut.Class
2463 * @fileOverview Pre-process Numeric Picture.
2464 * @version 0.0.1
2465 */
2466
2467/**
2468 * @constructor
2469 * @param Object {jsonModel: {_sPicture: String}}
2470 */
2471
2472(function(_,xfalib){
2473    var NumPictureDesc = xfalib.ut.NumPictureDesc = xfalib.ut.Class.extend({
2474
2475        initialize: function() {
2476            this.hasRadix = false;
2477            this.hasExpon = false;
2478            this.hasSign = false;
2479            this.hasPercent = false;
2480            this.fracDigit = 0;
2481            this.intDigit = 0;
2482
2483            this._mbLeftParenSeen = false;
2484            this._mbRightParenSeen = false;
2485            this._compactPattern();
2486            this._xlatePattern();
2487            NumPictureDesc._super.initialize.call(this);
2488        },
2489        
2490        getPicture : function(){
2491            return this.jsonModel._sPicture;
2492        },
2493
2494        _match2Char : function (char1, char2, idx){
2495            if(idx+1 < this.jsonModel._sPicture.length){
2496                return (this.jsonModel._sPicture.charAt(idx) ==char1 && this.jsonModel._sPicture.charAt(idx+1) ==char2);
2497            }else{
2498                return false;
2499            }
2500        },
2501
2502        _xlatePattern : function(){
2503            var patPos = 0;
2504            for(var token = xfalib.ut.Scanner.lookupNext(this.jsonModel._sPicture, patPos, this._acceptPatternChar); token != null;  ){
2505                this._consume(token);
2506                patPos = patPos + token.len;
2507                token = xfalib.ut.Scanner.lookupNext(this.jsonModel._sPicture, patPos, this._acceptPatternChar);
2508            }
2509        },
2510        
2511        _compactPattern : function(){
2512            var buf = new Array();
2513            for(var index =0, len = this.jsonModel._sPicture.length; index <len; index++){
2514                if(this._match2Char('D','B',index)){
2515                    buf.push('D');
2516                    index++;
2517                }else if(this._match2Char('d','b',index)){
2518                    buf.push('d');
2519                    index++;
2520                }else if(this._match2Char('C','R',index)){
2521                    buf.push('C');
2522                    index++;
2523                }else if(this._match2Char('c','r',index)){
2524                    buf.push('c');
2525                    index++;
2526                }else{
2527                    buf.push(this.jsonModel._sPicture.charAt(index));
2528                }
2529            }
2530            this.jsonModel._sPicture = buf.join("");
2531        },
2532
2533        _acceptPatternChar : function(chr){
2534            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
2535        },
2536
2537        _consume : function(token){
2538            if(token.type == 2){
2539                this._subConsume(token.patChar, token.len);
2540            }// else not a pattern
2541        },
2542
2543        _subConsume : function(chr, chrCnt){
2544            switch (chr) {
2545                case'E' :
2546                    if (chrCnt > 1 || this.hasExpon || (this.fracDigit + this.intDigit)==0)
2547                        throw "Illegal Numeric Picture: more than one Expon";
2548                    this.hasExpon = true;
2549                    break;
2550                case '(':
2551                    if (chrCnt > 1 || this._mbLeftParenSeen	|| this.fracDigit + this.intDigit >0 )
2552                        throw "Illegal Numeric Picture:  ()";
2553                    this._mbLeftParenSeen = true;
2554                    break;
2555
2556                case ')':
2557                    if (chrCnt > 1 || ! this._mbLeftParenSeen || this._mbRightParenSeen)
2558                        throw "Illegal Numeric Picture:  ()";
2559                    this._mbRightParenSeen = true;
2560                    if(this.fracDigit + this.intDigit >0) this.hasSign = true;
2561                    break;
2562                case 'S':
2563                case 's':
2564                case 'C': //CR
2565                case 'c': //cr
2566                case 'D': //DB
2567                case 'd': //db
2568                    this.hasSign = true;
2569                    break;
2570                case '%' :
2571                    this.hasPercent = true;
2572                    break;
2573                case '.':
2574                case 'V':
2575                case 'v':
2576                    if (chrCnt > 1 || this.hasRadix)
2577                        throw "Illegal Numeric Picture: too many vV.";
2578                    this.hasRadix = true;
2579                    this._mbFracStartSeen = true;
2580                    break;
2581                case '8' :
2582                case '9' :
2583                case 'Z':
2584                case 'z':
2585                    if (this.hasRadix){
2586                        this.fracDigit += chrCnt;
2587                    } else{
2588                        this.intDigit += chrCnt;
2589                    }
2590                    break;
2591            }
2592        },
2593
2594        parseNumberInfo : function(msText){
2595            var text=msText,
2596                num = Number(text),
2597                negative = false
2598            if(num < 0){
2599                negative = true;
2600                num = -num;
2601                text = text.replace("-","");
2602            }
2603            if(this.hasPercent){
2604                num *= 100;
2605                text = ""+num;
2606            }
2607            var shift = 0;
2608            if(this.hasExpon){
2609                var threshold = Math.pow(10,this.intDigit);
2610                if(num < threshold){
2611                    while(num*10 < threshold) {
2612                        num *= 10;
2613                        shift--;
2614                    }
2615                }else{
2616                    while(num > threshold){
2617                        num /= 10;
2618                        shift++;
2619                    }
2620                }
2621                text = num+"";
2622            }
2623            var radixPos = text.indexOf(".", 0),
2624                fractionDigit = radixPos<0 ? 0 : text.length - radixPos - 1
2625
2626            if(this.fracDigit < fractionDigit) {
2627                num = num.toFixed(this.fracDigit);
2628                text = num +""
2629            }
2630
2631            if(text.indexOf("0") == 0 && msText.indexOf("0") != 0) {
2632                text = text.substring(1);
2633            }
2634
2635            radixPos = text.indexOf(".", 0)
2636            var integerDigit = radixPos < 0 ? text.length : radixPos,
2637                offset = this.intDigit - integerDigit
2638
2639            if(offset <0 ){
2640                throw "Exit: most significant " + offset +" digit lost";
2641            }
2642            return {
2643                "integerDigit" : integerDigit,
2644                "radixPos" : radixPos ,
2645                "fractionDigit" :  radixPos<0 ? 0 : text.length - radixPos - 1,
2646                "msText" : text,
2647                "shift" : shift,
2648                "isNegative" : negative,
2649                "padding" :offset
2650            };
2651        }
2652    });
2653
2654    NumPictureDesc.gsDB = "DB";
2655    NumPictureDesc.gsCR = "CR";
2656    NumPictureDesc.gsE = "E";
2657    NumPictureDesc.gsDSP = "  ";
2658    NumPictureDesc.gsSSP = " ";
2659
2660})(_,xfalib);
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672    /**
2673 * @package xfalib.ut.TimeInfo
2674 * @import xfalib.ut.Class
2675 * @fileOverview A wrapper class for date related information.
2676 * @version 0.0.1
2677 */
2678
2679/**
2680 * @constructor
2681 */
2682(function(_,xfalib){
2683    var TimeInfo = xfalib.ut.TimeInfo = xfalib.ut.Class.extend({
2684
2685        initialize: function() {
2686            this.mHourOfMeriDiem = -1;
2687            this.mHourOfDay = -1;
2688            this.mMinuteOfHour = -1;
2689            this.mSecondOfMinute = -1;
2690            this.mThousandthOfSecond = -1;
2691        },
2692
2693        getISOTime : function(){
2694            var timeStr = "";
2695            if(this.mThousandthOfSecond>0){
2696                timeStr = "-" + this.formatNum(this.mThousandthOfSecond,3);
2697            }
2698            if(this.mSecondOfMinute>0 || timeStr!=""){
2699                timeStr = this.formatNum(this.mSecondOfMinute,2)+timeStr;
2700                timeStr = ":"+timeStr;
2701            }
2702            if(this.mMinuteOfHour>0 || timeStr!=""){
2703                timeStr = this.formatNum(this.mMinuteOfHour,2)+timeStr;
2704                timeStr = ":"+timeStr;
2705            }
2706            timeStr = this.formatNum(this.mHourOfDay,2) + timeStr;
2707
2708            return timeStr;
2709        },
2710
2711        formatNum : function(num, digits){
2712            if(num<0){
2713                num = 0;
2714            }
2715            return xfalib.ut.PictureUtils.padding(num, digits);
2716        },
2717
2718        getDate : function(){
2719            var date = new Date();
2720            this.setTime(date);
2721            return date;
2722        },
2723
2724        setTime : function(date){
2725            date.setHours(this.mHourOfDay);
2726            date.setMinutes(this.mMinuteOfHour);
2727            date.setSeconds(this.mSecondOfMinute);
2728            date.setMilliseconds(this.mThousandthOfSecond);
2729        }
2730    });
2731
2732    /**
2733     *
2734     * <p>Valid ISO8601/XFA time strings are in any one
2735     * of the following time patterns:
2736     * <ul>
2737     * <li> HH[MM[SS[.FFF][z]]]
2738     * <li> HH[MM[SS[.FFF][+HH[MM]]]]
2739     * <li> HH[MM[SS[.FFF][-HH[MM]]]]
2740     * <li> HH[:MM[:SS[.FFF][z]]]
2741     * <li> HH[:MM[:SS[.FFF][+HH[:MM]]]]
2742     * <li> HH[:MM[:SS[.FFF][-HH[:MM]]]]
2743     * </ul>
2744     */
2745    TimeInfo.Parse = function(isoDateStr, locale){
2746        var scanner = new xfalib.ut.Scanner({jsonModel:{_str:isoDateStr}});
2747        var hours = scanner.readInteger(2);
2748        var minitues = -1;
2749        if(!scanner.isEOF()){
2750            scanner.optionalConsumeChar(':');
2751            minitues = scanner.readInteger(2);
2752        }
2753        var seconds = -1;
2754        if(!scanner.isEOF()){
2755            scanner.optionalConsumeChar(':');
2756            seconds = scanner.readInteger(2);
2757        }
2758        var milliseconds = -1;
2759        if(!scanner.isEOF()){
2760            scanner.optionalConsumeChar('-');
2761            milliseconds = scanner.readInteger(3);
2762        }
2763        //TODO timezone
2764        var info = new xfalib.ut.TimeInfo();
2765       TimeInfo.setPropertyIfNotNull(info,hours,"mHourOfDay");
2766       TimeInfo.setPropertyIfNotNull(info,minitues,"mMinuteOfHour");
2767       TimeInfo.setPropertyIfNotNull(info,seconds,"mSecondOfMinute");
2768       TimeInfo.setPropertyIfNotNull(info,milliseconds,"mThousandthOfSecond");
2769        return info;
2770    };
2771
2772    /**
2773     *
2774     * static method
2775     */
2776    TimeInfo.setPropertyIfNotNull = function(object, value, proName){
2777        if(value!=null){
2778            var d = Number(value);
2779            if(!isNaN(d)){
2780                object[proName] = d;
2781            }
2782        }
2783    };
2784
2785})(_,xfalib);
2786/**
2787 * @package xfalib.ut.DateInfo
2788 * @import xfalib.ut.Class
2789 * @fileOverview A wrapper class for date related information.
2790 * @version 0.0.1
2791 */
2792
2793/**
2794 * @constructor
2795 */
2796
2797(function(_,xfalib) {
2798    var DateInfo = xfalib.ut.DateInfo = xfalib.ut.Class.extend({
2799
2800        initialize: function(options) {
2801            if (options && !options.isParsingCall ) { // skip setting internal values when called while parsing date formats
2802                this.date = new Date();
2803                this._year = this.date.getFullYear();
2804                this._month = this.date.getMonth() + 1;
2805                this._day = this.date.getDay();
2806            }
2807            DateInfo._super.initialize.call(this);
2808        },
2809
2810        formatNum : function(num, digits){
2811            if(num<0)
2812                num = 0;
2813            return xfalib.ut.PictureUtils.padding(num, digits);
2814        },
2815
2816        getDate : function(){
2817            return this.date;
2818        },
2819        setDate : function() {
2820          this.date = new Date(this._year,this._month-1,this._day)
2821        },
2822        getISODate : function(){
2823            var isoDate = [];
2824
2825            isoDate.push(this.formatNum(this._year, 4));
2826            isoDate.push("-");
2827            isoDate.push(this.formatNum(this._month, 2));
2828            isoDate.push("-");
2829            isoDate.push(this.formatNum(this._day, 2));
2830
2831            return isoDate.join("");
2832        },
2833
2834        year : function(y) {
2835            if(y && y > 0 && y <= 9999)
2836                this._year = y;
2837            else
2838                throw "undefined year";
2839        },
2840
2841        month : function(m) {
2842            if(m && m>0 && m < 13) {
2843               this._month = m;
2844            }
2845            else
2846                throw "Invalid month " + m;
2847        },
2848
2849        _leapYear : function() {
2850            var year = this._year;
2851            return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0);
2852        },
2853
2854        _maxDate : function(m) {
2855              if(this._leapYear() && m == 2)
2856                 return 29;
2857              else return DateInfo.dates[m-1];
2858        },
2859
2860        day : function(d) {
2861            if(d && d > 0 && d <= this._maxDate(this._month || 0))
2862                this._day = d;
2863            else
2864                throw "Invalid Date "+ d + " for the month "+(this._month);
2865        },
2866
2867        validate : function(y, m, d) {
2868                this.year(y);
2869                this.month(m);
2870                this.day(d);
2871        }
2872    });
2873
2874    DateInfo.ParseIsoString = function(isoDateStr, locale){
2875		var isDateRegexp = /^(\d{4})(?:-?(\d{1,2})(?:-?(\d{1,2}))?)?(?:T((\d{2}):(\d{2}):(\d{2}))Z)?$/;
2876        var match = isDateRegexp.exec(isoDateStr);
2877        if(match && match.length >= 4){
2878            var dateInfo = new DateInfo();
2879            var date = new Date(isoDateStr);
2880            // TODO - check if date is invalid.
2881            if(match[4] && date != null) { // if time is available then use date object for conversion otherwise use previous approach to support invalid date like 2012-10-101, 2010-02-29 etc for RTC CQ-4201274
2882                dateInfo.year(date.getFullYear());
2883                dateInfo.month(date.getMonth()+1);
2884                dateInfo.day(date.getDate());
2885            } else {
2886                try {
2887                    dateInfo.year(Number(match[1]));
2888                    dateInfo.month(Number(match[2]));
2889                    dateInfo.day(Number(match[3]));
2890                } catch(e) {
2891                    return null;
2892                }
2893            }
2894            dateInfo.setDate();
2895            return dateInfo;
2896        }
2897        return null;
2898    };
2899
2900    DateInfo.Parse = function(dateStr, locale, validateWithDefaultPatterns){
2901        locale = locale || "en_US";
2902        var patterns = xfalib.ut.PictureUtils.getLocaleObject(locale,"datePatterns"),
2903            isoDate = this.ParseIsoString(dateStr, locale);
2904        if(!_.isEmpty(isoDate)) {
2905            return isoDate;  // in case edit pattern is present, it'll be parsed by the widget during input and return an iso date string.
2906        }
2907        //if edit pattern is present then don't try to match it from default locale patterns.
2908        if(validateWithDefaultPatterns === false){
2909            _.find(patterns, function(pattern) {
2910                try {
2911                    isoDate = xfalib.ut.PictureFmt.parseDate(dateStr,pattern,locale);
2912                    return true;
2913                } catch(exception) {
2914                    return false;
2915                }
2916            });
2917        }
2918        isoDate = isoDate || dateStr;
2919        return DateInfo.ParseIsoString(isoDate);
2920    };
2921
2922    DateInfo.dates = [31,28,31,30,31,30,31,31,30,31,30,31];
2923    DateInfo.daysOfWeek = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
2924})(_,xfalib);
2925/**
2926 * @package xfalib.ut.PictureEngine
2927 * @import xfalib.ut.Scanner
2928 * @fileOverview The file is a facade to assembly all components together.
2929 * @version 0.0.1
2930 */
2931(function(_,xfalib) {
2932
2933    var PictureEngine = xfalib.ut.PictureEngine = xfalib.ut.Class.extend({
2934
2935        _lookupNext: xfalib.ut.Scanner.lookupNext,
2936
2937        MAX_XFA_PREC	: 8,		// Max no. of fractional digits in XFA.
2938        MAX_DBL_DIG	:18,		// Max no. of significant digits in a double.
2939        MAX_INT_DIG	:10,		// Max no. of significant digits in an integer.
2940        MAX_DBL_WIDTH	:15,		// Max width before precision loss in a double.
2941        INTEGRAL_FMT :  0,
2942        DECIMAL_FMT : 1,
2943        CURRENCY_FMT : 2,
2944        PERCENT_FMT : 3,
2945
2946        parseDate : function(sSource, sPicture, locale){
2947            return this._acceptVisitor(new xfalib.ut.DateParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource,_locale:this.jsonModel.locale}}));
2948        },
2949
2950        formatDate : function(dDate, sPicture){
2951            var validateWithDefaultPatterns = typeof sPicture !== 'undefined';
2952            var dateInfo = xfalib.ut.DateInfo.Parse(dDate, this.jsonModel.locale, validateWithDefaultPatterns);
2953            if(dateInfo == null){
2954                return null;
2955            }else{
2956                return this._acceptVisitor(new xfalib.ut.DateFormattingVisitor({jsonModel:{_sPicture:sPicture,_dateInfo:dateInfo,_locale:this.jsonModel.locale}}));
2957            }
2958        },
2959
2960        parseTime : function(sSource, sPicture){
2961            return this._acceptVisitor(new xfalib.ut.TimeParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource}}));
2962        },
2963
2964        formatTime : function(dDate, sPicture){
2965            var timeInfo = xfalib.ut.TimeInfo.Parse(dDate, this.jsonModel.locale);
2966            if(timeInfo == null){
2967                return null;
2968            }else{
2969                return this._acceptVisitor(new xfalib.ut.TimeFormattingVisitor({jsonModel:{_sPicture:sPicture,_timeInfo:timeInfo}}));
2970            }
2971        },
2972
2973        parseText : function(sSource, sPicture){
2974            return this._acceptVisitor(new xfalib.ut.TextParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource}}));
2975        },
2976
2977        formatText : function(sSource, sPicture,bRelaxed){
2978            return this._acceptVisitor(new xfalib.ut.TextFormattingVisitor({jsonModel:{_sPicture:sPicture,_text:sSource,relaxed:bRelaxed}}));
2979        },
2980
2981        parseNumeric : function(sSource, sPicture){
2982            var visitor = new xfalib.ut.NumParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource,_locale:this.jsonModel.locale}}); // TODO : Is locale required
2983            visitor.parse();
2984            return visitor.getResult();
2985        },
2986
2987       formatNumeric : function(sSource, sPicture,locale,bRelaxed,bFormatNumberFromasDefaultPC){
2988
2989             var sFormatPicture =sPicture;
2990             if( bRelaxed && bFormatNumberFromasDefaultPC){
2991                 sFormatPicture = this.getNumberFormat(sPicture,1, {formatOption: "WITH_GROUPINGS",
2992                                      "precision"  : this.getNumberPrecision(sSource),
2993                                    "width"      : sSource.length
2994                                   });
2995             }
2996             return this._acceptVisitor(new xfalib.ut.NumFormattingVisitor({jsonModel:{_sPicture:sFormatPicture,_locale:this.jsonModel.locale},text:sSource}));
2997        },
2998
2999        _acceptVisitor : function(visitor){
3000            this._scanPattern(visitor);
3001            return visitor.getResult();
3002        },
3003
3004        _scanPattern : function(visitor){
3005            var patPos = 0;
3006            var sPicture = visitor.getPicture();
3007            for(var token = this._lookupNext(sPicture, patPos, visitor.acceptPatternChar); token != null;  ){
3008                visitor.consume(token);
3009                patPos = patPos + token.len;
3010                token = this._lookupNext(sPicture, patPos, visitor.acceptPatternChar);
3011            }
3012        },
3013
3014       /**
3015          * Removes n bytes from this string starting at position nOffset.
3016         *
3017          * @param nOffset - start position for the remove
3018          * @param nLength - the number of characters to remove
3019          * @return This string
3020          */
3021
3022         _swallow : function(sString , nOffset, nLenToSwallow)
3023         {
3024             if(_.isEmpty(sString) || nLenToSwallow ==0){
3025                 return sString;
3026             }
3027
3028             if( (nOffset + nLenToSwallow)> sString.length ) {
3029                 nLenToSwallow = (nOffset + nLenToSwallow) - sString.length;
3030             }
3031            var subStr = sString.substr(0,nOffset) + sString.substr(offset + nLenToSwallow);
3032
3033             return subStr
3034         },
3035         /**
3036         * Replace some portion of one string with another String.
3037          * @param sString - the String where it has to be replaced.
3038          * @param sReplacement - the replacement string.
3039          * @param nOffset - start position for the replacement. Default value = 0.
3040          * @param nCutLength - the number of bytes to remove from the
3041          * original string.
3042          */
3043
3044         _replaceAll : function(sString ,sReplacement , nOffset ,nCutlength) {
3045             return sString.substr(0,nOffset) + sReplacement  + sString.substr(nOffset + nCutlength)
3046         },
3047
3048         //----------------------------------------------------------------------
3049         // SkipOver
3050         //
3051         // Scan this string for the first byte of the character not in the given set.
3052         // Similar to strspn().
3053         //----------------------------------------------------------------------
3054         _skipOver : function(fromString,sSkip, nOffset)
3055         {
3056             // starting at the offset position, scan the characters in this string
3057             // until it does not match any of the characters in the given set.
3058            var nCharsSkipped = nOffset;
3059             var i = 0;
3060             while (nCharsSkipped < fromString.length)
3061             {
3062                 i = nCharsSkipped;
3063                 if (sSkip.indexOf(fromString[i]) ==-1) {
3064                     break;
3065                 }
3066                 i++;
3067                 nCharsSkipped = i;
3068             }
3069
3070             return nCharsSkipped - nOffset;
3071         },
3072
3073         /*
3074          * Get the numeric format in the given style.
3075          * @param style in the range of values 0-2,
3076          * where (0 = integral, 1 = decimal, 2 = currency).
3077          * @param option in the set of format options:
3078          */
3079         getNumberFormat : function(format , style, option)
3080        {
3081             if (style < this.INTEGRAL_FMT || this.PERCENT_FMT < style) {
3082                 style = this.DECIMAL_FMT;
3083             }
3084
3085             var sFormat = format;
3086
3087             //
3088             // Use any alternate part because they handle negative values.
3089             //
3090             var  nBar = 0;
3091             if ((nBar = sFormat.indexOf('|')) != -1) {
3092                 sFormat = this._swallow(sFormat, 0, nBar + 1);
3093             }
3094             //
3095             // Determine position of radix (or anything like it)
3096             // and the replicating part of the pattern, i.e., from
3097             // the separator to this radix.
3098            //
3099             var nDot;
3100             if ( (nDot = sFormat.indexOf('.')) == -1) {
3101                 if ((nDot = sFormat.indexOf('v')) == -1) {
3102                     if ((nDot = sFormat.indexOf('V')) == -1) {
3103                         if ((nDot = sFormat.indexOf('E')) == -1) {
3104                             if ((nDot = sFormat.indexOf(' ')) == -1) {
3105                                 if ((nDot = sFormat.indexOf('%')) == -1) {
3106                                     nDot = sFormat.length;
3107                                 }
3108                             }
3109                         }
3110                     }
3111                 }
3112             }
3113             if (nDot) {
3114                 if (this._skipOver(sFormat,"89zZ", nDot - 1) != 1) {
3115                     nDot = sFormat.length;
3116                 }
3117             }
3118             var sZZZ;
3119             var nZed;
3120             if ( (nZed = sFormat.indexOf("z,")) != -1) {
3121                 //
3122                 // Watson 1230768.  Handle locales, like India, that have
3123                 // pictures with more than one grouping symbol.
3124                //
3125                 var nSep = nDot;
3126                 var nComma;
3127                 if ((nComma = sFormat.indexOf(',', nZed + 2)) !=-1) {
3128                    nSep = nComma;
3129                 }
3130                 if (nSep > nZed + 2) {
3131                     sZZZ = Array(nSep - nZed).join('z');
3132                 }
3133                 else {
3134                     sZZZ = Array(1).join('z');
3135                 }
3136             }
3137             else {
3138                nZed = 0;
3139             }
3140             //
3141             // If non-integral styles Then determine width and precision.
3142             //
3143             var nPrec = 0;
3144             var nWidth = this.MAX_INT_DIG;
3145             if (style != this.INTEGRAL_FMT) {
3146                 nPrec = option.precision; // (option >> 8) & 0xff;
3147                 var trim = ((nPrec & 0x80) == 0);
3148                 nPrec &= 0x7f;
3149                 if (nPrec == 0x7f) {
3150                     nPrec = this._skipOver(sFormat, "89zZ", nDot + 1);
3151                 }
3152                 if ((option.width) != undefined) {
3153                     nWidth = option.width;
3154                 }
3155                 else {
3156                     nWidth = this.MAX_DBL_DIG;
3157                 }
3158                 //
3159                 // Fix for Watson 1229423.  If the locale's format contains
3160                 // any sign pictures Then widen accordingly.  Also widen if
3161                 // precision of locale's picture format is greater than requested.
3162                 //
3163                 if (sFormat.indexOf('s')!=-1) {
3164                     nWidth += 1;
3165                 }
3166                 if (sFormat.indexOf('(')!=-1) {
3167                     nWidth += 1;
3168                 }
3169                 if (sFormat.indexOf(')') !=-1) {
3170                     nWidth += 1;
3171                 }
3172                var nFmtPrec = this._skipOver(sFormat,"89zZ", nDot + 1);
3173                 if (0 < nPrec && nPrec < nFmtPrec) {
3174                     nWidth += nFmtPrec - nPrec;
3175                 }
3176
3177                 //
3178                 // Pare down the precision if the width is big enough to yield
3179                 // IEEE 754 64-bit double precision errors, which appears to be
3180                 // anything over 14 significant digits.
3181                 //
3182                 if (trim && nPrec > 0 && nWidth > nPrec) {
3183                     //
3184                     // Fix for Watson 1211481.  If the given precision is less
3185                     // than what the locale's format dictates then widen the given
3186                     // width.
3187                    //
3188                     if (nPrec <= sFormat.length - 1 - nDot) {
3189                         nWidth += sFormat.length - 1 - nDot - nPrec;
3190                     }
3191                     for (var i = nWidth - 1; i > this.MAX_DBL_WIDTH; i--) {
3192                         //
3193                         // Never pare down the precision below what the locale's
3194                         // format dictates.
3195                         //
3196                         if (nPrec <= sFormat.length - 1 - nDot)
3197                            break;
3198                         nPrec--;
3199                     }
3200                 }
3201             }
3202             //Watson 1483675 - If the locale's format contains
3203             // a dollar sign or a space then widen accordingly.
3204             if (style == this.CURRENCY_FMT) {
3205                 if (sFormat.indexOf('$')!=-1) {
3206                     nWidth++;
3207                 }
3208
3209                 if (sFormat.indexOf(' ')!=-1) {
3210                     nWidth += 1;
3211                }
3212             }
3213
3214             //
3215             // If percent style was wanted Then truncate after the percent character.
3216             //
3217             if (style == this.PERCENT_FMT) {
3218                 var nTrim = this._skipOver(sFormat,"89zZ", nDot + 1);
3219                 sFormat = this._replaceAll(sFormat,"",nTrim,0)
3220                 //sFormat.Replace(jfString::EmptyString(), nDot + 1, nTrim);
3221
3222                 //Watson 1483675 - If the locale's format contains
3223                 // a percent sign then widen accordingly.
3224                 if (sFormat.indexOf('%')!=-1) {
3225                     nWidth++;
3226                 }
3227             }
3228             //
3229             // Else if integral style was wanted Then truncate at the radix character.
3230             //
3231             //
3232             // If integral style was wanted Then truncate at the radix character.
3233             //
3234             else if (style == this.INTEGRAL_FMT || nPrec == 0){// && option.formatOption == "WITHOUT_RADIX") {
3235                 var nTrim = this._skipOver(sFormat,"89zZ", nDot + 1);
3236                 sFormat = this._replaceAll(sFormat,"",nDot,nTrim+1);
3237             }
3238             //
3239             // Otherwise for decimal and currency styles Do
3240             // replace fractional 'z' pictures with '8's to requested precision,
3241             //
3242             else if (option.formatOption == "WITH_EIGHTS") {
3243                 var nEight = nDot + 1;
3244                 while ((nEight =sFormat.indexOf('z'))!=-1) {
3245                     this._replaceAll(sFormat, '8', nEight,'8'.length);
3246                 }
3247                 while (sFormat.Length() - nDot <= nPrec) {
3248                     sFormat = this._replaceAll(sFormat, "8", nDot + 1, 0);
3249                 }
3250             }
3251             //
3252             // Or replace fractional '9' pictures with 'z's to requested precision
3253             // Watson 1322850 - add option to keep nines, previously this function
3254             // would force frac. digits to be either z's or 8's with no option for 9's.
3255             //
3256             else if ((option.formatOption) == "WITH_ZEDS" && !((option.formatOption) == "KEEP_NINES")) {
3257                 var nNine = nDot + 1;
3258                 while ((nNine = sFormat.indexOf('9'))!=-1) {
3259                     this._replaceAll(sFormat, 'z', nNine,1);
3260                 }
3261                 while (sFormat.Length() - nDot <= nPrec) {
3262                     this._replaceAll(sFormat, "z", nDot + 1, 0);
3263                 }
3264             }
3265             //
3266             // Replicate section from separator to radix to requested width.
3267             //
3268             if (!sZZZ) {
3269                 sZZZ = "z";
3270             }
3271            else if ((option.formatOption) == "WITHOUT_GROUPINGS" ) {
3272                 //
3273                 // Watson 1230768.  Handle locales, like India, that have
3274                 // pictures with more than one grouping symbol.
3275                 //
3276                 var nComma = nZed + 1 ;
3277                 this._replaceAll(sFormat, 'z' ,nComma,1);
3278                 while ( nComma!= -1 && (nComma < nDot)) {
3279                     nComma = sFormat.indexOf(',');
3280                     sFormat = this._replaceAll(sFormat,'z',nComma,1);
3281                 }
3282             }
3283             else if ((option.formatOption == "WITH_GROUPINGS")) {
3284                 sZZZ = this._replaceAll(sZZZ,',',0,1);
3285                 nWidth += (nWidth + sZZZ.length) / sZZZ.length;
3286             }
3287             while (sFormat.length < nWidth) {
3288                 sFormat = this._replaceAll(sFormat, sZZZ, nZed + 1, 0);
3289             }
3290             return sFormat;
3291         },
3292
3293         /**
3294          * Get the decimal precision of the given numeric string.
3295          * @return the decimal precision or 0 for integral values.
3296          */
3297         getNumberPrecision: function(sVal)
3298         {
3299             var nRadix = 0;
3300             var i = -1;
3301             // Reason for not using the commented line. We are always storing the value in model with . as decimal separator
3302             // Passing field locale/ browser locale would lead to precision width being zero for non-english locales where
3303             // decimal separater may be different.
3304             // var rIndex = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel.locale,"numberSymbols").decimal;
3305             // so hardcoding . for now
3306             var rIndex = ".";
3307             if( (nRadix = sVal.indexOf(rIndex))!=-1)
3308             {
3309                     for(; nRadix <=sVal.length ;nRadix++) {
3310                         i++;
3311                     }
3312
3313                 return i;
3314             }
3315             return 0;
3316          }
3317    })
3318})(_,xfalib);
3319/**
3320 * @package xfalib.ut.FormattingVisitorBase
3321 * @import xfalib.ut.VisitorBase
3322 * @fileOverview Base class for visitor
3323 * @version 0.0.1
3324 */
3325
3326/**
3327 * @constructor
3328 * @param Object {jsonModel: {_sPicture: String]}
3329 */
3330
3331(function(_,xfalib) {
3332    var FormattingVisitorBase = xfalib.ut.FormattingVisitorBase = xfalib.ut.VisitorBase.extend({
3333
3334        initialize: function() {
3335            this._buffer = []; //TODO: ASK Ren where does this _buffer comes from
3336            FormattingVisitorBase._super.initialize.call(this);
3337        },
3338
3339        consumeStringWildCard : function(token){
3340            //'?' '*' '+
3341            this._buffer.push(" ");
3342        },
3343
3344        consumeStringLiteral : function(token){
3345            this._buffer.push(this.jsonModel._sPicture.substr(token.startPos+1,token.len-2));
3346        },
3347
3348        consumeCharLiteral : function(token){
3349            this._buffer.push(""+ this.jsonModel._sPicture.charAt(token.startPos));
3350        }
3351    })
3352
3353})(_,xfalib);
3354/**
3355 * @package xfalib.ut.ParsingVisitorBase
3356 * @import xfalib.ut.VisitorBase
3357 * @fileOverview Base class for visitor
3358 * @version 0.0.1
3359 */
3360
3361/**
3362 * @constructor
3363 * @param Object {jsonModel: {_sPicture: String,_dataString: String}}
3364 */
3365
3366(function(_,xfalib){
3367    var ParsingVisitorBase = xfalib.ut.ParsingVisitorBase = xfalib.ut.VisitorBase.extend({
3368
3369        initialize: function() {
3370            this._strLen = this.jsonModel._dataString.length;
3371            this._strPos = 0;
3372            ParsingVisitorBase._super.initialize.call(this);
3373        },
3374
3375        consumeStringWildCard : function(token){
3376            if (chr == '?') {
3377                if (this._strPos < this._strLen)//&& Character.isDefined(str.charAt(strPos))
3378                    this._strPos += 1;
3379            } else if (chr == '+') {
3380                if (this._strPos >= this._strLen)// || ! Character.isWhitespace(str.charAt(strPos)))
3381                    throw "Mismatch";
3382                this._strPos += 1;
3383                while (this._strPos < this._strLen)// && Character.isWhitespace(str.charAt(strPos)))
3384                    this._strPos += 1;
3385            } else if (chr == '*') {
3386                while (this._strPos < this._strLen)// && Character.isWhitespace(str.charAt(strPos)))
3387                    this._strPos += 1;
3388            }
3389
3390        },
3391
3392        consumeStringLiteral : function(token){
3393            for(var offset=0; offset<token.len-2 ;offset++){ //-2, heading and trailing quote
3394                if(this.jsonModel._sPicture.charAt(token.startPos+offset+1) != this.jsonModel._dataString.charAt(this._strPos+offset)){
3395                    throw ("Mismatch" + this.jsonModel._sPicture.substr(token.startPos, token.len));
3396                }
3397            }
3398            this._strPos += token.len-2;
3399
3400        },
3401
3402        consumeCharLiteral : function(token){
3403            if(this.jsonModel._sPicture.charAt(token.startPos) == this.jsonModel._dataString.charAt(this._strPos)){
3404                this._strPos += 1;
3405            }else{
3406                throw "Mismatch";
3407            }
3408        }
3409    })
3410})(_,xfalib);
3411
3412/**
3413 * @package xfalib.ut.DateFormattingVisitor
3414 * @import xfalib.ut.FormattingVisitorBase
3415 * @fileOverview The file provides formating logic on date pattern characters.
3416 * @version 0.0.1
3417 */
3418
3419
3420/**
3421 * @constructor
3422 * @param object {jsonModel: {_sPicture:String,_dateInfo: xfalib.ut.DateInfo}}
3423 */
3424
3425(function(_,xfalib) {
3426    var PictureUtils =  xfalib.ut.PictureUtils;
3427    var DateFormattingVisitor = xfalib.ut.DateFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3428
3429        consumeSubPattern : function(token){
3430            var chr = token.patChar;
3431            var chrCnt = token.len;
3432
3433            switch (chr) {
3434                case 'D':
3435                    var dayOfMonth=this.jsonModel._dateInfo.date.getDate();
3436                    switch(chrCnt){
3437                        case 1:
3438                            break;
3439                        case 2:
3440                            dayOfMonth = PictureUtils.padding(dayOfMonth,2);
3441                            break;
3442                    }
3443                    this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,dayOfMonth));
3444                    break;
3445                case 'J':
3446
3447                    //this._mDayOfYear;
3448                    break;
3449                case 'M':
3450                    var monthOfYear = this.jsonModel._dateInfo.date.getMonth();
3451                    switch(chrCnt){
3452                        case 1:
3453                            this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,monthOfYear+1));
3454                            break;
3455                        case 2:
3456                            this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,PictureUtils.padding(monthOfYear+1,2)));
3457                            break;
3458                        case 3:
3459                            var monthNames = PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.abbrmonthNames");
3460                            this._buffer.push(monthNames[monthOfYear]);
3461                            break;
3462                        case 4:
3463                            var monthNames = PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.monthNames");
3464                            this._buffer.push(monthNames[monthOfYear]);
3465                            break;
3466                    }
3467
3468                    break;
3469                case 'E':
3470                    var dayOfWeek = this.jsonModel._dateInfo.date.getDay();
3471                    var dayNames;
3472                    switch(chrCnt) {
3473                        case 1:
3474                            this._buffer.push(dayOfWeek);
3475                            break;
3476                        case 3:
3477                            dayNames =  PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.abbrdayNames");
3478                            this._buffer.push(dayNames[dayOfWeek]);
3479                            break;
3480                        case 4:
3481                            dayNames =   PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.dayNames");
3482                            this._buffer.push(dayNames[dayOfWeek]);
3483                            break;
3484                        default:
3485                            throw "unsupported Picture Clause ";
3486                    }
3487                    break;
3488                case 'e':
3489                    break;
3490                case 'G':
3491                    break;
3492                case 'Y':
3493
3494                    var yearOfEra = this.jsonModel._dateInfo.date.getFullYear()
3495                    switch(chrCnt){
3496                        case 2:
3497                            if(yearOfEra>2029 || yearOfEra < 1930){
3498                                throw "unsupported " + yearOfEra + " by pattern YY";
3499                            }
3500                            yearOfEra = PictureUtils.padding(yearOfEra % 100, 2);
3501                            break;
3502                        case 4:
3503                            yearOfEra = PictureUtils.padding(yearOfEra, 4); // 2 digit(0000-9999)
3504                            break;
3505                    }
3506                    this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,yearOfEra));
3507                    break;
3508                case 'w':
3509                    break;
3510                case 'W':
3511                    break;
3512                default: throw "Unsupported pattern";
3513            }
3514
3515        },
3516        /**
3517         *
3518         * @override
3519         */
3520        getResult : function(){
3521            return this._buffer.join("");
3522        }
3523
3524    });
3525})(_,xfalib);
3526
3527
3528/**
3529 * @package xfalib.ut.TextFormattingVisitor
3530 * @import xfalib.ut.FormattingVisitorBase
3531 * @fileOverview Formats a string according to Text Picture.
3532 * @version 0.0.1
3533 */
3534
3535/**
3536 * @constructor
3537 * @param Object { jsonModel:{_sPicture: String, _text: String}}
3538 */
3539(function(_,xfalib){
3540    var TextFormattingVisitor = xfalib.ut.TextFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3541
3542        initialize: function() {
3543            this._textPos = 0;
3544            this._relaxed = typeof this.jsonModel.relaxed === "undefined" ? true: this.jsonModel.relaxed;
3545            TextFormattingVisitor._super.initialize.call(this);
3546        },
3547
3548        consumeSubPattern : function(token){
3549            var chr = token.patChar;
3550            var chrCnt = token.len;
3551            for(var index = 0; index < chrCnt && (!this._relaxed || this._textPos < this.jsonModel._text.length); index++){
3552                switch (chr) {
3553                    case '9': // Numeric
3554                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3555                        if(!xfalib.ut.PictureUtils.isDigit(cUni)){
3556                            throw "TextFormatting: not a digit as expected";
3557                        }
3558                        this._buffer.push(cUni);
3559                        break;
3560                    case 'A': // Alphebetic
3561                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3562                        if(!xfalib.ut.PictureUtils.isLetter(cUni)){
3563                            throw "TextFormatting: not a character as expected";
3564                        }
3565                        this._buffer.push(cUni);
3566                        break;
3567                    case 'O': // Alphanumeric
3568                    case '0':
3569                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3570                        // cUni === "" is a hack for LC-6152
3571                        // To prevent extra loop[one more time than the length of the string] for which cUni was ""
3572                        // which was neither a letter nor a digit
3573                        // so we were getting textformatting error
3574                        //which caused email id validation to fail for chars less than picture clause
3575                        if(!(cUni ==="" || xfalib.ut.PictureUtils.isLetter(cUni) || xfalib.ut.PictureUtils.isDigit(cUni))){
3576                            throw "TextFormatting: not a character or digit as expected";
3577                        }
3578                        this._buffer.push(cUni);
3579                        break;
3580                    case 'X':
3581                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3582                        this._buffer.push(cUni);
3583                        break;
3584                    case 't':
3585                        this._buffer.push("\t");
3586                        break;
3587                    default: this._buffer.push(chr);
3588                }
3589            }
3590
3591        },
3592
3593        /**
3594         *
3595         * @override
3596         */
3597        getResult : function(){
3598            if(this._textPos < this.jsonModel._text.length)
3599                throw "TextFormatting: picture clause smaller than input Text";
3600            return this._buffer.join("");
3601        },
3602
3603        /**
3604         *
3605         * @override
3606         */
3607        acceptPatternChar : function(chr){
3608            return xfalib.ut.PictureUtils.inString(chr, "9AO0Xt");
3609        },
3610
3611        consumeCharLiteral : function(token){
3612         this._buffer.push(""+ this.jsonModel._sPicture.charAt(token.startPos));
3613         // LC-3869 : forward the text pointer after literal is present and matched with the picture.
3614         if(this.jsonModel._sPicture.charAt(token.startPos) == this.jsonModel._text.charAt(token.startPos))
3615             this._textPos++;
3616        }
3617    })
3618
3619})(_,xfalib);
3620
3621
3622/**
3623 * @package xfalib.ut.TextFormattingVisitor
3624 * @import xfalib.ut.FormattingVisitorBase
3625 * @fileOverview The file provides formating logic on date pattern characters.
3626 * @version 0.0.1
3627 */
3628
3629/**
3630 * @constructor
3631 * @param object {jsonModel: {_sPicture:String,_timeInfo: xfalib.ut.TimeInfo}}
3632 */
3633
3634(function(_,xfalib){
3635    var TimeFormattingVisitor = xfalib.ut.TimeFormattingVisitor=  xfalib.ut.FormattingVisitorBase.extend({
3636
3637        consumeSubPattern : function(token){
3638            var chr = token.patChar;
3639            var chrCnt = token.len;
3640
3641            switch (chr) {
3642                case 'H':
3643                case 'K':
3644                    var hourOfDay = this.jsonModel._timeInfo.mHourOfDay;
3645                    if(chr=='K'){
3646                        hourOfDay += 1;
3647                    }
3648                    switch(chrCnt){
3649                        case 1:
3650                            this._buffer.push(hourOfDay);
3651                            break;
3652                        case 2:
3653                            this._buffer.push(xfalib.ut.PictureUtils.padding(hourOfDay,2));
3654                            break;
3655                    }
3656                    break;
3657
3658                case 'M':
3659                    var minuteOfHour = this.jsonModel._timeInfo.mMinuteOfHour;
3660                    switch(chrCnt){
3661                        case 1:
3662                            this._buffer.push(minuteOfHour);
3663                            break;
3664                        case 2:
3665                            this._buffer.push(xfalib.ut.PictureUtils.padding(minuteOfHour,2));
3666                            break;
3667                    }
3668
3669                    break;
3670                case 'S':
3671                    var secondOfMinute = this.jsonModel._timeInfo.mSecondOfMinute;
3672                    switch(chrCnt){
3673                        case 1:
3674                            this._buffer.push(secondOfMinute);
3675                            break;
3676                        case 2:
3677                            this._buffer.push(xfalib.ut.PictureUtils.padding(secondOfMinute,2));
3678                            break;
3679                    }
3680                    break;
3681                case 'F':
3682                    var Milliseconds =this.jsonModel._timeInfo.mThousandthOfSecond;
3683                    this._buffer.push(xfalib.ut.PictureUtils.padding(Milliseconds,3));
3684                    break;
3685
3686                default: throw "Unsupported pattern";
3687            };
3688
3689        },
3690
3691        /**
3692         *
3693         * @override
3694         */
3695        getResult : function(){
3696            return this._buffer.join("");
3697        }
3698
3699    });
3700
3701})(_,xfalib);
3702
3703
3704/**
3705 * @package xfalib.ut.NumFormattingVisitor
3706 * @import xfalib.ut.FormattingVisitorBase
3707 * @fileOverview Formats a string according to Text Picture.
3708 * @version 0.0.1
3709 */
3710
3711/**
3712 * @constructor
3713 * @param Object { jsonModel:{_sPicture: String}, text: String}
3714 */
3715
3716(function(_,xfalib){
3717    var PictureUtils =  xfalib.ut.PictureUtils;
3718    var NumFormattingVisitor = xfalib.ut.NumFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3719
3720        initialize: function(options) {
3721            NumFormattingVisitor._super.initialize.call(this);
3722            this._textPos = 0;
3723
3724            //boolean value used for internal state track
3725            this._mbDigitAddedToOutput = false; // at least one digit has been added to output
3726            this._mbSignAddedToOutput = false;
3727            this._nScannedPatternDigit = 0; //how many digit(98Zz) characters scanned in pattern, reset to 0 after '.Vv'
3728            this._mbRadixSeen = false;
3729
3730            this._pictureDesc = new xfalib.ut.NumPictureDesc({jsonModel:{_sPicture:this.jsonModel._sPicture}});
3731            this.jsonModel._sPicture= this._pictureDesc.getPicture();
3732            this._numberInfo = this._pictureDesc.parseNumberInfo(options.text);
3733
3734            this._mbNegative = this._numberInfo.isNegative;
3735            this._msText = this._numberInfo.msText;
3736            this._leadingPadding = this._numberInfo.padding;
3737            //
3738            this._mNumberSymbols = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale,"numberSymbols");
3739            this._mCurrencySymbols = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale,"currencySymbols");
3740        },
3741
3742        _checkAndAddDecimalPoint: function(fw) {
3743            if(this._mAddRadix) {
3744                this._buffer.push(this._fmtStr(this._mNumberSymbols.decimal, fw));
3745                this._mAddRadix = false;
3746            }
3747        },
3748
3749        consumeSubPattern : function(token){
3750            var chr = token.patChar,
3751                chrCnt = token.len;
3752            switch (chr) {
3753                case '9':
3754                case '8':
3755                case 'Z': // Digit or space if zero.
3756                case 'z':// Digit or nothing if zero.
3757                    if(!this._mbSignAddedToOutput)
3758                        this._ensureSignIsAdded();
3759                    while (chrCnt-- > 0 ) {
3760                        if(!this._mbRadixSeen){
3761                            if(this._leadingPadding > this._nScannedPatternDigit++){
3762                                var placeHolder = null;
3763                                if(this._mbDigitAddedToOutput){
3764                                    placeHolder = this._mNumberSymbols.zero;
3765                                }else{
3766                                    if(chr == '9' || chr =='8') {
3767                                        placeHolder = this._mNumberSymbols.zero;
3768                                        this._mbDigitAddedToOutput = true;
3769                                    }else if(chr == 'Z'){
3770                                        placeHolder = " ";
3771                                    }
3772                                }
3773                                if(placeHolder){
3774                                    this._buffer.push(this._matchChr(placeHolder));
3775                                }
3776                            }else {
3777                                var cValue = this._msText.charAt(this._textPos++);
3778                                this._ensureCharIsDigit(cValue);
3779                                this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3780                                this._mbDigitAddedToOutput = true;
3781                            }
3782                        }else{  //handling fractional part
3783                            if(this._nScannedPatternDigit++  < this._numberInfo.fractionDigit ){
3784                                var cValue = this._msText.charAt(this._textPos++);
3785                                this._ensureCharIsDigit(cValue);
3786                                this._checkAndAddDecimalPoint();
3787                                this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3788                                this._mbDigitAddedToOutput = true;
3789                            }else{
3790                                if(chr == '9'|| chr =='Z') {
3791                                    this._checkAndAddDecimalPoint();
3792                                    this._buffer.push(this._matchChr(this._mNumberSymbols.zero));
3793                                } else if(chr == '8') {
3794                                    var cValue = this._msText.charAt(this._textPos++);
3795                                    if(cValue != '' && this._ensureCharIsDigit(cValue)) {
3796                                        this._checkAndAddDecimalPoint();
3797                                        this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3798                                        this._mbDigitAddedToOutput = true;
3799                                    }
3800                                }
3801                            }
3802                        }
3803
3804                    }
3805
3806                    break;
3807                case 'E': // Exponent.
3808                    this._buffer.push('E');
3809                    this._buffer.push("" + this._numberInfo.shift);
3810                    break;
3811                case 'C': // CR symbol if negative and spaces if positive.
3812                    this._buffer.push((this._mbNegative) ? xfalib.ut.NumPictureDesc.gsCR : xfalib.ut.NumPictureDesc.gsDSP);
3813                    break;
3814                case 'c': // CR symbol if negative and nothing if positive.
3815                    if (this._mbNegative){
3816                        this._buffer.push(xfalib.ut.NumPictureDesc.gsCR);
3817                    }
3818                    break;
3819                case 'D': // DB symbol if negative and spaces if positive.
3820                    this._buffer.push((this._mbNegative) ? xfalib.ut.NumPictureDesc.gsDB : xfalib.ut.NumPictureDesc.gsDSP);
3821                    break;
3822                case 'd': // DB symbol if negative and nothing if positive.
3823                    if (this._mbNegative){
3824                        this._buffer.push(xfalib.ut.NumPictureDesc.gsDB);
3825                    }
3826                    break;
3827                case 'S': // Minus sign if negative and a space if positive.
3828                case 's':
3829                    if (this._mbNegative){
3830                        this._buffer.push(this._fmtStr(	this._mNumberSymbols.minus));
3831                    }else{
3832                        if('S' == chr){
3833                            this._buffer.push(this._matchChr(' '));
3834                        }
3835                    }
3836                    break;
3837                case 'V': // Implied decimal sign if parsing.
3838                case '.':
3839                case 'v': // Implied decimal sign.
3840                    if (this._textPos < this._msText.length && this._msText.charAt(this._textPos) == '.'){
3841                        this._textPos++; //consume a '.'
3842                    }
3843                    if (chr == 'V' || chr == '.'){
3844                        this._mAddRadix = true;
3845                        //this._buffer.push(this._fmtStr(this._mNumberSymbols.decimal, ));
3846                    }
3847                    this._mbRadixSeen = true;
3848                    this._nScannedPatternDigit = 0;
3849                    break;
3850
3851                case 0xFF0C: // Fullwidth ','.
3852                case ',': // Grouping separator.
3853                    while (chrCnt-- > 0) {
3854                        if (this._mbDigitAddedToOutput){
3855                            this._buffer.push(this._fmtStr(	this._mNumberSymbols.grouping ));
3856                        }
3857                        this._mbCommaSeen = true;
3858                    }
3859                    break;
3860                case 0xFF04: // Fullwidth '$'.
3861                case '$': // Currency name or symbol.
3862                    while (chrCnt-- > 0) {
3863                        this._buffer.push(this._fmtStr(	this._mCurrencySymbol
3863s.symbol ));
3864                    }
3865                    break;
3866                case 0xFF05: // Fullwidth '%'.
3867                case '%': // Percent symbol.
3868                    while (chrCnt-- > 0) {
3869                        this._buffer.push(this._fmtStr(	this._mNumberSymbols.percent));
3870                    }
3871                    break;
3872                case 0xFF08: // Fullwidth '('.
3873                case 0xFF09: // Fullwidth ')'.
3874                case '(': // Left parenthesis.
3875                case ')': // Right parenthesis.
3876                    this._buffer.push(this._matchChr((this._mbNegative) ? chr : ' '));
3877                    break;
3878                default:
3879            }
3880        },
3881
3882        _ensureCharIsDigit : function(cValue){
3883            if ('0' > cValue || cValue > '9'){
3884                throw "Nuberic Formatting: not a digit as expected " + cValue;
3885            }
3886        },
3887
3888
3889        _fmtStr : function(str){
3890            return str;
3891        },
3892
3893        _matchStr : function(str){
3894            return str;
3895        },
3896
3897        _matchChr : function(str){
3898            return str;
3899        },
3900
3901        _ensureSignIsAdded : function(){
3902            if (this._mbNegative && ! this._mbDigitAddedToOutput && ! this._pictureDesc.hasSign) {
3903                this._buffer.push(this._mNumberSymbols.minus);
3904                this._mbSignAddedToOutput = true;
3905            }
3906        },
3907
3908        /**
3909         *
3910         * @override
3911         */
3912        getResult : function(){
3913            return this._buffer.join("");
3914        },
3915
3916        /**
3917         *
3918         * @override
3919         */
3920        acceptPatternChar : function(chr){
3921            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
3922        }
3923
3924    });
3925
3926})(_,xfalib);
3927
3928
3929/**
3930 * @package xfalib.ut.TimeParsingVisitor
3931 * @import xfalib.ut.ParsingVisitorBase
3932 * @fileOverview The file provides parsing/formating logic on date pattern characters.
3933 * @version 0.0.1
3934 */
3935
3936/**
3937 * @constructor
3938 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
3939 */
3940
3941(function(_,xfalib){
3942    var TimeParsingVisitor = xfalib.ut.TimeParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
3943
3944        initialize: function() {
3945            this._timeInfo = new xfalib.ut.TimeInfo();
3946            TimeParsingVisitor._super.initialize.call(this);
3947        },
3948
3949        consumeSubPattern : function(token){
3950            var chr = token.patChar;
3951            var chrCnt = token.len;
3952            var curPos = this._strPos;
3953            var scannedChar = chrCnt;
3954            this._assert(curPos+chrCnt <=this.jsonModel._dataString.length, "Mismatch");
3955
3956            switch (chr) {
3957                case 'h':
3958                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
3959                        throw "ambiguity time string";
3960                    }
3961                    var hourOfMeriDiem=-1;
3962                    switch(chrCnt){
3963                        case 1:
3964                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
3965                            hourOfMeriDiem = parsed.value;
3966                            scannedChar = parsed.len;
3967                            break;
3968                        case 2:
3969                            hourOfMeriDiem = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
3970                            break;
3971                    }
3972
3973                    this._timeInfo.mHourOfMeriDiem = hourOfMeriDiem -1;
3974                    this._assert(this._timeInfo.mHourOfMeriDiem>=0 && this._timeInfo.mHourOfMeriDiem<=11, "Invalid Hour Of MeriDiem value.");
3975                    break;
3976
3977                case 'k':
3978                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
3979                        throw "ambiguity time string";
3980                    }
3981                    var hourOfMeriDiem=-1;
3982                    switch(chrCnt){
3983                        case 1:
3984                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-11)
3985                            hourOfMeriDiem = parsed.value;
3986                            scannedChar = parsed.len;
3987                            break;
3988                        case 2:
3989                            hourOfMeriDiem = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-11)
3990                            break;
3991                    }
3992
3993                    this._timeInfo.mHourOfMeriDiem = hourOfMeriDiem;
3994                    this._assert(this._timeInfo.mHourOfMeriDiem>=0 && this._timeInfo.mHourOfMeriDiem<=11, "Invalid hour of meriDiem value.");
3995                    break;
3996
3997                case 'H':
3998                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
3999                        throw "ambiguity time string";
4000                    }
4001                    var hourOfDay=-1;
4002                    switch(chrCnt){
4003                        case 1:
4004                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4005                            hourOfDay = parsed.value;
4006                            scannedChar = parsed.len;
4007                            break;
4008                        case 2:
4009                            hourOfDay = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4010                            break;
4011                    }
4012
4013                    this._timeInfo.mHourOfDay = hourOfDay;
4014                    this._assert(this._timeInfo.mHourOfDay>=0 && this._timeInfo.mHourOfDay<=23, "Invalid hour of day value.");
4015                    break;
4016
4017                case 'K':
4018                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
4019                        throw "ambiguity time string";
4020                    }
4021                    var hourOfDay=-1;
4022                    switch(chrCnt){
4023                        case 1:
4024                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4025                            hourOfDay = parsed.value;
4026                            scannedChar = parsed.len;
4027                            break;
4028                        case 2:
4029                            hourOfDay = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4030                            break;
4031                    }
4032
4033                    this._timeInfo.mHourOfDay = hourOfDay - 1;
4034                    this._assert(this._timeInfo.mHourOfDay>=0 && this._timeInfo.mHourOfDay<=23, "Invalid hour of day value.");
4035                    break;
4036                case 'M':
4037                    if(this._timeInfo.mMinuteOfHour != -1){
4038                        throw "ambiguity time string";
4039                    }
4040                    var minuteOfHour=-1;
4041                    switch(chrCnt){
4042                        case 1:
4043                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4044                            minuteOfHour = parsed.value;
4045                            scannedChar = parsed.len;
4046                            break;
4047                        case 2:
4048                            minuteOfHour = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4049                            break;
4050                    }
4051
4052                    this._timeInfo.mMinuteOfHour = minuteOfHour;
4053                    this._assert(this._timeInfo.mMinuteOfHour>=0 && this._timeInfo.mMinuteOfHour<=59, "Invalid minute of hour.");
4054                    break;
4055                case 'S':
4056                    if(this._timeInfo.mSecondOfMinute != -1){
4057                        throw "ambiguity time string";
4058                    }
4059                    var secondOfMinute=-1;
4060                    switch(chrCnt){
4061                        case 1:
4062                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4063                            secondOfMinute = parsed.value;
4064                            scannedChar = parsed.len;
4065                            break;
4066                        case 2:
4067                            secondOfMinute = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4068                            break;
4069                    }
4070
4071                    this._timeInfo.mSecondOfMinute = secondOfMinute;
4072                    this._assert(this._timeInfo.mSecondOfMinute>=0 && this._timeInfo.mSecondOfMinute<=59, "Invalid second of minute.");
4073                    break;
4074                case 'F':
4075
4076                    this._assert(chrCnt==3, "Invalid pattern F.");
4077                    this._timeInfo.mThousandthOfSecond = this.parseIntExact(this.jsonModel._dataString, curPos, 3);
4078                    this._assert(this._timeInfo.mThousandthOfSecond>=0 && this._timeInfo.mThousandthOfSecond<=999, "Invalid thousand of second.");
4079                    break;
4080
4081                default: throw "Unsupported pattern";
4082            }
4083
4084            this._strPos += scannedChar;
4085        },
4086
4087        parseIntAggressive : xfalib.ut.PictureUtils.parseIntAggressive,
4088
4089        parseIntExact : xfalib.ut.PictureUtils.parseIntExact,
4090
4091        getResult : function(){
4092            return this._timeInfo.getISOTime();
4093        },
4094
4095        getTimeInfo : function(){
4096            return this._timeInfo;
4097        },
4098
4099        _assert : function(condition, message){
4100            if(!condition){
4101                throw message;
4102            }
4103        }
4104    });
4105})(_,xfalib);
4106
4107
4108
4109/**
4110 * @package xfalib.ut.TextParsingVisitor
4111 * @import xfalib.ut.ParsingVisitorBase
4112 *
4113 * @fileOverview Parses a string according to Text Picture.
4114 * @version 0.0.1
4115 */
4116
4117/**
4118 * @constructor
4119 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
4120 */
4121(function(_,xfalib){
4122    var TextParsingVisitor = xfalib.ut.TextParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4123
4124        initialize: function() {
4125            TextParsingVisitor._super.initialize.call(this);
4126            this._buffer = [];
4127        },
4128
4129        consumeSubPattern : function(token){
4130            var chr = token.patChar;
4131            var chrCnt = token.len;
4132            for(var index = 0; index < chrCnt; index++){
4133                switch (chr) {
4134                    case '9': // Numeric
4135                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4136                        if(!xfalib.ut.PictureUtils.isDigit(cUni)){
4137                            throw "TextParsing: not a digit as expected";
4138                        }
4139                        this._buffer.push(cUni);
4140                        break;
4141                    case 'A': // Alphebetic
4142                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4143                        if(!xfalib.ut.PictureUtils.isLetter(cUni)){
4144                            throw "TextParsing: not a character as expected";
4145                        }
4146                        this._buffer.push(cUni);
4147                        break;
4148                    case 'O': // Alphanumeric
4149                    case '0':
4150                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4151                        if(!xfalib.ut.PictureUtils.isLetterOrDigit(cUni)){
4152                            throw "TextParsing: not a character or digit as expected";
4153                        }
4154                        this._buffer.push(cUni);
4155                        break;
4156                    case 'X':
4157                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4158                        this._buffer.push(cUni);
4159                        break;
4160                    case 't':
4161                        if(this.jsonModel._dataString.charAt(this._strPos++)=="\t"){
4162                            this._buffer.push("\t");
4163                        }else{
4164                            throw "TextParsing: not a Tab as expected";
4165                        }
4166                        break;
4167                    default:
4168                        if(this.jsonModel._dataString.charAt(this._strPos++)== chr){
4169                            this._buffer.push(chr);
4170                        }else{
4171                            throw "TextParsing: not '" + chr+"' as expected";
4172                        }
4173                }
4174            }
4175
4176        },
4177        /**
4178         *
4179         * @override
4180         */
4181        getResult : function(){
4182            if(this._strPos < this.jsonModel._dataString.length)
4183                throw "TextParsing: picture clause smaller than input Text";
4184            return this._buffer.join("");
4185        },
4186        /**
4187         *
4188         * @override
4189         */
4190        acceptPatternChar : function(chr){
4191            return xfalib.ut.PictureUtils.inString(chr, "9AO0Xt");
4192        }
4193
4194    });
4195})(_,xfalib);
4196
4197
4198/**
4199 * @package xfalib.ut.NumParsingVisitor
4200 * @import xfalib.ut.ParsingVisitorBase
4201 * @fileOverview Parses a string according to Text Picture.
4202 * @version 0.0.1
4203 */
4204
4205/**
4206 * @constructor
4207 * @param Object {jsonModel: {_sPicture: String,_dataString: String}}
4208 */
4209
4210(function(_,xfalib){
4211    var NumParsingVisitor = xfalib.ut.NumParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4212
4213        initialize: function(options) {
4214            this._pictureDesc = new xfalib.ut.NumPictureDesc({jsonModel:{_sPicture:this.jsonModel._sPicture}});
4215            this.jsonModel._sPicture = this._pictureDesc.getPicture();
4216            this._buffer = [];
4217            this._strPos = 0;
4218            this._hasRadix = false;
4219            this._mbNegative = false;
4220            this._mbDigitSeen = false; // at least one digit has been added to output
4221            this._mbSignSeen = false;
4222            this._mBacktrack = null;
4223            this._hasPercent = false;
4224            this._mbExponSeen = false;
4225
4226            this._mNumberSymbols = xfalib.ut.PictureUtils.getLocaleObject(this.options._locale,"numberSymbols");
4227            this._mCurrencySymbols = xfalib.ut.PictureUtils.getLocaleObject(this.options._locale,"currencySymbols");
4228        },
4229
4230        _lookupNext : xfalib.ut.Scanner.lookupNext,
4231
4232        parse : function(){
4233            var patPos = 0;
4234            while(true){
4235                try{
4236                    for(var token = this._lookupNext(this.jsonModel._sPicture, patPos, this.acceptPatternChar); token != null;  ){
4237                        this.consume(token);
4238                        patPos = patPos + token.len;
4239                        token = this._lookupNext(this.jsonModel._sPicture, patPos, this.acceptPatternChar);
4240                    }
4241                }catch(e){
4242                    //mismatch, try again!
4243                    if(this._mBacktrack){
4244                        patPos = this._mBacktrack.patPos;
4245                        this._buffer.length = 0;
4246                        this._strPos = this._mBacktrack.strPos;
4247                        this._mbDigitSeen = false;
4248                        this._mBacktrack = null;
4249                        continue;
4250                    }
4251                }
4252                break;
4253            }
4254        },
4255        consumeSubPattern : function(token){
4256
4257            var chr = token.patChar;
4258            var chrCnt = token.len;
4259            var fw = false;
4260            switch (chr) {
4261                case '9':
4262                case '8':
4263                case 'Z': // Digit or space if zero.
4264                case 'z':// Digit or nothing if zero.
4265                    while (chrCnt-- > 0 ) {
4266                        if(!this._mbDigitSeen){
4267                            var cUni = this.jsonModel._dataString.charAt(this._strPos);
4268                            if(cUni == '-'){
4269                                this._mbNegative = true;
4270                                cUni = this.jsonModel._dataString.charAt(++this._strPos);
4271                            }
4272                            if(chr== '9' || chr == '8'){
4273                                if(!xfalib.ut.PictureUtils.isDigit(cUni)){
4274                                    throw "TextParsing: not a digit as expected";
4275                                }
4276                                this._buffer.push(cUni);
4277                                this._mbDigitSeen =true;
4278                            }else if(chr =='Z'){
4279                                if(xfalib.ut.PictureUtils.isDigit(cUni)){
4280                                    this._buffer.push(cUni);
4281                                    this._mbDigitSeen =true;
4282                                }else if(cUni != ' '){
4283                                    throw "TextParsing: not a digit or space as expected";
4284                                }
4285                            }else {
4286                                // has to be 'z', eagerly try to match a digit, if a mismatch is latterly found, backtrack
4287                                if(xfalib.ut.PictureUtils.isDigit(cUni)){
4288                                    this._buffer.push(cUni);
4289                                    this._mbDigitSeen =true;
4290                                    this._mBacktrack = {
4291                                        "patPos" : token.patPos + token.len - chrCnt, //new position from next char after 'z'
4292                                        "strPos" : this._strPos
4293                                    };
4294                                }else {
4295                                    throw "TextParsing: not a digit or space as expected";
4296                                }
4297                            }
4298                            ++this._strPos;
4299                        }else{
4300                            var cUni = this.jsonModel._dataString.charAt(this._strPos);
4301                            if(xfalib.ut.PictureUtils.isDigit(cUni)){
4302                                this._buffer.push(cUni);
4303                                ++this._strPos;
4304                            }else{
4305                                if(chr !='z'){
4306                                    throw "TextParsing: not a digit as expected";
4307                                }else{
4308                                    ++this._strPos;
4309                                }
4310                            }
4311                        }
4312                    }
4313
4314                    break;
4315                case 'V' :
4316                case 'v' :
4317                case '.' :
4318                    if(this._matchStr(this._mNumberSymbols.decimal)){
4319                        this._hasRadix = true;
4320                        this._buffer.push('.');
4321                        this._mbDigitSeen =true;
4322                    }else{
4323                        throw "TextParsing: not a radix as expected";
4324                    }
4325                    break;
4326                case 'E': // Exponent.
4327                    if(this._matchStr('E')){
4328                        this._buffer.push('E');
4329                        if(this._matchStr('+')){
4330                            //
4331                        }else if(this._matchStr('-')){
4332                            this.jsonModel._buffer.push('-');
4333                        }
4334                        var strLen = this.jsonModel._dataString.length;
4335                        while(this._strPos < strLen &&
4336                            xfalib.ut.PictureUtils.isDigit(this.jsonModel._dataString.charAt(this._strPos))){
4337                            this._buffer.push(this.jsonModel._dataString.charAt(this._strPos++));
4338                        }
4339                    }
4340                    break;
4341
4342                case 'C': // CR symbol if negative and spaces if positive.
4343                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsCR)){
4344                        this._mbNegative = true;
4345                    }else if(!this._matchStr(xfalib.ut.NumPictureDesc.gsDSP)){
4346                        throw "TextParsing: not a CR as expected";
4347                    }
4348                    break;
4349                case 'c': // CR symbol if negative and nothing if positive.
4350                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsCR)){
4351                        this._mbNegative = true;
4352                    }
4353                    break;
4354                case 'D': // DB symbol if negative and spaces if positive.
4355                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsDB)){
4356                        this._mbNegative = true;
4357                    }else if(!this._matchStr(xfalib.ut.NumPictureDesc.gsDSP)){
4358                        throw "TextParsing: not a CR as expected";
4359                    }
4360                    break;
4361                case 'd': // DB symbol if negative and nothing if positive.
4362                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsDB)){
4363                        this._mbNegative = true;
4364                    }
4365                    break;
4366                case 'S': // Minus sign if negative and a space if positive.
4367                    if(this._matchStr(this._mNumberSymbols.negative,fw)){
4368                        this._mbNegative = true;
4369                    }else if(!this._matchStr(" ")){
4370                        throw "TextParsing: not a CR as expected";
4371                    }
4372                    break;
4373                case 's':
4374                    if(this._matchStr(this._mNumberSymbols.negative,fw)){
4375                        this._mbNegative = true;
4376                    }
4377                    break;
4378                case 0xFF0C: // Fullwidth ','.
4379                case ',': // Grouping separator.
4380                    while (chrCnt-- > 0) {
4381                        if(!this._matchStr(this._mNumberSymbols.grouping, fw)){
4382                            throw "TextParsing: not a grouping symbol as expected";
4383                        }
4384                    }
4385                    break;
4386                case 0xFF04: // Fullwidth '$'.
4387                case '$': // Currency name or symbol.
4388                    while (chrCnt-- > 0) {
4389                        if(!this._matchStr(this._mCurrencySymbol
4389s.symbol, fw)){
4390                            throw "TextParsing: not a grouping symbol as expected";
4391                        }
4392                    }
4393                    break;
4394                case 0xFF05: // Fullwidth '%'.
4395                case '%': // Percent symbol.
4396                    while (chrCnt-- > 0) {
4397                        if(!this._matchStr(this._mNumberSymbols.percent, fw)){
4398                            throw "TextParsing: not a grouping symbol as expected";
4399                        }
4400                    }
4401                    this._hasPercent = true;
4402                    break;
4403                case 0xFF08: // Fullwidth '('.
4404                case 0xFF09: // Fullwidth ')'.
4405                case '(': // Left parenthesis.
4406                case ')': // Right parenthesis.
4407                    if(this._matchStr(chr,fw)){
4408                        this._mbNegative = true;
4409                    }else if(!this._matchStr(" ")){
4410                        throw "TextParsing: not parentesis as expected";
4411                    }
4412                    break;
4413                case 't': // tab.
4414                    while (chrCnt-- > 0) this._matchStr('\t',fw);
4415            }
4416        },
4417        getResult : function(){
4418            var stringNum =  this._buffer.join("");
4419            if(this._hasPercent) {
4420                var buf = new Array();
4421                stringNum = Number(stringNum).toString();
4422                var dot = stringNum.indexOf('.');
4423
4424                var pos = dot-2;
4425                if(pos ==0) buf.push("0");
4426                else if(pos ==-1) buf.push("0.0");
4427                else if(pos ==-3) pos = stringNum.length - 2;
4428                for(var index=0;index < stringNum.length; index++){
4429                    if(index == pos){
4430                        buf.push(".");
4431                    }
4432                    if(index != dot){
4433                        buf.push(stringNum.charAt(index));
4434                    }
4435                }
4436                stringNum = buf.join("");
4437            }
4438            var number = Number(stringNum);
4439            if(this._mbNegative) number = -number;
4440            return number.toString();
4441        },
4442
4443        _matchStr : function(target){
4444            if(xfalib.ut.PictureUtils.matchString(this.jsonModel._dataString, this._strPos, target)){
4445                this._strPos+= target.length;
4446                return true;
4447            }else{
4448                return false;
4449            }
4450        },
4451
4452        /**
4453         *
4454         * @override
4455         */
4456        acceptPatternChar : function(chr){
4457            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
4458        }
4459    });
4460})(_,xfalib);
4461/**
4462 * @package xfalib.ut.DateParsingVisitor
4463 * @import xfalib.ut.ParsingVisitorBase
4464 * @fileOverview The file provides parsing/formating logic on date pattern characters.
4465 * @version 0.0.1
4466 */
4467
4468/**
4469 * @constructor
4470 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
4471 */
4472
4473(function(_,xfalib) {
4474    var DateParsingVisitor = xfalib.ut.DateParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4475
4476        initialize: function() {
4477            this._dateInfo = new xfalib.ut.DateInfo({isParsingCall : true});
4478            this._dayOfMonth = this._monthOfYear = this._yearOfEra = null; // used to validate date once all sub patterns are consumed
4479            DateParsingVisitor._super.initialize.call(this);
4480        },
4481
4482        consumeSubPattern : function(token){
4483            var chr = token.patChar;
4484            var chrCnt = token.len;
4485            var curPos = this._strPos;
4486            var scannedChar = chrCnt;
4487
4488            //TODO: need to remove this assert.
4489            this._assert(curPos+chrCnt <=this.jsonModel._dataString.length, "Mismatch");
4490
4491            switch (chr) {
4492                case 'D':
4493                    switch(chrCnt){
4494                        case 1:
4495                            var parsed = xfalib.ut.PictureUtils.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-31)
4496                            this._dayOfMonth = parsed.value;
4497                            scannedChar = parsed.len;
4498                            break;
4499                        case 2:
4500                            this._dayOfMonth = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-31)
4501                            break;
4502                    }
4503                    this._assert(this._dayOfMonth <= 31 && this._dayOfMonth >0, "Invalid date string1");
4504                    break;
4505                case 'J':
4506
4507                    //this._mDayOfYear;
4508                    break;
4509                case 'M':
4510                    var symbol = "";
4511                    switch(chrCnt){
4512                        case 1:
4513                            var parsed = xfalib.ut.PictureUtils.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
4514                            this._monthOfYear = parsed.value;
4515                            scannedChar = parsed.len;
4516                            break;
4517                        case 2:
4518                            this._monthOfYear = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 2 digit(01-12)
4519                            break;
4520                        case 3:
4521                            symbol = "calendarSymbols.abbrmonthNames";
4522                            break;
4523                        case 4:
4524                            symbol = "calendarSymbols.monthNames"
4525                            break;
4526
4527                    }
4528                    if(symbol) {
4529                        var hashObj = xfalib.ut.PictureUtils.getHashOfLocaleObject(this.jsonModel._locale,symbol),
4530                            str = this.jsonModel._dataString.toLowerCase(),
4531                            hash = 0,
4532                            curStr = ""
4533                        scannedChar = 0;
4534                        while(curPos+scannedChar < str.length) {
4535                            hash += (scannedChar+1)*str.charCodeAt(curPos+scannedChar)
4536                            curStr+= str.charAt(curPos+scannedChar);
4537                            scannedChar++;
4538                            if(hashObj[hash] && hashObj[hash].indexOf(curStr) > -1 ) break;
4539                        }
4540                        var monthNames = _.map(xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale, symbol), function (str) {
4541                            return str.toLowerCase();
4542                        });
4543                        this._monthOfYear = monthNames.indexOf(curStr) + 1; // months are from 1 to 12
4544                    }
4545                    //TODO: remove this assert
4546                    this._assert(this._monthOfYear <= 12 && this._monthOfYear >0, "Invalid date string2");
4547                    break;
4548                case 'E':
4549                    var symbol = ""
4550                    switch(chrCnt) {
4551                        case 1:
4552                            scannedChar = 1;
4553                            break;
4554                        case 3:
4555                            symbol = "calendarSymbols.abbrdayNames";
4556                            break;
4557                        case 4:
4558                            symbol = "calendarSymbols.dayNames"
4559                            break;
4560                        default:
4561                            throw "unsupported Picture Clause ";
4562                    }
4563                    if(symbol) {
4564                        var hashObj = xfalib.ut.PictureUtils.getHashOfLocaleObject(this.jsonModel._locale,symbol);
4565                        scannedChar = 0;
4566                        var str = this.jsonModel._dataString.toLowerCase();
4567                        var hash = 0;
4568                        var curStr = "";
4569                        while(curPos+scannedChar < str.length) {
4570                            hash += (scannedChar+1)*str.charCodeAt(curPos+scannedChar)
4571                            curStr+= str.charAt(curPos+scannedChar);
4572                            scannedChar++;
4573                            if(hashObj[hash] && hashObj[hash].indexOf(curStr) > -1) break;
4574                        }
4575                    }
4576                    break;
4577
4578                case 'e':
4579                    break;
4580                case 'G':
4581                    break;
4582                case 'Y':
4583
4584                    switch(chrCnt){
4585                        case 2:
4586                            this._yearOfEra = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 2 digit(00-99)
4587                            this._yearOfEra+=2000;
4588                            if(this._yearOfEra >= 2029){
4589                                this._yearOfEra -=100;
4590                            }
4591                            break;
4592                        case 4:
4593                            this._yearOfEra = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 4); // 2 digit(0000-9999)
4594                            break;
4595                    }
4596
4597                    this._assert(this._yearOfEra <= 9999 && this._yearOfEra >=0, "Invalid date string3");
4598                    break;
4599                case 'w':
4600                    break;
4601                case 'W':
4602                    break;
4603                default: throw "Unsupported pattern";
4604            }
4605
4606            if(this._yearOfEra && this._monthOfYear && this._dayOfMonth){
4607                this._dateInfo.validate(this._yearOfEra, this._monthOfYear, this._dayOfMonth);
4608            }
4609
4610            this._strPos += scannedChar;
4611        },
4612
4613        getDate : function(){
4614            return this._dateInfo.date;
4615        },
4616
4617        getResult: function(){
4618            if (this._strPos < this.jsonModel._dataString.length) {
4619                throw "DateParsing: picture clause smaller than input Date";
4620            }
4621            return this._dateInfo.getISODate();
4622        },
4623
4624        _assert : function(condition, message){
4625            if(!condition){
4626                throw message;
4627            }
4628        }
4629    });
4630})(_,xfalib);
4631
4632/*************************************************************************
4633 *
4634 * ADOBE CONFIDENTIAL
4635 * ___________________
4636 *
4637 *  Copyright 2013 Adobe Systems Incorporated
4638 *  All Rights Reserved.
4639 *
4640 * NOTICE:  All information contained herein is, and remains
4641 * the property of Adobe Systems Incorporated and its suppliers,
4642 * if any.  The intellectual and technical concepts contained
4643 * herein are proprietary to Adobe Systems Incorporated and its
4644 * suppliers and are protected by trade secret or copyright law.
4645 * Dissemination of this information or reproduction of this material
4646 * is strictly forbidden unless prior written permission is obtained
4647 * from Adobe Systems Incorporated.
4648 **************************************************************************/
4649
4650
4651
4652(function(_, $, xfalib){
4653
4654    var LocalizationUtil = xfalib.ut.LocalizationUtil = xfalib.ut.Class.extend({
4655
4656        getLocalizedMessage: function(category, message, snippets){
4657            var resolvedMessage = message;
4658            if(snippets){
4659                //resolve message with snippet
4660                resolvedMessage = resolvedMessage.replace(/{(\d+)}/g, function(match, number) {
4661                    return typeof snippets[number] != 'undefined'
4662                        ? snippets[number]
4663                        : match
4664                        ;
4665                });
4666            }
4667            var text = "";
4668            if (category) {
4669                text += " [" + category + "]";
4670            }
4671            text += "  " + resolvedMessage + "\r\n" ;
4672            return text;
4673        }
4674
4675    });
4676})(_, $, xfalib);
4677
4678
4679/*************************************************************************
4680 * ADOBE CONFIDENTIAL
4681 * ___________________
4682 *
4683 *  Copyright 2013 Adobe Systems Incorporated
4684 *  All Rights Reserved.
4685 *
4686 * NOTICE:  All information contained herein is, and remains
4687 * the property of Adobe Systems Incorporated and its suppliers,
4688 * if any.  The intellectual and technical concepts contained
4689 * herein are proprietary to Adobe Systems Incorporated and its
4690 * suppliers and are protected by all applicable intellectual property
4691 * laws, including trade secret and copyright laws.
4692 * Dissemination of this information or reproduction of this material
4693 * is strictly forbidden unless prior written permission is obtained
4694 * from Adobe Systems Incorporated.
4695 **************************************************************************/
4696
4697
4698
4699
4700(function(_, $, xfalib){
4701    xfalib.view.util.TextMetrics = {
4702        xfaUtil : xfalib.ut.XfaUtil.prototype,
4703        ERROR_MARGIN : 1,
4704        $measureEl : null,
4705        initialize : function(divEl){
4706            if(!divEl){
4707                var $div = $("<div></div>");
4708                $div.attr("id", "textMetrics");
4709                var divStyles = {};
4710                divStyles.left = -1000;
4711                divStyles.top = -1000;
4712                divStyles.position = "absolute";
4713                divStyles.visibility = "hidden";
4714                this.xfaUtil.$css($div.get(0), divStyles);
4715                this.$measureEl = $div;
4716                $("body").append(this.$measureEl);
4717            }else{
4718                this.$measureEl = divEl;
4719            }
4720        },
4721
4722        measureExtent : function(text, options){
4723            text = text + " ";
4724            if(!this.$measureEl){
4725                this.initialize();
4726            }
4727            options = options || {};
4728            var textStyles = {};
4729            var $refEl =  $(options.refEl || "<div></div>") ;
4730            var refEl = $refEl.get(0);
4731            textStyles.fontSize = $refEl.css("fontSize") || options["font-size"] || options["fontSize"];
4732            textStyles.fontStyle = $refEl.css("fontStyle") || options["font-style"] || options["fontStyle"];
4733            textStyles.fontWeight = $refEl.css("fontWeight") || options["font-weight"] || options["fontWeight"];
4734            textStyles.fontFamily = $refEl.css("fontFamily") || options["font-family"] || options["fontFamily"];
4735            textStyles.lineHeight = refEl.style.lineHeight || options["line-height"] || options["lineHeight"];
4736            textStyles.letterSpacing = $refEl.css("letterSpacing") || options["letter-spacing"] || options["letterSpacing"];
4737            textStyles.whiteSpace =  $refEl.css("whiteSpace") || options["white-space"] || options["whiteSpace"] || "pre-wrap";
4738            if( $.browser.mozilla && $refEl.is("textarea"))      // for Bug #3621180
4739                textStyles.whiteSpace = "pre-wrap";
4740            textStyles.wordBreak =  $refEl.css("wordBreak") || options["word-break"] || options["wordBreak"] || "break-all";
4741            textStyles.wordWrap =  $refEl.css("wordWrap") || options["word-wrap"] || options["wordWrap"] || "break-word";
4742            textStyles.width = this._elWidth(refEl, options);
4743            textStyles.height = this._elHeight(refEl, options);
4744            textStyles.minWidth = this._elMinWidth(refEl, options);
4745            textStyles.minHeight = this._elMinHeight(refEl, options);
4746            textStyles.maxWidth = this._elMaxWidth(refEl, options);
4747            textStyles.maxHeight = this._elMaxHeight(refEl, options);
4748            this.xfaUtil.$css(this.$measureEl.get(0), textStyles);
4749            // for text fields/areas and draw requiring rich text support
4750            if(options.contentType === "text/html"){
4751              // retaining for future use . If we use the above property for other rich text
4752               if(options.skipXSSProtection) {
4753                 this.$measureEl.html(text);
4754               } else {
4755                 this.$measureEl.html(xfalib.ut.XfaUtil.prototype.encodeScriptableTags(text));
4756               }
4757            }else {
4758               text = text.replace(/\n\r/g,"\n").replace(/\r\n/g,"\n").replace(/\r/g, "\n");
4759               this.$measureEl.text(text);
4760            }
4761            var measuredWidth =  this.$measureEl.width();
4762            var measuredHeight =  this.$measureEl.height();
4763
4764            if(measuredWidth == Math.ceil(options["width"]) || measuredWidth == Math.floor(options["width"])){
4765                measuredWidth = options["width"];
4766            }
4767            /*
4768             FORMS-11363 : fix for height calculation of table cell
4769             Enable this toggle for old behaviour (if any regression comes)
4770             */
4771            else if ((window.FD && window.FD.isToggleEnabled("FT_FORMS-11363")) && (options["maxWidth"] > measuredWidth || (measuredWidth > options["minWidth"] > 0 && (options["maxWidth"] || -1) < 0))) {
4772                //complicated, please simplify if below hurts you:  Add error margin if there is scope of further extension of extent
4773                measuredWidth = measuredWidth + 1;
4774            } else if (options["maxWidth"] > measuredWidth || (measuredWidth > options["minWidth"] > 0 && (options["maxWidth"] || -1) < 0)) {
4775                //complicated, please simplify if below hurts you:  Add error margin if there is scope of further extension of extent
4776                measuredWidth = measuredWidth;
4777            }
4778
4779            if(measuredHeight == Math.ceil(options["height"]) || measuredHeight == Math.floor(options["height"])){
4780                measuredHeight = options["height"];
4781            }
4782            else if( $refEl.is("textarea") && (options["maxHeight"] > measuredHeight || (measuredHeight > options["minHeight"] > 0 && (options["maxHeight"] || -1) < 0))){
4783                measuredHeight = measuredHeight +1;
4784            }
4785            this.$measureEl.empty();
4786            return {width : measuredWidth, height : measuredHeight};
4787        },
4788
4789        _elWidth : function(refEl, options){
4790            if(options["minWidth"] && options["minWidth"] > -1)
4791                return "auto";
4792            else if(options["maxWidth"] && options["maxWidth"] > -1)
4793                return "auto";
4794            else
4795                return options["width"] || "auto";
4796        },
4797
4798        _elHeight : function(refEl, options){
4799            // TODO: check for calculations here for floating field and other cases.
4800            if(options["contentType"] === "text/html")
4801                return "auto";
4802            if(options.isDraw) { // for handling the case of draw having floating fields
4803                return "auto";
4804            }
4805            if(!$(refEl).is("textarea"))
4806                return options["height"] || "auto";
4807            if(options["minHeight"] && options["minHeight"] > -1)
4808                return "auto";
4809            else if(options["maxHeight"] && options["maxHeight"] > -1)
4810                return "auto";
4811            else
4812                return options["height"] || "auto";
4813        },
4814
4815        _elMinWidth : function(refEl, options){
4816            if(options["minWidth"] && options["minWidth"] > -1)
4817                return options["minWidth"];
4818            else
4819                return "0"; //default css value
4820        },
4821
4822        _elMinHeight : function(refEl, options){
4823            if(options["minHeight"] && options["minHeight"] > -1)
4824                return options["minHeight"];
4825            else
4826                return "0"; //default css value
4827        },
4828
4829        _elMaxWidth : function(refEl, options){
4830            if(options["maxWidth"] && options["maxWidth"] > -1)
4831                return options["maxWidth"];
4832            else
4833                return "none"; //default css value
4834        },
4835
4836        _elMaxHeight : function(refEl, options){
4837            if(options["maxHeight"] && options["maxHeight"] > -1)
4838                return options["maxHeight"];
4839            else
4840                return "none"; //default css value
4841        },
4842
4843        _destroy : function() {
4844            $("#textMetrics").remove();
4845            this.$measureEl = null;
4846        }
4847    }
4848})(_, $, xfalib);
4849(function($, _) {
4850
4851	$.alertBox = {
4852
4853		verticalOffset: -75,
4854		horizontalOffset: 0,
4855		repositionOnResize: true,
4856		overlayOpacity: 0.01,
4857		overlayColor: '#FFF',
4858		draggable: false,
4859		dialogClass: null,
4860		imageDirectory: "..",
4861		images: ["A_Warning_Lg_N.png", "A_Alert2_Lg_N.png", "C_QuestionBubble_Xl_N.png", "A_InfoBlue_32x32_N.png"],
4862
4863		alert: function(img, message, title, callback) {
4864			this._show(img, title, message, null, 'OK', function(result) {
4865				if( callback ) callback(result);
4866			});
4867		},
4868
4869		okCancel: function(img, message, title, callback) {
4870			this._show(img, title, message, null, 'OK-Cancel', function(result) {
4871				if( callback ) callback(result);
4872			});
4873		},
4874		yesNo: function(img, message, title, callback) {
4875			this._show(img, title, message, null, 'Yes-No', function(result) {
4876				if( callback ) callback(result);
4877			});
4878		},
4879
4880		yesNoCancel: function(img, message, title, callback) {
4881			this._show(img, title, message, null, 'Yes-No-Cancel', function(result) {
4882				if( callback ) callback(result);
4883			});
4884		},
4885
4886		_createBox: function(msgBox_message,buttons,callback) {
4887			var that = this;
4888			$("#"+msgBox_message).after("<div id='msgBox_panel'>");
4889			_.each(buttons.split("-"),function(val,i) {
4890                var dispval = xfalib.locale.Strings[val.toLowerCase()] ? xfalib.locale.Strings[val.toLowerCase()] : val;  // keys in loaclization files are in lower-case
4891                $("#msgBox_panel").append("<input type='button' value='"+dispval+"' id = 'msgBox_"+val+"' class=msgbox_input />");
4892				$("#msgBox_"+val).click( function() {
4893					that._hide();
4894					callback(!i);
4895				});
4896				if(!i) $("msgBox_"+val).focus();
4897			});
4898		},
4899
4900		_show: function(img, title, msg, value, type, callback) {
4901
4902			this._hide();
4903			this._overlay('show');
4904
4905			$("BODY").append(
4906			  '<div id="msgBox_container">' +
4907			    '<h1 id="msgBox_title"></h1>' +
4908			    '<div id="msgBox_content">' +
4909			      '<div id="msgBox_message"></div>' +
4910				'</div>' +
4911			  '</div>');
4912
4913			if( this.dialogClass ) $("#msgBox_container").addClass($.alertBox.dialogClass);
4914
4915			$("#msgBox_container").css({
4916				position: 'absolute',
4917				zIndex: 99999,
4918				padding: 0,
4919				margin: 0
4920			});
4921
4922			$("#msgBox_title").text(title);
4923			$("#msgBox_content").addClass("msgBoxType"+img);//css("background-image","url("+this.imageDirectory+ this.images[img]+")");
4924			msg = xfalib.ut.XfaUtil.prototype.encodeScriptableTags(msg.replace(/\n/g, '<br />'));
4925            $("#msgBox_message").html(msg);
4926
4927			$("#msgBox_container").css({
4928				minWidth: $("#msgBox_container").outerWidth(),
4929				maxWidth: $("#msgBox_container").outerWidth()
4930			});
4931
4932			this._reposition();
4933			this._maintainPosition(true);
4934
4935			this._createBox("msgBox_message",type,callback);
4936
4937			//TODO: Make keyboard input work
4938			/*$("#msgBox_ok").keypress( function(e) {
4939				if( e.keyCode == 13 || e.keyCode == 27 ) $("#msgBox_ok").trigger('click');
4940			});
4941			$("#msgBox_cancel").keypress( function(e) {
4942				if( e.keyCode == 13 ) $("#msgBox_ok").trigger('click');
4943				if( e.keyCode == 27 ) $("#msgBox_cancel").trigger('click');
4944			});
4945			$("#msgBox_yes, #msgBox_no").keypress( function(e) {
4946				if( e.keyCode == 13 ) $("#msgBox_yes").trigger('click');
4947					if( e.keyCode == 27 ) $("#msgBox_no").trigger('click');
4948				});*/
4949
4950		},
4951
4952		_hide: function() {
4953			$("#msgBox_container").remove();
4954			this._overlay('hide');
4955			this._maintainPosition(false);
4956		},
4957
4958		_overlay: function(status) {
4959			switch( status ) {
4960				case 'show':
4961					this._overlay('hide');
4962					$("BODY").append('<div id="msgBox_overlay"></div>');
4963					$("#msgBox_overlay").css({
4964						position: 'absolute',
4965						zIndex: 99998,
4966						top: '0px',
4967						left: '0px',
4968						width: '100%',
4969						height: $(document).height(),
4970						background: this.overlayColor,
4971						opacity: this.overlayOpacity
4972					});
4973				break;
4974				case 'hide':
4975					$("#msgBox_overlay").remove();
4976				break;
4977			}
4978		},
4979
4980		_reposition: function() {
4981            var windowHeight = $(window).height() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
4982                windowWidth = $(window).width() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
4983                windowScrollTop =  $(window).scrollTop() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
4984                windowScrollLeft =  $(window).scrollLeft() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
4985			    top = ((windowHeight / 2) - ($("#msgBox_container").outerHeight() / 2)) + this.verticalOffset,
4986			    left = ((windowWidth / 2) - ($("#msgBox_container").outerWidth() / 2)) + this.horizontalOffset;
4987			if( top < 0 ) top = 0;
4988			if( left < 0 ) left = 0;
4989
4990			// IE6 fix
4991			if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + windowScrollTop;
4992
4993			$("#msgBox_container").css({
4994				top: top + windowScrollTop + 'px',
4995				left:  left + windowScrollLeft + 'px'
4996			});
4997			$("#msgBox_overlay").height( $(document).height() );
4998		},
4999
5000		_maintainPosition: function(status) {
5001			if( this.repositionOnResize ) {
5002				switch(status) {
5003					case true:
5004						$(window).on('resize', this._reposition);
5005					break;
5006					case false:
5007						$(window).off('resize', this._reposition);
5008					break;
5009				}
5010			}
5011		}
5012
5013	};
5014})($, window._);/*************************************************************************
5015 * ADOBE CONFIDENTIAL
5016 * ___________________
5017 *
5018 *  Copyright 2016 Adobe Systems Incorporated
5019 *  All Rights Reserved.
5020 *
5021 * NOTICE:  All information contained herein is, and remains
5022 * the property of Adobe Systems Incorporated and its suppliers,
5023 * if any.  The intellectual and technical concepts contained
5024 * herein are proprietary to Adobe Systems Incorporated and its
5025 * suppliers and are protected by all applicable intellectual property
5026 * laws, including trade secret and copyright laws.
5027 * Dissemination of this information or reproduction of this material
5028 * is strictly forbidden unless prior written permission is obtained
5029 * from Adobe Systems Incorporated.
5030 **************************************************************************/
5031
5032
5033(function(_, $, xfalib){
5034    xfalib.view.util.HtmlUtil = {
5035        /*
5036        * Most of the time it returns undefined while accessing an undefined attribute of a dom element.
5037        * But some browsers can throw specific exceptions while accessing an attribute which is un-supported for a specific case.
5038        * This API is to make this behaviour consistent across browsers and return undefined for un-supported attributes.
5039        * */
5040        getHTMLSupportedAttr : function($domElement, attr){
5041           try{
5042               return $domElement[attr];
5043            }
5044           catch (err){
5045               return undefined;
5046            }
5047        },
5048
5049        /**
5050         * Checks if the attribute is supported for the given HTML element.
5051         * This is primarily useful to support HTML5 features in widgets
5052         * @param element       name of HTML element
5053         * @param attribute     attribute to check on the element
5054         * @returns {boolean}
5055         */
5056        elementSupportsAttribute : function (element, attribute) {
5057            var test = document.createElement(element);
5058            if (attribute in test) {
5059                $(test).remove();
5060                test = null;
5061                return true;
5062            } else {
5063                $(test).remove();
5064                test = null;
5065                return false;
5066            }
5067        }
5068    }
5069})(_, $, xfalib);
5070/*************************************************************************
5071*
5072* ADOBE CONFIDENTIAL
5073* ___________________
5074*
5075*  Copyright 2013 Adobe Systems Incorporated
5076*  All Rights Reserved.
5077*
5078* NOTICE:  All information contained herein is, and remains
5079* the property of Adobe Systems Incorporated and its suppliers,
5080* if any.  The intellectual and technical concepts contained
5081* herein are proprietary to Adobe Systems Incorporated and its
5082* suppliers and are protected by trade secret or copyright law.
5083* Dissemination of this information or reproduction of this material
5084* is strictly forbidden unless prior written permission is obtained
5085* from Adobe Systems Incorporated.
5086**************************************************************************/
5087
5088
5089
5090(function(_, $, xfalib){
5091    xfalib.view.util.Styles = {
5092        xfaUtil : xfalib.ut.XfaUtil.prototype,
5093        _deviceResolution :  144.0, //DPI
5094        _in2mmFactor : 25.4,
5095        _pdfResolution : 72.0 ,
5096        getStyleForEdge : function (edgeElement, str, cssStyleObj){
5097            var style = { "raised" : "outset" ,
5098                "dashDot" : "dashed" ,
5099                "dashDotDot" : "dashed" ,
5100                "dashed" : "dashed" ,
5101                "dotted" : "dotted" ,
5102                "embossed" : "groove" ,
5103                "etched" : "inset" ,
5104                "lowered" : "ridge",
5105                "solid" : "solid"};
5106            if(edgeElement && edgeElement.jsonModel.presence != "hidden" && edgeElement.jsonModel.presence !="invisible") {
5107                cssStyleObj['border'+str+'width'] = this._subPixelValue(this._convertToPx(edgeElement.getAttribute('thickness'))) || "1px";
5108                if(edgeElement.getElement("color") && edgeElement.getElement("color").getAttribute("value") !="")  {
5109                    var color =   edgeElement.getElement("color").getAttribute("value");
5110                    color = "rgb(" + color + ")";
5111                    cssStyleObj['border'+str+'color']   = color  ;
5112                }
5113                else {
5114                    cssStyleObj['border'+str+'color'] = "rgb(0,0,0)"  ;
5115                }
5116                cssStyleObj['border'+str+'style']   = style[edgeElement.getAttribute('stroke')] || "solid" ;
5117            } else {
5118                cssStyleObj['border'+str+'width'] =  "0px";
5119                return 1;
5120            }
5121
5122        },
5123
5124        getStyleForBorder : function (border) {
5125            if(border) {
5126                var edge  =  border.getElement('edge', 0, true),
5127                    edge1 = border.getElement('edge', 1, true),
5128                    edge2 = border.getElement('edge', 2, true),
5129                    edge3 = border.getElement('edge', 3, true);
5130                if(edge || edge1 || edge2 || edge3) {
5131                    var cssStyleObj = {} ;
5132                    var e0 = this.getStyleForEdge(edge, "-top-",cssStyleObj);
5133                    var e1 = this.getStyleForEdge(edge1 || edge,"-right-",cssStyleObj);
5134                    var e2 = this.getStyleForEdge(edge2|| edge,"-bottom-",cssStyleObj);
5135                    var e3 = this.getStyleForEdge(edge3 || edge,"-left-",cssStyleObj);
5136                    if(e0 !=1|| e1 !=1|| e2 !=1|| e3!=1)
5137                        return cssStyleObj ;
5138                }
5139            }
5140                return null;
5141        },
5142
5143        _convertToPx : function(size){
5144            if(!size)
5145                return 0;
5146            size = "" + size;
5147            var pxSize = size;
5148            if(size.indexOf("in") >=0){
5149                pxSize = this._mm2px(parseFloat(size) * this._in2mmFactor);
5150            }
5151            else if(size.indexOf("mm") >=0){
5152                pxSize = this._mm2px(size);
5153            }
5154            else if(size.indexOf("cm") >=0){
5155                pxSize = this._mm2px(parseFloat(size) * 10);
5156            }
5157            else if(size.indexOf("pt") >=0){
5158                pxSize = parseFloat(size) * (this._deviceResolution/this._pdfResolution);
5159            }
5160            else if(size.indexOf("px") >=0){
5161                pxSize = parseFloat(size);
5162            }
5163            return pxSize;
5164        },
5165
5166        _mm2px : function(mmSize){
5167            var mmSizeNum = 0;
5168            if(_.isNumber(mmSize))
5169                mmSizeNum = mmSize;
5170            else{
5171                mmSizeNum = parseFloat(mmSize)
5172            }
5173            var mm2in = 1/25.4 ;
5174            var pxSize = mmSizeNum*mm2in*this._deviceResolution;
5175            return pxSize;
5176        },
5177
5178        _subPixelValue : function(value){
5179            if(value > 0.01)
5180                return Math.max(value, 1.0);
5181            else
5182                return value;
5183        }
5184    }
5185})(_, $, xfalib);
5186/*************************************************************************
5187 * ADOBE CONFIDENTIAL
5188 * ___________________
5189 *
5190 *  Copyright 2017 Adobe Systems Incorporated
5191 *  All Rights Reserved.
5192 *
5193 * NOTICE:  All information contained herein is, and remains
5194 * the property of Adobe Systems Incorporated and its suppliers,
5195 * if any.  The intellectual and technical concepts contained
5196 * herein are proprietary to Adobe Systems Incorporated and its
5197 * suppliers and are protected by all applicable intellectual property
5198 * laws, including trade secret and copyright laws.
5199 * Dissemination of this information or reproduction of this material
5200 * is strictly forbidden unless prior written permission is obtained
5201 * from Adobe Systems Incorporated.
5202 **************************************************************************/
5203
5204
5205
5206
5207(function(_, $, xfalib){
5208    xfalib.view.util.traversalManager = {
5209
5210        // compute tabIndex for the provided page
5211        _computTabIndex : function (pageView) {
5212            var pageNum = pageView._pageNumber(),
5213                tabIndex = this._tabIndexBasedOnRange(pageNum);
5214            this.geographicalOrder = [];
5215            this._createGeographicalOrder(pageView);
5216            this._createFinalTraversalOrder(tabIndex); // assign tab index using traversal element and geographicalOrder
5217            // keep tracks of the last field on the page to get tab index so that handler to render next page can be added on getting focus through tabbing
5218            this._lastFieldTabbed = null;
5219        },
5220
5221        _tabIndexBasedOnRange : function (pageNum) {
5222            var behaviorConfig = new xfalib.ut.Version(formBridge.userConfig["behaviorConfig"]),
5223                tabIndexConfig = (behaviorConfig.isOn('mfRangeTabIndex')|| behaviorConfig.isOn('rangeTabIndex')),
5224                /*assuming single page can not have more than 1000 fields.[index -> 0 to 999]
5225                  this is also configurable by passing the maximum number of fields allowable in the page
5226                  in the config parameter */
5227                maxFieldInPageForTabIndex = tabIndexConfig? parseInt(tabIndexConfig):1000;
5228
5229            return pageNum * maxFieldInPageForTabIndex;
5230        },
5231
5232        // to create geographical order array which will be containing all the views in the geographical order
5233        _createGeographicalOrder : function (currentView) {
5234            var sortedChildViewWrapper = this._sortViewGeographically(currentView.childViews);
5235            _.each(sortedChildViewWrapper, function (wrapper) {
5236                var currentView = wrapper.view,
5237                    instanceCheckMap = this._getMapOfInstanceCheck(currentView),
5238                    isViewEligibleForTabbing = this._isViewEligibleForTabbing(currentView);
5239                //  If the child view is fieldView, drawView, exclGroupView or subformView then we will push these views in this.geographicalOrder array,
5240                //  as we need their traverse object during final traversing
5241                if (((instanceCheckMap.isField && !instanceCheckMap.isChildOfExclGroup) || instanceCheckMap.isSubform || instanceCheckMap.isDraw
5242                    || instanceCheckMap.isExclGroup) && isViewEligibleForTabbing) {
5243                    this.geographicalOrder.push({
5244                        view : currentView,
5245                        visited : false
5246                    });
5247                }
5248                if (instanceCheckMap.isContainer && isViewEligibleForTabbing) {
5249                    this._createGeographicalOrder(currentView);
5250                }
5251            }, this);
5252        },
5253
5254        // to sort provided views in geographical order
5255        _sortViewGeographically : function (views) {
5256            var viewsWrapper = [];   // wrapper of view and their geographical reference
5257            _.each(views, function(view) {
5258                var position = view.$el.offset(),
5259                    paddedX = xfalib.ut.XfaUtil.prototype.padString(parseInt(position.left), 5, '0'),
5260                    marginTop = view._marginTop(),
5261                    paddedY = position.top - parseFloat(marginTop),
5262                    positionalReference = parseInt("" + parseInt(paddedY) + paddedX);
5263                viewsWrapper.push({
5264                    positionalReference: positionalReference,
5265                    view: view
5266                });
5267            });
5268            return _.sortBy(viewsWrapper, function(viewWrapper){ return viewWrapper.positionalReference; });
5269        },
5270
5271        // Walk through views in geographical order and assign tab index honouring traversal object if present
5272        _createFinalTraversalOrder : function (tabIndex) {
5273            var geographicalOrderLength = this.geographicalOrder.length,
5274                currentWrappedObj = null,
5275                index = -1,
5276                traversalIndex = 0,  // index of the element to be traversed
5277                viewTraversed = 0;  // counter of view traversed
5278
5279            while (1) {
5280                if (traversalIndex >= geographicalOrderLength) {
5281                    traversalIndex = 0;
5282                }
5283                currentWrappedObj = this.geographicalOrder[traversalIndex];
5284
5285                if (!currentWrappedObj || currentWrappedObj.visited) {  // if the wrapped object does not exist or it has been visited move to the next one
5286                    traversalIndex++;
5287                } else {
5288                    currentWrappedObj.visited = true;
5289                    viewTraversed++;
5290                    var currentView = currentWrappedObj.view,
5291                        instanceCheckMap = this._getMapOfInstanceCheck(currentView),
5292                        currentModel = currentView.model,
5293                        nextView = null,
5294                        nextViewSom = null;
5295
5296                    // get the first traversal of the subform if traversal object is present, else move to the next geographical element
5297                    // next of the subform will be taken care when we will be finding the next view to be traversed,
5298                    // as we will be checking if the ancestor contain next before moving to geographically next view
5299                    if (instanceCheckMap.isSubform) {
5300                        if (currentModel && currentModel.getTraversalObject()) {
5301                            // get the first element to be traversed and update traversalIndex
5302                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.firstTraversal);
5303                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5304                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5305                        } else {
5306                            traversalIndex++;
5307                        }
5308                    // get the next traversal for the field/draw if traversal object is present, else move to the next geographical element
5309                    // update the tabindex for the field
5310                    } else if (instanceCheckMap.isField || instanceCheckMap.isDraw) {
5311                        if (instanceCheckMap.isField) {
5312                            currentView.updateTabIndex(tabIndex);
5313                            this._lastFieldTabbed = currentView;
5314                            tabIndex++;
5315                        }
5316                        if (currentModel && currentModel.getTraversalObject()) {
5317                            //get next element to be traversed and update traversalIndex
5318                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5319                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5320                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5321                        } else {
5322                            traversalIndex = this._findNextViewToBeTraversed(traversalIndex);
5323                        }
5324                    // if traversal object present get the next element to be traversed, if first is also present then update tab index of the first element
5325                    // else look for the traversal element in the children
5326                    } else if (instanceCheckMap.isExclGroup) {
5327                        if (currentModel && currentModel.getTraversalObject()) {
5328                            // get next element to be traversed and update traversalIndex
5329                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5330                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5331                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5332                            // if first is also present assign tab index to that referred child else assign same tab index to all child
5333                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.firstTraversal);
5334                            tabIndex = this._updateTabIndexOfExclGroupChildren(currentView, tabIndex, nextViewSom);
5335                        } else {
5336                            tabIndex = this._updateTabIndexOfExclGroupChildren(currentView, tabIndex);
5337                            traversalIndex = this._findTraversalInExclGroupChildren(currentView, traversalIndex);
5338                        }
5339                    } else {
5340                        traversalIndex++;
5341                    }
5342                }
5343
5344                // if all the view are traversed, we have assigned tab index to all the views
5345                if (viewTraversed >= geographicalOrderLength) {
5346                    this._renderNextPageFuture();
5347                    break;
5348                }
5349            }
5350        },
5351
5352        // Check if the nextView is a sibling of the currentView (shares the same parent)
5353        // if it is not a sibling, check if the parent has a NEXT traversal.
5354        // if so get the node traversed to else recurse to see if nextView is a sibling of our parent
5355        // return -1 if the provided next node is sibling of current node or if no ancestor contain next traversal
5356        // else return index of the next traversal object of parent
5357        _getParentNextTraversal : function (currentView, nextView, traversalIndex) {
5358            var parentView = currentView.parentView,
5359                parentModel = parentView.model,
5360                nextViewParentModel = nextView.parentView.model,
5361                traversalObj = null,
5362                nextIndex = -1;
5363
5364            if (parentModel && nextViewParentModel && parentModel.somExpression != nextViewParentModel.somExpression) {
5365                if(parentView && parentView instanceof xfalib.view.SubformView) {
5366                    if (parentModel.getTraversalObject()) {
5367                        var nextViewSom = parentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5368                        nextIndex = this._findViewInGeographicalOrderArray(nextViewSom);
5369                        if (nextIndex != -1 && !this.geographicalOrder[
5369nextIndex].visited) {
5370                            return nextIndex;
5371                        } else {
5372                            return traversalIndex++;
5373                        }
5374                    } else {
5375                        this._getParentNextTraversal(parentView, nextView, traversalIndex);
5376                    }
5377                } else {  // parentView is not a subform so skip up a level and re-check sibling
5378                    this._getParentNextTraversal(parentView, nextView, traversalIndex);
5379                }
5380            } else {
5381                return -1;  //provided currentView and nextView are sibling
5382            }
5383            return traversalIndex++;
5384        },
5385
5386        // return the index of the view having provided somExpression in the geographicalOrder array
5387        _findViewInGeographicalOrderArray : function (somExpression) {
5388            return _.findIndex(this.geographicalOrder, function (viewWrapper) {
5389                var currentViewModel = viewWrapper.view.model;
5390                return (currentViewModel && currentViewModel.somExpression == somExpression);
5391            });
5392        },
5393
5394        // find the next element to be traversed based on the provided traversalIndex
5395        _findNextViewToBeTraversed : function (traversalIndex) {
5396            var currentView = this.geographicalOrder[traversalIndex].view,
5397                index = this._getNextUnvisited(traversalIndex),   //get next unvisited based on geographical location
5398                nextView = null,
5399                nextIndex = -1;
5400
5401            if (index != -1) {
5402                nextView = this.geographicalOrder[index].view;
5403                //check if both are sibling and if not find the next of the parent and update traversalIndex
5404                nextIndex = this._getParentNextTraversal(currentView, nextView, traversalIndex);
5405                return nextIndex != -1 ? nextIndex : index;
5406            }
5407            return traversalIndex++;
5408        },
5409
5410        // return the next unvisited node based on geographical location
5411        // starting from the traversalIndex and wraps around to check all the views
5412        _getNextUnvisited : function (traversalIndex) {
5413            var geographicalOrderLength = this.geographicalOrder.length,
5414                index = 0,
5415                actualIndex = 0;
5416            while(index < geographicalOrderLength) {
5417                actualIndex = (index + traversalIndex) % geographicalOrderLength;
5418                if(!this.geographicalOrder[actualIndex].visited) {
5419                    return actualIndex;
5420                }
5421                index++;
5422            }
5423            return -1;
5424        },
5425
5426        // assign same tab index to all the child of exclude group
5427        // if exclude group contain first traverse object, then the child being referred as first should have less tabindex
5428        // compared to other child
5429        _updateTabIndexOfExclGroupChildren : function (exclGroupView, tabIndex, firstChildSom) {
5430            _.each(exclGroupView.childViews, function(child){
5431                if (this._isViewEligibleForTabbing(child)) {
5432                    if(firstChildSom && child.model.somExpression == firstChildSom) {
5433                        tabIndex++;
5434                        child.updateTabIndex(tabIndex-1);
5435                        this._lastFieldTabbed = child;
5436                    } else {
5437                        child.updateTabIndex(tabIndex);
5438                    }
5439                }
5440            }, this);
5441            if (!firstChildSom) {
5442                this._lastFieldTabbed = exclGroupView.childViews[0];
5443            }
5444            return ++tabIndex;
5445        },
5446
5447        // find if any child contains next pointer and update traversal index
5448        // start with the last in the geographical order of the children and find child which have next traversal
5449        _findTraversalInExclGroupChildren : function (exclGroupView, traversalIndex) {
5450            var sortedChildView = this._sortViewGeographically(exclGroupView.childViews),
5451                tempObj = null,
5452                childView = null,
5453                childModel = null,
5454                traversalObj = null,
5455                nextViewSom = null,
5456                index = -1;
5457
5458            sortedChildView.reverse();
5459            tempObj = _.find(sortedChildView, function(child) {
5460                childView = child.view;
5461                childModel = childView.model;
5462                if(childModel && (traversalObj = childModel.getTraversalObject())) {
5463                    return traversalObj.length > 0;
5464                }
5465            });
5466
5467            if (tempObj) {
5468                nextViewSom = tempObj.model.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5469                index = this._findViewInGeographicalOrderArray(nextViewSom);
5470                traversalIndex = index != -1 ? index : traversalIndex + 1;
5471            } else { // else get next unvisited based on geographical location
5472                traversalIndex = this._findNextViewToBeTraversed(traversalIndex);
5473            }
5474            return traversalIndex;
5475        },
5476
5477        // check if the view is initialized and visible
5478        _isViewEligibleForTabbing : function (view) {
5479            if (view._initialized && view.$el.css("visibility") != "hidden") {
5480                return true;
5481            }
5482            return false;
5483        },
5484
5485        // return map of whethter provided view is instance of the various views
5486        _getMapOfInstanceCheck : function (view) {
5487            var instanceCheckMap = {};
5488            instanceCheckMap.isSubform = view instanceof xfalib.view.SubformView;
5489            instanceCheckMap.isField = view instanceof xfalib.view.FieldView;
5490            instanceCheckMap.isDraw = view instanceof xfalib.view.XfaDrawView;
5491            instanceCheckMap.isExclGroup = view instanceof xfalib.view.ExclGroupView;
5492            instanceCheckMap.isChildOfExclGroup = view.parentView instanceof xfalib.view.ExclGroupView;
5493            instanceCheckMap.isContainer = view instanceof xfalib.view.ContainerView;
5494
5495            return instanceCheckMap;
5496        },
5497
5498        // add event handler for rendering next page on tabbing on last field of the page
5499        _renderNextPageFuture : function () {
5500            if (this._lastFieldTabbed) {
5501                this._lastFieldTabbed.$el.one('focusin.traversalManager', function() {
5502                    var pagingManager = window.formBridge ? window.formBridge.pagingManager() : null;
5503                    $(window).on( "keyup.traversalManager", function (e) {
5504                        var code = (e.keyCode ? e.keyCode : e.which);
5505                        if (code == 9 && pagingManager && pagingManager.hasMorePages()) {
5506                            pagingManager.renderNextPage();
5507                            $(window).off("keyup.traversalManager");
5508                        }
5509                    });
5510                });
5511            }
5512        },
5513        _destroy : function() {
5514            this.geographicalOrder = null;
5515        }
5516    }
5517})(_, $, xfalib);
5518/*************************************************************************
5519*
5520* ADOBE CONFIDENTIAL
5521* ___________________
5522*
5523*  Copyright 2013 Adobe Systems Incorporated
5524*  All Rights Reserved.
5525*
5526* NOTICE:  All information contained herein is, and remains
5527* the property of Adobe Systems Incorporated and its suppliers,
5528* if any.  The intellectual and technical concepts contained
5529* herein are proprietary to Adobe Systems Incorporated and its
5530* suppliers and are protected by trade secret or copyright law.
5531* Dissemination of this information or reproduction of this material
5532* is strictly forbidden unless prior written permission is obtained
5533* from Adobe Systems Incorporated.
5534**************************************************************************/
5535
5536
5537
5538(function(_, $, xfalib){
5539
5540    var ErrorManager = xfalib.view.util.ErrorManager = xfalib.ut.Class.extend({
5541
5542        options: {
5543            warningMessageVisible:false,
5544            errorMessageVisible: false
5545        },
5546
5547        initialize: function () {
5548            $(window).on("destroy.xfa", function () {
5549                $("#error-msg").hide();
5550                $("#warning-msg").hide();
5551            });
5552        },
5553
5554        onFieldEnter: function (jqWidget) {
5555            var element = jqWidget.element;
5556            if (jqWidget.option("errorMessage")|| jqWidget.option("warningMessage")) {
5557                var pos = $(element).offset(),
5558                    styles = {};
5559                styles.left = (pos.left * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + element.width() + 5) + "px";
5560                styles.top = pos.top * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + "px";
5561                if (jqWidget.option("errorMessage")) {
5562                    jqWidget.$css($("#error-msg").get(0), styles);
5563                    $("#error-msg").text(jqWidget.option("errorMessage")).show();
5564                    jqWidget.option("errorMessageVisible",true);
5565                }
5566                else if (jqWidget.option("warningMessage")) {
5567                    jqWidget.$css($("#warning-msg").get(0), styles);
5568                    $("#warning-msg").text(jqWidget.option("warningMessage")).show();
5569                    jqWidget.option("warningMessageVisible",true);
5570                }
5571            }
5572        },
5573
5574        onFieldExit: function (jqWidget) {
5575            if (jqWidget.option("errorMessageVisible")) {
5576                $("#error-msg").hide();
5577                jqWidget.option("errorMessageVisible",false);
5578            } else if (jqWidget.option("warningMessageVisible")) {
5579                $("#warning-msg").hide();
5580                jqWidget.option("warningMessageVisible",false);
5581            }
5582        },
5583
5584        markError: function (jqWidget, msg, type) {
5585            // assigning role="alert" so that JAWS reads-out the validation message
5586            if (type != "warning") {
5587                if ($("#error-msg").length < 1)
5588                    $("<div id='error-msg' role='alert'></div>").appendTo('body');
5589                jqWidget.option("errorMessage",msg);
5590                jqWidget.element.addClass("dataInvalid");
5591            } else {
5592                if ($("#warning-msg").length < 1)
5593                    $("<div id='warning-msg' role='alert'></div>").appendTo('body');
5594                jqWidget.option("warningMessage",msg);
5595            }
5596
5597        },
5598
5599        clearError: function (jqWidget) {
5600            this.onFieldExit(jqWidget);
5601            jqWidget.element.removeClass("dataInvalid");
5602            jqWidget.option("errorMessage",null);
5603            jqWidget.option("warningMessage",null);
5604        }
5605    });
5606})(_, $, xfalib);
5607(function(_,$, xfalib) {
5608    var xfaUtil = xfalib.ut.XfaUtil.prototype,
5609        BUFFER_SPC = 20;
5610
5611    /* template for the clear Button */
5612    var clearButtonTemplate = '<div class="dp-clear">' +
5613        '<a></a>' +
5614        '</div>';
5615
5616    /* template for the calendar
5617    * header contains the navigation icons (left and right arrows)
5618    * and the current caption (which can be date, year or month)
5619    *
5620    * monthview displays the grid for showing the dates for a particular
5621    * month
5622    *
5623    * yearview displays all the months of that year
5624    *
5625    * yearsetview displays a grid of 16 years. This can be configured
5626    * through the option: yearsPerView
5627    *
5628    */
5629    var calendarTemplate = '<div class="dp-header">' +
5630        '<div class="dp-leftnav"></div>' +
5631        '<div class="dp-caption"></div>' +
5632        '<div class="dp-rightnav"></div>' +
5633        '</div>' +
5634        '<div role="table" class="view dp-monthview"></div>' +
5635        '<div role="table" class="view dp-yearview"></div>' +
5636        '<div role="table" class="view dp-yearsetview"></div>';
5637
5638    /*template for the timer: not implemented yet */
5639    var watchTemplate = '<div class="dp-header">' +
5640        '<div class="dp-leftnav"></div>' +
5641        '<div class="dp-caption"></div>' +
5642        '<div class="dp-rightnav"></div>' +
5643        '</div>' +
5644        '<div class="view dp-monthview"></div>' +
5645        '<div class="view dp-yearview"></div>' +
5646        '<div class="view dp-yearsetview"></div>';
5647
5648    /** default configuration options
5649     *
5650     * container: the html element where the datepicker template will be added
5651     *
5652     * yearsPerView: number of years to show in the yearset view
5653     *
5654     * width: with of the widget
5655     *
5656     * viewHeight: Height of the month,year and yearset view. This doesn't include
5657     *             the height of the header
5658     *
5659     * locale: locale information for the locale in which to show the datepicker which comprises of
5660     *        days: day names to display in the monthview
5661     *        months: month names to display in the yearview
5662     *        zero: string representation of zero in the locale. Numbers will be
5663     *              displayed in that locale only
5664     *        clearText: Text to display for the reset button
5665     *        name: name of the locale
5666     *
5667     * format: input format for the datepicker (not implemented)
5668     *
5669     * pickerType: type of the datetimepicker (date, datetime and time)
5670     *
5671     * positioning: element around which datepicker will be displayed. if null then it
5672     *              will be displayed around the input element
5673     *
5674     * showCalendarIcon: to show the Calendar on the right of the text field or not
5675     */
5676
5677    var defaults = {
5678        container: "body",
5679        yearsPerView: 16,
5680        width: 340,
5681        viewHeight: 248,
5682        locale: {
5683            days:["S","M","T","W","T","F","S"],
5684            months: ["January","February","March","April","May","June","July","August","September","October","November","December"],
5685            zero: "0",
5686            clearText: "Clear",
5687            name:"en_US"
5688        },
5689        format:"YYYY-MM-DD",
5690        pickerType:"date",
5691        positioning: null,
5692        showCalendarIcon: false
5693    },
5694    dates = [31,28,31,30,31,30,31,31,30,31,30,31],
5695    /*
5696     *  Actions to perform when clicked on the datepicker buttons
5697     *  for different views
5698     *  caption: view to show when clicked on caption
5699     *           (Year/YearSet/Month/null) null means don't change the view
5700     *  li: view to show when clicked on date, month or year element
5701     *  upDown: add(up key) or subtract(down key) current date (for monthview),
5702     *          month(Year View) or year(YearSetView) with the number provided
5703     *  key: identifies the key that needs to be changed for that view
5704     */
5705    viewAction = {
5706        Month: {
5707            caption: 'Year',
5708            li: null,
5709            key:"day",
5710            upDown:7
5711        },
5712        Year: {
5713            caption: "Yearset",
5714            li: "Month",
5715            key:"month",
5716            upDown:3
5717        },
5718        Yearset: {
5719            caption: null,
5720            li: "Year",
5721            key:"year",
5722            upDown:4
5723        }
5724    },
5725    headerClass = "header",
5726
5727    DateTimePicker = function() {
5728        this.initialized = false;
5729    }
5730
5731    $.extend(DateTimePicker.prototype, {
5732        /*
5733         * create the widget using the provided options
5734         */
5735        create: function(options) {
5736            var $dp,self = this,html="",prevNavWidth,nextNavWidth;
5737            if (window.FD && window.FD.isToggleEnabled("FT_FORMS-13599")) {
5738                    defaults.width = 433;
5739                }
5740            this.options = $.extend({},defaults,options);
5741            // prevent memory leak since options.positioning holds reference to HTML DOM
5742            this.options.positioning = null;
5743            // If width of date-picker exceeds screen width then it'll take up the entire screen width in AF
5744            if(window.guideBridge && this.options.width > window.innerWidth && window.innerWidth > 0) {
5745               this.options.width=window.innerWidth - BUFFER_SPC; // buffer
5746            }
5747            if(this.options.pickerType.match(/date/)) {
5748                html += calendarTemplate;
5749            }
5750
5751            if(this.options.pickerType.match(/time/)) {
5752                html += watchTemplate;
5753            }
5754
5755            html += clearButtonTemplate;
5756
5757            $.extend(this, {
5758                selectedDay:0,
5759                selectedMonth:0,
5760                selectedYear:0,
5761                currentDay:0,
5762                currentMonth:0,
5763                currentYear:0,
5764                touchSupported : xfalib.ut.TouchUtil.TOUCH_ENABLED,
5765                _visible:false,
5766                _defaultView:"Month",
5767                _keysEnabled:false,
5768                focusedOnDatepickerItem : false,
5769                keyboardAccessibility : true,
5770                $dp:$("<div></div>").addClass("datetimepicker")
5771                                    .width(this.options.width)
5772                                    .append(html)
5773                                    .addClass("datePickerTarget")
5774                                    .appendTo(this.options.container)
5775                                    .toggleClass("datetimepicker-notouch",this.touchSupported),
5776                $month: $(".dp-monthview",this.$dp).height(this.options.viewHeight),
5777                $year: $(".dp-yearview",this.$dp).height(this.options.viewHeight),
5778                $yearset : $(".dp-yearsetview",this.$dp).height(this.options.viewHeight)
5779            });
5780            this.actualWidth = Math.floor(this.$dp.width());
5781            this.$clear = $('.dp-clear a', this.$dp).on("click", $.proxy(this._clearDate, this));
5782            this.$prevNavWidthBtn = $(".dp-leftnav", this.$dp).on("click",
5783                                                            function(evnt) {
5784                                                                self._adjustDate(-1, self.view, false)
5785                                                            });
5786            this.$nextNavWidthBtn = $(".dp-rightnav", this.$dp).on("click",
5787                                                            function(evnt) {
5788                                                                self._adjustDate(1, self.view, false)
5789                                                            });
5790            prevNavWidth = this.$prevNavWidthBtn.outerWidth(true);
5791            nextNavWidth = this.$nextNavWidthBtn.outerWidth(true);
5792            this.$caption = $(".dp-caption", this.$dp).width(this.actualWidth - prevNavWidth - nextNavWidth)
5793                                                     .on("click",
5794                                                            function(evnt) {
5795                                                                if(!self.$caption.hasClass("disabled")) {
5796                                                                    self._layout(viewAction[self.view].caption);
5797                                                                }
5798                                                      });
5799            if (this.keyboardAccessibility) {
5800                _.each([this.$prevNavWidthBtn, this.$caption, this.$nextNavWidthBtn, this.$clear], function (elem, i) {
5801                    elem.attr("tabIndex", i + 1);
5802                });
5803            }
5804            // attach click event on entire datePicker popup
5805            $(this.$dp).on("click",
5806                function(evnt) {
5807                    //focus only if the device doesn't support touch
5808                    // input otherwise on screen keyboard will popup
5809                    if(!self.touchSupported)
5810                        self._curInstance.$field.focus();
5811                });
5812
5813            $(window).on("touchstart.datetimepicker mousedown.datetimepicker",self._checkWindowClicked);
5814            this._curInstance = null;
5815        },
5816
5817        /*
5818         * attaches the date picker to the field. This is a one time operation
5819         * First creates a configuration object and stores it in the field data attributes
5820         * then attaches event handlers on click, focus (to show the picker) and blur (to hide) events
5821         */
5822        _attachField: function($field,options, value) {
5823            var inst = this._newInst($field,options, value),
5824                self = this,
5825                activateField = function(evnt) {
5826                    var data = xfaUtil.$data(evnt.target,"datetimepicker");
5827                    if(self._isFieldDisabled(data)) {
5828                        return;
5829                    }
5830                    if(!self._curInstance)
5831                         self._activateField(evnt);
5832
5833                    if(self.options.showCalendarIcon) {
5834                        if (evnt.type === self.getEvent()) {
5835                            if (self._iconClicked) {
5836                                self._iconClicked = false;
5837                                if (self._visible) {
5838                                    self._hide(); // hide the calendar popup if visible when calendar icon is clicked
5839                                    self._curInstance.$field.focus(); // bring back focus in field
5840                                } else {
5841                                    self._show(); //// show the calendar popup if not visible when calendar icon is clicked
5842                                }
5843                            }
5844                        }
5845                    } else {
5846                        /*show the popup only if
5847                         1. click/touch event
5848                         2. focus event in case of non-touch devices and focus is not done using script
5849                         */
5850                        if (evnt.type === self.getEvent() || (evnt.type === "focus" && !self.touchSupported && !self.scriptFocus)) {
5851                            self._show(evnt);
5852                        }
5853                    }
5854
5855                    self._clickedWindow = true;
5856                    self.scriptFocus = false;
5857                },
5858                deactivateField = function(evnt) {
5859                    //deactivate only if clicked outside window
5860                    // on touch devices only keyboard or calander should be active at once, touching keyboard should deactivate calendar
5861                    if ((self._clickedWindow && !self.focusedOnDatepickerItem) && (self.options.showCalendarIcon || !self.touchSupported)) {
5862                        self._hide();
5863                        self._deactivateField();
5864                        self._clickedWindow = true;
5865                    }
5866                };
5867
5868            xfaUtil.$data($field[0],"datetimepicker",inst);
5869
5870            $field.on(this.getEvent(),activateField)
5871                  .focus(activateField)
5872                  .blur(deactivateField);
5873            if(options.showCalendarIcon) {
5874                var calendarIcon = $("<div></div>")
5875                                    .addClass("datepicker-calendar-icon")
5876                                    .css({
5877                                        "width": options.iconWidth + "px",
5878                                        "height": options.iconHeight + "px"
5879                                    });
5880                calendarIcon.insertAfter($field);
5881
5882                if (this.keyboardAccessibility) {
5883                    calendarIcon.attr("tabindex", 0);
5884                }
5885
5886                calendarIcon.on(this.getEvent(), function (evnt) {
5887                                self._iconClicked = true;
5888                                $field.click();
5889                              })
5890                              .on("keydown", function (event) {
5891                                    if (event.keyCode === 32 || event.keyCode === 13) {
5892                                        // Check if field is disabled before triggering click
5893                                        var data = xfaUtil.$data($field[0], "datetimepicker");
5894                                        if (data && !self._isFieldDisabled(data)) {
5895                                            $field.click();
5896                                        }
5897                                    }
5898                              });
5899            }
5900        },
5901
5902        _newInst: function($f,options, value) {
5903            return {
5904                $field:$f,
5905                locale: options.locale,
5906                positioning: options.positioning || $f,
5907                access:options.access,
5908                selectedDate:options.value,
5909                editValue :options.editValue,
5910                minValidDate : options.minValidDate,
5911                maxValidDate : options.maxValidDate,
5912                exclMinDate :  options.exclMinDate,
5913                exclMaxDate : options.exclMaxDate
5914            }
5915        },
5916
5917        /*
5918         * To check where the click happened, if happened outside the datepicker
5919         * then hide the picker. This is checked whether any ancestor of clicked target
5920         * has a class datePickerTarget. This class is added to the attached element as well
5921         */
5922        _checkWindowClicked : function(evnt) {
5923            var self = adobeDateTimePicker;
5924            if(self._curInstance) {
5925                // datepickerTarget class depicts that the component is a part of the Date Field
5926                // and on click of that class, we should not hide the datepicker or fire exit events.
5927                if(!$(evnt.target).closest(".datePickerTarget").length) {
5928                    //non-touch devices do not deactivate on blur. Hence needs to be done here
5929                    if(self.touchSupported) {
5930                        self._hide()
5931                        //clicking outside a field doesn't blur the field in IPad. Doing it by script
5932                        self._curInstance.$field[0].blur()
5933                        self._deactivateField()
5934                    } else{
5935                        self._clickedWindow = true;
5936                        // set focusedOnDatepickerItem to false, it hides the datepicker see method deactivateField.
5937                        self.focusedOnDatepickerItem = false;
5938                        self._curInstance.$field.blur()
5939                    }
5940                }
5941                else {
5942                    self._clickedWindow = false;
5943                }
5944            }
5945        },
5946
5947        /**
5948         * Checks if the current datepicker field is disabled.
5949         *
5950         * Fields marked as "readOnly" or with access set to false are considered
5951         * disabled and should not allow datepicker interaction.
5952         *
5953         * @param {Object} [data] - Optional data object to check. If not provided, uses current instance.
5954         * @returns {boolean} True if the field is disabled (access is "readOnly" or false), false otherwise.
5955         *                   Returns false if no current instance exists.
5956         */
5957        _isFieldDisabled: function(data) {
5958            if (data) {
5959                return data.access === false || data.access === "readOnly";
5960            }
5961            return this._curInstance && (this._curInstance.access === false || this._curInstance.access === "readOnly");
5962        },
5963
5964        /*
5965         * handling of key strokes. All the key strokes prevent the default browser action
5966         * unless specified otherwise
5967         * tab: set focus on calendar icon when dateinput field is active, navigates through date picker buttons when datepicker is open,
5968         * otherwise perform default browser action
5969         * escape: hides the datepicker
5970         * down arrow key: navigate the picker downwards by the number specified in actionView.upDown of the current View
5971         * up arrow key: navigate the picker upwards by the number specified in actionView.upDown of the current View
5972         * left arrow key: navigate the picker one unit of that view backward
5973         * right arrow key: navigate the picker one unit of that view forward
5974         * shift + up: perform the action that happens on clicking the caption (as specified in actionView.caption)
5975         * shift + left: perform the action that happens on clicking the left navigation button
5976         * shift + right: perform the action that happens on clicking the right navigation button
5977         * space/enter: triggers the click event for the current focused element from datepicker/ opens datepicker when calendar icon is focused.
5978         */
5979        _hotKeys: function(evnt) {
5980            var handled = false, date;
5981            switch(evnt.keyCode) {
5982                case 9: //tab
5983                    // CQ-4239352 : Setting clickedWindow property to true on tabbing so that deactivateField logic gets executed
5984                    // When clicking on "x" on input field in in IE and when selecting the content and releasing the mouse select outside the field
5985                    // the click event is not trigerred on the field and hence activateField is not executed, so clickedWindow remains as false
5986                    adobeDateTimePicker._clickedWindow = true;
5987                    handled = false;
5988                    break;
5989                case 27://escape
5990                    if(this._visible) {
5991                        adobeDateTimePicker._hide();
5992                        this._curInstance.$field.focus();
5993                        handled = true;
5994                    }
5995                    break;
5996                case 32: //space
5997                case 13: // enter
5998                    if($(evnt.target).hasClass("datepicker-calendar-icon")){
5999                        // Check if field is disabled before showing datepicker
6000                        // disabled fields are marked as readOnly in the form
6001                        if(this._isFieldDisabled()) {
6002                            return;
6003                        }
6004                        if(!this._visible) {
6005                            this._show();
6006                            return;
6007                        }
6008                        this.$focusedDate.addClass("dp-focus");
6009                    }
6010                    break;
6011                case 40: //down arrow key
6012                    if(!this._visible) {
6013                        // Check if field is disabled before showing datepicker
6014                        if(this._isFieldDisabled()) {
6015                            return;
6016                        }
6017                        this._show();
6018                        return;
6019                    }
6020                    this.$focusedDate.addClass("dp-focus");
6021                    break;
6022            }
6023
6024            if(adobeDateTimePicker._visible && this._keysEnabled) {
6025                var v = viewAction[this.view].key,
6026                    updown=viewAction[this.view].upDown;
6027                switch(evnt.keyCode) {
6028                    case 9: // tab
6029                        if (evnt.shiftKey) {
6030                            if ($(evnt.target).hasClass("dp-leftnav") || $(evnt.target).hasClass("dp-focus")) {
6031                                this._hide();
6032                                this._curInstance.$field.focus();
6033                                handled = true;
6034                            } else {
6035                                handled = false;
6036                            }
6037                        } else {
6038                            var buttonTabindex = $(evnt.target).attr("tabindex");
6039                            if (buttonTabindex === '0') {
6040                                if (evnt.target.tagName.toLocaleLowerCase() === "input") {
6041                                    this._hide();
6042                                    handled = false;
6043                                } else {
6044                                    this.$prevNavWidthBtn.focus();
6045                                    handled = true;
6046                                }
6047                            } else if (buttonTabindex === '4') {
6048                                this._hide();
6049                                this._curInstance.$field.focus();
6050                                handled = true;
6051                            } else {
6052                                handled = false;
6053                            }
6054                        }
6055                        break;
6056                    case 32: //select on space
6057                    case 13: // select on enter
6058                        this.hotKeyPressed = true;
6059                        this.focusedOnDatepickerItem = false;
6060                        if (!this.focusedOnDatepickerItem) {
6061                            $(evnt.target, this.$dp).triggerHandler("click");
6062                        } else {
6063                            if (this.$focusedDate) {
6064                                this.$focusedDate.trigger("click");
6065                            }
6066                        }
6067                        this.hotKeyPressed = false;
6068                        handled = true;
6069                        break;
6070                    case 37: //left arrow key
6071                        if (evnt.shiftKey) {
6072                            $(".dp-leftnav", this.$dp).triggerHandler("click");
6073                        } else {
6074                            this._adjustDate(-1, v, true);
6075                        }
6076                        handled = true;
6077                        break;
6078                    case 38: //up arrow key
6079                        if (evnt.shiftKey) {
6080                            this.$caption.triggerHandler("click");
6081                        } else {
6082                            this._adjustDate(-updown, v, true);
6083                        }
6084                        handled = true;
6085                        break;
6086                    case 39: //right arrow key
6087                        if (evnt.shiftKey) {
6088                            $(".dp-rightnav", this.$dp).triggerHandler("click");
6089                        } else {
6090                            this._adjustDate(+1, v, true);
6091                        }
6092                        handled = true;
6093                        break;
6094                    case 40: //down arrow key
6095                        this._adjustDate(updown, v, true);
6096                        handled = true;
6097                        break;
6098                    default:
6099                }
6100            }
6101            if(handled) {
6102                evnt.preventDefault();
6103            }
6104        },
6105
6106        /*
6107         * show the datepicker.
6108         */
6109        _show: function() {
6110            if(this._isFieldDisabled())
6111                return;
6112            this.options.locale = this._curInstance.locale;
6113            if(!this._visible) {
6114                var self = this,
6115                    date = new Date(),
6116                    val,
6117                    maxDateInfo,
6118                    minDateInfo,
6119                    validDate;
6120                //Bug#3607735:
6121                // Date constructor in ipad 5.1 doesn't support "YYYY-MM-DD", hence parsing the date on our own
6122                validDate = xfalib.ut.DateInfo.ParseIsoString(this._curInstance.selectedDate);
6123                date = (validDate != null)? validDate.getDate(): new Date();
6124                this.selectedDay = this.currentDay = date.getDate();
6125                this.selectedMonth = this.currentMonth = date.getMonth();
6126                this.selectedYear = this.currentYear = date.getFullYear();
6127                maxDateInfo = this.options.maxValidDate ? xfalib.ut.DateInfo.ParseIsoString(this._curInstance.maxValidDate) : null;
6128                this.maxValidDate = maxDateInfo ? maxDateInfo.getDate() : null;
6129                minDateInfo = this.options.minValidDate ? xfalib.ut.DateInfo.ParseIsoString(this._curInstance.minValidDate) : null;
6130                this.minValidDate = minDateInfo ? minDateInfo.getDate() : null;
6131                this.exclMaxDate = this._curInstance.exclMaxDate;
6132                this.exclMinDate = this._curInstance.exclMinDate;
6133                $('.dp-clear a',this.$dp).text(this.options.locale.clearText);
6134                this._layout('Month');
6135                this._position();
6136                this.$dp.show();
6137                // if li element of datepicker is focused then set focusedOnDatepickerItem to true, it manages the visibility of the datepicker.
6138                this.focusedOnDatepickerItem = false;
6139                this._visible = true;
6140                if (this.options.showCalendarIcon) {
6141                    this._curInstance.$field.attr('readonly', true);    // when the datepicker is active, deactivate the field
6142                }
6143            }
6144
6145            //   Disabling the focus on ipad  due to a bug where value of
6146            // date picker is not being set
6147            // Removing this code will only hamper one use case
6148            // where on ipad if you click on the calander then
6149            // the field becomes read only so
6150            // there is no indication where the current focus is
6151            // And  if you remove this foucs code all together
6152            // then what happens is that on desktop MF in iframe the exit event
6153            // is not getting called hence calander getting remained open even
6154            // when you click somewhere on window or focus into some other field
6155            if (this.options.showCalendarIcon  && !this.touchSupported) {
6156                if(this.$focusedDate.length > 0) {
6157                    this.$focusedDate.focus();  // shift focus on current date or selected date.
6158                } else {
6159                    this._curInstance.$field.focus(); // field loses focus after being marked readonly, causing blur event not to be fired later
6160                }
6161            }
6162        },
6163
6164        /*
6165         * position the datepicker around the positioning element
6166         * provided in the options
6167         */
6168        _position: function() {
6169            var $elem = this._curInstance.positioning,
6170                windowScrollX = window.scrollX/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6171                windowScrollY = window.scrollY/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6172                windowInnerHeight = window.innerHeight/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6173                windowInnerWidth = window.innerWidth/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6174                height = $elem.outerHeight(true),
6175                width  = $elem.outerWidth(true),
6176                top = $elem.offset().top / xfalib.ut.XfaUtil.prototype.formScaleFactor + height,
6177                left = $elem.offset().left / xfalib.ut.XfaUtil.prototype.formScaleFactor,
6178                styles = {"top": (top+"px"), "left": (left+"px")},
6179                diffBottom = top + this.$dp.outerHeight(true) - windowInnerHeight - windowScrollY,
6180                newLeft,
6181                newTop;
6182            if(diffBottom > 0) {
6183                //can't appear at the bottom
6184                //check top
6185                newTop = top - height - this.$dp.outerHeight(true) - BUFFER_SPC;
6186                if(newTop < windowScrollY) {
6187                    //can't appear at the top as well ... the datePicker pop up overlaps the date field
6188                    newTop = top - diffBottom;
6189                    // Fix for BUG #3626974
6190                    if(xfaUtil.isWebkit() && !this.options.showCalendarIcon) {
6191                        this._curInstance.$field.trigger("onoverlap.datetimepicker");
6192                    }
6193                }
6194                styles.top = newTop + "px";
6195            }
6196            if(left + this.$dp.outerWidth(true) > windowScrollX + windowInnerWidth ) {
6197                //align with the right edge
6198                newLeft = windowScrollX + windowInnerWidth - this.$dp.outerWidth(true) - BUFFER_SPC;
6199                styles.left = newLeft + "px";
6200            }
6201            xfaUtil.$css(this.$dp.get(0), styles);
6202            return this;
6203        },
6204
6205        /*
6206         * layout the nextView. if nextView is null return
6207         *
6208         */
6209        _layout: function(nextView) {
6210            if(nextView == null) {
6211                this._hide();
6212            } else {
6213                if(this.view)
6214                    this['$'+this.view.toLowerCase()].hide();
6215                this.view = nextView;
6216                this.$caption.toggleClass("disabled",!viewAction[this.view].caption);
6217                this['$'+this.view.toLowerCase()].show();
6218                this["show"+this.view]();
6219            }
6220            return this;
6221        },
6222
6223        /*
6224         * show the month view
6225         */
6226        showMonth: function() {
6227            var self = this,
6228                curDate = new Date(this.currentYear, this.currentMonth),
6229                maxDay =   this._maxDate(this.currentMonth),
6230                prevMaxDay = this._maxDate((this.currentMonth + 11)%12),
6231                day1 = new Date(this.currentYear,this.currentMonth,1).getDay(),
6232                data,display;
6233
6234            this.tabulateView(
6235                {
6236                    caption: this.options.locale.months[this.currentMonth] + ", "+ this._convertNumberToLocale(this.currentYear),
6237                    header:this.options.locale.days,
6238                    numRows:7,
6239                    numColumns:7,
6240                    elementAt: function(row,col) {
6241                        var day = (row-1)*7 + col - day1 + 1;
6242                        var monthVal = self.currentMonth + 1;
6243                        display = self._convertNumberToLocale(day);
6244                        data = day;
6245                        if(day < 1) {
6246                            display = self._convertNumberToLocale(prevMaxDay + day);
6247                            data = -1;
6248                            monthVal = self.currentMonth;
6249                        }
6250                        else if(day > maxDay) {
6251                            display = self._convertNumberToLocale(day-maxDay);
6252                            data = -1;
6253                            monthVal = self.currentMonth + 2;
6254                        }
6255                        else {
6256                            curDate.setDate(day);
6257                            var compareFn = xfalib.ut.XfaUtil.prototype._compareVal;
6258                            // check if the currentdate is valid based on max and min valid date
6259                            if(compareFn(curDate, self.maxValidDate, self.exclMaxDate) || compareFn(self.minValidDate, curDate, self.exclMinDate)) {
6260                                data = -1;
6261                            }
6262                        }
6263                        return {
6264                            data : data,
6265                            display : display,
6266                            ariaLabel : self.options.editValue(self.currentYear+"-"+self._pad2(monthVal)+"-"+self._pad2(display))
6267                        };
6268                    }
6269                });
6270        },
6271
6272
6273
6274        /*
6275         * show the year view
6276         */
6277        showYear: function() {
6278            var self = this,
6279                minDate = this.minValidDate ? new Date(this.minValidDate.getFullYear(), this.minValidDate.getMonth()) : null,
6280                maxDate = this.maxValidDate ? new Date(this.maxValidDate.getFullYear(), this.maxValidDate.getMonth()) : null,
6281                curDate = new Date(this.currentYear, 0), //can't omit month, if only one param present it is treated as millisecond
6282                data,
6283                month;
6284            this.tabulateView(
6285                {
6286                    caption : this._convertNumberToLocale(this.currentYear),
6287                    numRows : 4,
6288                    numColumns : 3,
6289                    elementAt : function(row,col) {
6290                        data = month =  row*3 + col;
6291                        curDate.setMonth(month);
6292                        if ((minDate && curDate < minDate) || (maxDate && curDate > maxDate)) {
6293                            data = -1;
6294                        }
6295                        return {
6296                            data : data,
6297                            display : self.options.locale.months[month],
6298                            ariaLabel : self.options.locale.months[month] + " " +self.currentYear
6299                        };
6300                    }
6301                });
6302        },
6303
6304        /*
6305         * show the year set view
6306         */
6307        showYearset: function() {
6308            var year,
6309                minDate = this.minValidDate ? new Date(this.minValidDate.getFullYear(), 0
6309) : null ,
6310                maxDate = this.maxValidDate ? new Date(this.maxValidDate.getFullYear() + 1, 0) : null,
6311                curDate = new Date(),
6312                data,
6313                self = this;
6314            this.tabulateView(
6315                {
6316                    caption: this._convertNumberToLocale(this.currentYear - this.options.yearsPerView/2) +"-"+this._convertNumberToLocale(this.currentYear - this.options.yearsPerView/2 + this.options.yearsPerView - 1),
6317                    numRows:4,
6318                    numColumns:4,
6319                    elementAt: function(row,col) {
6320                        data = year =  self.currentYear - 8 + (row*4 + col);
6321                        curDate.setFullYear(year);
6322                        if ((minDate && curDate < minDate) || (maxDate && curDate > maxDate)) {
6323                            data = -1;
6324                        }
6325                        return {
6326                            "data" : data,
6327                            "display" : self._convertNumberToLocale(year),
6328                            ariaLabel : year
6329                        };
6330                    }
6331                });
6332        },
6333
6334        insertRow :  function(rowNum,rowArray,isHeader,height) {
6335            var $view = this["$"+this.view.toLowerCase()],
6336                width = (this.actualWidth)/rowArray.length,
6337                $row = $("ul",$view).eq(rowNum),
6338                items,$li,element,$tmp,
6339                self= this;
6340            if(!$row.length)
6341                $row = $("<ul></ul>").attr("aria-label", "").attr("role", "row").appendTo($view).toggleClass(headerClass,isHeader);
6342            $row.height(height);
6343            items = $("li",$row).length;
6344            while(items++ < rowArray.length) {
6345                $tmp = $("<li></li>").attr("role", "cell").appendTo($row);
6346                if(!isHeader)
6347                    $tmp.on("click", $.proxy(this._selectDate,this));
6348            }
6349
6350            _.each(rowArray, function(el,index) {
6351                $li = $("li",$row).eq(index);
6352                if(isHeader)
6353                    $li.text(rowArray[index]);
6354                else {
6355                    element = rowArray[index];
6356                    xfaUtil.$data($li.get(0), "value", element.data);
6357                    if(self._checkDateIsFocussed(element.data)) {
6358                        if(self.$focusedDate) {
6359                            self.$focusedDate.removeClass("dp-focus");
6360                            self.$focusedDate.attr("tabindex", "-1");
6361                        }
6362                        self.$focusedDate = $li;
6363                        if(self._keysEnabled)
6364                            self.$focusedDate.addClass("dp-focus")
6365                    }
6366                    $li.toggleClass("dp-selected",self._checkDateIsSelected(element.data))
6367                        .toggleClass("disabled", element.data == -1).text(element.display)
6368                        .attr("title", element.ariaLabel)
6369                        .attr("aria-label", element.ariaLabel)
6370                        .attr("tabindex", -1);
6371                }
6372                $li.css( {"height":height+"px","width":width+"px","line-height":height+"px"});
6373            });
6374            return $row;
6375        },
6376
6377        /*
6378         * creates a tabular view based on the options provided. The options that can be passed are
6379         * numRows: number of rows that needs rendering
6380         * numCols: number of columns that needs rendering
6381         * caption: text for the datepickers caption element
6382         * header: an array of elements that identifies the header row
6383         * elementAt: a function(row, column) that returns an object (data: <data>, display: <display>) where
6384         *            <data> is the value to set for that view when the element at (row,column) is clicked and
6385         *            <display> is the value that will be visible to the user
6386         */
6387        tabulateView : function(options) {
6388            var r = 0,rows = 0,
6389                row = [],
6390                ht =  this.options.viewHeight/options.numRows,
6391                c;
6392            this.$caption.text(options.caption);
6393            if(options.header) {
6394                this.insertRow(r++,options.header,true,ht);
6395            }
6396            while(r < options.numRows) {
6397                c = 0;
6398                while(c < options.numColumns) {
6399                    row[c] = options.elementAt(r,c);
6400                    c++;
6401                }
6402                this.insertRow(r++,row,false,ht);
6403            }
6404        },
6405
6406        _activateField : function(evnt) {
6407            this._curInstance = xfaUtil.$data(evnt.target,"datetimepicker");
6408            this._curInstance.$field.trigger("onfocus1.datetimepicker").addClass("datePickerTarget");
6409            // Issue LC-7049:
6410            // datepickerTarget should be added when activate the field and should be removed
6411            // after the fields gets deactivated.
6412            if (this.options.showCalendarIcon) {
6413                this._curInstance.$field.parent().addClass("datePickerTarget");
6414            }
6415            //enable hot keys only for non touch devices
6416            if(!this.touchSupported && !this._keysEnabled) {
6417                $(window).on("keydown.datetimepicker", $.proxy(this._hotKeys,this));
6418                this._keysEnabled = true;
6419            }
6420        },
6421
6422        _deactivateField: function() {
6423            if(this._curInstance) {
6424                if(this._keysEnabled) {
6425                    $(window).off("keydown.datetimepicker")
6426                    this._keysEnabled = false;
6427                }
6428                //Bug#3607499: on deactivate check the value in the input box, if that is
6429                // different than the selected Date, change the selectedDate
6430                //if (this._curInstance.selectedDate != this._curInstance.$field.val()) {
6431                //    this._curInstance.selectedDate = this._curInstance.$field.val();
6432                //}
6433                this._curInstance.$field.trigger("onfocusout.datetimepicker").removeClass("datePickerTarget");
6434                // Issue LC-7049:
6435                // datepickerTarget should be added when activate the field and should be removed
6436                // after the fields gets deactivated. Otherwise clicking on any other datefield
6437                // will not hide the existing datepicker
6438                if (this.options.showCalendarIcon) {
6439                    this._curInstance.$field.parent().removeClass("datePickerTarget");
6440                }
6441                this._curInstance = null;
6442            }
6443        },
6444
6445        _hide: function() {
6446            if(this._visible) {
6447                this.$dp.hide();
6448                this._curInstance.$field.trigger("onclose.datetimepicker");
6449                this._visible = false;
6450                if (this.options.showCalendarIcon) {
6451                    this._curInstance.$field.attr('readonly', false);    // when the datepicker is deactivated, activate the field
6452                }
6453            }
6454        },
6455
6456        _adjustDate: function(step, view, focus) {
6457            var maxDate,prevMaxDate;
6458            var _focus = focus || false;
6459            switch(view.toLowerCase()) {
6460                case "day":
6461                    this.currentDay += step;
6462                    maxDate = this._maxDate(this.currentMonth)
6463                    if(this.currentDay < 1) {
6464                        prevMaxDate =  this._maxDate((this.currentMonth - 1 + 12)%12);
6465                        this.currentDay = prevMaxDate + this.currentDay;
6466                        return this._adjustDate(-1, "month", _focus);
6467                    }
6468                    if(this.currentDay > maxDate) {
6469                        this.currentDay -= maxDate;
6470                        return this._adjustDate(+1, "month", _focus);
6471                    }
6472                    break;
6473                case "month":
6474                    this.currentMonth += step;
6475                    if(this.currentMonth > 11) {
6476                        this.currentYear++;
6477                        this.currentMonth = 0;
6478                    }
6479                    if(this.currentMonth < 0) {
6480                        this.currentYear--;
6481                        this.currentMonth = 11;
6482                    }
6483                    break;
6484                case "year":
6485                    this.currentYear += step;
6486                    break;
6487                case "yearset":
6488                    this.currentYear += step*this.options.yearsPerView;
6489                    break;
6490            }
6491            this._layout(this.view);
6492            if (_focus) {
6493                this.focusedOnDatepickerItem = true;
6494                this.$focusedDate.attr("tabindex", 0)[0].focus();
6495            }
6496        },
6497
6498        _checkDateIsSelected: function(data) {
6499            switch(this.view.toLowerCase()) {
6500                case "month":
6501                    return this.currentYear == this.selectedYear && this.currentMonth == this.selectedMonth && data == this.selectedDay;
6502                case "year":
6503                    return this.currentYear == this.selectedYear && this.selectedMonth == data;
6504                case "yearset":
6505                    return this.selectedYear == data;
6506            }
6507        },
6508
6509        _checkDateIsFocussed: function(data) {
6510            switch(this.view.toLowerCase()) {
6511                case "month":
6512                    return data == this.currentDay;
6513                case "year":
6514                    return this.currentMonth == data;
6515                case "yearset":
6516                    return this.currentYear == data;
6517            }
6518        },
6519
6520        _convertNumberToLocale : function(number) {
6521            var zeroCode = this.options.locale.zero.charCodeAt(0);
6522            number += "";
6523            var newNumber = [];
6524            for(var i = 0;i < number.length;i++) {
6525                newNumber.push(String.fromCharCode(zeroCode + parseInt(number.charAt(i))));
6526            }
6527            return newNumber.join("");
6528        },
6529
6530        _clearDate: function() {
6531            var isDateEmpty = this._curInstance.$field.val() ? false : true;
6532            this.selectedYear
6533                = this.selectedMonth
6534                = this.selectedYear
6535                = -1;
6536            this._curInstance.selectedDate = "";
6537            this._curInstance.$field.val("");
6538            if (!isDateEmpty) {
6539                this._curInstance.$field.trigger("onvaluechange.datetimepicker", [
6540                    {selectedDate: ""}
6541                ]);
6542            }
6543            $(".dp-selected",this['$'+this.view.toLowerCase()]).removeClass("dp-selected");
6544        },
6545
6546        getEvent : function() {
6547            return "click";//this.touchSupported ? "touchstart" : "click";
6548        },
6549
6550        _pad2: function(m) {
6551            return m = m < 10 ?"0"+m:m;
6552        },
6553
6554        toString : function() {
6555            return this.selectedYear +"-"+this._pad2(this.selectedMonth + 1)+"-"+this._pad2(this.selectedDay);
6556        },
6557
6558        _selectDate : function(evnt) {
6559            var val = xfaUtil.$data(evnt.target, "value"),
6560                nextView = viewAction[this.view].li,
6561                editVal;
6562            //disabled dates have a value of -1. Do nothing in that case
6563            if(val == -1)
6564                return;
6565            switch(this.view.toLowerCase()) {
6566                case "month":
6567                    this.selectedMonth = this.currentMonth;
6568                    this.selectedYear = this.currentYear;
6569                    this.selectedDay = val;
6570                    this._curInstance.selectedDate = this.toString();
6571                    editVal = this._curInstance.editValue(this.toString());
6572                    this._curInstance.$field.val(editVal).focus();
6573                    this._curInstance.$field.trigger("onvaluechange.datetimepicker", [
6574                        {selectedDate: editVal}
6575                    ]);
6576                    $(".dp-selected",this['$'+this.view.toLowerCase()]).removeClass("dp-selected");
6577                    $(evnt.target).addClass("dp-selected");
6578                    break;
6579                case "year":
6580                    this.currentMonth = val;
6581                    break;
6582                case "yearset":
6583                    this.currentYear = val;
6584                    break;
6585            }
6586            this._layout(nextView);
6587            //manually focus on the field if clicked on the popup buttons for non-touch device
6588            if(!this.touchSupported) {
6589                //No need to focus if selection is made by pressing space.
6590                if(!this.hotKeyPressed) {
6591                    this.scriptFocus = true;
6592                    if(nextView == null) {
6593                        this.focusedOnDatepickerItem = false;
6594                    }
6595                }
6596            } else if(nextView == null){
6597                //For touch devices, deactivate the field if a selection is made
6598                this.focusedOnDatepickerItem = false;
6599                this._deactivateField()
6600            }
6601        },
6602
6603        _leapYear : function() {
6604            return this.currentYear % 400 == 0 || (this.currentYear % 100 != 0 && this.currentYear % 4 == 0);
6605        },
6606
6607        _maxDate : function(m) {
6608            if(this._leapYear() && m == 1)
6609                return 29;
6610            else return dates[m];
6611        },
6612
6613        _access: function(val) {
6614            if(typeof val == "undefined")
6615                return this.access
6616            this.access = val;
6617        },
6618
6619        _value:function(val) {
6620            if(typeof val == "undefined")
6621                return this.$field.val()
6622            else {
6623                this.selectedDate = val;
6624                var editValue = this.editValue(val);
6625                // update the field val with provided value instead of null
6626                if (!editValue) {
6627                    editValue = val;
6628                }
6629                this.$field.val(editValue);
6630            }
6631        }
6632    });
6633
6634    var adobeDateTimePicker = new DateTimePicker();
6635
6636    $.fn.adobeDateTimePicker = function(options, value) {
6637        if(!adobeDateTimePicker.initialized) {
6638            adobeDateTimePicker.create(options);
6639            adobeDateTimePicker.initialized = true;
6640        }
6641        if(typeof options === "object") {
6642            adobeDateTimePicker._attachField(this, options);
6643        }
6644        else if(typeof options === "string") {
6645            if(arguments.length == 2)
6646                adobeDateTimePicker["_"+options].apply(xfaUtil.$data(this[0],"datetimepicker"),[value])
6647            else
6648                return adobeDateTimePicker["_"+options].apply(xfaUtil.$data(this[0],"datetimepicker"))
6649        }
6650        return this;
6651    }
6652})(_, $, xfalib);
6653(function (xfalib) {
6654    xfalib.ut.TouchUtil = (function () {
6655        var touchAvailable = !!("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch) ,
6656            pointerEnabled = !!(window.MSPointerEvent || window.PointerEvent) ,
6657            POINTER_DOWN_EVENT = "mousedown",
6658            POINTER_MOVE_EVENT = "mousemove",
6659            POINTER_UP_EVENT = "mouseup",
6660            EVENT_TYPE = "MouseEvent";
6661
6662        if (window.PointerEvent) { //> IE11
6663            POINTER_DOWN_EVENT = "pointerdown";
6664            POINTER_MOVE_EVENT = "pointermove";
6665            POINTER_UP_EVENT = "pointerup";
6666            EVENT_TYPE = "PointerEvent";
6667
6668        } else if (window.MSPointerEvent) { // IE10
6669            POINTER_DOWN_EVENT = "MSPointerDown";
6670            POINTER_MOVE_EVENT = "MSPointerMove";
6671            POINTER_UP_EVENT = "MSPointerUp";
6672            EVENT_TYPE = "MSPointerEvent" ;
6673
6674        } else if (touchAvailable) {  // other touch devices
6675            POINTER_DOWN_EVENT = "touchstart";
6676            POINTER_MOVE_EVENT = "touchmove";
6677            POINTER_UP_EVENT = "touchend";
6678            EVENT_TYPE = "TouchEvent";
6679        }
6680        return {
6681            TOUCH_ENABLED: touchAvailable,
6682            // new MS Pointer Events
6683            POINTER_EVENT: EVENT_TYPE,
6684            POINTER_ENABLED: pointerEnabled,
6685            POINTER_DOWN: POINTER_DOWN_EVENT,
6686            POINTER_MOVE: POINTER_MOVE_EVENT,
6687            POINTER_UP: POINTER_UP_EVENT,
6688            getTouchEvent: function (evt) {
6689                var target;
6690                if (pointerEnabled) {
6691                    target = evt.originalEvent;
6692                } else if (touchAvailable) {
6693                    target = evt.originalEvent || evt;
6694                    target = target.touches[0];
6695                    //if (evt.originalEvent && evt.originalEvent.changedTouches && evt.originalEvent.changedTouches[0]) {
6696                    //    te = evt.originalEvent.changedTouches[0];
6697                    //}
6698                }
6699
6700                return target || evt;
6701            },
6702            getPointerEvent: function (eventType) {
6703                var event = null;
6704                if ((typeof PointerEvent) === "function") {
6705                    event = new PointerEvent(eventType, {
6706                        bubbles: true,
6707                        cancelable: true
6708                    });
6709                } else {
6710                    event = document.createEvent(EVENT_TYPE);
6711                    event.initEvent(eventType, true, true);
6712                }
6713                return event;
6714            },
6715            getTouches:function(evt){
6716                var touches = [];
6717                if(touchAvailable && evt.originalEvent && evt.originalEvent.touches ){
6718                    touches = evt.originalEvent.touches;
6719                }
6720                return touches;
6721            }
6722        };
6723    })();
6724})(xfalib);
6725(function ($, _) {
6726    $.widget("xfaWidget.abstractWidget", {
6727
6728        $userControl: null,
6729
6730        $data: xfalib.ut.XfaUtil.prototype.$data,
6731
6732        $css: xfalib.ut.XfaUtil.prototype.$css,
6733
6734        getOrElse: xfalib.ut.Class.prototype.getOrElse,
6735
6736        dIndexOf: xfalib.ut.XfaUtil.prototype.dIndexOf,
6737
6738        btwn: xfalib.ut.XfaUtil.prototype.btwn,
6739
6740        logger: xfalib.ut.XfaUtil.prototype.getLogger,
6741
6742        localeStrings: xfalib.ut.XfaUtil.prototype.getLocaleStrings,
6743
6744        logMsgs: xfalib.ut.XfaUtil.prototype.getLogMessages,
6745
6746        errorManager: xfalib.ut.XfaUtil.prototype.getErrorManager,
6747
6748        _widgetName: "abstractWidget",
6749
6750        // if there are any specific black listed attributes, each widget should define their own
6751        _blackListedAttributes : ["type"],
6752
6753        options: {
6754            name: "",
6755            value: null,
6756            commitProperty: "value",
6757            displayValue: null,
6758            screenReaderText: null,
6759            tabIndex: 0,
6760            role: null,
6761            paraStyles: null,
6762            dir: null,
6763            errorMessage: null,
6764            warningMessage: null,
6765            hScrollDisabled: false,
6766            placeholder:"",
6767            isValid:true,
6768            mandatory: false
6769        },
6770
6771        getOptionsMap: function () {
6772            return {
6773                "tabIndex": function (val) {
6774                    this.$userControl.attr("tabindex", val);
6775                },
6776                "role": function (val) {
6777                    if (val)
6778                        this.$userControl.attr("role", val);
6779                },
6780                "screenReaderText": function (val) {
6781                    if (val)
6782                        this.$userControl.attr("aria-label", val)
6783                },
6784                "paraStyles": function (val) {
6785                    if (val)
6786                        this.$css(this.$userControl.get(0), val);
6787                },
6788                "dir": function (val) {
6789                    if (val)
6790                        this.$userControl.attr("dir", this.options.dir);
6791                },
6792                "height": function (val) {
6793                    if (val) {
6794                        this.$css(this.$userControl[0], {"height": val})
6795                    }
6796                },
6797                "width": function (val) {
6798                    if (val)
6799                        this.$css(this.$userControl[0], {"width": val})
6800                },
6801                "isValid": function (val) {
6802                    if(val){
6803                      this.$userControl.removeAttr("aria-invalid");
6804                    } else {
6805                      this.$userControl.attr("aria-invalid",true);
6806                    }
6807                },
6808                "color" : function(value) {
6809                    if(!_.isEmpty(value)) {
6810                        var color = "rgb(" + value + ")";
6811                        this.$css(this.$userControl[0], {"color": color});
6812                    }
6813                },
6814                "font-style" : function (value) {
6815                    if (!_.isEmpty(value)) {
6816                        this.$css(this.$userControl[0], {"font-style": value});
6817                    }
6818                },
6819                "mandatory" : function (value) {
6820                    if(value){
6821                        this.$userControl.attr("aria-required", true);
6822                    } else {
6823                        this.$userControl.removeAttr("aria-required");
6824                    }
6825                }
6826            };
6827        },
6828
6829        getEventMap: function () {
6830            return {
6831                "focus": xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
6832                "blur": xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
6833                "click": xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT
6834            };
6835        },
6836
6837        /**
6838         * Copies all the attributes from source jquery object to destination jquery object
6839         * @param $src      source jquery object
6840         * @param $dest     destination jquery object
6841         */
6842        copyAttributesFromSrcToDest : function($src, $dest){
6843            var that = this;
6844            // let's get all the attribute from the src element and copy it to dest jquery object
6845            if($src != null && $src[0] && $src[0].attributes && $dest != null){
6846                $.each($src[0].attributes, function() {
6847                    // we don't add the black listed set of attributes
6848                    if(this.specified && this.value != null && _.isString(this.value) && this.value.length > 0 && that._blackListedAttributes.indexOf(this.name) === -1) {
6849                        $dest.attr(this.name, this.value);
6850                    }
6851                });
6852            }
6853        },
6854
6855        _create: function () {
6856            this.widgetEventPrefix = "";
6857            this.element.addClass(this._widgetName);
6858            this.$userControl = this.render();
6859            this.optionsHandler = this.getOptionsMap();
6860            this.eventMap = this.getEventMap();
6861            this._initializeOptions();
6862            this._initializeEventHandlers();
6863            this.errObj = this.errorManager();
6864            //call it only after render
6865            // Dirty hack to prevent this being called in Guide
6866            if (typeof guidelib === "undefined") {
6867                this.$css(this.$userControl.get(0), {
6868                    "box-sizing": "border-box",
6869                    "position": "absolute"
6870                });
6871            }
6872        },
6873
6874        _initializeEventHandlers: function () {
6875            xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "initialize event handlers for " + this._widgetName);
6876            _.each(this.eventMap, function (xfaevent, htmlevent) {
6877                var self = this;
6878                if (xfaevent) {
6879                    if (!(xfaevent instanceof  Array)) {
6880                        xfaevent = [xfaevent];
6881                    }
6882                    for (var i = 0; i < xfaevent.length; i++) {
6883                        xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "binding " + htmlevent + " with " + xfaevent[i]);
6884                        this.$userControl.on(htmlevent,
6885                            (function (xfevnt) {
6886                                return function (evnt) {
6887                                    xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "trigger " + evnt.type +
6888                                    " xfa-event " + xfevnt);
6889                                    self._preProcessEvent.apply(self, [xfevnt, evnt]);
6890                                    //since the fix https://github.com/jquery/jquery/pull/972, Fix for keeping namespace when triggering an event using an Event #972
6891                                    //we need to clear the namespace and its regular expression of triggering event, as the listeners are registered on un-namespaced events
6892                                    evnt.namespace = "";
6893                                    evnt.namespace_re = "";
6894                                    self._trigger(xfevnt, evnt);
6895                                    self._postProcessEvent.apply(self, [xfevnt, evnt]);
6896                                }
6897                            })(xfaevent[i])
6898                        )
6899
6900                    }
6901                }
6902            }, this)
6903        },
6904
6905        _preProcessEvent: function (xfaevent, htmlevent) {
6906            if (xfaevent == this.options.commitEvent) {
6907                this.preProcessCommit(htmlevent);
6908            }
6909            switch (xfaevent) {
6910                case xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT:
6911                    this.preProcessEnter(htmlevent);
6912                    break;
6913                case xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT:
6914                    this.preProcessExit(htmlevent);
6915                    break;
6916                case xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT:
6917                    this.preProcessChange(htmlevent);
6918                    break;
6919                case xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT:
6920                    this.preProcessClick(htmlevent);
6921                    break;
6922            }
6923
6924        },
6925
6926        _postProcessEvent: function (xfaevent, htmlevent) {
6927            if (xfaevent == this.options.commitEvent) {
6928                this.postProcessCommit(htmlevent);
6929            }
6930            switch (xfaevent) {
6931                case xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT:
6932                    this.postProcessEnter(htmlevent);
6933                    break;
6934                case xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT:
6935                    this.postProcessExit(htmlevent);
6936                    break;
6937                case xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT:
6938                    this.postProcessChange(htmlevent);
6939                    break;
6940                case xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT:
6941                    this.postProcessClick(htmlevent);
6942                    break;
6943            }
6944        },
6945
6946        _initializeOptions: function () {
6947            _.each(this.optionsHandler, function (value, key) {
6948                if (typeof value === "function")
6949                    value.apply(this, [this.options[key]]); // TODO: check whether it is needed for initialization or not
6950            }, this)
6951        },
6952
6953        _setOption: function (key, value) {
6954            if (this.options[key] != value) {
6955                this.options[ key ] = value;
6956                if (typeof this.optionsHandler[key] === "function") {
6957                    this.optionsHandler[key].apply(this, [this.options[key]])
6958                }
6959            }
6960        },
6961
6962        /**
6963         * @override
6964         */
6965        option: function (key, value) {
6966            if (arguments.length === 1 &&
6967                typeof key === "string" &&
6968                this.options.hasOwnProperty(key) &&
6969                this.options[key] === undefined) {
6970                return undefined;
6971            }
6972            return $.Widget.prototype.option.apply(this, arguments)
6973        },
6974
6975        destroy: function () {
6976            this.$userControl.removeClass(this._widgetName);
6977        },
6978
6979
6980        render: function () {
6981            var control;
6982            if (this.element.children().length > 0) {
6983                control = $(this.element.children().get(0));
6984            }
6985            else
6986                control = this.element;
6987            control.attr("name", this.options.name)
6988            return control;
6989        },
6990
6991
6992        preProcessCommit: function (evnt) {
6993            this.options.value = this.getCommitValue();
6994            xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "passing commit value " + this.options.value +
6995            "to model ");
6996        },
6997
6998        getCommitValue: function () {
6999
7000        },
7001
7002        preProcessExit: function (evnt) {
7003
7004        },
7005
7006        preProcessEnter: function (evnt) {
7007            //Only focus the enabled widgets
7008            if (this.options.access === "open") {
7009                this._showError();
7010                this.showValue();
7011            }
7012        },
7013
7014        preProcessChange: function (evnt) {
7015
7016        },
7017
7018        preProcessClick: function (evnt) {
7019
7020        },
7021
7022        postProcessCommit: function (evnt) {
7023            this.showDisplayValue();
7024        },
7025
7026        postProcessExit: function (evnt) {
7027            //Only for the enabled widgets
7028            if (this.options.access === "open") {
7029                this.showDisplayValue();
7030                this._hideError();
7031            }
7032        },
7033
7034        postProcessEnter: function (evnt) {
7035        },
7036
7037        postProcessChange: function (evnt) {
7038
7039        },
7040
7041        postProcessClick: function (evnt) {
7042
7043        },
7044
7045        showDisplayValue: function () {
7046            this.$userControl.val(this.options.displayValue)
7047        },
7048
7049        /**
7050         * Checks if the edit value is same as value present in the user control(html form element)
7051         * @returns {boolean}
7052         */
7053        _isValueSame : function(){
7054            return (((this.options.value === null) && (this.$userControl.val() === "")) || (this.options.value === this.$userControl.val()));
7055        },
7056
7057        showValue: function () {
7058            // May be $userControl doesn't have val(), using it as of now
7059            // If the value of the field is not same as edit value, only then set the value, this also solves IE bug of cursor
7060            // moving to the end of field on click
7061            if(!this._isValueSame()) {
7062                this.$userControl.val(this.options.value)
7063            }
7064        },
7065
7066        focus: function () {
7067            var that = this;
7068            // setTimeout added to fix CQ-51141
7069            // While using setFocus API in adaptive form, the focus was not being set in TextBox on chrome
7070            // and also on click of caption of RadioButton/Checkbox, due to fast event execution, he
7070nce adding delay during focus.
7071            setTimeout(function(){
7072                that.$userControl[0].focus();
7073            }, 1);
7074        },
7075
7076        click: function () {
7077            this.focus();
7078            this.$userControl.triggerHandler("click"); // we do not want the exact click as might bubble up to the field.
7079        },
7080
7081        /* widget specific code */
7082
7083        _showError: function () {
7084            if(this.errObj && _.isFunction(this.errObj.onFieldEnter)) {
7085                this.errObj.onFieldEnter(this);
7086            }
7087        },
7088
7089        _calculatePaddingForVAlign:function(diff){
7090           var flagForMoz = $.browser.mozilla && !xfalib.ut.Utilities.isIE11() &&
7091                              this.options.multiLine,
7092               vAlignBottomOrTop = this.options.paraStyles &&
7093                                   (this.options.paraStyles["vertical-align"] == "bottom" ||
7094                                    this.options.paraStyles["vertical-align"] == "top");
7095
7096           if(flagForMoz && vAlignBottomOrTop || $.browser.msie && this.options.multiLine) {
7097              return;
7098           }
7099           // to handle the edge cases, if the diff is like -0.01 the whole operation is getting aborted
7100           // this diff comes mainly due to scroll height getting rounded off when widgetHeight is like x.999999
7101           diff = (diff > -0.01) ? Math.abs(diff) : diff;
7102           if (this.options.paraStyles && diff > 0) {
7103                var vAlign = this.options.paraStyles["vertical-align"];
7104                if (vAlign == "bottom") {
7105                    diff = diff - this.options.paraStyles["padding-bottom"];
7106                    this.$userControl.css("padding-top", diff);
7107                    this.padding = this.$userControl.css("padding-top");
7108                }
7109                else if (vAlign == "top" || (vAlign != "middle" && vAlign == undefined)) {
7110                    if (this.options.paraStyles["padding-top"])
7111                        diff = diff - this.options.paraStyles["padding-top"];
7112                    this.$userControl.css("padding-bottom", diff);
7113                    this.padding = this.$userControl.css("padding-bottom");
7114                }
7115                else if (this.options.multiLine && vAlign == "middle") {
7116                    var newDiff = diff / 2;
7117                    newDiff = newDiff - this.options.paraStyles["padding-bottom"];
7118                    if (this.options.paraStyles["padding-top"])
7119                        newDiff = newDiff + this.options.paraStyles["padding-top"];
7120                    this.$userControl.css("padding-top", newDiff);
7121                }
7122            }
7123        },
7124
7125        _handleVAlignOnExit: function (evnt) {
7126
7127            if (!this.options.paraStyles) {
7128                //vAlign has to be handled only if there is paraStyles
7129                return;
7130            }
7131            var value = this.options.displayValue,
7132                lineHeight = xfalib.view.util.TextMetrics.measureExtent(value, {refEl: this.$userControl.get(0), maxHeight: -1}).height,
7133                widgetHeight = this.options.height,
7134                diff = widgetHeight - lineHeight;
7135            this._calculatePaddingForVAlign(diff);
7136
7137        },
7138
7139        _handleVAlignOnEnter: function (evnt) {
7140            //Only align the enabled widgets
7141            var flagForIE = $.browser.msie && this.options.multiLine;
7142            if (this.options.paraStyles && !flagForIE) {
7143                 var vAlign = this.options.paraStyles["vertical-align"];
7144                 if (vAlign == "bottom" && this.padding)
7145                     this.$userControl.css("padding-top", this.padding);
7146                 else if (vAlign == "top" && this.padding)
7147                     this.$userControl.css("padding-bottom", this.padding);
7148            }
7149        },
7150
7151        _hideError: function () {
7152            if(this.errObj && _.isFunction(this.errObj.onFieldExit)) {
7153                this.errObj.onFieldExit(this);
7154            }
7155        },
7156
7157        markError: function (msg, type) {
7158            if(this.errObj && _.isFunction(this.errObj.markError)) {
7159                this.errObj.markError(this, msg, type);
7160            }
7161        },
7162
7163        clearError: function () {
7164            if(this.errObj && _.isFunction(this.errObj.clearError)) {
7165                this.errObj.clearError(this);
7166            }
7167        },
7168
7169        getEditValue: function(value) {
7170            if(this.options.editPattern == null) {
7171                return value;
7172            }
7173            try {
7174                return xfalib.ut.PictureFmt.format(value, this.options.editPattern);
7175            } catch(e) {
7176                return null;
7177            }
7178        },
7179
7180        parseEditValue: function(value) {
7181            if(this.options.editPattern == null) {
7182                return value;
7183            }
7184            try {
7185                return xfalib.ut.PictureFmt.parse(value, this.options.editPattern);
7186            } catch(e) {
7187                return value;
7188            }
7189        }
7190    });
7191})($, window._);
7192(function($) {
7193    $.widget( "xfaWidget.defaultWidget", $.xfaWidget.abstractWidget, {
7194
7195        _widgetName: "defaultWidget",
7196
7197        getOptionsMap: function() {
7198            var parentOptionsMap = $.xfaWidget.abstractWidget.prototype.getOptionsMap.apply(this,arguments);
7199            return $.extend({},parentOptionsMap,{
7200                "access": function(val) {
7201                    switch(val) {
7202                        case "open" :
7203                            this.$userControl.removeAttr("readOnly");
7204                            this.$userControl.removeAttr("aria-readonly");
7205                            this.$userControl.removeAttr("disabled");
7206                            this.$userControl.removeAttr("aria-disabled");
7207                            break;
7208                        case "nonInteractive" :
7209                        case "protected" :
7210                            this.$userControl.attr("disabled", "disabled");
7211                            this.$userControl.attr("aria-disabled", "true");
7212                            break;
7213                        case "readOnly" :
7214                            this.$userControl.attr("readOnly", "readOnly");
7215                            this.$userControl.attr("aria-readonly", "true");
7216                            break;
7217                        default  :
7218                            this.$userControl.removeAttr("disabled");
7219                            this.$userControl.removeAttr("aria-disabled");
7220                            break;
7221                    }
7222                },
7223
7224                "displayValue": function(val) {
7225                    if(this.options.commitProperty) {
7226                        if($.browser.mozilla && this.options.commitProperty == "value") {
7227                            // on submitting form firefox does not remember autocomplete values, if updated through attr()
7228                            this.$userControl.val(this._displayEmptyStringForIE(this.options.displayValue));
7229                        } else {
7230                            this.$userControl.prop(this.options.commitProperty, this._displayEmptyStringForIE(this.options.displayValue));
7231                            this.$userControl.attr(this.options.commitProperty, this._displayEmptyStringForIE(this.options.displayValue));
7232                        }
7233                    } else {
7234                        this.logger().debug("xfaView", "[DefaultWidget._update], User Control or Commit Property is null");
7235                    }
7236                },
7237
7238                "placeholder": function(value){
7239                    this.$userControl.attr("placeholder", value);
7240                }
7241            });
7242        },
7243
7244        _displayEmptyStringForIE: function(value){
7245            /*CQ-69417: By default "null" is displayed in the comments text box
7246              "null" values shown in IE */
7247            // CQ-69107 included check for edge as well
7248            return (value == null && xfalib.ut.XfaUtil.prototype.detectIE()) ? '' : value;
7249        },
7250
7251        render : function() {
7252            var control = $.xfaWidget.abstractWidget.prototype.render.apply(this,arguments)
7253            this._attachEventHandlers(control)
7254            return control
7255        },
7256
7257        getCommitValue: function() {
7258            var value = this.$userControl.val();
7259            if(this.options.hScrollDisabled && !this.options.multiLine)
7260                var value = xfalib.ut.XfaUtil.prototype.splitStringByWidth(this.$userControl.val(),this.$userControl.width(),this.$userControl.get(0)) ;
7261            return value;
7262        },
7263
7264        _attachEventHandlers: function($control) {
7265            $control.keydown($.proxy(this._handleKeyDown,this));
7266            $control.keypress($.proxy(this._handleKeyPress,this));
7267            $control.on('paste',$.proxy(this._handlePaste,this));
7268            $control.on('cut',$.proxy(this._handleCut,this));
7269        },
7270
7271        _compositionUpdateCallback : function (event) {
7272            return false;
7273        },
7274
7275        _attachCompositionEventHandlers : function($control) {
7276            var isComposing = false; // IME Composing going on
7277            var hasCompositionJustEnded = false; // Used to swallow keyup event related to compositionend
7278            // IME specific handling, to handle japanese languages max limit
7279            // since enter can also be invoked during composing, a special handling is done here
7280            var that = this,
7281                changeCaratPosition = function() {
7282                    // change the carat selection position to further limit input of characters
7283                    var range = window.getSelection();
7284                    range.selectAllChildren(that.$userControl[0]);
7285                    range.collapseToEnd();
7286                };
7287            $control.keyup(function(event) {
7288                if (/*isComposing || */hasCompositionJustEnded) {
7289                    if (that._compositionUpdateCallback(event)) {
7290                        changeCaratPosition();
7291                    }
7292                    // IME composing fires keydown/keyup events
7293                    hasCompositionJustEnded = false;
7294                }
7295            });
7296            $control.on("compositionstart",
7297                function(event) {
7298                    isComposing = true;
7299                })
7300                .on("compositionupdate",
7301                    function(event) {
7302                        // event.originalEvent.data refers to the actual content
7303                        if (that._compositionUpdateCallback(event)) {
7304                            changeCaratPosition();
7305                        }
7306                    })
7307                .on("compositionend",
7308                    function(event) {
7309                        isComposing = false;
7310                        // some browsers (IE, Firefox, Safari) send a keyup event after
7311                        //  compositionend, some (Chrome, Edge) don't. This is to swallow
7312                        // the next keyup event, unless a keydown event happens first
7313                        hasCompositionJustEnded = true;
7314                    })
7315                .on("keydown",
7316                    function(event) {
7317                        // Safari on OS X may send a keydown of 229 after compositionend
7318                        if (event.which !== 229) {
7319                            hasCompositionJustEnded = false;
7320                        }
7321                    });
7322        },
7323
7324        _handleKeyDown : function(event){
7325            if(event.keyCode == 13 || event.charCode == 13 || event.which == 13) // touch devices may return charCode
7326                event.preventDefault();
7327        },
7328
7329        _handleKeyPress : function(event){
7330            if(event.keyCode == 13 || event.charCode == 13 || event.which == 13) // touch devices may return charCode
7331                event.preventDefault();
7332        }
7333    });
7334})($);
7335(function($, _) {
7336    var xfaUtil = xfalib.ut.XfaUtil.prototype;
7337    $.widget( "xfaWidget.dateTimeEdit", $.xfaWidget.defaultWidget, {
7338
7339        _widgetName : "dateTimeEdit",
7340
7341        getEventMap: function() {
7342            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
7343            if(this._nativeWidget === false) {
7344                return $.extend({}, parentOptionsMap, {
7345                    "onfocus1.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
7346                    "onvaluechange.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
7347                    "onfocusout.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
7348                    "onoverlap.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT, // Custom Event to fix BUG #3626974
7349                    "input": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT, // TODO : add handler for xfa.event.change
7350                    "focus": null,
7351                    "blur": null
7352                })
7353            } else {
7354                return $.extend({}, parentOptionsMap, {
7355                    "change": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
7356                })
7357            }
7358        },
7359
7360        _getAdobeDatePickerOptionsMap : function(parentOptionsMap) {
7361            return {
7362                "access" : function (val) {
7363                    switch (val) {
7364                        case "open" :
7365                            this.$userControl.adobeDateTimePicker("access", true);
7366                            break;
7367                        case "nonInteractive" :
7368                        case "protected" :
7369                        case "readOnly" :
7370                            this.$userControl.adobeDateTimePicker("access", false);
7371                            break;
7372                    }
7373                    parentOptionsMap.access.apply(this, arguments);
7374                },
7375                "displayValue" : function (val) {
7376                    // set the value in the datepicker plugin
7377                    this.$userControl.adobeDateTimePicker("value", this.options.value);
7378                    // show the display value
7379                    this.showDisplayValue();
7380                }
7381            }
7382        },
7383
7384        _getNativeDatePickerOptionsMap: function (parentOptionsMap) {
7385            return {
7386                "displayValue": function (val) {
7387                    this.showDisplayValue();
7388                }
7389            }
7390        },
7391
7392
7393        getOptionsMap: function() {
7394            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments),
7395                datePickerOptions = this._nativeWidget === false ? this._getAdobeDatePickerOptionsMap(parentOptionsMap)
7396                    : this._getNativeDatePickerOptionsMap(parentOptionsMap),
7397                commonOptions = {
7398                    "paraStyles": function (paraStyles) {
7399                        parentOptionsMap.paraStyles.apply(this, arguments);
7400                        this._handleVAlignOnExit();
7401                    },
7402
7403                     "access": function(val) {
7404                        // update width on change of access (as width of widget is dependent on access)
7405                        // The calender icon should be hidden, and widget should take full space when readOnly
7406                        parentOptionsMap.access.apply(this, arguments);
7407                        this.getOptionsMap().width.apply(this,[this.options.width]);
7408                      },
7409                     "width": function (val) {
7410                        parentOptionsMap.width.apply(this, arguments);
7411                        if (this.options.showCalendarIcon && val && this.options.access == "open") {
7412                            var effectiveWidth = val > this.options.calendarIconWidth ? val - this.options.calendarIconWidth : val;
7413                            this.$userControl.width(effectiveWidth);  // leave space for the cal icon
7414                        }
7415                    },
7416
7417                    "height": function(val) {
7418                        parentOptionsMap.height.apply(this, arguments);
7419                        this._handleVAlignOnExit();
7420                    },
7421                    "screenReaderText": function (val) {
7422                        var editPattern = this.options.editPattern;
7423                        var defaultEditPattern = this._nativeWidget ? "mm/dd/yyyy" : "YYYY-MM-DD";
7424                        var regex = /(?:date){0,1}{(.*)}/;
7424 // date{<pattern>} or {<pattern>} both are valid as per xfa spec
7425                        editPattern = typeof editPattern === "string" ? editPattern.match(regex)[1] : defaultEditPattern;
7426                        var defaultLabel = "Please Enter date in {0} format only";
7427                        if (editPattern) {
7428                            var ariaLabel = xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("",
7429                                xfalib.locale.Strings.datePickerAriaLabel || defaultLabel, [editPattern])
7430                        }
7431                        var finalVal = val !== undefined ? val + " " + ariaLabel : val;
7432                        this.$userControl.attr("aria-label", finalVal);
7433                    }
7434                };
7435            return $.extend({},parentOptionsMap,datePickerOptions, commonOptions);
7436        },
7437
7438        postProcessExit: function(evnt) {
7439            $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
7440            this._handleVAlignOnExit ();
7441        },
7442
7443        preProcessEnter: function(evnt) {
7444            $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
7445            this._handleVAlignOnEnter();
7446        },
7447
7448        preProcessChange: function(evnt) {
7449           //CQ-46332:loss of date value in date-picker , setting the value here or else
7450           //it gets lost during focus
7451           if(this._nativeWidget === true){
7452            this.options.value = this.$userControl.val();
7453           }
7454        },
7455
7456        showDisplayValue: function() {
7457            if(this._nativeWidget === false) {
7458                $.xfaWidget.defaultWidget.prototype.showDisplayValue.apply(this, arguments);
7459            } else {
7460                this.showValue();
7461            }
7462        },
7463
7464
7465        showValue: function () {
7466            if (this._nativeWidget == false) {
7467                this.$userControl.adobeDateTimePicker("value", this.options.value);
7468            } else {
7469                $.xfaWidget.defaultWidget.prototype.showValue.apply(this, arguments);
7470            }
7471            $.xfaWidget.textField.prototype._selectOnFocusInIE.apply(this, arguments);
7472        },
7473
7474        getCommitValue: function() {
7475            if (this._nativeWidget === false) {
7476                var value = this.$userControl.adobeDateTimePicker("value"),
7477                    parsedValue = this.parseEditValue(value);
7478                return parsedValue;
7479            }
7480            return $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
7481        },
7482
7483        render: function() {
7484            var self = this,
7485                textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
7486                $control = $.xfaWidget.abstractWidget.prototype.render.apply(this, arguments),
7487                $source = $control,
7488                id,
7489                existingInlineStyleAttributeValues,
7490                newInlineStyleAttributeValues,
7491                combinedInlineStyleAttributeValues;
7492            existingInlineStyleAttributeValues = this.element.find("input").attr("style") || '';
7493            this._nativeWidget = true;
7494            if(this.options.useNativeWidget === false || $control[0].type !== "date") {
7495                this._nativeWidget = false;
7496                id = this.element.find("input")[0].id;
7497                this.element.children().remove();
7498                $("<div></div>").css({position: "relative", width: "100%", height: "100%"}) // want to fill entire width of containing table cell
7499                    .append($("<input type='text'/>"))
7500                    .appendTo(this.element);
7501                $control = $("input", this.element).
7502                    attr("style", textStyle).
7503                    attr("name", this.options.name).
7504                    attr("id", id).
7505                    adobeDateTimePicker({
7506                        positioning: this.element,
7507                        locale: {
7508                            months: this.options.months,
7509                            days: this.options.days,
7510                            zero: this.options.zero,
7511                            clearText: this.options.clearText
7512                        },
7513                        access: this.options.access,
7514                        value: this.options.value,
7515                        showCalendarIcon: this.options.showCalendarIcon,
7516                        iconWidth: this.options.calendarIconWidth,
7517                        minValidDate : this.options.minValidDate,
7518                        maxValidDate : this.options.maxValidDate,
7519                        exclMinDate :  this.options.exclMinDate,
7520                        exclMaxDate : this.options.exclMaxDate,
7521                        editValue: function (value) {
7522                            return self.getEditValue(value);
7523                        }
7524                    });
7525            }
7526            this._attachEventHandlers($control);
7527            newInlineStyleAttributeValues = this.element.find("input").attr("style") || '';
7528            //append the previous inlineStyleAttributeValues to newInlineStyleAttributeValues so that the inline styles
7529            //added from the dialog are applied.
7530            combinedInlineStyleAttributeValues = newInlineStyleAttributeValues + existingInlineStyleAttributeValues;
7531            this.element.find("input").attr("style", combinedInlineStyleAttributeValues);
7532            // only in case of adaptive form, we would copy the attributes back
7533            if(window.guideBridge) {
7534                // restore the original attribute back to destination object
7535                this.copyAttributesFromSrcToDest($source, this.element.find("input"));
7536            }
7537            return $control;
7538        }
7539    }) ;
7540
7541})($, _);
7542(function($, _) {
7543$.widget("xfaWidget.numericInput", $.xfaWidget.defaultWidget, {
7544
7545    _widgetName: "numericInput",
7546
7547	options : {
7548		value : null,
7549		curValue: null,
7550        pos: 0,
7551        lengthLimitVisible: true,
7552        zero:"0",
7553        decimal:".",
7554        minus:"-"
7555	},
7556
7557    //TODO: to support writing in different locales \d should be replaced by [0-9] for different locales
7558    _matchArray : {
7559                    "integer":"^[+-]?{digits}*$",
7560                    "decimal":"^[+-]?{digits}{leading}({decimal}{digits}{fraction})?$",
7561                    "float":"^[+-]?{digits}*({decimal}{digits}*)?$"
7562                  },
7563
7564    _regex : null,
7565
7566    _engRegex : null,
7567
7568    _writtenInLocale : false,
7569
7570    _previousCompositionVal : "",
7571
7572
7573    _toLatinForm : function (halfOrFullWidthStr) {
7574        // refer http://www.fileformat.info/info/unicode/block/halfwidth_and_fullwidth_forms/utf8test.htm
7575        return halfOrFullWidthStr.replace(
7576            /[\uff00-\uffef]/g,
7577            function(ch) { return String.fromCharCode(ch.charCodeAt(0) - 0xfee0); }
7578        );
7579    },
7580
7581    getOptionsMap: function() {
7582        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
7583        return $.extend({},parentOptionsMap,{
7584            "paraStyles": function(paraStyles){
7585                parentOptionsMap.paraStyles.apply(this,arguments);
7586                this._handleVAlignOnExit ();
7587            } ,
7588
7589            "height": function(val) {
7590                if(val)   {
7591                    this.$css(this.$userControl[0],{"height" :val});
7592                    this._handleVAlignOnExit();    // To Handle the case of expandable Fields
7593                }
7594            }
7595
7596        })
7597    },
7598
7599    getEventMap: function() {
7600        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
7601        return $.extend({},parentOptionsMap,{
7602            "onKeyInput.numericInput" : xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
7603        })
7604    },
7605
7606    _getDigits: function() {
7607        var zeroCode = this.options.zero.charCodeAt(0),
7608            digits = "";
7609        for(var i = 0;i < 10;i++) {
7610            digits += String.fromCharCode(zeroCode + i);
7611        }
7612        return "["+digits+"]"
7613    },
7614
7615    _escape: function(str) {
7616      return str.replace(".","\\.")
7617    },
7618
7619    postProcessExit: function(evnt) {
7620        $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
7621        this._handleVAlignOnExit ();
7622    },
7623
7624    preProcessEnter: function(evnt) {
7625        $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
7626        this._handleVAlignOnEnter();
7627    },
7628
7629	render : function() {
7630        var matchStr =  this._matchArray[this.options.dataType];
7631        if(matchStr) {
7632            var ld = this.options.leadDigits,
7633                fd = this.options.fracDigits,
7634                ldstr = ld && ld != -1 ? "{0,"+ld+"}"
7635                    : "*",
7636                fdstr = fd && fd != -1 ? "{0,"+fd+"}"
7637                    : "*",
7638                matchStr =  matchStr.replace("{leading}",ldstr)
7639                                    .replace("{fraction}",fdstr),
7640                localeStr = matchStr.replace(/{digits}/g,this._getDigits())
7641                                    .replace("{decimal}",this._escape(this.options.decimal)),
7642                engStr = matchStr.replace(/{digits}/g,"[0-9]")
7643                                .replace("{decimal}","\\.")
7644            this._processValue = !(this._getDigits() == "[0123456789]" && this.options.decimal == ".")
7645            this._regex = new RegExp(localeStr, "g");
7646            this._engRegex = new RegExp(engStr, "g");
7647        }
7648        return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
7649    },
7650
7651    getCommitValue: function() {
7652        var value = $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
7653        // we support full width, half width and locale specific numbers
7654        value = this._toLatinForm(value);
7655        if(value.length > 0 && this._processValue && !value.match(this._engRegex)) {
7656            this._writtenInLocale = true;
7657            value = this._convertValueFromLocale(value);
7658        } else {
7659            this._writtenInLocale = false
7660        }
7661        if(value && value.length >= this.options.combCells )
7662            value = value.slice(0,this.options.combCells);
7663        this._previousCompositionVal = value;
7664        return value;
7665    },
7666
7667    _compositionUpdateCallback : function (event) {
7668        var that = this;
7669        var flag = false;
7670        var leadDigits = that.options.leadDigits;
7671        var fracDigits = that.options.fracDigits;
7672        // we don't check use-case where just fracDigits is set since in case of composition update, the value to update is not known
7673        if (leadDigits !== -1) {
7674            var val = that.$userControl.val();
7675            if (event.type === "compositionupdate" && event.originalEvent.data) {
7676                val = val + event.originalEvent.data.substr(event.originalEvent.data.length - 1);
7677            }
7678            // can't use the existing regex (since current regex checks for english digits), rather doing leadDigit compare
7679            var totalLength = leadDigits + (fracDigits !== -1 ? (fracDigits + that.options.decimal.length) : 0);
7680            if (val.indexOf(that.options.decimal) === -1) {
7681                totalLength = leadDigits;
7682            }
7683            var latinVal = this._toLatinForm(val);
7684            // match both since we support full width, half width and locale specific input
7685            var match = latinVal.match(that._regex)|| latinVal.match(this._engRegex);
7686            flag  = !match;
7687            if (match === null) {
7688                // entered invalid character, revert to previous value
7689                that.$userControl.val(that._previousCompositionVal);
7690                flag = true;
7691            } else if (flag) {
7692                // if max reached
7693                var newVal = val.substr(0, totalLength);
7694                that.$userControl.val(newVal);
7695                that._previousCompositionVal = newVal;
7696                flag = true;
7697            } else {
7698                that._previousCompositionVal = val;
7699            }
7700        }
7701        return flag;
7702    },
7703
7704    _attachEventHandlers : function($control) {
7705        $.xfaWidget.defaultWidget.prototype._attachEventHandlers.apply(this, arguments);
7706        // IME specific handling, to handle japanese languages max limit
7707        $.xfaWidget.defaultWidget.prototype._attachCompositionEventHandlers.apply(this, arguments);
7708	},
7709
7710    _handleKeyInput : function(event, character, code){
7711        if(event.ctrlKey && !_.contains(['paste', 'cut'], event.type)) {
7712            return true;
7713        }
7714
7715        $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this,arguments);
7716        this.options.lengthLimitVisible = true;
7717
7718        var val = this.$userControl.prop(this.options.commitProperty) || '',
7719            // if selectionStart attribute isn't supported then its value will be undefined
7720            selectionStart = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionStart"),
7721            isSelectionAttrSupported = !(selectionStart === undefined || selectionStart === null),
7722            selectionStart = selectionStart || 0,
7723            selectionEnd = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionEnd") || 0,
7724            combCells = parseInt(this.options.combCells) || 0,
7725            current,
7726            change = character;
7727
7728        if (combCells > 0 ) {
7729            change = character.substr(0, combCells - val.length + selectionEnd - selectionStart);
7730        }
7731
7732        current = val.substr(0, selectionStart) + change + val.substr(selectionEnd);
7733        // done to handle support for both full width, half width or mixed input in number field
7734        var latinCurrentValue = this._toLatinForm(current);
7735
7736	// we want to check regex first and then see whether it was numeric or not.
7737        if (!(this._regex == null || latinCurrentValue.match(this._regex) || latinCurrentValue.match(this._engRegex))) {
7738            event.preventDefault();
7739            return false;
7740        }
7741
7742	// CQ-4245407 : selectionStart and selectionEnd attributes aren't supported in case of input type = number
7743        // it is used for providing native HTML5 implementation for numeric field, so no further processing is required
7744        // As it is specific to AF and AF doesn't support change event on each keypress, so this change should be fine
7745        if (!isSelectionAttrSupported) {
7746            return true;
7747        }
7748
7749        if (!_.contains(['keydown', 'cut'], event.type) && combCells && (val.length >= combCells || current.length > combCells) && selectionStart === selectionEnd) {
7750            event.preventDefault();
7751            return false;
7752        }
7753
7754        this.options.curValue = val;
7755        this._previousCompositionVal = val;
7756        this.options.pos = selectionStart;
7757
7758        if(this.options.hScrollDisabled && !_.contains(['keydown', 'cut'], event.type)) {
7759            var expectedWidth = xfalib.view.util.TextMetrics.measureExtent(current, {refEl: this.$userControl[0], maxWidth:-1}).width;
7760            if(!event.ctrlKey && expectedWidth > this.$userControl.width() - 5){
7761                event.preventDefault();
7762                this.options.lengthLimitVisible = false;
7763            }
7764        }
7765
7766        this.$userControl.trigger({
7767            type : "onKeyInput.numericInput",
7768            originalType : event.type,
7769            character : character,  // contains the pasted string or pressed key
7770            keyCode : event.keyCode || 0,
7771            charCode : event.charCode || 0,
7772            which : event.which || 0,
7773            ctrlKey : event.ctrlKey || event.metaKey || false,
7774            shiftKey : event.shiftKey || false,
7775            keyDown : false, // This property is available only for list boxes and drop-down lists
7776            selectionStart: selectionStart,
7777            selectionEnd: selectionEnd
7778        });
7779    },
7780
7781    _handleKeyDown : function(event){
7782        if (event) {
7783            var code = event.charCode || event.which || event.keyCode || 0;
7784            if(code == 8 || code == 46) // backspace and del
7785               this._handleKeyInput(event, "", code);
7786            else if(code == 32) { // suppress space
7787                event.preventDefault();
7788                return false;
7789            }
7790        }
7791    },
7792
7793    _isValidChar: function (character) {
7794        character = this._toLatinForm(character);
7795        var lastSingleDigitChar = String.fromCharCode(this.options.zero.charCodeAt(0) + 9);
7796        // we only full width, half width and also locale specific if customer has overlayed the i18n file
7797        return (character >= "0" && character <= "9") || (character>=this.options.zero && character<=lastSingleDigitChar) || character===this.options.decimal || character===this.options.minus;
7798    },
7799
7800    _handleKeyPress : function(event){
7801        if (event) {
7802            var code = event.charCode || event.which || event.keyCode || 0,
7803                character = String.fromCharCode(code);
7804
7805            if(xfalib.ut.XfaUtil.prototype.isNonPrintableKey(event.key)) { // mozilla also generates a keypress, along with keydown
7806                return true;                                               // for all keys, so only handling printable keys in keypress
7807            }
7808
7809            if (this._isValidChar(character))
7810                this._handleKeyInput(event, character, code);
7811            else if (!event.ctrlKey){
7812                event.preventDefault();
7813                return false;
7814            }
7815        }
7816    },
7817
7818    _handlePaste : function(event){
7819        if (event) {
7820            var pastedChar = undefined;
7821            if (window.clipboardData && window.clipboardData.getData) { // IE
7822                pastedChar = window.clipboardData.getData('Text');
7823            } else if (event.originalEvent.clipboardData && event.originalEvent.clipboardData.getData) {
7824                pastedChar = event.originalEvent.clipboardData.getData('text/plain');
7825            }
7826
7827            if(pastedChar) {
7828                var allPastedCharsValid = _.every(pastedChar.split(''), function (character) {
7829                    return this._isValidChar(character);
7830                }, this);
7831                if (allPastedCharsValid) {
7832                    // during paste we support both half width, full width and locale specific numbers
7833                    pastedChar = this._toLatinForm(pastedChar);
7834                    this._handleKeyInput(event, pastedChar, 0);
7835                }
7836                else if (!event.ctrlKey) {
7837                    event.preventDefault();
7838                    return false;
7839                }
7840            }
7841        }
7842    },
7843
7844    _handleCut : function(event) {
7845        if (event) {
7846            this._handleKeyInput(event, "", 0);
7847        }
7848    },
7849    // CQ-107886 : added handling for negative values, as for '-', '-3' was getting returned
7850    _convertValueToLocale: function(val) {
7851        var zeroCode = this.options.zero.charCodeAt(0);
7852        return  _.map(val,function(c) {
7853            if(c == ".") {
7854                return this.options.decimal;
7855            } else if(c == "-") {
7856                return this.options.minus;
7857            } else {
7858                return String.fromCharCode(parseInt(c) + zeroCode);
7859            }
7860        },this).join("");
7861    },
7862
7863    _convertValueFromLocale: function(val) {
7864        val = this._toLatinForm(val);
7865        var zeroCode = this.options.zero.charCodeAt(0);
7866        return  _.map(val,function(c) {
7867            if(c == this.options.decimal) {
7868                return ".";
7869            } else if(c == this.options.minus) {
7870                return "-";
7871            } else {
7872                return (c.charCodeAt(0) - zeroCode).toString();
7873            }
7874        },this).join("");
7875    },
7876
7877    showValue : function() {
7878       // if the value is same, don't do anything
7879       if(!this._isValueSame()){
7880           if(this.options.value && this._writtenInLocale) {
7881               this.$userControl.val(this._convertValueToLocale(this.options.value))
7882           } else {
7883               this.$userControl.val(this.options.value)
7884           }
7885       }
7886       //IE doesn't show selected text if we focus and set its value all the time so force selection
7887       $.xfaWidget.textField.prototype._selectOnFocusInIE.apply(this, arguments);
7888    }
7889});
7890})($, window._);(function ($, _) {
7891    $.widget("xfaWidget.dropDownList", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
7892
7893        _widgetName: "dropDownList",
7894
7895        options: {
7896            value: [],
7897            items: [],
7898            editable: false,
7899            placeholder: "",
7900            displayValue: []
7901        },
7902
7903        widgetSkeleton: '<select name="" style="" size = "1"></select>',
7904        optionSkeleton: '<option data-user-option></option>',
7905        optGroupSkeleton: '<optgroup label=""></optgroup>',
7906        AF_OPTGROUP_NAME: "afOptGroupName",
7907        PLACE_HOLDER_STYLE_CLASS : "placeHolder",
7908
7909        getOptionsMap: function () {
7910            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
7911            return $.extend({}, parentOptionsMap, {
7912                "value": function (val) {
7913                    if (!_.isArray(val)) {
7914                        val = [val];
7915                    }
7916                    var selectedOptionFound = false,
7917                        that = this;
7918                    //sync option selection as per new values
7919                    $("option", this.$userControl).each(function (index) {
7920                        var selectValue = $(this).val();
7921                        //Check if this value is present in options value array
7922                        if (_.contains(val, selectValue)) {
7923                            $(this).prop("selected", true);
7924                            selectedOptionFound = true;
7925                        } else {
7926                            $(this).prop("selected", false);
7927                            if (this.id === "emptyValue") {
7928                                $(this).val("").html(that.options.placeholder);
7929                                //Hiding emptyValue with no placeholder text configured.
7930                                if(that.options.placeholder.length == 0) {
7931                                    $(this).hide();
7932                                }
7933                            }
7934                        }
7935                    });
7936
7937                    /* Add default option if :
7938                    / 1. If placeholder add an extra option
7939                    / 2. If the value is set anything other than the options (and null/"") create a new option
7940                     */
7941                    if ((!selectedOptionFound && val.length != 0 && val[0] != null) || that.options.placeholder.length != 0) {
7942                        if (this.$userControl.children('[data-empty-option]').length == 0) {
7943                            var extraOption = document.createElement("option");
7944                            extraOption.setAttribute("data-empty-option", "");
7945                            extraOption.setAttribute("role", "none");
7946                            extraOption.setAttribute("value", "")
7947                            this.$userControl[0].insertBefore(extraOption, this.$userControl[0].firstChild);
7948                        }
7949                        // If placeholder is present the set value of empty option to placeholder
7950                        if (that.options.placeholder.length != 0) {
7951                            this.$userControl.children('[data-empty-option]').text(that.options.placeholder);
7952                        }
7953                        // If placeholder is present and value is not present then select placeholder
7954                        if (val.length == 0 || val[0] == null) {
7955                            this.$userControl.children('[data-empty-option]').prop("selected", true);
7956                        } // If value is set anything other than option then set empty option to value
7957                        else if (!selectedOptionFound && val.length != 0 && val[0] != null) {
7958                            this.$userControl.children('[data-empty-option]').text(val[0]).
7959                            prop("selected", true).
7960                            val(_.escape(val[0])).
7961                            show();
7962                        }
7963
7964                    }
7965                    else if (that.options.placeholder.length == 0) {
7966                        // Delete default option if value is found in options while adding options
7967                        if (selectedOptionFound && this.$userControl.children('[data-empty-option]').val() != that.options.displayValue) {
7968                            if (this.$userControl.children('[data-empty-option]').length > 0) {
7969                                this.$userControl[0].removeChild(this.$userControl.children('[data-empty-option]')[0]);
7970                            }
7971                        }
7972                        // Reset the value of dropdown based on rule
7973                        else if (!selectedOptionFound && (val.length == 0 || val == null || val[0] == null)) {
7974                            this.$userControl[0].value = "";
7975                        }
7976                    }
7977                    this.$userControl.toggleClass(this.PLACE_HOLDER_STYLE_CLASS, val.length == 0 || val == null);
7978                },
7979
7980                "items": function (val) {
7981                    if (!_.isArray(val)) {
7982                        val = [val];
7983                    }
7984
7985                    var AF_OPTGROUP_NAME = "afOptGroupName";
7986                    var i, j, optgroupOptions = [], element, $viewOptgroup, $preOptgroup;
7987                    var viewOptgroups = $("optgroup", this.$userControl);
7988                    // Removes all options which earlier didn't belong to any optgroup.
7989                    if (viewOptgroups.length == 0) {
7990                        // save selected value because when value is set before items in setWidgetOptions
7991                        // the selected value would get lost in html
7992                        var selectedOption = this.$userControl.find('[selected]');
7993                        this.$userControl.children("option[data-user-option]").remove();
7994                    }
7995                    for (i = 0, j = 0; j < val.length; j++) {
7996                        element = val[j];
7997                        if (element.save != AF_OPTGROUP_NAME) {
7998                            // Add options to String[] which will be later synced to the optgroup.
7999                            optgroupOptions.push(element);
8000                        } else {
8001                            $viewOptgroup = viewOptgroups[i++];
8002                            // When optgroup is less than the required optgroups.
8003                            if (i > viewOptgroups.length) {
8004                                $viewOptgroup = this.addGroup(element.display);
8005                            }
8006                            // Undefined as it may not occur even once when list is purely of options.
8007                            if (!_.isUndefined($viewOptgroup) && $viewOptgroup.label != element.display) {
8008                                $viewOptgroup.label = element.display || '';
8009                            }
8010                            // Check to skip the first optgroup.
8011                            if (j != 0) {
8012                                // Syncs options to the prev optgroup.
8013                                // Prev optgroup because current optgroup marks the end of options of prev.
8014                                this.handleOptions($preOptgroup, optgroupOptions);
8015                                // Clear options of the optgroup for next optgroup.
8016                                optgroupOptions = [];
8017                            }
8018                            $preOptgroup = $viewOptgroup;
8019                        }
8020                    }
8021                    // Removes all extra optgroups.
8022                    while (i < viewOptgroups.length) {
8023                        $viewOptgroup = viewOptgroups[i++];
8024                        this.deleteGroup($viewOptgroup.label);
8025                    }
8026                    //Add remaining options to respective optgroup.
8027                    if (optgroupOptions.length != 0) {
8028                        this.handleOptions($preOptgroup, optgroupOptions, selectedOption);
8029                    }
8030
8031                    //Intentionally left the selection check -> I am relying on the fact that "value" sync event is called after "items" sync.
8032                },
8033
8034                "displayValue": function () {
8035                },
8036                "placeholder": function(value){
8037                    // overriding the default handling of place holder options setter
8038                },
8039                "access": function (val) {
8040                    switch (val) {
8041                        case "open" :
8042                            this.$userControl.removeAttr("disabled");
8043                            this.$userControl.removeAttr("aria-disabled");
8044                            this.$userControl.removeAttr("aria-readonly");
8045                            var options = this.$userControl[0];
8046                            if(options && options.length > 0) {
8047                                _.each(this.$userControl[0], function (element) {
8048                                    element.removeAttribute("disabled");
8049                                });
8050                            }
8051                            break;
8052                        case "nonInteractive" :
8053                        case "protected" :
8054                            // In case of nonInteractive and protected, field should be disabled and cannot be tabbed.
8055                            this.$userControl.attr("disabled", "disabled");
8056                        case "readOnly" :
8057                            this.$userControl.attr("aria-disabled", "true");
8058                            this.$userControl.attr("aria-readonly", "true");
8059                            var options = this.$userControl[0];
8060                            if(options && options.length > 0) {
8061                                _.each(this.$userControl[0], function (element) {
8062                                    element.disabled = true;
8063                                });
8064                            }
8065                            break;
8066                        default  :
8067                            this.$userControl.removeAttr("disabled");
8068                            this.$userControl.removeAttr("aria-disabled");
8069                            this.$userControl.removeAttr("aria-readonly");
8070                            break;
8071                    }
8072                }
8073            })
8074        },
8075
8076        getEventMap: function () {
8077            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
8078            return $.extend({}, parentOptionsMap, {
8079                "focus": [xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT, xfalib.ut.XfaUtil.prototype.XFA_PREOPEN_EVENT],
8080                "change": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
8081            })
8082        },
8083
8084        render: func
8084tion () {
8085            var existingInlineStyleAttributeValues = this.element.find("select").attr("style"),
8086                newInlineStyleAttributeValues,
8087                combinedInlineStyleAttributeValues,
8088                size = 1;
8089
8090            this.element.addClass(this._widgetName);
8091            this.element.children().remove();
8092
8093            var inputName = _.uniqueId("select"),  //Unique Id
8094                textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
8095                $widgetSkeleton = $(this.widgetSkeleton)
8096                                    .attr('style', textStyle)
8097                                    .attr('name', inputName);
8098            if(this.options.editable) {
8099                $widgetSkeleton.addClass('combobox');
8100            }
8101
8102            if(this.options.items && this.options.items.length>0){
8103                size = this.options.items.length
8104            }
8105            if(this.options.multiSelect) {
8106                $widgetSkeleton.addClass('multiDropdown');
8107                $widgetSkeleton.attr('multiple','multiple');
8108                $widgetSkeleton.attr('size',size);
8109                $widgetSkeleton.attr('data-multiple-selection',"true");
8110            }
8111
8112            var $parEl = $widgetSkeleton;
8113            _.each(this.options.items, function(item){
8114                var saveItem = _.isString(item.save) ? item.save.replace(/\"/g, "&quot;") : "";
8115                if (saveItem === this.AF_OPTGROUP_NAME){ // assuming optgroups appear before options
8116                    $parEl = $(this.optGroupSkeleton).attr('label', item.display).appendTo($widgetSkeleton);
8117                } else {
8118                    $(this.optionSkeleton).val(saveItem).text(item.display).appendTo($parEl);
8119                }
8120            },this);
8121
8122            this.element.append($widgetSkeleton);
8123
8124            var control = this.element.children().eq(0).attr("name", this.options.name);
8125            this._attachEventHandlers(control);
8126            newInlineStyleAttributeValues = this.element.find("select").attr("style");
8127            //append the previous inlineStyleAttributeValues to newInlineStyleAttributeValues so that the inline styles
8128            //added from the dialog are applied.
8129            combinedInlineStyleAttributeValues = newInlineStyleAttributeValues + existingInlineStyleAttributeValues;
8130            this.element.find("select").attr("style", combinedInlineStyleAttributeValues);
8131            return control;
8132        },
8133
8134        //syncs the options to the optgroup dynamically.
8135        handleOptions : function ($viewOptgroup, val, selectedOption) {
8136            //When the list so far consists purely of options.
8137            if (_.isUndefined($viewOptgroup)) {
8138                $viewOptgroup = this.$userControl[0];
8139            }
8140            var viewOptions = $("option[data-user-option]", $viewOptgroup);
8141            //Syncs the value of options.
8142            for (var i = 0, j = 0; i < viewOptions.length && j < val.length; i++, j++) {
8143                var $viewOption = viewOptions[i];
8144                var element = val[j];
8145                if ($viewOption.text != element.display) {
8146                    $viewOption.text = element.display || '';
8147                }
8148                if ($viewOption.value != element.save) {
8149                    $viewOption.value = element.save || '';
8150                }
8151            }
8152            //Deletes options if count is more than required.
8153            while (i < viewOptions.length) {
8154                this.deleteOption(viewOptions[i++])
8155            }
8156            //Add options if count is less than required.
8157            while (j < val.length) {
8158                this.addOption($viewOptgroup, val[j++], selectedOption);
8159            }
8160            // Set empty value to dropdown if placeholder and default value is not present
8161            if (this.options.placeholder.length == 0) {
8162            	if (this.checkForEmptyValue(this.options.value)) {
8163            		this.$userControl[0].value = "";
8164            	}
8165            }
8166            // since options are removed and added again during items we need to set the access again options.
8167            this.optionsHandler["access"].apply(this, [this.options["access"]]);
8168        },
8169
8170        addOption : function ($viewOptgroup, element, selectedOption) {
8171            var $newOption = $(this.optionSkeleton).val(element.save).text(element.display);
8172            $newOption.appendTo($viewOptgroup);
8173            if(selectedOption) {
8174                if(element.save === selectedOption.val() && element.display === selectedOption.text()) {
8175                    $newOption.prop("selected", true);
8176                }
8177            }
8178            // Since the displayValue is a '\n' separated string of selected values in case of multiSelect,
8179            // we convert it to an array and check whether that array contains the save value of the element
8180            var values;
8181            if (this.options.value && _.isString(this.options.value)) {
8182                values = this.options.value.split('\n');
8183            } else if (_.isArray(this.options.value)) {
8184                // In the case of AF we have value/displayValue as an array
8185                values = this.options.value
8186            }
8187            if (values && values.indexOf(element.save) >= 0) {
8188                //Delete emptyValue with no placeholder text configured and value is found in options
8189                if (this.options.placeholder.length == 0 && this.$userControl.children('[data-empty-option]').length > 0) {
8190                    this.$userControl[0].removeChild(this.$userControl.children('[data-empty-option]')[0]);
8191                }
8192                this.$userControl.children().filter(function() {
8193                    return this.value == element.save;
8194                }).prop("selected", true);
8195            }
8196        },
8197
8198        deleteOption: function ($viewOption) {
8199            this.$userControl.find('option[value='+$viewOption.value+']').remove();
8200        },
8201
8202        checkForEmptyValue: function(value) {
8203            if ((value && _.isArray(value) && value[0] == null) || (this.options.value == null))
8204                return true;
8205            else
8206                return false;
8207        },
8208
8209        addGroup: function(label) {
8210            //Creates a optgroup Node.
8211            var optionGroup = document.createElement("OPTGROUP");
8212            optionGroup.label = label;
8213            this.$userControl[0].appendChild(optionGroup);
8214            return optionGroup;
8215        },
8216
8217        deleteGroup: function(label) {
8218            this.$userControl.children().remove('optgroup[label='+label+']');
8219        },
8220
8221        addItem: function(itemValues) {
8222            var newOption = new Option(itemValues.sDisplayVal || '', itemValues.sSaveVal || ''),
8223                val = this.options.value;
8224            this.$userControl[0].add(newOption, null);
8225            // if item has same value as present in options then mark it as selected
8226            if (_.contains(val, itemValues.sSaveVal)) {
8227                this.$userControl.find("option[value=" + itemValues.sSaveVal + "]").prop("selected", true);
8228                var emptyValue = this.$userControl.children('[data-empty-option]');
8229                if (emptyValue.length > 0 && emptyValue.val() === itemValues.sSaveVal) {
8230                    this.$userControl[0].removeChild(emptyValue[0]);
8231                }
8232            } else if ((val == null || val.length == 0 || val[0] == null) && this.options.placeholder.length == 0) {
8233                // Value should remain empty if option is not already selected & placeholder is empty
8234                this.$userControl[0].value = "";
8235            }
8236        },
8237
8238        clearItems: function () {
8239            //Deleting all the options including optGroup except the empty value.
8240            this.$userControl.children().not('[data-empty-option]').remove();
8241        },
8242
8243        deleteItem: function (nIndex) {
8244            //check for emptyValue instead of blindly doing + 1
8245            if (this.$userControl[0].item(0) && this.$userControl[0].item(0).id == "emptyValue")
8246                nIndex = nIndex + 1;
8247            //if there is emptyValue element then just delete one index higher
8248            //this check is must instead of blindly increasing the index by 1 because NWKListBox extends this class and that doesn't maintain emptyValue
8249            this.$userControl[0].remove(nIndex);
8250        },
8251
8252        getCommitValue: function (event) {
8253            var value = $("option:selected", this.$userControl).map(function () {
8254                return $(this).val();
8255            }).get();
8256            return value;
8257        },
8258
8259        showDisplayValue: function () {
8260        },
8261
8262        destroy: function () {
8263            this.element.
8264                removeClass(this._widgetName).
8265                children().remove().
8266                text("");
8267
8268            // call the base destroy function
8269            $.xfaWidget.defaultWidget.prototype.destroy.apply(this, arguments);
8270        },
8271
8272        _handleKeyDown: function (event) {
8273
8274            if (event.keyCode == 13) {
8275                //do nothing
8276                //just override the return key behaviour and over to defaultWidget for rest of the stuff.
8277                //return key is intercepted to avoid submission of form which is default behavior of html form element
8278                //but as a side effect it also stops the closing of drop down only in IE -> probably I should use IE condition but
8279                // this code works fine in          chrome as well so keeping it that way.
8280                //watson bug#3675141
8281            }
8282            else
8283                $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this, arguments);
8284        },
8285
8286        // CQ-51462 : focus and commit event (change) happen together hence first selection was modifying the value
8287        // we do not want focus to modify the value that is about to be committed
8288        showValue : function() {
8289
8290        }
8291    });
8292})($, _);
8293(function($, _){
8294	$.widget( "xfaWidget.listBox", $.xfaWidget.defaultWidget, {
8295
8296    _widgetName: "listBoxWidget",
8297
8298    options : {
8299        value : [],
8300        items : [],
8301        multiSelect : false
8302    },
8303
8304    getOptionsMap: function() {
8305        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
8306        return $.extend({},parentOptionsMap,{
8307            "width" : function(val) {
8308                //Bug#3597771. setting the height more than 0.95 brings scrollbar
8309                this.options.width = val*0.95
8310                parentOptionsMap.width.apply(this,[this.options.width])
8311            },
8312            "access" : function() {},
8313            "value": function(val) {
8314                var newValues = this.options.value,
8315                    self = this,
8316                    tabSet = false;
8317                if(!_.isArray(newValues))
8318                    newValues = [newValues];
8319                var tabSet
8320                this.$userControl.children().each(function(){
8321                    var saveVal = $(this).attr("data-save");
8322
8323                    // Check if this value is present in options value array
8324                    if(newValues && _.contains(newValues, saveVal)){
8325                        self._selectListItem($(this));
8326                        tabSet = true;
8327
8328                        // Set the selected data attribute to true.
8329                        if (!$.data(this, "_xfaInitialized")) {
8330                            //Initialized data- attributes parse for once using this call.
8331                            // Next onward don't use this. Instead use $.data which is cheap/
8332                            $(this).data();
8333                            $.data(this, "_xfaInitialized", true); //Mark the element to say that data has been initialized.
8334                        }
8335                        $.data(this, "selected", true);
8336
8337                    }
8338                    else{
8339                        $(this).removeClass("item-selected");
8340                        $(this).addClass("item-selectable");
8341                        $(this).attr("tabIndex", "-1");
8342                    }
8343                });
8344                if(!tabSet) {
8345                    $(this.$userControl.children().get(0)).attr("tabIndex", this.options.tabIndex);
8346                }
8347            },
8348
8349            "items" : function(val) {
8350                if(!_.isArray(val))
8351                    val = [val];
8352                var viewItems = this.$userControl.children();
8353
8354                //if number of items are not same in model and view then balance it
8355                if((viewItems.length) > val.length){
8356                    for(var i=viewItems.length; i >  val.length; i--){
8357                        this.deleteItem(i-1);
8358                    }
8359                }
8360                else if((viewItems.length) < val.length){
8361                    for(var i=viewItems.length; i < (val.length); i++){
8362                        this.addItem({sDisplayVal: val[i].display, sSaveVal: val[i].save});
8363                    }
8364                }
8365
8366                _.each(val, function(element, index){
8367                    var $viewItem = $(viewItems[index]);
8368                    if( $viewItem.text() != element.display){
8369                        $viewItem.text(element.display || '');
8370                    }
8371
8372                    if( $viewItem.attr("data-save") != element.save){
8373                        $viewItem.attr("data-save", element.save || '');
8374                    }
8375                });
8376
8377                //Intentionally left the selection check -> I am relying on the fact that "value" sync event is called after "items" sync.
8378            },
8379
8380            "displayValue" : function(){;},
8381
8382            "tabIndex": function() {
8383                var selectedItem = this.$userControl.children(".item-selected"),
8384                    children =this.$userControl.children()
8385                if(selectedItem.length) {
8386                    selectedItem.eq(0).attr("tabIndex", this.options.tabIndex);
8387                }
8388                else if(children.length > 0) {
8389                    children.eq(0).attr("tabIndex", this.options.tabIndex);
8390                }
8391            }
8392        })
8393    },
8394
8395    getEventMap: function() {
8396        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
8397        return $.extend({},parentOptionsMap,{
8398            "listboxenter":xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
8399            "listboxexit":xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
8400            "listboxchange":xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
8401            "focus":null,
8402            "blur":null
8403        })
8404    },
8405
8406    showDisplayValue : function() {
8407        },
8408
8409    render : function() {
8410        this.element.addClass( this._widgetName);
8411        this.element.children().remove();
8412
8413        //TODO: add a function for geting textStyle
8414        var textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
8415            that = this,
8416            //Bug#3597771 width and height are provided by the view itself.
8417            listElTemplate =
8418            '<ol style="position:absolute;<%=textStyle%>" role="listbox">' +
8419                '<% _.each(items, function(item){ %>' +
8420                '<% var saveItem = item.save ? item.save.replace(/\"/g,"&quot;"):null %>'+
8421                    '<li role="option" data-save="<% print(saveItem) %>" data-selected="false"><% print(item.display) %></li>'+
8422                '<%})%>'+
8423            '</ol>',
8424            compiledListElTemplate = _.template(listElTemplate),
8425            templateOptions = _.extend({
8426                "textStyle" : textStyle
8427                }, this.options),
8428            resolvedListEl = compiledListElTemplate(templateOptions);
8429        that.element.html(xfalib.ut.XfaUtil.prototype.encodeScriptableTags(resolvedListEl));
8430        var control = $(that.element.children().get(0)).attr("name",this.options.name);
8431        this._attachEventHandlers(control);
8432        return control
8433    },
8434
8435    focus: function() {
8436        if(this.$userControl.children(".item-selected").length > 0) {
8437            this.$userControl.children(".item-selected")[0].focus();
8438        }
8439        else if(this.$userControl.children().length > 0) {
8440            this.$userControl.children()[0].focus();
8441        }
8442    },
8443
8444    addItem : function(itemValues){
8445        $("<li></li>")
8446            .attr("data-save", itemValues.sSaveVal || '')
8447            .text(itemValues.sDisplayVal || '')
8448            .appendTo(this.$userControl)
8449            .click($.proxy(this._handleItemClick, this))
8450            .focus($.proxy(this._handleItemFocus, this));
8451
8452        // add new item as selected if the value is already present in options
8453        if (_.contains(this.options.value, itemValues.sSaveVal)) {
8454            this._selectListItem(this.$userControl.find("[data-save=" + itemValues.sSaveVal+ "]"));
8455        }
8456    },
8457
8458    clearItems : function(){
8459        $(this.$userControl).empty();
8460    },
8461
8462    deleteItem : function(nIndex){
8463        $(this.$userControl).children('li').each(function(index,element){
8464            if(index==nIndex){
8465                $(element).off("click").off("focus").remove();
8466            }
8467        })
8468    },
8469
8470
8471    _attachEventHandlers : function($control){
8472        var self = this;
8473        $control.keydown($.proxy(this._hotKeys,this))
8474            .children().on("mousedown",function() {
8475                    if(self.inFocus == true) {
8476                        self.mouseDown = true;
8477                    }
8478                })
8479            .click($.proxy(this._handleItemClick, this))
8480            .focus($.proxy(this._handleItemFocus, this))
8481            .blur($.proxy(this._handleFocusOut,this))
8482
8483    },
8484
8485     _hotKeys : function(event){
8486         if(this.options.access != "open")
8487             return;
8488         if(this.itemInFocus){
8489             switch(event.which) {
8490                 case 38: //arrow up
8491                     var prevSibling = $(this.itemInFocus).prev();
8492                     if(prevSibling){
8493                         this.keyDown = true;
8494                         prevSibling.focus();
8495                         this.keyDown = false;
8496                     }
8497                     event.preventDefault();
8498                     break;
8499                 case 40: //arrow down
8500                     var nextSibling = $(this.itemInFocus).next();
8501                     if(nextSibling){
8502                         this.keyDown = true;
8503                         nextSibling.focus();
8504                         this.keyDown = false;
8505                     }
8506                     event.preventDefault();
8507                     break;
8508                 case 91: //left arrow
8509                 case 92: //right arrow
8510                     event.preventDefault();
8511                     break;
8512                 case 32:
8513                     this._toggleItem(this.itemInFocus);
8514                     event.preventDefault();
8515                     break;
8516                 default:
8517             }
8518         }
8519     },
8520
8521     _toggleItem: function(item) {
8522         var $item = $(item),
8523             multiMode = this.options.multiSelect, // && event.ctrlKey ;
8524             that = this;
8525             //toggle selected state of this item
8526             this.$data(item, "selected", !this.$data(item, "selected"));
8527         var state = this.$data(item, "selected")
8528
8529         if(!multiMode) {
8530             var $selectedItem = this.$userControl.children(".item-selected")
8531             if($selectedItem.length) {
8532                 this.$data($selectedItem[0],"selected",false)
8533                 $selectedItem.removeClass("item-selected").addClass("item-selectable")
8534             }
8535         }
8536         $item.toggleClass("item-selectable",!state).
8537               toggleClass("item-selected",state)
8538
8539         this.$userControl.trigger("listboxchange");
8540     },
8541
8542     getCommitValue: function() {
8543         var that = this,
8544             multiMode = this.options.multiSelect;
8545
8546
8547         return this.$userControl.children().map(function(){
8548             // intentionally using $this.attr("data-save") instead of $this.data("data")
8549             return that.$data(this, "selected") ? $(this).attr("data-save") : null;
8550         }).get();
8551     },
8552
8553      _handleItemFocus : function(event){
8554          if(this.options.access != "open")
8555              return;
8556          var item = event.target;
8557          this.itemInFocus = item;
8558
8559          // overriding default widgets handleFocus
8560          if(!(this.keyDown || this.mouseDown)) {        //we do not need to fire focus event if
8561              this.$userControl.trigger("listboxenter")  // clicked on another li element or pressed a key to move the selectio
8562          }
8563          this.mouseDown = false;
8564          this.inFocus = true;
8565      },
8566
8567     _handleItemClick : function(event){
8568        // Bug#3501811 If clicked onlistbox entry more than once, exit event is not fired
8569        // Clicking on the same entry does not call focus and hence we were not resetting the state. Doing it in onClick
8570        if(this.mouseDown == true)
8571            this.mouseDown = false;
8572        if(this.options.access != "open")
8573             return;
8574        this._toggleItem(event.target)
8575    },
8576
8577    _handleFocusOut: function(){
8578        if(!(this.keyDown || this.mouseDown)) {
8579            this.$userControl.trigger("listboxexit");
8580            this.inFocus = false
8581        }
8582    },
8583
8584    _selectListItem : function ($elem) {
8585        if ($elem && $elem.length) {
8586            $elem.removeClass("item-selectable")
8587                .addClass("item-selected")
8588                .attr("tabIndex", this.options.tabIndex);
8589        }
8590    },
8591
8592    destroy: function() {
8593        this.element.
8594            removeClass(this._widgetName).
8595            children().remove().
8596            text("");
8597
8598        $.xfaWidget.defaultWidget.prototype.destroy.apply(this, arguments);
8599    }
8600});
8601})($, window._);
8602(function($) {
8603    $.widget( "xfaWidget.nwkListBox",  $.xfaWidget.dropDownList, {            //non-webkit listbox
8604
8605        _widgetName : "nwkListBox",
8606
8607        options : {
8608            value : [],
8609            multiSelect : false
8610        },
8611
8612        render : function() {
8613            var $control = $.xfaWidget.dropDownList.prototype.render.apply(this, arguments);
8614            if($control){
8615                $control.children("#emptyValue").remove();
8616                if(this.options.multiSelect)
8617                    $control.attr("multiple", "multiple");
8618            }
8619            this._updateSelectSize($control);
8620            return $control;
8621        },
8622
8623        addItem : function(itemValues){
8624            $.xfaWidget.dropDownList.prototype.addItem.apply(this, arguments);
8625            this._updateSelectSize();
8626        },
8627
8628        clearItems : function(){
8629            $.xfaWidget.dropDownList.prototype.clearItems.apply(this, arguments);
8630            this._updateSelectSize();
8631        },
8632
8633        deleteItem : function(nIndex){
8634            $.xfaWidget.dropDownList.prototype.deleteItem.apply(this, arguments);
8635            this._updateSelectSize();
8636        },
8637
8638        _updateSelectSize : function($control){
8639            $control = $control || this.$userControl;
8640            $control.attr("size", (this.options.items || []).length);
8641        },
8642
8643        // Bug#3597771
8644        // focus and commit event happen together hence first selection was modifying the value
8645        // we do not want focus to modify the value that is about to be committed
8646        showValue : function() {
8647
8648        }
8649
8650  });
8651})($);
8652(function ($) {
8653    $.widget("xfaWidget.xfaButton", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
8654
8655        _widgetName: "xfaButton",
8656
8657        options: {
8658            value: null,
8659            svgCaption: false //option to indicate if button already has an SVG caption
8660        },
8661
8662        getOptionsMap: function () {
8663            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
8664            return $.extend({}, parentOptionsMap, {
8665                "access": function (val) {
8666                    switch (val) {
8667                        case "open" :
8668                            this.$userControl.removeAttr("disabled");
8669                            this.$userControl.removeAttr("aria-disabled");
8670                            break;
8671                        case "nonInteractive" :
8672                        case "protected" :
8673                        case "readOnly" :
8674                            this.$userControl.attr("disabled", "disabled");
8675                            this.$userControl.attr("aria-disabled", "true");
8676                            break;
8677                        default  :
8678                            this.$userControl.removeAttr("disabled");
8679                            this.$userControl.removeAttr("aria-disabled");
8680                            break;
8681                    }
8682                },
8683                "value": function () {
8684                },
8685                "displayValue": function () {
8686                },
8687                "svgCaption": function (val) {
8688                    if (val) {
8689                        this.$userControl.removeAttr("value");
8690                    }
8691                }
8692            })
8693        },
8694
8695        _attachEventHandlers: function ($control) {
8696            $control.click(function () {
8697                this.focus()
8698            });
8699        },
8700
8701        getCommitValue: function () {
8702            return this.options.value;
8703        },
8704
8705        showValue: function () {
8706        },
8707
8708        showDisplayValue: function () {
8709        }
8710    });
8711})($);(function ($) {
8712    $.widget("xfaWidget.XfaCheckBox", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
8713
8714        _widgetName: "XfaCheckBox",
8715
8716        options: {
8717            value: null,
8718            state: -1,
8719            states: 2,
8720            values: [],
8721            mandatory: false
8722        },
8723
8724        checkedState: false,
8725        clickPending: false,
8726
8727        getOptionsMap: function () {
8728            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
8729            return $.extend({}, parentOptionsMap, {
8730                "access": function (val) {
8731                    switch (val) {
8732                        case "open" :
8733                            this.$userControl.removeAttr("disabled");
8734                            this.$userControl.removeAttr("aria-disabled");
8735                            break;
8736                        case "nonInteractive" :
8737                        case "protected" :
8738                        case "readOnly" :
8739                            this.$userControl.attr("disabled", "disabled");
8740                            this.$userControl.attr("aria-disabled", "true");
8741                            break;
8742                        default  :
8743                            this.$userControl.removeAttr("disabled");
8744                            this.$userControl.removeAttr("aria-disabled");
8745                            break;
8746                    }
8747                },
8748
8749                "displayValue": function (val) {
8750                    this.$userControl.attr(this.options.commitProperty, this.options.value);
8751                    this._state(this.dIndexOf(this.options.values, this.options.value));
8752                    this.$userControl.attr("checked", this.checkedState ? "checked" : null);
8753                    this.$userControl.prop("checked", this.checkedState ? "checked" : null);
8754                    //for accessibility
8755                    this.$userControl.attr("aria-checked", this.checkedState);
8756                    if (this.options.state == 2)
8757                        this.$userControl.addClass("neutral");
8758                    else if (this.options.states == 3)
8759                        this.$userControl.removeClass("neutral");   // since current state != neutral
8760                },
8761
8762                "allowNeutral": function (val) {
8763                    var intVal = parseInt(val);
8764                    if (intVal == 0 || intVal == 1) {
8765                        this.options.states = 2 + intVal;
8766                    }
8767                },
8768
8769                "paraStyles": function (paraStyles) {
8770                    parentOptionsMap.paraStyles.apply(this, arguments);
8771                    this._handleVAlignOnExit();
8772                }
8773            })
8774        },
8775
8776        getEventMap: function () {
8777            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
8778            return $.extend({}, parentOptionsMap, {
8779                 "xfacheckboxchange" :  xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
8780                 "xfacheckboxclick" :   xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT,
8781                 "change": null,
8782                 "click" : null
8783               })
8784        },
8785
8786        _attachEventHandlers: function ($control) {
8787            var that = this;
8788            var focusFunc = function (evnt) {
8789                if (!that.inFocus) {
8790                    that.focus();
8791                    that.inFocus = true;
8792                }
8793            }
8794            var focusOutFunc = function (evnt) {
8795                that.inFocus = false;
8796            }
8797            $control.click(focusFunc).change(focusFunc).blur(focusOutFunc);
8798            $control.change($.proxy(this._handleChange,this)).click($.proxy(this._handleClick,this));   //LC-5106
8799        },
8800
8801        getCommitValue: function () {
8802            this._state((this.options.state + 1) % this.options.states);
8803            this.$userControl.attr("checked", this.checkedState ? "checked" : null);
8804            //for accessibility
8805            this.$userControl.attr("aria-checked", this.checkedState)
8806            if (this.options.state == 2) {
8807                this.$userControl.addClass("neutral");
8808            }
8809            else if (this.options.states == 3)
8810                this.$userControl.removeClass("neutral"); // since current state != neutral
8811
8812            return this.options.values[this.options.state];
8813        },
8814
8815        _handleVAlignOnExit: function (evnt) {
8816            //--this is being kept empty as no other browser (i.e Mozilla and Chrome) take the padding-bottom or padding-top into account.
8817            // the only browser to take it into consideration is IE. And moreover the alignment and padding considerations have already been taken into account in
8818            // calculations in CheckButtonFieldView.js. And on removing the entire function it takes up the _handleVAlignOnExit() of AbstractWidget.
8819
8820        },
8821
8822        _handleChange: function (evnt) {
8823            this.$userControl.trigger("xfacheckboxchange"); //change is always fired
8824            if(this.clickPending === true) {
8825              this.clickPending = false;
8826              this.$userControl.trigger("xfacheckboxclick");
8827            } else {
8828                // handling of this.clickPending is added to handle the case when clicked on checkbox/radiobutton label/caption
8829                this.clickPending = true;
8830            }
8831        },
8832
8833        _handleClick: function (evnt) {
8834             var isChrome = xfalib.ut.XfaUtil.prototype.detectChrome(),
8835                 isIE = xfalib.ut.XfaUtil.prototype.detectIE(),
8836                 isSafari = xfalib.ut.XfaUtil.prototype.isSafari(),
8837                 userControlType = this.$userControl.attr("type");
8838             // click will not be fired if the previous state of the radiobutton is 'on'.
8839             // NPR-35652 : Checkbox movement - Click event works fine on chrome but not in iOS safari for collapsible fields
8840             // CQ-103023 : Click Event on Radio Button not working correctly in Chrome 53
8841             // CQ-103715 : CQ-103715 : Click Event on Check Box not working correctly in Chrome and Firefox, added handling for checkbox also
8842             // handling of this.clickPending is added to handle the case when clicked on checkbox/radiobutton label/caption
8843             if(($.browser.mozilla || isChrome || isSafari) && !isIE && this.clickPending === false && ((userControlType === "radio" && this.checkedState === false) || (userControlType === "checkbox"))) {
8844               this.clickPending = true;
8845             }
8846             else {
8847                this.$userControl.trigger("xfacheckboxclick");
8848                this.clickPending = false;
8849             }
8850        },
8851
8852        _state: function (newState) {
8853            if (newState == undefined)
8854                return this.options.state;
8855            else
8856                this.options.state = newState;
8857            this.checkedState = (newState == 0 || newState == 2);
8858        },
8859
8860        click: function () {
8861            // trigger change for check box and for radio only if it is not selected
8862            // otherwise radio button will go in deselected state
8863            if (this.$userControl.attr("type") !== "radio" || this.options.state !== 0) {
8864                this.$userControl.trigger("change");
8865            }
8866            //we should call only the handler since calling click will trigger change.
8867            this.$userControl.triggerHandler("click");
8868        }
8869    });
8870})($);
8871(function($, _){
8872    $.widget( "xfaWidget.textField", $.xfaWidget.defaultWidget, {
8873
8874        _widgetName: "textField",
8875
8876        options: {
8877            curValue : null ,
8878            pos:0,
8879            lengthLimitVisible: true,
8880            maxChars:0 ,
8881            flag:"",
8882            // by default html5Type is set to true
8883            // we leverage pattern, maxLength support from HTML5 browser for mobile forms
8884            html5Type : "text",
8885            length : null,
8886            minLength : 0,
8887            totalLengthMessage : "",
8888            minimumLengthMessage : "",
8889        },
8890
8891        getOptionsMap: function() {
8892            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
8893            return $.extend({},parentOptionsMap,{
8894                "maxChars": function(maxchars) {
8895                    if(this._maxCharsReached(this.options.value)) {
8896                        var value = this.options.value.slice(0,maxchars)
8897                        this._setOption("value", value);
8898                        this._setOption("displayValue", value);
8899                    }
8900
8901                },
8902
8903                "multiLine ": function(val) {
8904                    if(this.options.multiLine)
8905                        this.$userControl.attr("aria-multiline", "true");
8906                    else
8907                        this.$userControl.removeAttr("aria-multiline", "false");
8908                },
8909
8910                "height": function(val) {
8911                    if(val)   {
8912                        this.$css(this.$userControl[0],{"height" :val})
8913                        this._handleVAlignOnExit();    // To Handle the case of expandable Fields
8914                    }
8915                },
8916                "width": function(val){
8917                    parentOptionsMap.width.apply(this,arguments);
8918                    // handle valign on width change as well
8919                    // as content height(scrollHeight) varies according to width
8920                    this._handleVAlignOnExit();
8921                },
8922                "paraStyles": function(paraStyles){
8923                    parentOptionsMap.paraStyles.apply(this,arguments);
8924                    this._handleVAlignOnExit();
8925                }
8926
8927            })
8928        },
8929
8930        render : function() {
8931            var control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
8932            // use the control to set HTML5 attributes
8933            if (control && control.length > 0 && this.options.html5Type) {
8934                var minLength = this.options.minLength,
8935                    maxLength = this.options.maxChars,
8936                    length = this.options.length;
8937                    isMinLengthSet = minLength != null && minLength > 0,
8938                    isMaxLengthSet = maxLength != null && maxLength > 0,
8939                    isLengthSet = length != null && length > 0,
8940                    isMultiline = this.options.multiLine,
8941                    minLengthMsg = this.options.minimumLengthMessage,
8942                    totLengthMsg = this.options.totalLengthMessage,
8943                    pattern = ""; // html5 pattern is not supported for textarea
8944
8945                // order of execution matters for the below code snippet
8946                if (isMinLengthSet) {
8947                    // add minLength though it is not fully supported in all browsers
8948                    // hence also adding pattern attribute
8949                    control.attr("minlength", parseInt(minLength));
8950                    if(minLengthMsg && minLengthMsg.length > 0) {
8951                        control.attr("title", this.options.minimumLengthMessage); // html5 supported message on pattern validation failure
8952                    }
8953                }
8954
8955                if (isMaxLengthSet) {
8956                    control.attr("maxlength", parseInt(maxLength));
8957                }
8958
8959                // if both min and max length is set
8960                if(isMinLengthSet && isMaxLengthSet){
8961                    pattern += ".{" + minLength + "," + maxLength + "}";
8962                } else if(isMinLengthSet) {
8963                    // if only min length set
8964                    pattern += ".{" + minLength + ",}";
8965                }
8966
8967                // if length is set then set min and max length in pattern equal to length
8968                if (isLengthSet) {
8969                    if(isMultiline){ // set both min and maxlength as pattern is not supported
8970                        control.attr("minlength", parseInt(length));
8971                        control.attr("maxlength", parseInt(length));
8972                    }
8973                    if(totLengthMsg && totLengthMsg.length > 0) {
8974                        control.attr("title", this.options.totalLengthMessage);
8975                    }
8976                    // reset the pattern string
8977                    pattern = ".{" + length + "," + length + "}";
8978                }
8979                // if required is set, set the required attribute, it is necessary else an empty value will be excluded from constraint validation
8980                if (this.options.required) {
8981                    control.attr("required", true);
8982                }
8983                // set the pattern if not empty and check if this is not multiline, since pattern is not supported for textarea
8984                if (pattern && pattern.length > 0 && !isMultiline) {
8985                    control.attr("pattern", pattern);
8986                }
8987            }
8988            return control;
8989        },
8990
8991        /*  This function aligns vAlign when:
8992         1. parastyles is present and the widget contains a value.
8993         2. During initial rendering if no content present fallback to the previous logic.
8994         3. Presence of content in widget.
8995        */
8996        _handleVAlignOnExit: function(){
8997             var value = this.options.displayValue,
8998                 noContentPresent = _.isEmpty(this.$userControl.val() || this.options.displayValue),
8999                 contentHeight,widgetHeight,diff,tempCSS;
9000
9001             //the widget doesn't have value as yet but content exists [ Rendering of widget]
9002             if (!this.options.paraStyles || noContentPresent) {
9003                //vAlign has to be handled only if there is paraStyles and widget has content
9004                return;
9005             }
9006
9007             // mozilla results in vAlign regression hence made this change only for textarea
9008             if($(this.element[0]).find("textarea").length >0 && !noContentPresent)  {
9009               /* measureExtent not returning correct height of content in textarea even with all
9010                 css values */
9011               tempCSS={'height':this.$userControl.css('height'),'padding':this.$userControl.css('padding')};
9012               this.$css(this.$userControl[0],{'height':'1px','padding':'0px'});
9013
9014               contentHeight = this._getContentHeight();
9015               this.$css(this.$userControl[0],tempCSS);
9016               widgetHeight = this.options.height;
9017               diff = widgetHeight - contentHeight;
9018               this._calculatePaddingForVAlign(diff);
9019             } else {
9020                // widget has no initial content or is a textfield.Proceed as before.
9021                $.xfaWidget.defaultWidget.prototype._handleVAlignOnExit.apply(this,arguments);
9022             }
9023        },
9024
9025        getEventMap: function() {
9026            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
9027            return $.extend({},parentOptionsMap,{
9028                "onKeyInput.textField" : xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
9029            })
9030        },
9031
9032        _maxCharsReached: function(val) {
9033            var isMaxLengthSupported = false,
9034                elementName = this.options.multiLine ? "textarea" : "input";
9035            // in browsers, where max length is supported, we don't custom javascript checks, we let HTML do the validation of max length
9036            if(this.options.html5Type && xfalib.view.util.HtmlUtil.elementSupportsAttribute(elementName, "maxLength")){
9037                isMaxLengthSupported = true;
9038            }
9039            return !isMaxLengthSupported && this.options.maxChars
9040                   && this.options.maxChars!=="0"
9041                   && val
9042                   &&  val.length >= this.options.maxChars
9043        },
9044
9045        _handleKeyInput : function(event, character, code) {
9046            if(event.ctrlKey && !_.contains(['paste', 'cut'], event.type)) {
9047                return true;
9048            }
9049
9050            if(!this.options.multiLine) {
9051                $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this, arguments);
9052                character = (code == 13) ? '' : character ;
9053            }
9054
9055            var val =  this.$userControl.val(),
9056                selectionStart = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionStart") || 0,
9057                selectionEnd = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionEnd") || 0,
9058                pos = selectionStart,
9059                // CQ-4260239 : "&nbsp" taking space of 5 chars for restricting the length to visible area
9060                newVal = (val.substr(0, selectionStart) + character + val.substr(selectionEnd));
9061            this.options.curValue = val;
9062            if(!this.options.multiLine) { //TODO:looks like a bug
9063                this.options.lengthLimitVisible = true;
9064                this.options.pos = pos;
9065                if(this.options.hScrollDisabled && !_.contains(['keydown', 'cut'], event.type)) {
9066                    var expectedWidth = xfalib.view.util.TextMetrics.measureExtent(newVal, {refEl: this.$userControl[0], maxWidth:-1}).width;
9067                    if(!event.ctrlKey && expectedWidth > this.$userControl.width()){   // Why  allowance of 5 required??
9068                        this.options.lengthLimitVisible = false;
9069                        event.preventDefault();
9070                        return false;
9071                    }
9072                }
9073            } else if (this.options.multiLine && this.options.hScrollDisabled) {  // LC-4656 : wait till user input, if it causes an overflow revert to old text
9074                var $textArea = this.$userControl;
9075                $textArea.css("padding", "0px 0px 0px");  // TODO : take care of multiline selection & padding later
9076
9077                // TODO : find a scheme to avoid attaching and detaching listeners, currently $.val() causes 'input' to fire, resulting in an infinite loop
9078                $textArea.one("input", function () {
9079                    if ($textArea.prop('scrollHeight') > $textArea.prop('offsetHeight')) {
9080                        $textArea.val(val)
9081                                 .prop("selectionStart", selectionEnd)
9082                                 .prop("selectionEnd", selectionEnd);  // LC-4656 : reset the cursor pos, afterwards
9083                        character = null;
9084                        code = 0;
9085                    }
9086                });
9087            }
9088
9089            if (!_.contains(['keydown', 'cut'], event.type) && this._maxCharsReached(val) && selectionStart === selectionEnd) {
9090                event.preventDefault();
9091                return false;
9092            }
9093
9094            this.$userControl.trigger({
9095                type : "onKeyInput.textField",
9096                originalType : event.type,
9097                character : character,  // contains the pasted string or pressed key
9098                keyCode : event.keyCode || 0,
9099                charCode : event.charCode || 0,
9100                which : event.which || 0,
9101                ctrlKey : event.ctrlKey || event.metaKey || false,
9102                shiftKey : event.shiftKey || false,
9103                keyDown: false, // This property is available only for list boxes and drop-down lists
9104                selectionStart: selectionStart,
9105                selectionEnd: selectionEnd
9106            });
9107        },
9108
9109        _handleKeyDown : function(event){
9110            if (event) {
9111                var code = event.charCode || event.which || event.keyCode || 0;
9112                if(code == 8 || code == 46) // backspace and del
9113                   this._handleKeyInput(event, "", code);
9114            }
9115        },
9116
9117        _handleKeyPress : function(event){
9118            if (event) {
9119                var code = event.charCode || event.which || event.keyCode || 0,
9120                    character = (code == 13) ? "\n" : String.fromCharCode(code); // modified '\r\n' -> '\n'
9121
9122            if(xfalib.ut.XfaUtil.prototype.isNonPrintableKey(event.key)) { // mozilla also generates a keypress, along with keydown
9123                return true;                                               // for all keys, so only handling printable keys in keypress
9124            }
9125
9126            this._handleKeyInput(event, character, code);
9127            }
9128        },
9129
9130        _compositionUpdateCallback : function (event) {
9131            var that = this;
9132            var val = that.$userControl.val();
9133            if (event.type === "compositionupdate" && event.originalEvent.data) {
9134                // this has been deliberately done to get the actual data in case of max character.
9135                if (that.options.maxChars) {
9136                    val = event.originalEvent.data;
9137                } else {
9138                    val = val + event.originalEvent.data.substr(event.originalEvent.data.length - 1);
9139                }
9140            }
9141            var flag = that._maxCharsReached(val);
9142            if (flag) {
9143                // if max reached
9144                var newVal = val.substr(0, that.options.maxChars);
9145                //in case the value is not changed then we do not need to update value and close the android keyboard.
9146                if (val === newVal) {
9147                    return false;
9148                }
9149                that.$userControl.val(newVal);
9150            }
9151            return flag;
9152        },
9153
9154        _attachEventHandlers: function($control) {
9155            $.xfaWidget.defaultWidget.prototype._attachEventHandlers.apply(this, arguments);
9156            // IME specific handling, to handle japanese languages max limit
9157            $.xfaWidget.defaultWidget.prototype._attachCompositionEventHandlers.apply(this, arguments);
9158        },
9159
9160        _handlePaste : function(event){
9161            if (event) {
9162                var pastedChar = undefined;
9163                if (window.clipboardData && window.clipboardData.getData) { // IE
9164                    pastedChar = window.clipboardData.getData('Text');
9165                } else if (event.originalEvent.clipboardData && event.originalEvent.clipboardData.getData) {
9166                    pastedChar = event.originalEvent.clipboardData.getData('text/plain');
9167                }
9168                if(pastedChar) {
9169                    this._handleKeyInput(event, pastedChar, 0);
9170                }
9171            }
9172        },
9173
9174        _handleCut : function(event) {
9175            if (event) {
9176                this._handleKeyInput(event, "", 0);
9177            }
9178        },
9179
9180        postProcessExit: function(evnt) {
9181            $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
9182            if (this.options.multiLine && this.options.hScrollDisabled) {
9183                return;
9184            }
9185            this._handleVAlignOnExit();
9186        },
9187
9188        preProcessEnter: function(evnt) {
9189            $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
9190            if(this.options.multiLine && this.options.hScrollDisabled)
9191                return;
9192            this._handleVAlignOnEnter();
9193        },
9194
9195        /**
9196         * @brief: Select the given field on focus in Internet Explorer
9197         *
9198         */
9199        _selectOnFocusInIE : function(){
9200            // if the value is not same only then do selection in IE
9201            // For Issue: LC-9895, we check if value not same
9202            if($.browser.msie && !this._isValueSame()) {
9203                this.$userControl.select();
9204            }
9205            else {
9206                //all other browsers behave like a good boy
9207            }
9208        },
9209
9210        showValue : function() {
9211            $.xfaWidget.defaultWidget.prototype.showValue.apply(this,arguments);
9212            //IE doesn't show selected text if we focus and set its value all the time so force selection
9213            this._selectOnFocusInIE();
9214        },
9215
9216        getCommitValue: function() {
9217            var value = $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
9218
9219            if(this._maxCharsReached(value)) {
9220                value = value.slice(0,this.options.maxChars);
9221            }
9222
9223            this.$userControl.val(this.options.value);
9224
9225            //TODO: ask Sharad whether it is right
9226            if(this.options.multiLine && this.options.hScrollDisabled)  {
9227                //var str= this._checkLines(value);
9228                //if(value != str) {
9229                    return value;
9230                //}
9231            }
9232            return value;
9233        },
9234
9235        /*
9236        ** returns the contentHeight which needs to be considered for padding for valign,
9237        ** if no contentHeight is present then fontSize is returned.
9238        */
9239        _getContentHeight: function () {
9240            var contentHeight = Math.ceil(this.$userControl.get(0).scrollHeight);
9241            return contentHeight ? contentHeight : this.options.fontSize;
9242        }
9243    });
9244})($, window._);
9245/*************************************************************************
9246 *
9247 * ADOBE CONFIDENTIAL
9248 * __________________
9249 *
9250 *  Copyright 2019 Adobe Systems Incorporated
9251 *  All Rights Reserved.
9252 *
9253 * NOTICE:  All information contained herein is, and remains
9254 * the property of Adobe Systems Incorporated and its suppliers,
9255 * if any.  The intellectual and technical concepts contained
9256 * herein are proprietary to Adobe Systems Incorporated and its
9257 * suppliers and may be covered by U.S. and Foreign Patents,
9258 * patents in process, and are protected by trade secret or copyright law.
9259 * Dissemination of this information or reproduction of this material
9260 * is strictly forbidden unless prior written permission is obtained
9261 * from Adobe Systems Incorporated.
9262 **************************************************************************/
9263
9264(function ($) {
9265    $.widget("xfaWidget.richTextField", $.xfaWidget.textField, {
9266
9267        _widgetName : "richTextField",
9268
9269        _richTextWidget : null,
9270
9271        _changeAccess : function (val) {
9272            switch (val) {
9273                case "open":
9274                    if (this._richTextWidget) {
9275                        this._richTextWidget.editor.enable();
9276                        this._richTextWidget.$toolbar.removeClass("hideToolbar");
9277                    }
9278                    break;
9279                case "readOnly":
9280                    if (this._richTextWidget) {
9281                        this._richTextWidget.editor.disable();
9282                        this._richTextWidget.$toolbar.addClass("hideToolbar");
9283                    }
9284                    break;
9285            }
9286        },
9287
9288        getOptionsMap : function () {
9289            var parentOptionsMap = $.xfaWidget.textField.prototype.getOptionsMap.apply(this, arguments);
9290            return $.extend({}, parentOptionsMap, {
9291                "value" : function (val) {
9292                    if (this._richTextWidget) {
9293                        this._richTextWidget.setRichTextEditorContent(val);
9294                    }
9295                },
9296                "access" : function (val) {
9297                    this._changeAccess(val);
9298                }
9299            });
9300        },
9301
9302        getEventMap : function () {
9303            // in case of IE browsers, focus event is delayed, hence adding activate method for content editable
9304            if (xfalib.ut.XfaUtil.prototype.isIE()) {
9305                var parentOptionsMap = $.xfaWidget.textField.prototype.getEventMap.apply(this, arguments);
9306                return $.extend({}, parentOptionsMap, {
9307                    "activate.richTextField" : xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT
9308                });
9309            } else {
9310                return $.xfaWidget.textField.prototype.getEventMap.apply(this, arguments);
9311            }
9312        },
9313
9314        render : function () {
9315            var $richTextWidget = this.element.find("div.richTextWidget").eq(0);
9316            if(!$richTextWidget.length){
9317                var attachedTextareaClasses = this.element.children().attr('class');
9318                var richTextWidgetElement = '<div class="richTextWidget ' + attachedTextareaClasses + '" id="richTextField_' + this.options.name + '_' + attachedTextareaClasses + '"></div>';
9319                this.element.children().remove();
9320                this.element.append(richTextWidgetElement);
9321                $richTextWidget = this.element.find("div.richTextWidget").eq(0);
9322            }else{
9323                $richTextWidget.children().remove();
9324            }
9325            $richTextWidget.append(this.options.value);
9326            return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9327        },
9328
9329        getCommitValue : function () {
9330            var value = "";
9331            if (this._richTextWidget) {
9332                value = this._richTextWidget.getRichTextEditorContent();
9333            }
9334            return value;
9335        },
9336
9337        preProcessEnter : function (evnt) {
9338            $.xfaWidget.textField.prototype.preProcessEnter.apply(this, arguments);
9339            var $richTextDiv = this.$userControl.find("div.richTextWidget").eq(0);
9340            if(!$richTextDiv.length){
9341                $richTextDiv = this.element.find("div.richTextWidget").eq(0);
9342                this.changeDefaultToolbarConfig();
9343                this.$userControl.parents('.richtextsupport').css('z-index', 'auto');
9344            }
9345            if (window.Form === undefined || window.Form.rte === undefined) {
9346                /* Forms RTE is part of Forms Addon package only. Dont do anything if addon is not installed.*/
9347                return;
9348            } else if (this._richTextWidget === null) {
9349                this._initializeRTEToolbar();
9350                this._richTextWidget = new window.Form.rte.RichTextEditor({
9351                    selector : $richTextDiv.attr("id"),
9352                    toolbar : window.Form.rte.RichTextEditor.MFToolbar,
9353                    data : this.options.value,
9354                    locale : $richTextDiv.data("locale")
9355                });
9356                var that = this;
9357                this._richTextWidget.editor.on("blur:composer", function () {
9358                    that.$userControl.trigger("blur");
9359                });
9360                // initialize the access
9361                if (this.options.access) {
9362                    this._changeAccess(this.options.access);
9363                }
9364            }
9365        },
9366
9367        changeDefaultToolbarConfig: function(){
9368            if(window.Form && window.Form.rte){
9369                var toolbarDefaultConfigData = window.Form.rte.DefaultConfig;
9370                toolbarDefaultConfigData.fontSize.defaultValue = this.options.fontSize;
9371                toolbarDefaultConfigData.fontFamily.defaultValue = this.options.fontFamily;
9372
9373                // Adding 'isFontInPx' flag and overriding two utility functions
9374                // 'getDefaultParaStyle' and 'getMissingParaStyle' are responsible for adding RTE font styling attributes to rich text elements
9375                toolbarDefaultConfigData.isFontInPx = true;
9376                this.changeDefaultParaStyleUtility();
9377                this.changeMissingParaStyleUtility();
9378
9379                // Adding dropdown values in default config if not available in options
9380                if(toolbarDefaultConfigData.fontSize.options.indexOf(this.options.fontSize) === -1){
9381                    toolbarDefaultConfigData.fontSize.options.push(this.options.fontSize);
9382                }
9383                if(toolbarDefaultConfigData.fontFamily.options.indexOf(this.options.fontFamily) === -1){
9384                    toolbarDefaultConfigData.fontFamily.options.push(this.options.fontFamily);
9385                }
9386            }
9387        },
9388
9389        changeDefaultParaStyleUtility: function(){
9390            Form.rte.util.HtmlUtils.getDefaultParaStyle = function (config) {
9391                var style = "";
9392                if (config) {
9393                    style += 'font-family:' + config.fontFamily.defaultValue + ';';
9394                    if(config.isFontInPx){
9395                        style += 'font-size:' + config.fontSize.defaultValue + 'px;';
9396                        style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'px;';
9397                    }else{
9398                        style += 'font-size:' + config.fontSize.defaultValue + 'pt;';
9399                        style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'pt;';
9400                    }
9401                    style += 'color:#000000;';
9402                    style += 'text-align:left;';
9403                }
9404
9405                return style;
9406            };
9407        },
9408
9409        changeMissingParaStyleUtility : function(){
9410            Form.rte.util.HtmlUtils.getMissingParaStyle = function (style, config) {
9411                if (style && style.length > 0) {
9412                    if (config) {
9413                        if (!Form.rte.util.StringHelper.endsWith(style, ";")) {
9414                            style += ";";
9415                        }
9416                        if (style.indexOf("font-family") < 0) {
9417                            style += 'font-family:' + config.fontFamily.defaultValue + ';';
9418                        }
9419                        if (style.indexOf("font-size") < 0) {
9420                            if(config.isFontInPx){
9421                                style += 'font-size:' + config.fontSize.defaultValue + 'px;';
9422                            }else{
9423                                style += 'font-size:' + config.fontSize.defaultValue + 'pt;';
9424                            }
9425                        }
9426                        if (style.indexOf("letter-spacing") < 0) {
9427                            if(config.isFontInPx){
9428                                style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'px;';
9429                            }else{
9430                                style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'pt;';
9431                            }
9432                        }
9433                        if (style.indexOf("color") < 0) {
9434                            style += 'color:#000000;';
9435                        }
9436                        if (style.indexOf("text-align") < 0) {
9437                            style += 'text-align:left;';
9438                        }
9439                    }
9440                } else {
9441                    style = Form.rte.util.HtmlUtils.getDefaultParaStyle(config);
9442                }
9443                return style;
9444            };
9445        },
9446
9447        _initializeRTEToolbar : function () {
9448            window.Form.rte.RichTextEditor.MFToolbar = window.Form.rte.RichTextEditor.MFToolbar || {
9449                defaultMode : 'basic',
9450                toolbars : {
9451                    basic : {
9452                        layout : [
9453                            {
9454                                items : [Form.rte.Commands.HEADER]
9455                            },
9456                            {
9457                                items : [Form.rte.Commands.BOLD, Form.rte.Commands.ITALIC, Form.rte.Commands.UNDERLINE]
9458                            },
9459                            {
9460                                command : 'lists',
9461                                icon : 'list',
9462                                title : "List Type",
9463                                type : 'popover',
9464                                placement : 'bottom',
9465                                items : [Form.rte.Commands.INSERT_UNORDERED_LIST,
9466                                    Form.rte.Commands.INSERT_ORDERED_LIST,
9467                                    Form.rte.Commands.INSERT_LOWERCASE_ALPHABET_LIST]
9468                            },
9469                            {
9470                                title : 'Expand',
9471                                command : Form.rte.Commands.MODE,
9472                                value : Form.rte.ToolbarMode.FULL,
9473                                icon : 'resize-full'
9474                            }
9475                        ],
9476                        floating : true
9477                    },
9478                    full : {
9479                        layout : [
9480                            {
9481                                items : [Form.rte.Commands.BOLD, Form.rte.Commands.ITALIC, Form.rte.Commands.UNDERLINE]
9482                            },
9483                            {
9484                                items : [Form.rte.Commands.SUPERSCRIPT, Form.rte.Commands.SUBSCRIPT]
9485                            },
9486                            {
9487                                items : [
9488                                    Form.rte.Commands.HEADER, Form.rte.Commands.FONT_FAMILY, Form.rte.Commands.LINE_HEIGHT, Form.rte.Commands.FORE_COLOR, Form.rte.Commands.HILITE_COLOR, Form.rte.Commands.LINK
9489                                ]
9490                            },
9491                            {
9492                                items : [Form.rte.Commands.INSERT_UNORDERED_LIST, Form.rte.Commands.INSERT_ORDERED_LIST, Form.rte.Commands.INSERT_LOWERCASE_ALPHABET_LIST
9493                                ]
9494                            },
9495                            {
9496                                title : 'Collapse',
9497                                command : Form.rte.Commands.MODE,
9498                                value : Form.rte.ToolbarMode.BASIC,
9499                                icon : 'resize-small',
9500                                selected : true
9501                            }
9502                        ]
9503                    }
9504                }
9505            };
9506        }
9507    });
9508
9509})($);(function($){
9510	$.widget( "xfaWidget.imageField", $.xfaWidget.defaultWidget, {
9511
9512    _widgetName:"imageField",
9513
9514    options: {
9515        tabIndex: 0,
9516        "role": "img"
9517    },
9518
9519    getEventMap: function () {
9520        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
9521        return $.extend({}, parentOptionsMap, {
9522            "imagechange": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
9523        })
9524    },
9525
9526    getOptionsMap: function() {
9527        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
9528        return $.extend({},parentOptionsMap,{
9529            "screenReaderText": function(val) {
9530                if(val)
9531                    this.$userControl.attr("alt", val)
9532            },
9533            "displayValue": function(val) {
9534                var widgetValue;
9535                if (this.options.value) {
9536                    widgetValue = "data:;base64," + this.options.value;
9537                } else {
9538                    widgetValue = "";
9539                }
9540                this.$userControl.prop(this.options.commitProperty, widgetValue);
9541                this.$userControl.attr(this.options.commitProperty, widgetValue);
9542            },
9543            "access" : function() {},
9544
9545            // CQ-85514 : use max-ht & max-wd to honor image's intrinsic ht & wd attributes & prevent distortion
9546            "height" : function (val) {
9547                // in case aspect is actual then we need to crop the image, which will be not possible if max height and width are set
9548                if (val && this.options.aspect != "actual") {
9549                    this.$css(this.$userControl[0], {"max-height": val});
9550                }
9551            },
9552            "width" : function (val) {
9553                if (val && this.options.aspect != "actual") {
9554                    this.$css(this.$userControl[0], {"max-width": val});
9555                }
9556            },
9557            "aspect" : function (val) {
9558                // value of actual turns off scaling, causing the image to be drawn at its native size,
9559                // as per xfa spec Adobe implementations crop the image
9560                if(this.options.aspect == "actual") {
9561                    var right = this.$userControl.attr("width"),
9562                        bottom = this.$userControl.attr("height");
9563                    right = right.indexOf("px") >= 0 ? right : right + "px";
9564                    bottom = bottom.indexOf("px") >= 0 ? bottom : bottom + "px";
9565                    this._cropImage("0px", right, bottom, "0px");
9566                    this.$userControl.removeAttr("height width");
9567                // value of none indicates no aspect ratio
9568                // as per xfa spec image is independently scaled in the horizontal and vertical directions to exactly f
9568ill the field,
9569                // which are already set to fill the field
9570                } else if (this.options.aspect != "none") {
9571                // A value of fit, which is the default, causes the scale to be such that the image fills as much of the field as possible
9572                // without overflowing it in either dimension.
9573                    this.$userControl.attr({"height" : "auto", "width" : "auto"});
9574                }
9575            }
9576        });
9577    },
9578
9579    // crop the image using top,right, bottom, left coordiantes of the image
9580    _cropImage : function (top, right, bottom, left) {
9581        var clipRect = "rect(" + top + "," + right + "," + bottom + "," + left + ")";
9582        var clipPathPolygon = "polygon( 0px 0px, 0px " + bottom + "," + right + " " + bottom +"," + right + " 0px)";
9583        // clip property is deprecated but still supported by all the major browsers
9584        // clip-path replaces the deprecated clip property but still is not fully supported by all major browser
9585        this.$userControl.css({"clip" : clipRect, "clip-path" : clipPathPolygon});
9586    },
9587
9588    render : function() {
9589        var self = this;
9590        if (typeof FileReader !== "undefined") {
9591            this.reader = new FileReader();
9592        } else {
9593            xfalib.ut.XfaUtil.prototype.getLogger().error("Image Field is supported only for HTML5 supported browsers.");
9594        }
9595        if (this.element) {
9596            // change event triggered when new image is selected
9597            this.$widgetInput = this.element.find("input").on("change.imageField", function() {
9598                self._handleInputChange();
9599            }).click(function(event) {
9600                // to stop bubbling of event from input to widget
9601                event.stopPropagation();
9602            });
9603            this.$widgetImg = this.element.on("click.imageField", function() {
9604                self._imageClick();
9605            }).find("img");
9606        }
9607        if (this.reader) {
9608            //load event is triggered each time the reading operation is successfully completed
9609            this.reader.addEventListener("load", function () {
9610                self.$widgetImg.attr("src",self.reader.result);
9611                self.$widgetImg.trigger("imagechange");
9612            }, false);
9613        }
9614        return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9615    },
9616
9617    getCommitValue: function() {
9618        return this._extractData(this.$userControl.attr("src"));
9619    },
9620
9621    // hidden input change handler, input change will be triggered on selecting a new image
9622    _handleInputChange : function() {
9623        this._displayImage();
9624    },
9625
9626    _imageClick : function(clickEvent) {
9627        //as the input button is hidden we trigger click explicitly on click of the widget
9628        this.$widgetInput.trigger("click");
9629    },
9630
9631    // removes "data\:.*\;base64," from the image base64 string
9632    _extractData : function(value) {
9633        return value.replace(/data\:.*\;base64,/, "");
9634    },
9635
9636    // previews image in the imagefield widget
9637    _displayImage : function() {
9638        var imageFile = this.$widgetInput.get(0).files ? this.$widgetInput.get(0).files[0] : null;
9639        if (imageFile && this._isFileOfImageType(imageFile.name)) {
9640            if (this.reader) {
9641                //readAsDataURL method is used to read the contents of the specified file, result attribute contains  the data as a URL representing the file's data as a base64 encoded string
9642                this.reader.readAsDataURL(imageFile);
9643            }
9644        }
9645    },
9646
9647    // Test for supported image file(jpg,jpeg,png,gif,tif,bmp)
9648    _isFileOfImageType : function(fileName) {
9649        if (fileName) {
9650            return (/\.(jpe?g|png|gif|tif|bmp)$/i.test(fileName));
9651        }
9652        return false;
9653    }
9654});
9655})($);
9656/**
9657 * Created with IntelliJ IDEA.
9658 * User: rpandey
9659 * Date: 12/24/12
9660 * Time: 8:06 PM
9661 * To change this template use File | Settings | File Templates.
9662 */
9663
9664
9665(function($){
9666    $.widget( "xfaWidget.signatureField", $.xfaWidget.defaultWidget, {
9667
9668        _widgetName:"signatureField",
9669
9670        getOptionsMap: function() {
9671            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
9672            return $.extend({},parentOptionsMap,{
9673                "displayValue": function(val) {},
9674                "access": function(val) {}
9675            })
9676        },
9677
9678        render : function() {
9679            var $control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9680            //pessimistic checks
9681            if($control) {
9682                $control.attr("readOnly","readonly").attr("disabled", true);
9683            }
9684            return $control;
9685        }
9686    });
9687})($);
9688/*
9689 * ADOBE CONFIDENTIAL
9690 * ___________________
9691 *
9692 * Copyright 2011-2012 Adobe Systems Incorporated
9693 * All Rights Reserved.
9694 *
9695 * NOTICE:  All information contained herein is, and remains
9696 * the property of Adobe Systems Incorporated and its suppliers,
9697 * if any.  The intellectual and technical concepts contained
9698 * herein are proprietary to Adobe Systems Incorporated and its
9699 * suppliers and may be covered by U.S. and Foreign Patents,
9700 * patents in process, and are protected by trade secret or copyright law.
9701 * Dissemination of this information or reproduction of this material
9702 * is strictly forbidden unless prior written permission is obtained
9703 * from Adobe Systems Incorporated.
9704 */
9705 
9706/**
9707 * widget definition for scribbleable field
9708 */
9709(function($,xfalib){
9710
9711 var TouchUtil=xfalib.ut.TouchUtil;
9712 var ScribbleUtil=(function(){
9713      return {
9714          localeString:function(id){
9715                    return xfalib.ut.XfaUtil.prototype.encodeScriptableTags($.xfaWidget.abstractWidget.prototype.localeStrings()[id])  || id;
9716          }
9717      };
9718 })();
9719 var DELETE_KEY = 46;
9720 var ESC_KEY = 27;
9721 var ENTER_KEY = 13;
9722/**
9723 * Scribble class definition, used for drawing on canvas using mouse or touch
9724 */
9725function Scribble( canvasID,image,_width,_height, callback) {
9726    this._callback = callback;
9727    this.canvasID = canvasID;
9728    this._lineWidth=5;
9729    this.canvas = $("#"+canvasID);
9730    this.context = this.canvas.get(0).getContext("2d"); 
9731    this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
9732    this._enabled=true;
9733    this.context.strokeStyle = "#000000";
9734    this.canvasBorderWidth = parseInt(this.canvas.css('border-left-width'),10); // assuming top and left borders are same width
9735    this.context.lineWidth = this._lineWidth;
9736    this.lastMousePoint = {x:0, y:0};
9737    
9738    this.canvas[0].width = _width;// this.canvas.parent().innerWidth();
9739    this.canvas[0].height = _height;//this.canvas.parent().innerHeight();
9740    if(!image){
9741        this.context.fillStyle   = '#ffffff';
9742        this.context.clearRect(0,0,_width,_height);
9743    } else {
9744        this.context.drawImage(image,0,0);
9745    }
9746    this.canvas.on( TouchUtil.POINTER_DOWN, this.onCanvasMouseDown() );
9747}
9748Scribble.prototype.setLineWidth=function(w){
9749    this._lineWidth=w;
9750};
9751Scribble.prototype.onCanvasMouseDown = function () {
9752    var self = this;
9753    return function(event) {
9754        if(TouchUtil.getTouches(event).length < 2){
9755            self.mouseMoveHandler = self.onCanvasMouseMove();
9756            self.mouseUpHandler = self.onCanvasMouseUp();
9757            //CQ-4261765 : Scribble sign scroll issue with ios
9758            //https://stackoverflow.com/questions/49500339/cant-prevent-touchmove-from-scrolling-window-on-ios
9759            //https://github.com/jquery/jquery/issues/2871
9760            document.addEventListener(TouchUtil.POINTER_MOVE, self.mouseMoveHandler,{ passive: false });
9761            $(document).on(TouchUtil.POINTER_UP, self.mouseUpHandler );
9762            self.updateMousePosition( event );
9763            self.updateCanvas( event );
9764        }
9765    }
9766};
9767
9768Scribble.prototype.onCanvasMouseMove = function () {
9769    var self = this;
9770    return function(event) {
9771        if(TouchUtil.getTouches(event).length < 2){
9772            self.updateCanvas( event );
9773            event.preventDefault();
9774            return false;
9775        }
9776    }
9777};
9778
9779Scribble.prototype.onCanvasMouseUp = function (event) {
9780    var self = this;
9781    return function(event) {
9782        document.removeEventListener(TouchUtil.POINTER_MOVE, self.mouseMoveHandler,{ passive: false });
9783        $(document).off(TouchUtil.POINTER_UP, self.mouseUpHandler );
9784        self.mouseMoveHandler = null;
9785        self.mouseUpHandler = null;
9786    }
9787};
9788
9789Scribble.prototype.updateMousePosition = function (event) {
9790    if(!this._enabled) return ;
9791    var target = TouchUtil.getTouchEvent(event);
9792
9793    var offset = this.canvas.offset();
9794    /* In IE>=10 pageX values are incorrect when using zoom
9795     so calculate them using clientX and scrollLeft */
9796    this.lastMousePoint.x = target.clientX + $(window).scrollLeft() - offset.left - this.canvasBorderWidth;
9797    this.lastMousePoint.y = target.clientY + $(window).scrollTop() - offset.top - this.canvasBorderWidth;
9798
9799};
9800Scribble.prototype._isInsideCanvas = function(x,y){
9801    return y>=0 && y<this.canvas[0].height && x>=0 && x < this.canvas[0].width;
9802};
9803    Scribble.prototype.updateCanvas = function (event) {
9804    if(!this._enabled) {
9805       return;
9806    }
9807    var oldX,oldY,dX,dY,canDraw,scaleX,scaleY,cssWidth,cssHeight;
9808    cssWidth = parseInt(this.canvas[0].style.width,10);
9809    cssHeight = parseInt(this.canvas[0].style.height,10);
9810    scaleX =  cssWidth?this.canvas[0].width/cssWidth:1;
9811    scaleY = cssHeight?this.canvas[0].height/cssHeight:1;
9812
9813    scaleX /= xfalib.ut.XfaUtil.prototype.formScaleFactor;
9814    scaleY /= xfalib.ut.XfaUtil.prototype.formScaleFactor;
9815
9816    oldX = this.lastMousePoint.x*scaleX;
9817    oldY = this.lastMousePoint.y*scaleY;
9818   
9819    this.updateMousePosition( event );
9820
9821    var newX =  this.lastMousePoint.x*scaleX;
9822    var newY =  this.lastMousePoint.y*scaleY;
9823
9824    dX = Math.abs(newX - oldX );
9825    dY = Math.abs(newY - oldY );
9826
9827    canDraw = ( dX > 0 || dY > 0 ) && this._isInsideCanvas(oldX,oldY) && this._isInsideCanvas(newX,newY);;
9828
9829    if(canDraw){
9830        this.context.beginPath();
9831        this.context.moveTo( oldX, oldY );
9832        this.context.lineTo(newX, newY );
9833        this.context.lineWidth=this._lineWidth;
9834        this.context.lineCap='round';
9835        this.context.stroke();
9836		
9837        this._callback();
9838		
9839    }
9840};
9841
9842Scribble.prototype.toString = function () {
9843
9844    var dataString = this.canvas.get(0).toDataURL("image/png");
9845    //var index = dataString.indexOf( "," )+1;
9846    //dataString = dataString.substring( index );
9847
9848    return dataString;
9849};
9850Scribble.prototype.setEnabled=function(enable){
9851    this._enabled=enable;
9852};
9853Scribble.prototype.clear = function () {
9854
9855    var c = this.canvas[0];
9856    this.context.clearRect( 0, 0, c.width, c.height );
9857};
9858
9859
9860// ImageEdit dialog box
9861var imageEditDialog=(function(_){
9862  
9863    // html used to construct dialog box
9864    var htmlStr=(function(){
9865         var html=[
9866             '<div id="iEBox_container" tabindex="0" role="dialog" aria-label="'+ScribbleUtil.localeString("pleaseSignText")+'">',
9867                  '<div id="iEBox_panel">',
9868                      '<div  id = "iEBox_Cancel" class="iEBox_button" tabindex="0" role="button" aria-label="'+ScribbleUtil.localeString("cancel")+'" title="'+ScribbleUtil.localeString("cancel")+'" ></div>',
9869                  '</div>',
9870                  '<div id="iEBox_content">',
9871                      '<div id="iEBox_canvases" align=center>',
9872                          '<div style="display:inline-block; vertical-align:top;">',
9873                               '<canvas  id="iEBox_canvas" style="margin:0px;border-bottom:0px;" width="696" height="390" ></canvas>' ,
9874                               '<input type="text" id="keyboard_Sign_Box" name="signatureText" placeholder="'+ScribbleUtil.localeString("typeYourSignatureHere")+'">',
9875                               '<fieldset id="iEBox_caption"><legend align="center">
9875'+ScribbleUtil.localeString("pleaseSignText")+'</legend></fieldset>',
9876                          '</div>',
9877                          '<canvas id="iEBox_geoCanvasRight" width="0" height="0" ></canvas>',
9878                          '<div><canvas id="iEBox_geoCanvasBottom" width="0" height="0" ></canvas></div>',
9879                      '</div>',
9880                      '<div>',
9881                          '<div id="iEBox_Brush" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("brushes")+'"  title="'+ScribbleUtil.localeString("brushes")+'"></div>',
9882                          '<div id="iEBox_Clear" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("clear")+'"  title="'+ScribbleUtil.localeString("clear")+'" ></div>',
9883                          '<div id="iEBox_Geo" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("geolocation")+'"  title="'+ScribbleUtil.localeString("geolocation")+'" ></div>',
9884                          '<div id="iEBox_Text" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("typeYourName")+'"  title="'+ScribbleUtil.localeString("typeYourName")+'"></div>',
9885                          '<div id="iEBox_title"></div>',
9886                          '<div id="iEBox_Ok" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("ok")+'"  title="'+ScribbleUtil.localeString("ok")+'" ></div>',
9887                      '</div>' ,
9888                  '</div>' ,
9889                  '<div id="iEBox_moveframe" ></div>',
9890                  '<div id="iEBox_brushList" ></div>',
9891              '</div>'].join("");
9892           return function(){
9893              return html;
9894           };
9895    });
9896	
9897    /**
9898	 *   
9899	 */
9900	
9901    var dialogObj = {
9902        verticalOffset: 0, // removing the magic value of -75 since it was not causing any impact
9903        horizontalOffset: 0,
9904        repositionOnResize: true,
9905        overlayOpacity: .75,
9906        overlayColor: '#CCCCCC',
9907        draggable: true,
9908        _brushes:[2,3,4,5,6,7,8,9,10],
9909		_buttonsEnabled:{},
9910		_isOpen:false,
9911        show:function(title,callback){
9912           this._show(callback);
9913		   this._buttonsEnabled={Geo:true,Clear:true,Ok:true,Cancel:true,Brush:true,Text:true};
9914        },
9915		setEnabled:function(button,enable){
9916		    if(this._buttonsEnabled[button]!=enable){
9917		           this._buttonsEnabled[button]=enable;
9918				   if(enable){
9919				       $('#iEBox_'+button).empty('<div style="background:white;width:100%;height:100%;opacity:0.75;"></div>').
9920				                  removeClass("disable_button");
9921				   } else {
9922				       $('#iEBox_'+button).append('<div style="background:white;width:100%;height:100%;opacity:0.75;"></div>').
9923				                  addClass("disable_button");
9924				   }
9925			       
9926			}
9927		},
9928		enableButtons:function(buttons){
9929		    for(var k in buttons){
9930				   this.setEnabled(k,buttons[k]);
9931			}
9932		},
9933        toggleBrushList:function(event){
9934                var that = this;
9935                if($('#iEBox_brushList').css('display')!='none'){
9936                    $('#iEBox_brushList').css({display:'none'});
9937                    return;
9938                }
9939                 var tmpFn =  document.onselectstart;
9940                 document.onselectstart=function(){return false;};
9941                 $('#iEBox_brushList').css({display:'block',visibility:'hidden'});
9942                    $('#iEBox_brushList').offset($('#iEBox_Brush').offset());
9943                    $('#iEBox_brushList').offset({top:$('#iEBox_Brush').offset().top-$('#iEBox_brushList').height()});
9944                    $('#iEBox_brushList').css({display:'block',visibility:'visible'});
9945                  //  $('#iEBox_brushList').focus();
9946                     $('#iEBox_brushList').one('mouseleave',function(event){
9947                         $('#iEBox_brushList').css({display:'none'});
9948                          document.onselectstart=tmpFn;
9949                     });
9950        },
9951        _attachCallbacks: function(callback) {
9952            var that = this;
9953            var sigCanvas = $('#iEBox_canvas')[0];
9954            var ctx=sigCanvas.getContext("2d");
9955            var minSigCanvasFontSize=10;
9956            var maxSigCanvasFontSize=70;
9957            var sigCanvasFontSize=minSigCanvasFontSize;
9958            var initialSigCanvasFontSize=sigCanvasFontSize;
9959            var initialFontCalculatedFlag=false;
9960            var sigCanvasFontFamily="sans-serif, Georgia";
9961            var sigCanvasFontStyle="italic";
9962           _.each("Cancel-Clear-Geo-Ok-Brush-Text".split("-"),function(val,idx){
9963                    $("#iEBox_"+val).click( function(event) {
9964				       if(that._buttonsEnabled[val]){
9965                          event.stopPropagation();
9966                          callback(val);
9967				       }
9968                    });
9969					$("#iEBox_"+val).keydown( function(event) {
9970				       if(that._buttonsEnabled[val] && (event.keyCode == ENTER_KEY || event.charCode == ENTER_KEY || event.which == ENTER_KEY) ){
9971                          event.stopPropagation();
9972                          callback(val);
9973				       }
9974                    });
9975            });
9976            _.each($("#iEBox_brushList").children(),function(itm,idx){
9977                  $(itm).on(TouchUtil.POINTER_UP,function(event){
9978                         callback("BrushSelect",that._brushes[idx]);
9979                         $('#iEBox_brushList').css({display:'none'});
9980                          // $(itm).css({backgroundColor:'#FFFFFF'});
9981                  });
9982                  $(itm).on(TouchUtil.POINTER_DOWN,function(event){
9983                          // $(itm).css({backgroundColor:'#AAAAAA'});
9984                           event.preventDefault();
9985                  });
9986             });
9987
9988            $('#keyboard_Sign_Box').keydown(function (event){
9989                var inputSign=$('#keyboard_Sign_Box')[0].value;
9990
9991                if(event.key==="Backspace") {
9992                    ctx.font=sigCanvasFontStyle+sigCanvasFontSize+"px "+sigCanvasFontFamily;
9993                    sigCanvasFontSize=dialogObj._increaseFontForSignature(ctx.measureText(inputSign).width,sigCanvas.width,
9994                        sigCanvasFontSize,initialSigCanvasFontSize);
9995                    ctx.font=sigCanvasFontStyle+" "+sigCanvasFontSize+"px "+sigCanvasFontFamily;
9996                    ctx.clearRect(0, 0, sigCanvas.width, sigCanvas.height);
9997                    ctx.fillText(inputSign, 3, sigCanvasFontSize, sigCanvas.width-5);
9998                }
9999                event.stopPropagation();
10000            });
10001
10002            $("#keyboard_Sign_Box").keyup(function (event){
10003                var inputSign=$('#keyboard_Sign_Box')[0].value;
10004                if(inputSign.length==0) {
10005                    dialogObj.enableButtons({Ok: false, Clear: false});
10006                }
10007                if(inputSign.length>=1 && inputSign.trim().length!=0) {
10008                    dialogObj.enableButtons({Ok: true, Clear: true});
10009                }
10010                if(initialFontCalculatedFlag===false){
10011                    sigCanvasFontSize=sigCanvas.height-20;
10012                    sigCanvasFontSize=sigCanvasFontSize<minSigCanvasFontSize?minSigCanvasFontSize:sigCanvasFontSize;
10013                    sigCanvasFontSize=sigCanvasFontSize>maxSigCanvasFontSize?maxSigCanvasFontSize:sigCanvasFontSize;
10014                    initialSigCanvasFontSize=sigCanvasFontSize;
10015                    $('#keyboard_Sign_Box')[0].style.font=sigCanvasFontStyle+" 2rem "+sigCanvasFontFamily;
10016                    initialFontCalculatedFlag=true;
10017                }
10018                ctx.font=sigCanvasFontStyle+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10019                sigCanvasFontSize=dialogObj._decreaseFontForSignature(ctx,inputSign,sigCanvas.width,
10020                    sigCanvasFontSize,sigCanvasFontFamily);
10021                ctx.font=sigCanvasFontStyle+" "+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10022                ctx.clearRect(0, 0, sigCanvas.width, sigCanvas.height);
10023                ctx.fillText(inputSign,3,sigCanvasFontSize,sigCanvas.width-5);
10024                event.stopPropagation();
10025            });
10026
10027            // capture tab key and escape
10028            $('#iEBox_container').keydown(function(event){
10029                var firstFocusableItem = document.querySelector("#iEBox_container");
10030                var lastFocusableItem = document.querySelector("#iEBox_Ok");
10031                var KEYCODE_TAB = 9;
10032                var isTabPressed = (event.key === 'Tab' || event.keyCode === KEYCODE_TAB);
10033                if((event.keyCode == ESC_KEY || event.charCode == ESC_KEY || event.which == ESC_KEY)) {
10034                    event.stopPropagation();
10035                    event.preventDefault();
10036                    callback("Cancel");
10037                } else if (isTabPressed) {
10038                    // Trap focus inside the dialog box
10039                    if (event.shiftKey && document.activeElement === firstFocusableItem) {
10040                        // when shift + tab key is pressed
10041                        lastFocusableItem.focus();
10042                        event.preventDefault();
10043                    } else if (document.activeElement === lastFocusableItem) {
10044                        // when tab key is pressed
10045                        firstFocusableItem.focus();
10046                        event.preventDefault();
10047                    }
10048                }
10049
10050            });
10051
10052            if(this.draggable){
10053                this._makeDraggable(TouchUtil.TOUCH_ENABLED);
10054            }
10055        },
10056
10057        _decreaseFontForSignature:function(ctx,inputSign,sigCanvasWidth,fontSize,sigCanvasFontFamily){
10058            while(ctx.measureText(inputSign).width>sigCanvasWidth-5 && fontSize>20){
10059                fontSize=fontSize-10;
10060                ctx.font=fontSize+"px "+sigCanvasFontFamily;
10061            }
10062            return fontSize
10063        },
10064        _increaseFontForSignature:function(textWidth,sigCanvasWidth,fontSize,initialSigCanvasFontSize){
10065            if(sigCanvasWidth-textWidth>0){
10066                fontSize=initialSigCanvasFontSize;
10067            }
10068            return fontSize;
10069        },
10070        _makeDraggable:function(touchEnabled){
10071              var _isMouseDown=false;
10072              var _that=this;
10073              var dX;
10074              var dY;
10075              var offsetPos;
10076              var _mouseMovFun;
10077              var _mouseUpFun;
10078              $('#iEBox_panel').on(TouchUtil.POINTER_DOWN,function( event ){
10079              
10080                  if(TouchUtil.getTouches(event).length < 2){
10081                      if($(event.target).is('#iEBox_panel')){
10082                          $('body')[0].addEventListener(TouchUtil.POINTER_MO
10082VE,_mouseMovFun=function( event ){
10083                              if(TouchUtil.getTouches(event).length < 2 && _isMouseDown){
10084                                  event.preventDefault();
10085                                  var evt = TouchUtil.getTouchEvent(event);
10086                                  var delX = evt.pageX - dX;
10087                                  var delY = evt.pageY - dY;
10088                                  $('#iEBox_moveframe').offset({
10089                                      top: offsetPos.top+delY,
10090                                      left: offsetPos.left+delX
10091                                  });
10092                              }
10093                          }, { passive: false });
10094                          $('body').on(TouchUtil.POINTER_UP,_mouseUpFun=function(event){
10095                              if(_isMouseDown){
10096                                  var offsetMove = $('#iEBox_moveframe').offset();
10097                                  var topEdge  = $(window).scrollTop();
10098                                  var bottomEdge = topEdge + $(window).height();
10099                                  if(offsetMove.top - topEdge < 1){
10100                                      offsetMove.top = topEdge;
10101                                  }
10102                                  if(offsetMove.top - bottomEdge + $('#iEBox_panel').height() > 0 ){
10103                                      offsetMove.top = bottomEdge - $('#iEBox_panel').height();
10104                                  }
10105                                  $('#iEBox_container').offset(offsetMove );
10106                                  $('#iEBox_moveframe').css({display:'none'}).offset(offsetMove);
10107                                  _isMouseDown=false;
10108                                  $('body')[0].removeEventListener(TouchUtil.POINTER_MOVE,_mouseMovFun,{ passive: false });
10109                                  $('body').off(TouchUtil.POINTER_UP,_mouseUpFun);
10110                              }
10111                          });
10112
10113                          var evt = TouchUtil.getTouchEvent(event);
10114                          _isMouseDown=true; dX = evt.pageX;dY=evt.pageY;
10115                          offsetPos = $('#iEBox_container').offset();
10116                          $('#iEBox_moveframe').css({display:'block'});
10117                          $('#iEBox_moveframe').offset(offsetPos);
10118                          $('#iEBox_moveframe').css('width',$('#iEBox_container').css('width'));
10119                          $('#iEBox_moveframe').css('height',$('#iEBox_container').css('height'));
10120                      }
10121                  }
10122              });
10123             
10124        },
10125        _createBrushes:function(){
10126               var _that=this;
10127              _.each(this._brushes,function(val,idx){
10128                  var divel = document.createElement('DIV');
10129                  var cnv = document.createElement('CANVAS');
10130                  var ctx = cnv.getContext('2d');
10131                  cnv.style.border='1px solid #AAAAAA';
10132                  cnv.width=TouchUtil.TOUCH_ENABLED?200:100;
10133                  cnv.height=TouchUtil.TOUCH_ENABLED?40:20;;
10134                  ctx.lineWidth=val;
10135                  ctx.beginPath();
10136                  ctx.moveTo(10,cnv.height/2);
10137                  ctx.lineTo(cnv.width-10,cnv.height/2);
10138                  ctx.stroke();
10139                  divel.appendChild(cnv);
10140                  $('#iEBox_brushList').append(divel);
10141               });
10142        },
10143		getIsOpen:function(){
10144		    return dialogObj._isOpen;
10145		},
10146		setIsOpen:function(open){
10147		    dialogObj._isOpen = open;
10148		},
10149        _show: function(callback) {
10150            dialogObj.hide();
10151            dialogObj._overlay('show');
10152            
10153            $("BODY").append(htmlStr());
10154            dialogObj.setIsOpen(true);
10155            $('#iEBox_container').focus();
10156            dialogObj._createBrushes();
10157
10158            dialogObj._reposition();
10159
10160            // calculate spacing around canvas area
10161            // this will be used to find canvas dimensions based on available screen area.
10162            var container_el = $('#iEBox_container');
10163            var canvas_el =  $('#iEBox_canvas');
10164            var container_width = $('#iEBox_container').outerWidth(true);
10165            var container_height = $('#iEBox_container').outerHeight(true);
10166            var canvas_width = canvas_el[0].width;
10167            var canvas_height = canvas_el[0].height;
10168            dialogObj.canvas_spacing = { x:container_width - canvas_width, y:container_height-canvas_height};
10169
10170            dialogObj._maintainPosition(true);
10171            
10172            dialogObj._attachCallbacks(callback);
10173        },
10174
10175        hide: function() {
10176            $("#iEBox_container").remove();
10177            this._overlay('hide');
10178            dialogObj.setIsOpen(false);
10179            this._maintainPosition(false);
10180        },
10181        _overlayResize:function(event) {
10182            if($("#iEBox_overlay").height()!= $(document).height()){
10183                $("#iEBox_overlay").height( $(document).height() );
10184            }
10185
10186        },
10187        _disableMove:function(event) {
10188            event.preventDefault();
10189        },
10190        _overlay: function(status) {
10191            switch( status ) {
10192                case 'show':
10193                    this._overlay('hide');
10194                    $("BODY").append('<div id="iEBox_overlay"></div>');
10195                    $("#iEBox_overlay").css({
10196                        position: 'fixed',
10197                        zIndex: 99997,
10198                        top: '0px',
10199                        left: '0px',
10200                        width: '100%',
10201                        height: $(document).height(),
10202                        background: this.overlayColor,
10203                        opacity: this.overlayOpacity
10204                    });
10205                    if(xfalib.ut.XfaUtil.prototype.isSafari()) {
10206                        $("#iEBox_overlay").on('touchmove', this._disableMove);
10207                    }
10208                    $(document).on('scroll',this._overlayResize);
10209                break;
10210                case 'hide':
10211                    if(xfalib.ut.XfaUtil.prototype.isSafari()) {
10212                        $("#iEBox_overlay").off('touchmove');
10213                    }
10214                    $("#iEBox_overlay").remove();
10215                    $(document).off('scroll',this._overlayResize);
10216                break;
10217            }
10218        },
10219        /**
10220         * resize dialog based on available screen area
10221         */
10222        _resize:function(){
10223            // available screen area
10224            var aWidth = $(window).width();
10225            var aHeight = $(window).height();
10226
10227            var sigCnv = $('#iEBox_canvas')[0];
10228            var sigTextBox = $('#keyboard_Sign_Box')[0];
10229            var bGeoCnv = $('#iEBox_geoCanvasBottom')[0];
10230            var rGeoCnv = $('#iEBox_geoCanvasRight')[0];
10231
10232            // calculate amount of width height we need to reduce
10233
10234            var totalCnvWidth = sigCnv.width + rGeoCnv.width;
10235            var totalCnvHeight = sigCnv.height + bGeoCnv.height;
10236
10237
10238
10239
10240
10241            var diffW = totalCnvWidth + dialogObj.canvas_spacing.x - aWidth;
10242            if(diffW < 0) {
10243                diffW = 0;
10244            }
10245            var diffH = totalCnvHeight + dialogObj.canvas_spacing.y - aHeight;
10246            if(diffH < 0){
10247                diffH = 0;
10248            }
10249
10250            var newTotalCnvHeight, newTotalCnvWidth;
10251            if( diffW > 0 || diffH > 0 ){ // does any side need resize
10252
10253                if(diffH * totalCnvWidth > totalCnvHeight * diffW){ // need to reduce height
10254                   newTotalCnvHeight = totalCnvHeight - diffH;
10255                   newTotalCnvWidth = (newTotalCnvHeight * totalCnvWidth)/ totalCnvHeight;
10256                } else {
10257                   newTotalCnvWidth = totalCnvWidth - diffW;
10258                   newTotalCnvHeight = (newTotalCnvWidth * totalCnvHeight)/ totalCnvWidth;
10259                }
10260
10261                // distribute evenly the new dimensions
10262
10263
10264                var newSigCnvWidth   = (newTotalCnvWidth*sigCnv.width)/totalCnvWidth;
10265                var newSigCnvHeight = (newTotalCnvHeight*sigCnv.height)/totalCnvHeight;
10266
10267                sigCnv.style.width = newSigCnvWidth + "px";
10268                sigCnv.style.height = newSigCnvHeight + "px";
10269
10270                sigTextBox.style.width = newSigCnvWidth + "px";
10271                sigTextBox.style.height = newSigCnvHeight + "px";
10272
10273
10274                bGeoCnv.style.width = newSigCnvWidth +"px";
10275                bGeoCnv.style.height = (newTotalCnvHeight - newSigCnvHeight) +"px";
10276
10277                rGeoCnv.style.width = (newTotalCnvWidth - newSigCnvWidth) +"px";
10278                rGeoCnv.style.height = newSigCnvHeight + "px";
10279
10280
10281                $('#iEBox_caption').width(Math.floor(newSigCnvWidth));
10282
10283            } else {
10284                sigCnv.style.width =  sigCnv.width + "px";
10285                sigCnv.style.height = sigCnv.height + "px";
10286
10287                sigTextBox.style.width =  sigCnv.width + "px";
10288                sigTextBox.style.height = sigCnv.height + "px";
10289
10290                bGeoCnv.style.width =  bGeoCnv.width + "px";
10291                bGeoCnv.style.height = bGeoCnv.height + "px";
10292
10293                rGeoCnv.style.width =  rGeoCnv.width + "px";
10294                rGeoCnv.style.height = rGeoCnv.height + "px";
10295
10296                $('#iEBox_caption').width(sigCnv.width);
10297
10298            }
10299        },
10300        _reposition: function() {
10301            var top = (($(window).height() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) / 2) - ($("#iEBox_container").outerHeight() / 2)) + dialogOb
10301j.verticalOffset;
10302            var left = (($(window).width() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) / 2) - ($("#iEBox_container").outerWidth() / 2)) + dialogObj.horizontalOffset;
10303            if( top < 0 ) top = 0;
10304            if( left < 0 ) left = 0;
10305
10306            $("#iEBox_container").css({
10307                top: top + $(window).scrollTop() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + 'px',
10308                left: left + $(window).scrollLeft() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + 'px'
10309            });
10310            $("#iEBox_container").focus();   // scroll up to the canvas
10311            $("#iEBox_overlay").height( $(document).height() );
10312        },
10313        _maintainDialog:function(){
10314            dialogObj._resize();
10315            dialogObj._reposition();
10316        },
10317        _maintainPosition: function(status) {
10318            if(dialogObj.repositionOnResize ) {
10319                switch(status) {
10320                    case true:
10321                        $(window).on('orientationchange', dialogObj._maintainDialog); // also reposition if device is tilted
10322                    break;
10323                    case false:
10324                        $(window).off('orientationchange', dialogObj._maintainDialog);
10325                    break;
10326                }
10327            }
10328        }
10329        
10330    };
10331    return dialogObj;
10332})(window._);
10333
10334/**
10335 * class definition for GeoLocationQueryRequest
10336 * encapsulated success and error handlers 
10337 */
10338function GeoLocQuery(){}
10339GeoLocQuery.prototype={
10340    init:function(success,failure){
10341        this._successHandler = success;
10342        this._errorHandler = failure;
10343        this._active=true;
10344        return this;
10345    },
10346    _handleSuccess:function(data){
10347        this._successHandler(data); 
10348    },
10349    _handleError:function(err){
10350        this._errorHandler(err);   
10351    },
10352    query:function(){
10353         _that=this;
10354         navigator.geolocation.getCurrentPosition(function(pos){
10355          if(_that._active){
10356             _that._handleSuccess(pos);
10357          }
10358          _that._active=false;
10359       },function(err){
10360          if(_that._active){
10361             _that._handleError(err);
10362          }
10363          _that._active=false;
10364       },{timeout:10000});
10365    },
10366    cancel:function(){
10367        _that._active=false;
10368    }
10369
10370};
10371// GeoLocQuery definition ends here
10372
10373/**
10374*
10375*  Base64 encode / decode
10376*  http://www.webtoolkit.info/
10377*
10378**/
10379 
10380var Base64 = {
10381 
10382	// private property
10383	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
10384 
10385	// public method for encoding
10386	encode : function (input) {
10387		var output = "";
10388		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
10389		var i = 0;
10390 
10391		while (i < input.length) {
10392 
10393			chr1 = input.charCodeAt(i++);
10394			chr2 = input.charCodeAt(i++);
10395			chr3 = input.charCodeAt(i++);
10396 
10397			enc1 = chr1 >> 2;
10398			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
10399			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
10400			enc4 = chr3 & 63;
10401 
10402			if (isNaN(chr2)) {
10403				enc3 = enc4 = 64;
10404			} else if (isNaN(chr3)) {
10405				enc4 = 64;
10406			}
10407 
10408			output = output +
10409			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
10410			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
10411 
10412		}
10413 
10414		return output;
10415	},
10416 
10417	// public method for decoding
10418	decode : function (input) {
10419		var output = "";
10420		var chr1, chr2, chr3;
10421		var enc1, enc2, enc3, enc4;
10422		var i = 0;
10423 
10424		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
10425 
10426		while (i < input.length) {
10427 
10428			enc1 = this._keyStr.indexOf(input.charAt(i++));
10429			enc2 = this._keyStr.indexOf(input.charAt(i++));
10430			enc3 = this._keyStr.indexOf(input.charAt(i++));
10431			enc4 = this._keyStr.indexOf(input.charAt(i++));
10432 
10433			chr1 = (enc1 << 2) | (enc2 >> 4);
10434			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
10435			chr3 = ((enc3 & 3) << 6) | enc4;
10436 
10437			output = output + String.fromCharCode(chr1);
10438 
10439			if (enc3 != 64) {
10440				output = output + String.fromCharCode(chr2);
10441			}
10442			if (enc4 != 64) {
10443				output = output + String.fromCharCode(chr3);
10444			}
10445 
10446		}
10447 
10448		return output;
10449 
10450	}
10451 
10452	
10453 
10454};
10455
10456/**
10457 * Utility Singleton for handling PNG Data
10458 */
10459var PNGUtil=(function(){
10460    var slf={
10461   _LC_Scribble_MetaDataKey:"LC_SCIBBLE_METADATA",
10462           _isPng:function(b64data){
10463               return  b64data && b64data.replace(/\s+/g, "").indexOf("iVBORw0KGgo") == 0;   // LC-5711 : trim any leading WhiteSpace
10464               // TODO :  base64 encoding may have white spaces even between the magic numbers !! Think of a better way to stop stripping white spaces repeatedly in PNGUtil, and cache the result
10465           },
10466           _update_crc:function(crc,data){
10467               var c = crc;
10468               var n;
10469               for(n=0;n<data.length;n++){
10470                  c = this._XOR(slf._crc_table[(this._XOR(c,data.charCodeAt(n))&0xff)>>>0],(c>>>8));
10471               }
10472               return c;
10473           },
10474		   _XOR:function(a,b){
10475		       return (a^b)>>>0;
10476		   },
10477           _U32Int2Str:function(n){
10478                return String.fromCharCode((n>>>24)&0xFF)+String.fromCharCode((n>>>16)&0xFF)+String.fromCharCode((n>>>8)&0xFF)+String.fromCharCode(n>>>0&0xFF);
10479            },
10480           _init_crc_table:function(){
10481               var c=0;
10482               var n,k;
10483               slf._crc_table=[];
10484               for(n=0;n<256;n++){
10485                   c = n;
10486                   for(k=0;k<8;k++){
10487                      if(((c&1)>>>0)>0){
10488                          c = slf._XOR(0xedb88320 , (c>>>1));
10489                      } else {
10490                          c = c>>>1;
10491                      }
10492                   }
10493                   slf._crc_table[n]=c;
10494                }
10495           },
10496           _CRC:function(data){
10497                if(!this._crc_table) this._init_crc_table();
10498                return this._XOR(this._update_crc(0xffffffff,data) , 0xffffffff);
10499          },
10500          _prepareTextChunk:function(content,pad){
10501              // pad the data appropriately                      
10502               var len = content.length;
10503               var lenStr = slf._U32Int2Str(len);
10504               var chunkType="tEXt";
10505               var checkSumStr = slf._U32Int2Str(slf._CRC(chunkType+content));
10506               return lenStr+chunkType+content+checkSumStr;
10507           },
10508        _start:function(str){
10509           slf._startTime = new Date().getTime();
10510           slf._startFun=str;
10511        },
10512        _end:function(){
10513           var str = "Time "+slf._startFun+": "+(new Date().getTime()-slf._startTime);
10514          //  $('BODY').append("<p>"+str+"</p><br/>");
10515        },
10516        _readU32Int:function(ctx){
10517            var val=0;
10518            var d=ctx.d;
10519            val=((d.charCodeAt(ctx.p++)<<24)|(d.charCodeAt(ctx.p++)<<16)|(d.charCodeAt(ctx.p++)<<8)|(d.charCodeAt(ctx.p++)))>>>0;
10520             return val;
10521        },
10522       _readChunkType:function(ctx){
10523          var d = ctx.d;
10524          var str = d[ctx.p++]+d[ctx.p++]+d[ctx.p++]+d[ctx.p++];
10525          return str;
10526       },
10527        _makeReadOnly:function(b64data){
10528      slf._start("_makeReadOnly");
10529      // assume a valid png image encoded in base64;
10530      var bindata = slf._atob(b64data.replace(/\s+/g, '')); // remove white spaces that might have been inserted
10531      var pngctx={p:0,d:bindata};
10532      pngctx.p+=8;// skip pngheader
10533      // read IHDR
10534      var size = slf._readU32Int(pngctx);
10535      slf._readChunkType(pngctx); //IHDR
10536      pngctx.p+=size; //Data
10537      slf._readU32Int(pngctx);//CRC
10538      var metadataChunk = slf._prepareTextChunk(slf._LC_Scribble_MetaDataKey+String.fromCharCode(0)+"true");
10539      var newdata = pngctx.d.substring(0,pngctx.p)+metadataChunk+pngctx.d.substring(pngctx.p);
10540      var ret= slf._btoa(newdata);
10541      slf._end();
10542      return ret;
10543   },
10544   _atob:function(inp){
10545      if(window.atob){ return atob(inp); }
10546	  return Base64.decode(inp);
10547   },
10548   _btoa:function(inp){
10549      if(window.btoa){ return btoa(inp); }
10550	  return Base64.encode(inp);
10551   },
10552   _isReadOnly:function(b64data){
10553    slf._start("_isReadOnly");
10554       if(slf._isPng(b64data)){
10555           var testStr = slf._LC_Scribble_MetaDataKey+String.fromCharCode(0)+"true";
10556           var bindata = slf._atob(b64data.replace(/\s+/g, ''));
10556 // strip white spaces
10557           var pngctx={p:0,d:bindata};
10558           pngctx.p+=8;// skip header
10559           while(pngctx.p<pngctx.d.length){
10560               var size = slf._readU32Int(pngctx);
10561               var type = slf._readChunkType(pngctx);
10562               if(type=="tEXt"){
10563                   if(pngctx.d.indexOf(testStr,pngctx.p)==pngctx.p){
10564                       slf._end();
10565                       return true;
10566                   }
10567                  
10568              }
10569              pngctx.p+=size;
10570              slf._readU32Int(pngctx);// 
10571          }// while end
10572       }
10573       slf._end();
10574       return false;
10575   }
10576    };
10577    return slf;
10578})();
10579
10580/**
10581 * JQuery widget definition starts here
10582 */
10583$.widget( "xfaWidget.ScribbleImageField", $.xfaWidget.imageField, {
10584
10585    _widgetName:"ScribbleImageField",
10586    _geoLocQuery:null,
10587   _emptyImageVal:null,// should be null, but for now
10588   _extraInfo:null,
10589   _defaultStatus:"&nbsp;",
10590   _enforceGeoLoc:!!navigator.userAgent.match(/iPad/i),
10591   _sigCanvasWidth:696,
10592   _sigCanvasHeight:390,
10593   _geoCanvId:null,
10594    _geoLocAtBottom:false,
10595   _geoCanvasHeight:100,
10596   _geoCanvasWidth:696,
10597   
10598    _is_readonly:false,
10599	
10600    options: {
10601        tabIndex: 0,
10602        "role": "img"
10603    },
10604
10605    getOptionsMap: function() {
10606        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
10607        return $.extend({},parentOptionsMap,{
10608            "displayValue": function(val) {
10609                if(this.options.commitProperty) {
10610                    if(!val){
10611                        this._displayValue(this._extractData(this._createEmptyImageData()));
10612                        this.$userControl.addClass("emptyScribble");
10613                        this._is_readonly=false;
10614                    } else {
10615                        this.$userControl.removeClass("emptyScribble");
10616                        if(PNGUtil._isPng(val)){
10617                            var widgetValue = "data:image/png;base64,"+this.options.value;
10618                        }else {
10619                            var widgetValue = "data:;base64," + this.options.value;
10620                        }
10621                        this._setValue(widgetValue);
10622                    }
10623                }
10624            }
10625        })
10626    },
10627
10628    getEventMap: function() {
10629        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
10630        return $.extend({},parentOptionsMap,{
10631            "scribblefocus":xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
10632            "click":null,
10633            "scribbleclick":xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT,
10634            "change":null,
10635            "scribblechange":xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
10636            "blur":null,
10637            "scribbleclose":xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT
10638        })
10639    },
10640
10641	/**
10642	 * This function achieves following
10643	 * 1. Calculate dimensions of canvases to be used
10644	 * 2. Findout if right or bottom canvas is to be used for geo location
10645	 */
10646
10647	 aspectRatioToBeUsed :function(){
10648        var aspectRatio ;
10649        if(this.options.aspectRatio && parseFloat(this.options.aspectRatio) > 0){
10650           aspectRatio = 1/parseFloat(this.options.aspectRatio);  //--in MF ratio is computed as height/width instead of width/height
10651        } else {
10652           var imgEl = this.element.children("img"),
10653               width = imgEl.attr('width'),
10654               height = imgEl.attr('height'),
10655               fieldWidth,
10656               fieldHeight;
10657
10658           if(width){
10659              fieldWidth = parseInt(width,10);
10660           } else {
10661              fieldWidth = imgEl.width();
10662           }
10663           if(height){
10664              fieldHeight = parseInt(height,10);
10665           } else {
10666              fieldHeight = imgEl.height();
10667           }
10668           aspectRatio = fieldHeight/fieldWidth;
10669        }
10670	    return aspectRatio;
10671	 },
10672
10673    _setUpCanvas:function(){
10674        var aspectRatio ;
10675		aspectRatio = this.aspectRatioToBeUsed();
10676       
10677        // max width, height of generated image
10678        var maxWidth = 640;
10679        var maxHeight = 480;
10680        
10681        // width of field scaled to fit max image size
10682        var scaledWidth;
10683        var scaledHeight;
10684        
10685        
10686		// approx pixels required for rendering geo loc info in 12pt Arial font 
10687		var approxGeoLocWidth=250;
10688		var approxGeoLocHeight=84;
10689        
10690        scaledWidth = maxWidth;
10691        scaledHeight = maxWidth*aspectRatio;
10692        if(scaledHeight>maxHeight){
10693            scaledHeight = maxHeight;
10694            scaledWidth = maxHeight/aspectRatio;
10695        }
10696        
10697        // set canvas dimensions
10698        if(aspectRatio>=1){
10699			this._geoCanvId='iEBox_geoCanvasBottom';
10700            this._geoLocAtBottom=true;
10701          
10702			
10703             this._geoCanvasWidth = scaledWidth;
10704			 // limit height to 30% of full height;
10705			 this._geoCanvasHeight=Math.min(approxGeoLocHeight,scaledHeight/3);
10706             this._sigCanvasWidth = scaledWidth;
10707             this._sigCanvasHeight= scaledHeight-(this._enforceGeoLoc?this._geoCanvasHeight:0);
10708        } else {
10709			this._geoCanvId='iEBox_geoCanvasRight';
10710            this._geoLocAtBottom=false;
10711           
10712			
10713            this._geoCanvasHeight = scaledHeight;
10714			// limit width to 30% of full width;
10715			this._geoCanvasWidth=Math.min(approxGeoLocWidth,scaledWidth/3);
10716            this._sigCanvasHeight= scaledHeight;
10717            this._sigCanvasWidth= scaledWidth-(this._enforceGeoLoc?this._geoCanvasWidth:0);
10718        }
10719       
10720    },
10721
10722   render : function() {
10723       var geoLocMandatoryOnIpad = this.options.geoLocMandatoryOnIpad;
10724       if(typeof(geoLocMandatoryOnIpad)!="undefined"){
10725           this._enforceGeoLoc= this._enforceGeoLoc && (/^(true|1)$/i).test($.trim(geoLocMandatoryOnIpad));
10726       }
10727       this._wgtId="wid"+~~(Math.random()*2000)+"_"+new Date().getTime();
10728
10729       var $control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments)
10730
10731       if(this.options.value || this.options.value != this._emptyImageVal){
10732          this._is_readonly=!!PNGUtil._isReadOnly(this.options.value);
10733       }
10734   
10735       if(this._is_readonly){
10736          $control.after("<div id='"+this._wgtId+"' class='sc_popUpMenu'></div>");
10737       } else {
10738          $control.after("<div id='"+this._wgtId+"' style='display:none;' class='sc_popUpMenu'></div>");
10739       }
10740	   
10741	   this._setUpCanvas();
10742       return $control;
10743    },
10744
10745   click: function() {
10746        this.focus();
10747        var tmpEl = this.element.length?this.element[0]:this.element;
10748        if(this.options.access != "open")
10749          return;
10750       if (TouchUtil.POINTER_ENABLED || TouchUtil.TOUCH_ENABLED) {
10751           // simulate a click event
10752           tmpEl.dispatchEvent(TouchUtil.getPointerEvent(TouchUtil.POINTER_DOWN));
10753           tmpEl.dispatchEvent(TouchUtil.getPointerEvent(TouchUtil.POINTER_UP));
10754        }
10755        else {
10756              this.$userControl.triggerHandler("click");
10757        }
10758   },
10759
10760    _attachEventHandlers:function($control){
10761	     if(TouchUtil.POINTER_ENABLED || TouchUtil.TOUCH_ENABLED){
10762            this._attachTouchEventHandlers($control);
10763         } else {
10764            this._attachMouseEventHandlers($control);
10765         }
10766         $control.keydown($.proxy(this._handleKeyDown,this));
10767    },
10768	_attachEventHandlerForCrossIcon:function($control){
10769	    var _that = this;
10770	    $control.mouseenter(function(event){
10771             if(_that.options.access != "open")
10772                    return;
10773             event.stopPropagation();
10774             if(_that._is_readonly){
10775                $('#'+_that._wgtId).css({display:'block'});
10776                var bodyMoveHandler;
10777                $('body').on('mousemove',bodyMoveHandler=function(event){
10778                    if(event.target!=$('#'+_that._wgtId)[0]&&event.target!=_that.$userControl[0]){
10779                        $('#'+_that._wgtId).css({display:'none'});
10780                         $('body').off('mousemove',bodyMoveHandler);
10781                    }
10782                });
10783              }
10784       });
10785
10786       setTimeout(function(){ $("#"+_that._wgtId).click($.proxy(_that._onCrossClick,_that));},50);  
10787	},
10788    _attachTouchEventHandlers:function($control){
10789        var _timer,_that=this;
10790        var tmpEl = this.element.length?this.element[0]:this.element;
10791       tmpEl.addEventListener(TouchUtil.POINTER_DOWN,function(event){
10792           if(_that.options.access != "open")
10793              return;
10794             event.preventDefault();
10795           _timer = setTimeout(function(){
10796                _timer=0;
10797               _that._onCrossClick(event);
10798            },1000);
10799        });
10800       tmpEl.addEventListener(TouchUtil.POINTER_UP,function(event){
10801            if(_that.options.access != "open")
10802                return;
10803            event.preventDefault();
10804            if(_timer){
10805               clearTimeout(_timer);
10806               _that._onImageClick(event);
10807            } 
10808        });
10809		
10810	   if(TouchUtil.POINTER_ENABLED){
10811		     this._attachEventHandlerForCrossIcon($control);
10812			 setTimeout(function(){ $("#"+_that._wgtId).on(TouchUtil.POINTER_UP,function(event){
10813			        event.stopPropagation();
10814			 });},50);
10815	   }
10816    },
10817
10818    _attachMouseEventHandlers:function($control){
10819         var _timer=0,_that=this,_hoverTimer=0;
10820        $control.dblclick(function(event){
10821            if(_that.options.access != "open")
10822                return;
10823           event.preventDefault();event.stopPropagation();
10824           if(_timer.val){
10825             clearTimeout(_timer);_timer =0;
10826           }
10827           _that._onCrossClick(event);
10828        }).click(function(event){
10829           _that.$userControl.trigger("scribbleclick",event);
10830           if(_that.options.access != "open")
10831                return;
10832           event.preventDefault();
10833           event.stopPropagation();
10834           if(_timer){
10835              clearTimeout(_timer);_timer=0;
10836            } else {
10837              _timer = setTimeout(function(){
10838                 _timer=0;
10839                 _that._onImageClick(event);
10840              },500);
10841            }
10842       });
10843	   
10844	   this._attachEventHandlerForCrossIcon($control);
10845       
10846    },
10847
10848    _onCrossClick:function(event){
10849        if(!this._is_readonly) return;
10850        this.$userControl.trigger("scribblefocus",event);
10851        this.$userControl.trigger("scribbleclick",event);
10852        event.stopPropagation();
10853        $.alertBox.yesNo(null,
10854         this.localeStrings().clearSignatureConfirm,
10855         this.localeStrings().clearSignature,
10856         $.proxy(this._removeSigConfirmationHandler,this));
10857     },
10858
10859     _removeSigConfirmationHandler:function(isYes){
10860        if(isYes){
10861           this._saveValue(this._emptyImageVal);
10862           this._displayValue(this._extractData(this._createEmptyImageData()));
10863           this.$userControl.addClass("emptyScribble").trigger("scribbleclose",{});
10864           this._is_readonly=false;
10865        }
10866     },
10867
10868    _createEmptyImageData:function(){
10869         if(!this._emptyImageData){
10870            var emptyCanvasObj = document.createElement('canvas');
10871            emptyCanvasObj.style.width=this._sigCanvasWidth+'px';
10872            emptyCanvasObj.style.height=this._sigCanvasHeight+'px';
10873            emptyCanvasObj.width=this._sigCanvasWidth;
10874            emptyCanvasObj.height=this._sigCanvasHeight;
10875            var ctx = emptyCanvasObj.getContext('2d');
10876            ctx.fillStyle='#ffffff';
10877            ctx.clearRect(0,0,this._sigCanvasWidth,this._sigCanvasHeight);
10878            this._emptyImageData = emptyCanvasObj.toDataURL("image/png");
10879         }
10880         return this._emptyImageData;
10881     },
10882
10883    getCommitValue: function() {
10884        return this.options.value
10885    },
10886
10887    _saveValue:function(val){
10888        this.options.value=val;
10889        this.$userControl.trigger('scribblechange');
10890    },
10891
10892    _displayValue:function(val){
10893        if(this.options.commitProperty) {
10894            //hardcode the widget VALUE by unknown image type
10895            if(val){
10896              var widgetValue = "data:image/png;base64,"+val;
10897                this._setValue(widgetValue);
10898            }
10899        }
10900        else
10901            this.logger().debug("xfaView","[DefaultWidget._update], User Control or Commit Property is null" );
10902    },
10903
10904    _doOk:function(){
10905        var mainCanvas = document.createElement('CANVAS');
10906        var geoCnv = $('#'+this._geoCanvId)[0];
10907        var sigCnv = $('#iEBox_canvas')[0];
10908        var ctx = mainCanvas.getContext('2d');
10909       
10910        if(geoCnv.width>0&&geoCnv.height>0){
10911            
10912            if(this._geoLocAtBottom){
10913                mainCanvas.width=sigCnv.width;
10914                mainCanvas.height =sigCnv.height+geoCnv.height;
10915                ctx.drawImage(sigCnv,0,0);
10916                ctx.drawImage(geoCnv,0,sigCnv.height);
10917            } else {
10918                mainCanvas.width=sigCnv.width+geoCnv.width;
10919                mainCanvas.height =sigCnv.height;
10920                ctx.drawImage(sigCnv,0,0);
10921                ctx.drawImage(geoCnv,sigCnv.width,0);
10922            }
10923        } else {
10924             mainCanvas.width=sigCnv.width;
10925             mainCanvas.height =sigCnv.height;
10926             ctx.drawImage(sigCnv,0,0);
10927        }
10928        imageEditDialog.hide();
10929        var newdata = mainCanvas.toDataURL("image/png");//(this.myScribbleHandle||"").toString();
10930        
10931         var val,val1;
10932         if((val=/*=*/this._extractData(newdata))){
10933         //  val1 = PNGUtil._makeReadOnly(val);
10934            val = PNGUtil._makeReadOnly(val);
10935            this._saveValue(val);   
10936            this._is_readonly=true;       
10937          }
10938          this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
10939        this.$userControl.trigger("scribbleclose")
10940    },
10941    _handleOk:function(){
10942        if(this._enforceGeoLoc){
10943           this._geoLocQuery = new GeoLocQuery().init($.proxy(function(data){
10944               this._geoQuerySuccessHandler(data);
10945               this._doOk();
10946           },this),$.proxy(this._geoQueryErrorHandler,this));
10947           this._geoLocQuery.query();
10948           this._showMessage(this.localeStrings().fetchGeoLocation);
10949        } else {
10950          this._doOk();
10951        }
10952    },
10953
10954    _handleCancel:function(){
10955         imageEditDialog.hide();
10956         this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
10957        this.$userControl.trigger("scribbleclose")
10958    },
10959
10960    _handleClear:function(){
10961        this.myScribbleHandle.setEnabled(true);
10962        this._is_readonly=false;
10963        this._makeReadOnly(this._is_readonly);
10964        $('#iEBox_canvas')[0].width=this._sigCanvasWidth;
10965         $('#iEBox_caption').width(this._sigCanvasWidth);
10966		$('#iEBox_canvas')[0].height=this._sigCanvasHeight;
10967        $('#keyboard_Sign_Box')[0].value="";
10968        var geoCanv = $('#'+this._geoCanvId)[0];
10969        imageEditDialog.enableButtons({Ok:false,Clear:false});
10970        geoCanv.width=0;
10971        geoCanv.height=0;
10972        imageEditDialog._resize();
10973        this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
10974    },
10975    _makeReadOnly:function(readonly){
10976       imageEditDialog.enableButtons({Ok:false,Clear:false,Geo:!readonly,Brush:!readonly,Text:!readonly});
10977       if(readonly){
10978		   $('#iEBox_canvas').css({border:'1px solid gray'});
10979           $('#iEBox_caption').css({display:'none'});
10980
10981       }
10982       this._defaultStatus = "&nbsp;";
10983       this._showMessage(this._defaultStatus);
10984    },
10985
10986    _showMessage:function(msg){
10987        var _that = this;
10988        if(this._msgTimeout) { clearTimeout(this._msgTimeout); this._msgTimeout=0; }
10989         $("#iEBox_title").replaceWith('<div id="iEBox_title">'+msg+'</div>');
10990         this._msgTimeout = window.setTimeout(function(){
10991             $("#iEBox_title").replaceWith('<div id="iEBox_title">'+_that._defaultStatus+'</div>');
10992         },15000);
10993    },
10994
10995    _geoQueryErrorHandler:function(err){
10996        this._showMessage(this.localeStrings().errorFetchGeoLocation);
10997    },
10998
10999	_getLogMessage:function(key){
11000		     return this.logMsgs()[key]||key;
11001	},
11002
11003    _handleGeo:function(){
11004          // initiate geolocation 
11005       if(navigator.geolocation){
11006           this._geoLocQuery = new GeoLocQuery().init($.proxy(this._geoQuerySuccessHandler,this),$.proxy(this._geoQueryErrorHandler,this));
11007           this._geoLocQuery.query();
11008           this._showMessage(this.localeStrings().fetchGeoLocation);
11009       } else {
11010           this.logger().debug("xfaView",this._getLogMessage("ALC-FRM-901-011"));
11011       }
11012    },
11013
11014    // This Function is used to fetch the geolocation.
11015    calculateGeolocation: function(){
11016      this._handleGeo();
11017    },
11018
11019    _handleText:function(){
11020        var signBoxEl=document.getElementById("keyboard_Sign_Box");
11021        var signCanvasEl=document.getElementById("iEBox_canvas");
11022        if(signBoxEl.value.length==0){
11023            this._handleClear();
11024        }
11025        this._disableSignatureCanvas();
11026        this._enableSignatureTextBox();
11027        signBoxEl.focus();
11028    },
11029
11030    _disableSignatureTextBox:function(){
11031        document.getElementById("keyboard_Sign_Box").style.display = "none";
11032    },
11033
11034    _enableSignatureTextBox:function(){
11035        document.getElementById("keyboard_Sign_Box").style.display = "inline-block";
11036    },
11037
11038    _disableSignatureCanvas:function(){
11039        document.getElementById("iEBox_canvas").style.display = "none";
11040    },
11041
11042    _enableSignatureCanvas:function(){
11043        document.getElementById("iEBox_canvas").style.display = "inline-block";
11044    },
11045
11046    _handleBrushSelect:function(w){
11047        if(this.myScribbleHandle&&!this._is_readonly) {
11048            this.myScribbleHandle.setLineWidth(w);
11049        }
11050    },
11051
11052    _handleBrush:function(evt){
11053        if($('#keyboard_Sign_Box')[0].value.length>0){
11054            this._handleClear();
11055        }
11056        this._disableSignatureTextBox();
11057        this._enableSignatureCanvas();
11058        imageEditDialog.toggleBrushList(evt);
11059    },
11060	_handleKeyDown:function(event){
11061		if(event.keyCode == ENTER_KEY || event.charCode == ENTER_KEY || event.which == ENTER_KEY) { // touch devices may return charCode
11062		    event.preventDefault();
11063		    this._onImageClick(event);
11064		} else if(event.keyCode == DELETE_KEY || event.charCode == DELETE_KEY || event.which == DELETE_KEY) {
11065		    this._onCrossClick(event);
11066		}
11067    },
11068    _dialogCallback:function(button_val,arg1){
11069           // add back on click handler
11070         //  this.$userControl.click($.proxy(this._onImageClick, this));
11071                     
11072           switch(button_val){
11073               case "Ok":
11074               this._handleOk();
11075               break;
11076               case "Cancel":
11077               this._handleCancel();
11078               break;
11079               case "Clear":
11080               this._handleClear();
11081               break;
11082               case "Geo":
11083               this.calculateGeolocation();
11084               break;
11085               case "BrushSelect":
11086               this._handleBrushSelect(arg1);
11087               break;
11088               case "Brush":
11089               this._handleBrush(arg1);
11090               break;
11091               case "Text":
11092               this._handleText();
11093               break;
11094              
11095           }
11096    },
11097
11098    _geoQuerySuccessHandler:function(data){
11099        this._renderPosition(data);
11100    },
11101
11102	_fitGeoLocText:function(latStr,longStr,timeStr,ctx,maxWidth,maxHeight){
11103	    var fontSize=12;
11104		ctx.font="bold "+fontSize+"pt Arial";
11105		var width = Math.max(ctx.measureText(latStr).width,ctx.measureText(longStr).width,ctx.measureText(timeStr).width);
11106		var lineHeight = ctx.measureText("m").width*1.5;
11107		while((width>maxWidth||3*lineHeight>maxHeight)&&fontSize>1){
11108		    fontSize--;
11109		    ctx.font="bold "+fontSize+"pt Arial";
11110		    width = Math.max(ctx.measureText(latStr).width,ctx.measureText(longStr).width,ctx.measureText(timeStr).width);
11111		    lineHeight = ctx.measureText("m").width*1.5;
11112		}
11113		return {width:width,lineHeight:lineHeight,fontSize:fontSize};
11114	},
11115
11116    _renderPosition:function(position){
11117        if(position&&position.coords){
11118         this._showMessage("&nbsp;");
11119            var latStr = this.localeStrings().latitude+": " + position.coords.latitude;
11120            var longStr = this.localeStrings().longitude+": " + position.coords.longitude;
11121            var dateObj = new Date();
11122            var tZone = (dateObj.getTimezoneOffset()/60*-1);
11123            
11124            var timeStr = this.localeStrings().time+": "+(dateObj.getMonth()+1)+"/"+dateObj.getDate()+"/"+dateObj.getFullYear()+" "+dateObj.getHours()+":"+dateObj.getMinutes()+":"+dateObj.getSeconds()+((tZone>0)?" +":" ")+(tZone);
11125            var canvasObj  = $('#'+this._geoCanvId)[0];
11126			var sigCanvas = $('#iEBox_canvas')[0];
11127            var sigTextBox = $('#keyboard_Sign_Box')[0];
11128			var dummyCanvas = document.createElement('canvas');
11129            if(canvasObj){
11130			   var ctx = canvasObj.getContext('2d');
11131			   ctx.font="bold 12pt Arial";
11132
11133			   canvasObj.width=this._geoCanvasWidth;
11134               canvasObj.height=this._geoCanvasHeight;
11135			   var layout = this._fitGeoLocText(latStr,longStr,timeStr,ctx,canvasObj.width,canvasObj.height);
11136               var aspectRatio ;
11137     		   aspectRatio = this.aspectRatioToBeUsed();
11138			   if(!this._enforceGeoLoc){
11139			       if(this._geoLocAtBottom){
11140                     dummyCanvas.height = this._sigCanvasHeight-canvasObj.height;
11141                     dummyCanvas.width = dummyCanvas.height/aspectRatio;
11142                   } else {
11143                     dummyCanvas.width = this._sigCanvasWidth-canvasObj.width;
11144					 dummyCanvas.height = dummyCanvas.width*aspectRatio;
11145				   }
11146				   // move drawn signature to a temporary canvas and scale it to new dimension
11147                   dummyCanvas.getContext('2d').drawImage(sigCanvas,0,0,dummyCanvas.width,dummyCanvas.height);
11148                   if(this._geoLocAtBottom){
11149                     sigCanvas.height = dummyCanvas.height;
11150                     sigTextBox.height = dummyCanvas.height;
11151                     sigCanvas.getContext('2d').drawImage(dummyCanvas,(sigCanvas.width-dummyCanvas.width)/2,0);
11152                   } else {
11153                     sigCanvas.width = dummyCanvas.width;
11154                     sigTextBox.width = dummyCanvas.width;
11155                     sigCanvas.getContext('2d').drawImage(dummyCanvas,0,(sigCanvas.height-dummyCanvas.height)/2);
11156                   }
11157                   $('#iEBox_caption').width(sigCanvas.width);
11158				   imageEditDialog.enableButtons({Clear:true});
11159			   }
11160			      
11161			   var fwidth = layout.width;
11162               var fheight = layout.lineHeight;
11163			   var bottomMargin=2;
11164               ctx.fillStyle='#555555';
11165               ctx.font="bold "+layout.fontSize+"pt Arial";
11166               ctx.fillText(latStr,0,canvasObj.height-2*fheight-bottomMargin);
11167               ctx.fillText(longStr,0,canvasObj.height-fheight-bottomMargin);
11168               ctx.fillText(timeStr,0,canvasObj.height-bottomMargin);
11169			   
11170			   imageEditDialog._resize();
11171            }
11172        }
11173    },
11174    _scribbleCallback:function(){
11175       imageEditDialog.enableButtons({Clear:true,Ok:true});  //  enable clear and ok buttons
11176    },
11177    _onImageClick:function(){
11178       if(!imageEditDialog.getIsOpen()){
11179           var _that = this;
11180           imageEditDialog.show("&nbsp;",$.proxy(this._dialogCallback, this));
11181           if(!this._enforceGeoLoc){
11182               $('#iEBox_Geo').css({display:'inline-block'});
11183           }
11184           var image = new Image();
11185           image.onload=function(){
11186               _that.myScribbleHandle = new Scribble("iEBox_canvas",image,image.width,image.height,$.proxy(_that._scribbleCallback,_that));
11187               _that.myScribbleHandle.setEnabled(!_that._is_readonly);
11188               $('#iEBox_caption').width(image.width);
11189               $('#iEBox_container').css({display:'table'});
11190               if($('#iEBox_container').length == 1){
11191                   $('#iEBox_container')[0].focus();
11192               }
11193               imageEditDialog._resize();
11194               imageEditDialog._reposition();      // recalculate position, so that the values are updated, esp. in iPad
11195           }
11196           if(!this.options.value||this.options.value==this._emptyImageVal){
11197               this._is_readonly=false;
11198               this.$userControl.addClass("emptyScribble");
11199               image.src = this._createEmptyImageData();
11200           } else {
11201               this.$userControl.removeClass("emptyScribble");
11202               if(PNGUtil._isPng(this.options.value)){
11203                   this._is_readonly = !!PNGUtil._isReadOnly(this.options.value);
11204			       image.src = "data:image/png;base64,"+this.options.value;//this.createBl _that.$userControl.attr(_that.options.commitProperty);
11205               } else {
11206                   image.src = "data:;base64," + this.options.value;//this.createBl _that.$userControl.attr(_that.options.commitProperty);
11207		       }
11208           }
11209           this._makeReadOnly(this._is_readonly);
11210       }
11211    },
11212
11213    _extractData:function(datauri){
11214        var idx;
11215        if(datauri!=null&&datauri.length>0&&datauri.indexOf("data:")==0){
11216            if((idx=datauri.indexOf(","))>0){
11217                return datauri.substr(idx+1);
11218            }
11219        }
11220    },
11221
11222    _setValue:function(val){
11223        this.$userControl.prop(this.options.commitProperty, val);
11224        this.$userControl.attr(this.options.commitProperty, val);
11225        if(this._dummyImg){
11226            this._dummyImg.setAttribute(this.options.commitProperty,val);
11227        }
11228    }
11229});
11230 //hack for IOS5 touch bug
11231  $(function(){
11232         $('body').on('touchstart', function(e) {});
11233  });
11234  
11235})($,xfalib);
11236(function ($, window, _) {
11237
11238    var _defaults = {
11239        placeHolderText : "Enter comments here"
11240    };
11241
11242    var AdobeFileAttachment = function (element, options) {
11243        this.options = options;
11244        this.$elementFileUploadBtn = [];
11245        this.$elementFileList = [];
11246        this.$element = $(element);
11247        if (this.$element.attr("multiple") && !xfalib.ut.Utilities._isDataContainerSupported()) {
11248            // remove multiple attribute if multi file selection in one go is not supported
11249            this.$element.removeAttr("multiple");
11250        }
11251        this.$parent = this.$element.parent();
11252        this.invalidFeature = {
11253            "SIZE":1,
11254            "NAME":2,
11255            "MIMETYPE":3
11256        };
11257        Object.freeze(this.invalidFeature);
11258        // initialize the regex initially
11259        this.regexMimeTypeList  = this.options.mimeType.map(function (value, i) {
11260            try {
11261                return new RegExp(value.trim());
11262            } catch (e) {
11263                // failure during regex parsing, don't return anything specific to this value since the value contains
11264                // incorrect regex string
11265                if(window.console) {
11266                    console.log(e);
11267                }
11268            }
11269        });
11270    };
11271
11272    var isBrowserIE9OrIE10 = ($.browser.msie && ($.browser.version === '9.0' || $.browser.version === '10.0')),
11273        fileLabelsCount = 0;
11274
11275
11276    AdobeFileAttachment.prototype = {
11277        _fileIframeName : "guide-fu-iframe",
11278        _addFile : "Add File",
11279
11280        clear: function () {
11281            this.$element.val('');
11282            this.$elementFileList.empty();
11283        },
11284
11285        destroy: function () {
11286            this.$fileDomElements = $.map(this.$fileDomElements, function(item){
11287                // since item can be null or object, doing this check
11288                if(_.isObject(item) && item.val().length === 0) {
11289                    //TODO: remove item from dom, since there is a memory leak
11290                    return item;
11291                }
11292            });
11293            this.values = [];
11294            if(isBrowserIE9OrIE10){
11295                if(_.last(this.$fileDomElements) == null){
11296                    this.cloneFileInputAndUpdateIdForIE9();
11297                } else {
11298                    this.updateLabelForAttr(_.last(this.$fileDomElements).attr("id"));
11299                }
11300            }
11301            this.$element.trigger("change.fileupload");
11302        },
11303
11304        _setUrl : function(url, index){
11305            this.$elementFileList.find("span.guide-fu-fileName").eq(index).data("key", url);
11306        },
11307
11308        _getUrl : function(index) {
11309            return this.$elementFileList.find("span.guide-fu-fileName").eq(index).data("key");
11310        },
11311        getSetFilePathAndReturnNamePathMap: function(valueList) {
11312
11313            var mapOfObjectsHavingTempPathAndFileNames = {},
11314                $temp,
11315                tempPath;
11316
11317            $.each(this.$elementFileList.children(), function ( index, childLiElement) {
11318                $temp = $(childLiElement).find("span.guide-fu-fileName");
11319                tempPath = $temp.data("key");
11320                if(!tempPath && valueList && valueList[index]) {
11321                    $temp.data("key", valueList[index]);
11322                }
11323                mapOfObjectsHavingTempPathAndFileNames[$temp.html()] = tempPath || $temp.data("key");
11324            });
11325            return mapOfObjectsHavingTempPathAndFileNames;
11326        },
11327
11328
11329        value : function(value) {
11330            if(!_.isUndefined(value)) {
11331                var _self = this,
11332                    comments = this.comment(),
11333                    isChange = false,
11334                    fileNames = _.isArray(this.options.fileNames) ? this.options.fileNames : null,
11335                    oldUrls = {};
11336                // Cache the url before deletion
11337                this.$elementFileList.children().find("span.guide-fu-fileName").each(function(){
11338                    var url = $(this).data("key");
11339                    if(!_.isUndefined(url)){
11340                        var fileName = url.substring(url.lastIndexOf("/") + 1);
11341                        oldUrls[fileName] = url;
11342                    }
11343                });
11344                this.$elementFileList.empty();
11345                if(value != null) {
11346                    var arr = value.split("\n");
11347                    // contruct initial file name and value map
11348                    // this is done only once in entire live cycle, its done here, since we get value here
11349                    if (fileNames && _.isEmpty(this._initialFileValueFileNameMap)) {
11350                        for (var index = 0; index < fileNames.length; index++) {
11351                            _self._initialFileValueFileNameMap[arr[index]] = fileNames[index]
11352                        }
11353                    }
11354                    // Update the value array with the file
11355                    this.values = _.map(arr, function(fileName, index){
11356                        // Check if file Name is a path, if yes get the last part after "/"
11357                        var slash = fileName.lastIndexOf("/"),
11358                            fileUrl = fileName,
11359                            fileUploadUrl = null;
11360                        if(slash !== -1) {
11361                            // Store the cached url here
11362                            fileUrl = fileUploadUrl = fileName;
11363                            fileName = fileName.substring(slash + 1);
11364                            // case: when you click on save second time
11365                            if((_.isObject(_self.$fileDomElements[index]) && _self.$fileDomElements[index].val().length > 0) || _.isString(_self.$fileDomElements[index])){
11366                                isChange = true;
11367                                _self.$fileDomElements[index] = null;
11368                            } else if(_self.$fileDomElements[index] !== null) { // create a dummy file dom for the cached value
11369                                 isChange = true;
11370                                _self.$fileDomElements.splice(index, 0, null);
11371                            }
11372                        } else if (oldUrls[fileName]) {
11373                            fileUploadUrl = oldUrls[fileName];
11374                        }
11375                        // if fileNames options is explicitly passed, use it
11376                        if (fileNames && _self._initialFileValueFileNameMap[fileUrl]) {
11377                            fileName = _self._initialFileValueFileNameMap[fileUrl];
11378                        }
11379                        _self.showFileList(fileName, comments[index], fileUploadUrl);
11380                        return fileUrl;
11381                    });
11382                    if(isChange){
11383                        this.$element.trigger("change.fileupload");
11384                    }
11385                } else {
11386                    if(_.isArray(this.values) && this.values.length !== 0){
11387                        this.destroy();
11388                    }
11389                }
11390            }
11391            else {
11392                return this.values;
11393            }
11394        },
11395
11396        fileAttachment: function(){
11397            return this.values;
11398        },
11399
11400        comment : function(value){
11401            var _self = this,
11402                $elem = null,
11403                comments;
11404            if (!_.isUndefined(value)) {
11405                if(value != null) {
11406                    comments = value.split("\n");
11407                    $elem = this.$elementFileList.find('div.guide-fu-comment');
11408                    $elem.each(function(index){
11409                        $(this).text(comments[index]);
11410                    });
11411                }
11412            }
11413            else {
11414                $elem = this.$elementFileList.find('div.guide-fu-comment');
11415                comments = [];
11416                $elem.each(function(){
11417                    comments.push($(this).text());
11418                });
11419                return comments;
11420            }
11421        },
11422
11423        multiSelect : function(value){
11424            if(value !== undefined)
11425                this.options.multiSelect = value;
11426            else
11427                return this.options.multiSelect;
11428        },
11429
11430        fileSizeLimit : function(value){
11431            if(value !== undefined)
11432                this.options.fileSizeLimit = value;
11433            else
11434                return this.options.fileSizeLimit;
11435        },
11436
11437        mimeType : function(value){
11438            if(value !== undefined)
11439                this.options.mimeType = value;
11440            else
11441                return this.options.mimeType;
11442        },
11443
11444        access : function(value){
11445            if(value == "readOnly") {
11446                this.$element.attr("disabled", "disabled");
11447                //for readOnly hide the delete icon in file list
11448                $(this.$parent).addClass('guide-fu-disabled');
11449            }
11450            else if(value == "open") {
11451                this.$element.removeAttr("disabled");
11452                $(this.$parent).removeClass('guide-fu-disabled');
11453            }
11454        },
11455
11456        fileList : function(value) {
11457            var filtered,
11458                _self = this;
11459            if(value !== undefined){
11460                this.$fileDomElements = [];
11461                _.each(value, function(item, index){
11462                    if((_.isObject(item) && (isBrowserIE9OrIE10 || item.val().length > 0)) || (_.isString(item))){
11463                         // check if index is within the length
11464                         // this is written for delete case
11465                         // if item is a string, then it should be set null
11466                         if(_.isString(item)){
11467                             item = null;
11468                         }
11469                         _self.$fileDomElements[index] = item;
11470                    }
11471                });
11472                filtered = this.$fileDomElements;
11473                // In case of IE9, get the last element of fileDom and update the id for label
11474                if(isBrowserIE9OrIE10 && value !== null){
11475                    // Case: if it is single select, and then we do a restore and then after attaching another file we click save
11476                    if(_.last(this.$fileDomElements) == null){
11477                        this.cloneFileInputAndUpdateIdForIE9();
11478                    } else {
11479                        this.updateLabelForAttr(_.last(this.$fileDomElements).attr("id"));
11480                    }
11481                }
11482            }
11483            else {
11484                // here filtered is a new array
11485                // A new array is returned over here so that the user of this API doesn't try to change the widget array directly
11486                filtered = $.map(this.$fileDomElements, function(item, index){
11487                    if(!item) {
11488                        return _self._getUrl(index);
11489                    } else if((item[0].files && item[0].files.length !== 0)
11490                            || (_self.options.multiSelect || item[0].value.length > 0)) {
11491                        return item;
11492                    }
11493                });
11494            }
11495            return filtered;
11496        },
11497
11498        // file preview html
11499        fileItemPreview: function(){
11500            return $("<span></span>").addClass("guide-fu-filePreview glyphicon glyphicon-ok");
11501        },
11502
11503        // force flag indicates that forcefully set the dom but don't update the options
11504        buttonText: function (value, force) {
11505            if (value !== undefined) {
11506                if(!force)
11507                    this.options.buttonText = value;
11508                this.$elementFileUploadBtn.find('span.guide-fu-label').html(value);
11509            } else {
11510                return this.options.buttonText;
11511            }
11512        },
11513
11514        // To change the icon of the button, the user should customize the class
11515        btnIcon: function () {
11516            return $("<span></span>").addClass("guide-fu-icon glyphicon glyphicon-folder-open");
11517        },
11518
11519        btnLabel: function(){
11520            return $("<span></span>").addClass("guide-fu-label").html(this.options.buttonText);
11521        },
11522
11523        fileItemList: function(){
11524            return this.$parent.find(this.options.fileItemListClass);
11525        },
11526
11527        getNewCommentElementSummary : function(text){
11528            return $("<div title='Click to edit' tabindex='0'></p>").addClass("guide-fu-comment").text(text || _defaults.placeHolderText);
11529        },
11530
11531        getNewCommentElement : function(text){
11532            return $("<div contenteditable='true' tabindex='0'></div>").addClass("guide-fu-comment").text(text || "");
11533        },
11534
11535        fileItem: function(fileName, comment, fileUrl){
11536            var $fileItem = $("<li></li>").addClass("guide-fu-fileItem");
11537            var nameWithoutMarker = xfalib.ut.Utilities._getNameWithoutMarker(fileName);
11538            var $elem = $("<span tabindex='0'></span>").addClass("guide-fu-fileName").attr("aria-label", nameWithoutMarker).text(nameWithoutMarker).appendTo($fileItem).keypress(function(e) {
11539                if (e.keyCode === 13 || e.charCode === 32) {
11540                    $(e.target).click();
11541                }
11542            }).click($.proxy(this.handleFilePreview, this));
11543            if(this.options.disablePreview) {
11544               $elem.addClass('non-preview-fileName');
11545            }
11546            if(fileUrl != null){
11547                $elem.attr("data-key", fileUrl);
11548            }
11549            $("<span tabindex='0'></span>").addClass("guide-fu-fileClose close").attr("role", "button").attr("aria-label", xfalib.locale.Strings.FileCloseAccessText 
11549+ nameWithoutMarker).text("x").appendTo($fileItem).keypress(function(e) {
11550                if (e.keyCode === 13 || e.charCode === 32) {
11551                    $(e.target).click();
11552                }
11553            })
11554                .click($.proxy(this.handleClick, this));
11555
11556            this.fileItemPreview().appendTo($fileItem);
11557
11558            if(this.options.showComment){
11559                this.getNewCommentElementSummary(comment).appendTo($fileItem).focus($.proxy(this.handleCommentClick, this)).click($.proxy(this.handleCommentClick, this));
11560            }
11561            return $fileItem;
11562        },
11563
11564        toggleFileUploadBtn: function(){
11565            if(this.options.multiSelect) {
11566                // Change the look of file upload button
11567                if(this.$elementFileList.children().length > 0){
11568                    // Change the text
11569                    this.buttonText(this._addFile, true);
11570                    // Change the icon too
11571                    this.$elementFileUploadBtn.find('span.guide-fu-icon').removeClass("glyphicon-folder-open").addClass("glyphicon-plus");
11572                } else {
11573                    this.buttonText(this.options.buttonText);
11574                    this.$elementFileUploadBtn.find('span.guide-fu-icon').removeClass("glyphicon-plus").addClass("glyphicon-folder-open");
11575                }
11576            }
11577        },
11578
11579        showInvalidMessage: function(fileName, invalidFeature){
11580            var that = this;
11581            var IS_IPAD = navigator.userAgent.match(/iPad/i) !== null,
11582                IS_IPHONE = (navigator.userAgent.match(/iPhone/i) !== null);
11583            if(IS_IPAD || IS_IPHONE){
11584                setTimeout(function() {
11585                  that.invalidMessage(that,fileName, invalidFeature);
11586                }, 0);
11587            }
11588            else {
11589               this.invalidMessage(this,fileName, invalidFeature);
11590            }
11591        },
11592
11593        invalidMessage: function(refObj,fileName, invalidFeature){
11594            if(invalidFeature === refObj.invalidFeature.SIZE) {
11595                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileSizeGreater"], [fileName, refObj.options.fileSizeLimit]));
11596            } else if (invalidFeature === refObj.invalidFeature.NAME) {
11597                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileNameInvalid"], [fileName]));
11598            } else if (invalidFeature === refObj.invalidFeature.MIMETYPE) {
11599                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileMimeTypeInvalid"], [fileName]));
11600            }
11601        },
11602
11603        /***
11604         * Finds the value in the array, if the value is a url then it uses the filename in the url to search for the text
11605         * This is done since our model stores the URL too in case of draft restore or clicking on save in guide
11606         * @param text          string representing the text of which the index is to be found
11607         * @param $elem         reference to the jquery element. This is used if there are duplicate file names present in the file upload.
11608         * @returns {number}
11609         * @private
11610         */
11611        _getIndexOfText : function(text, $elem){
11612            var index = -1,
11613                self = this,
11614                isDuplicatePresent = false;
11615            _.find(this.values, function(value, iter){
11616                // if value is a url, then compare with last
11617                var tempValue = value,
11618                    // can't use getOrElse here since value can have "." in URL and getOrElse splits based on period to find key inside object
11619                    fileName =  (_.isObject(self._initialFileValueFileNameMap) && typeof self._initialFileValueFileNameMap[value] !== undefined) ? self._initialFileValueFileNameMap[value] : null;
11620                if(tempValue.match(/\//g) && tempValue.match(/\//g).length > 1){
11621                    tempValue =  value.substring(value.lastIndexOf("/")+1);
11622                    tempValue = xfalib.ut.Utilities._getNameWithoutMarker(tempValue);
11623                }
11624                // we pass file name explicityly as options, if passed use that as fallback to find the URL
11625                if(tempValue === text || fileName === text){
11626                    index = iter;
11627                    isDuplicatePresent = self.values.indexOf(value, index + 1) !== -1;
11628                    if($elem && isDuplicatePresent){
11629                        // now check if duplicate present and get its correct index
11630                        // today all files are wrapped under .guide-fu-fileItem node
11631                        index = $elem.closest(".guide-fu-fileItem").index();
11632                    }
11633                    // check if there is a duplicate
11634                    // this is to just break the loop
11635                    return value;
11636                }
11637            });
11638            return index;
11639        },
11640
11641
11642        /*
11643         * Since input file element might contain multiple files.
11644         * This function takes absolute file index as parameter & returns position of the file w.r.t input file elt
11645         */
11646        _getFileObjIdx : function (index) {
11647            if (index >= 0) {
11648                var currentIdx = 0;
11649                for (var fileInputEltIdx = 0; fileInputEltIdx < this.$fileDomElements.length; fileInputEltIdx++) {
11650                    if (this.$fileDomElements[fileInputEltIdx]) {
11651                        var files = this.$fileDomElements[fileInputEltIdx][0].files;
11652                        if (files) {
11653                            var filesLength =  files.length;
11654                            if ( index <= currentIdx + filesLength - 1 ) {
11655                                return [fileInputEltIdx, index - currentIdx];
11656                            }
11657                            currentIdx+=files.length;
11658                        }
11659                    } else {
11660                        if (index == currentIdx) {
11661                            return [fileInputEltIdx,0];
11662                        }
11663                        currentIdx++;
11664                    }
11665                }
11666            }
11667            return null;
11668        },
11669
11670        /*
11671         * This function returns FileList object of the passed file array
11672         */
11673        _getFileListItem : function (files) {
11674            try {
11675                var dataContainer = new DataTransfer() || (new ClipboardEvent("")).clipboardData;
11676                _.each(files, function (file) {
11677                    dataContainer.items.add(file);
11678                });
11679                return dataContainer.files;
11680            } catch(err) {
11681                console.error(err);
11682                throw err;
11683            }
11684        },
11685
11686        _updateFilesInDom : function($fileDom, files) {
11687            // in safari, a change event is trigged if files property is changed dynamically
11688            // hence adding this check to clear existing state only for safari browsers
11689            this._isFileUpdate = true;
11690            $fileDom[0].files = this._getFileListItem(files);
11691            this._isFileUpdate = false;
11692        },
11693
11694        /*
11695         * This function deletes files at specified indexes from input dom elt
11696         */
11697        _deleteFilesFromInputDom : function ($fileDomElt, deletedIndexes) {
11698            var remainingFiles = [];
11699            _.each($fileDomElt[0].files, function(file,idx){
11700                if(!deletedIndexes.includes(idx)){
11701                    remainingFiles.push(file);
11702                }
11703            });
11704            try {
11705                // in safari, a change event is trigged if files property is changed dynamically
11706                // hence adding this check to clear existing state only for safari browsers
11707                this._updateFilesInDom($fileDomElt, remainingFiles);
11708            } catch(err){
11709                console.error("Deleting files is not supported in your browser");
11710            }
11711        },
11712
11713        /**
11714         * This event listener gets called on click of close button in file upload
11715         *
11716         * @param event
11717         */
11718        handleClick: function(event){
11719
11720            var $elem = $(event.target),
11721                text = $elem.prev().text(),
11722                index = this._getIndexOfText(text, $elem),
11723                url = $elem.prev().data("key"),
11724                objectUrl = $elem.prev().data("objectUrl");
11725            if (index != -1) {
11726                this.values.splice(index, 1);
11727                var fileObjIdx = this._getFileObjIdx(index);
11728                var $fileDomElt = this.$fileDomElements[fileObjIdx[0]];
11729                if (!$fileDomElt || $fileDomElt[0].files.length === 1) {
11730                    this.$fileDomElements.splice(fileObjIdx[0], 1);
11731                } else {
11732                    this._deleteFilesFromInputDom($fileDomElt, [fileObjIdx[1]]);
11733                }
11734                if (isBrowserIE9OrIE10) {
11735                    this.cloneFileInputAndUpdateIdForIE9();
11736                }
11737                if (url != null) {
11738                    // remove the data so that others don't use this url
11739                    $elem.prev().removeData("key");
11740                }
11741                if(objectUrl) {
11742                    // revoke the object URL to avoid memory leaks in browser
11743                    // since file is anyways getting deleted, remove the object URL's too
11744                    window.URL.revokeObjectURL(objectUrl);
11745                }
11746            }
11747            // Remove the dom from view
11748            //All bound events and jQuery data associated with the element are also removed
11749            $elem.parent().remove();
11750            // trigger the change event to update the value
11751            this.$element.trigger("change.fileupload");
11752            // Set the focus on file upload button after click of close
11753            this.$elementFileUploadBtn.focus();
11754
11755        },
11756
11757
11758        displaySVG: function (objectUrl) {
11759            const url = objectUrl;
11760            const img = window.document.createElement('img');
11761            img.src = url;
11762            const newTab = window.open('', '_blank', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11763            newTab.document.body.appendChild(img);
11764        },
11765
11766
11767        _previewFileUsingObjectUrl : function (file) {
11768            if (file) {
11769                if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
11770                    window.navigator.msSaveOrOpenBlob(file, file.name);
11771                } else {
11772                    var url = window.URL.createObjectURL(file);
11773                    if (file.type === 'image/svg+xml') {
11774                        this.displaySVG(url);
11775                    } else {
11776                        window.open(url, '', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11777                    }
11778                    return url;
11779                }
11780            }
11781        },
11782
11783        // this function maintains a map for
11784        handleFilePreview: function(event){
11785            if(!this.options.disablePreview) {
11786                var $elem = $(event.target),
11787                    text = $elem.text(),
11788                    index = this._getIndexOfText(text, $elem),
11789                    fileDom = null,
11790                    fileName = null,
11791                    fileUrl = null,
11792                    timeStamp = new Date().getTime();
11793
11794                // for draft usecase, if text contains "/" in it, it means the file is already uploaded
11795                // text should contain the path, assuming that the fileUrl is stored in data element
11796
11797                if (index != -1) {
11798                    // Store the url of file as data
11799                    if(!_.isUndefined($elem.data("key")))
11800                        fileUrl = $elem.data("key");
11801
11802                    if(fileUrl)  {
11803                        //prepend context path if not already appended
11804                        if (!(fileUrl.lastIndexOf(this.options._getUrl, 0) === 0)) {
11805                            fileUrl =  this.options._getUrl + fileUrl;
11806                        }
11807                        this.previewFile.apply(this, [null, {"fileUrl" : fileUrl}]);
11808                    } else {
11809                        var previewFileObjIdx = this._getFileObjIdx(index);
11810                        var previewFile = this.$fileDomElements[previewFileObjIdx[0]][0].files[previewFileObjIdx[1]];
11811                        var objectUrl = this._previewFileUsingObjectUrl(previewFile);
11812                        if (objectUrl) {
11813                            $elem.data("objectUrl", objectUrl);
11814                        }
11815                    }
11816                }
11817            }
11818        },
11819
11820        previewFile: function(event){
11821            var url = null;
11822            if(_.isUndefined(arguments[1]))
11823                url = this.$element[this.options.uploaderPluginName]("getFileUrl");
11824            else
11825                url = arguments[1].fileUrl;
11826            var lastIndex = url.lastIndexOf('/');
11827            //to make sure url has a slash '/'
11828            if(lastIndex >= 0) {
11829                //encode the filename after last slash to ensure the handling of special characters
11830                url = url.substr(0, lastIndex) +'/'+ encodeURIComponent(url.substr(lastIndex + 1));
11831            }
11832            // this would work for dataURl or normal URL
11833            // todo: add support to preview base 64 encoded image, to preview base64 encoded binary, we would probably need
11834            // todo: the content type in the widget too
11835            window.open(url, '', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11836
11837        },
11838
11839        resetIfNotMultiSelect: function(){
11840            if(!this.options.multiSelect){
11841                // Reset the value and file array
11842                this.values = [];
11843                //this.comments = [];
11844            }
11845        },
11846
11847        showFileList: function(fileName, comment, fileUrl){
11848            if(!this.options.multiSelect || fileName == null || _.isUndefined(fileName)) {
11849                // if not multiselect, remove all the children of file list
11850                this.$elementFileList.empty();
11851            }
11852
11853            // Add the file item
11854            // On click of close, remove the element and update the model
11855            // handle on click of preview button
11856            if(fileName != null) {
11857                this.$fileItem = this.$elementFileList.append(this.fileItem(fileName, comment, fileUrl));
11858            }
11859        },
11860
11861        /**
11862         * Handles the click on comment field
11863         *
11864         * TODO: Implement show/hide behaviour instead of replaceWith
11865         * This may be cause problem during bubble up of event
11866         *
11867         * @param event
11868         */
11869        handleCommentClick : function(event){
11870            var $commentElem = null,
11871                $elem = $(event.target);
11872            if ($elem.text() === _defaults.placeHolderText) {
11873                $commentElem = this.getNewCommentElement()
11874            } else {
11875                $commentElem = this.getNewCommentElement($(event.target).text());
11876            }
11877            $elem.replaceWith($commentElem);
11878            // register the event again
11879            if(isBrowserIE9OrIE10){
11880                $commentElem.focus().focusout($.proxy(this.handleCommentBlur, this));
11881            } else {
11882                $commentElem.focus().blur($.proxy(this.handleCommentBlur, this));
11883            }
11884        },
11885
11886        handleCommentBlur : function(event){
11887            var $commentSummaryElem = null,
11888                $elem = $(event.target);
11889            if ($elem.text() === _defaults.placeHolderText) {
11890                $commentSummaryElem = this.getNewCommentElementSummary();
11891            } else {
11892                $commentSummaryElem = this.getNewCommentElementSummary($(event.target).text());
11893            }
11894            $elem.replaceWith($commentSummaryElem);
11895            $commentSummaryElem.focus($.proxy(this.handleCommentClick,this)).click($.proxy(this.handleCommentClick,this));
11896            // Add a div with the html
11897            this.$element.trigger("change.fileupload");
11898        },
11899
11900        // checks if file name is valid or not to prevent security threats
11901        isValid : function(fname) {
11902            var rg1=/^[^\\/:\*\;\$\%\?"<>\|]+$/; // forbidden characters \ / : * ? " < > | ; % $
11903            var rg2=/^\./; // cannot start with dot (.)
11904            var rg3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; // forbidden file names
11905            return rg1.test(fname) && !rg2.test(fname) && !rg3.test(fname);
11906        },
11907
11908        handleChange: function (evnt) {
11909            if (!this._isFileUpdate) {
11910                var currFileName = '',
11911                    inValidSizefileNames = '',
11912                    inValidNamefileNames = '',
11913                    inValidMimeTypefileNames = '',
11914                    $elem = $(evnt.target),
11915                    files = $elem[0].files;
11916                // Initially set the invalid flag to false
11917                // if not multiselect then remove the extra domELement clone
11918                if (!this.options.multiSelect && this.$fileDomElements.length > 1) {
11919                    this.$fileDomElements.splice(0, 1)
11920                }
11921
11922                var isInvalidSize = false,
11923                    isInvalidFileName = false,
11924                    isInvalidMimeType = false;
11925                this.resetIfNotMultiSelect();
11926                // Iterate through all the files
11927                if (isBrowserIE9OrIE10) { // IE9 doesn't support FileList, hence files variable is undefined
11928                    currFileName = $elem.val().split("\\").pop();
11929                    //update the last element of array
11930                    if (this.$fileDomElements.length > 0) {
11931                        this.$fileDomElements[this.$fileDomElements.length - 1] = $elem;
11932                    }
11933                    this.cloneFileInputAndUpdateIdForIE9();
11934
11935                    // In case of IE9, only do this
11936                    if (_.isUndefined(files)) {
11937                        this.showFileList(currFileName);
11938                        this.values.push(currFileName);
11939                        // trigger the change event to update the value
11940                        this.$element.trigger("change.fileupload");
11941                    }
11942                }
11943                if (!_.isUndefined(files)) {
11944                    var invalidFilesIndexes = [];
11945                    _.each(files, function (file, fileIndex) {
11946                        var isCurrentInvalidFileSize = false,
11947                            isCurrentInvalidFileName = false,
11948                            isCurrentInvalidMimeType = false;
11949                        currFileName = file.name.split("\\").pop();
11950                        // Now size is in MB
11951                        var size = file.size / 1024 / 1024;
11952                        // check if file size limit is within limits
11953                        if ((size > parseFloat(this.options.fileSizeLimit))) {
11954                            isInvalidSize = isCurrentInvalidFileSize = true;
11955                            inValidSizefileNames = currFileName + "," + inValidSizefileNames;
11956                        } else if (!this.isValid(currFileName)) {
11957                            // check if file names are valid (ie) there are no control characters in file names
11958                            isInvalidFileName = isCurrentInvalidFileName = true;
11959                            inValidNamefileNames = currFileName + "," + inValidNamefileNames;
11960                        } else if (file.type) {
11961                            var isMatch = this.regexMimeTypeList.some(function (rx) {
11962                                return rx.test(file.type);
11963                            });
11964                            if (!isMatch) {
11965                                isInvalidMimeType = isCurrentInvalidMimeType = true;
11966                                inValidMimeTypefileNames = currFileName + "," + inValidMimeTypefileNames;
11967                            }
11968                        }
11969
11970                        // if the file is not invalid, show it and push it to internal array
11971                        if (!isCurrentInvalidFileSize && !isCurrentInvalidFileName && !isCurrentInvalidMimeType) {
11972                            this.showFileList(currFileName);
11973                            this.values.push(currFileName);
11974                        } else {
11975                            invalidFilesIndexes.push(fileIndex);
11976                        }
11977
11978
11979                    }, this);
11980
11981                    if (invalidFilesIndexes.length > 0) {
11982                        var currentFileDomIndex,
11983                            $currentFileDomElement,
11984                            filesCount;
11985                        if (this.$fileDomElements.length > 0) {
11986                            currentFileDomIndex = this.$fileDomElements.length - 1;
11987                            $currentFileDomElement = this.$fileDomElements[currentFileDomIndex];
11988                            if ($currentFileDomElement && $currentFileDomElement.length > 0) {
11989                                filesCount = $currentFileDomElement[0].files.length;
11990                                //if all the files are invalid remove the input element as well otherwise only remove the invalid files.
11991                                if (filesCount === invalidFilesIndexes.length) {
11992                                    this.$fileDomElements.splice(-1, 1);
11993                                } else {
11994                                    this._deleteFilesFromInputDom($currentFileDomElement, invalidFilesIndexes);
11995                                }
11996                            }
11997                        }
11998
11999                        // in case of IE10, create one extra element
12000                        if (isBrowserIE9OrIE10) {
12001                            this.cloneFileInputAndUpdateIdForIE9();
12002                        }
12003                    }
12004
12005                    // trigger the change event to update the value
12006                    this.$element.trigger("change.fileupload");
12007                }
12008
12009                if (isInvalidSize) {
12010                    this.showInvalidMessage(inValidSizefileNames.substring(0, inValidSizefileNames.lastIndexOf(',')), this.invalidFeature.SIZE);
12011                } else if (isInvalidFileName) {
12012                    this.showInvalidMessage(inValidNamefileNames.substring(0, inValidNamefileNames.lastIndexOf(',')), this.invalidFeature.NAME);
12013                } else if (isInvalidMimeType) {
12014                    this.showInvalidMessage(inValidMimeTypefileNames.substring(0, inValidMimeTypefileNames.lastIndexOf(',')), this.invalidFeature.MIMETYPE);
12015                }
12016            }
12017        },
12018
12019        cloneFileInputAndUpdateIdForIE9 : function(){
12020            var elem = _.last(this.$fileDomElements),
12021                elemExists = elem != null,
12022                elemHasValue = elemExists && elem.val().length > 0,
12023                elemId = null,
12024                selector = null;
12025
12026            // CQ-4237903 : create clone to handle the case when user clicks cancel in chrome and for multiselect
12027            // on clicking cancel in chrome file browser, chrome removes all the files from the input element
12028            // remove the extra clone in $fileDomElement on handleChange
12029            if(!elemExists || elemHasValue) {
12030                elem = this.$element.clone();
12031                // copy the data attributes
12032                elem.data(this.$element.data());
12033                if(isBrowserIE9OrIE10){
12034                    elemId = this.$element.attr("id") + (++fileLabelsCount);
12035                    elem.attr("id", elemId);
12036                    elem.css({
12037                        'position' : 'absolute',
12038                        'top' : '-2000px',
12039                        'left': '-2000px'
12040                    });
12041                    elem.appendTo('body');
12042                    this.updateLabelForAttr(elemId);
12043                }
12044                elem.change($.proxy(this.handleChange, this));
12045                this.$fileDomElements.push(elem);
12046            }
12047            // Case: if it is not multiselect and if the first file dom element is null
12048            // this case would hit when we restore a single select file attachment and attach a new file
12049            if(!this.options.multiSelect && this.$fileDomElements[0] === null){
12050                //Splice null out of it, since we are attaching a new file
12051                this.$fileDomElements.splice(0, 1);
12052            }
12053            // if the browser is not IE9, then click it
12054            if(!isBrowserIE9OrIE10) {
12055                elem.click();
12056            }
12057            return true;
12058        },
12059
12060        /**
12061         * In case of IE9, get the last element of fileDom and update the id for label
12062         *
12063         * @param fileInputId
12064         */
12065        updateLabelForAttr : function(fileInputId){
12066            this.$label.attr("for" , fileInputId);
12067        },
12068
12069        createLabelForFileInput : function (fileInputId){
12070            if(isBrowserIE9OrIE10) {
12071                this.$label = $("<label></label>").addClass("guide-fu-attach-button button")
12072                        .text(this.options.buttonText)
12073                        .attr('for',fileInputId);
12074                this.$elementFileUploadBtn.replaceWith(this.$label);
12075                this.$label.parent().attr("tabindex", 0).attr("role", "button").attr("aria-label", this.options.screenReaderText || "");
12076            }
12077        },
12078
12079
12080        constructor: function () {
12081            // Initialize the self instance
12082            var _self = this,
12083                isFirst = true;
12084            //jquery instance of file upload button
12085            this.$elementFileUploadBtn = this.$parent.find(this.options.buttonClass);
12086            this.$elementFileUploadBtn.attr("aria-label", this.options.screenReaderText || "");
12087            if(isBrowserIE9OrIE10){
12088                this.elementId = this.$element.attr("id");
12089                this.createLabelForFileInput(this.$element.attr("id"));
12090            }
12091
12092            // html for file list
12093            this.$elementFileList = $(this.fileItemList());
12094            // Initialize the value and file(Refer FileList class mdn)
12095            this.values = [];
12096            this._initialFileValueFileNameMap = {};
12097            // List of dom elements of input type file
12098            this.$fileDomElements = [];
12099
12100            var flag = false,
12101                $currElem = null;
12102
12103            $(document).mousedown(function(e) {
12104                $currElem = $(e.target);
12105            });
12106            // Enter key should result in click of button
12107            this.$elementFileUploadBtn
12108                .focus(function(){
12109                    _self.$element.trigger("focus.fileupload");
12110                })
12111                .click($.proxy(this.cloneFileInputAndUpdateIdForIE9, this))
12112                .blur(function(event){
12113                    // Check if the currElem does not belong to the fileItemList
12114                    if(!flag && $currElem!= null && $currElem.closest(".guide-fu-fileItemList").length <=0){
12115                        _self.$element.trigger("focusout.fileupload");
12116                    }
12117                    flag = false;
12118                });
12119            //Initialize the filePreview Plugin
12120            this.$element[this.options.uploaderPluginName]({
12121                iframeContainer: this.options.iframeContainer,
12122                _filePath: this.options._filePath,
12123                _uuidGenerator: this.options._uuidGenerator,
12124                _getUrl: this.options._getUrl
12125
12126            });
12127            // Getting input file value
12128            // listening on fileuploaded event
12129            this.$element.change($.proxy(this.handleChange, this))
12130                .on("adobeFileUploader.fileUploaded", $.proxy(this.previewFile, this));
12131        }
12132    };
12133
12134    $.fn.adobeFileAttachment = function (option, value) {
12135        var get = '',
12136            element = this.each(function () {
12137                // in case of input type file
12138                if ($(this).attr('type') === 'file') {
12139                    var $this = $(this),
12140                        data = $this.data('adobeFileAttachment'),
12141                        options = $.extend({}, AdobeFileAttachment.prototype.defaults, typeof option === 'object' && option);
12142
12143                    // Save the adobeFileAttachment data in jquery
12144                    if (!data) {
12145                        $this.data('adobeFileAttachment', (data = new AdobeFileAttachment(this, options)));
12146                        data.constructor();
12147                    }
12148
12149                    // code to get and set an option
12150                    if (typeof option === 'string') {
12151                        get = data[option](value);
12152                    }
12153                }
12154            });
12155
12156        if (typeof get !== 'undefined') {
12157            return get;
12158        } else {
12159            return element;
12160        }
12161    };
12162
12163    // fileSizeLimit is in MB, default value is 2MB
12164    AdobeFileAttachment.prototype.defaults = {
12165        'buttonText': 'Attach',
12166        'multiSelect': false,
12167        'fileSizeLimit': 2,
12168        'uploaderPluginName': "adobeFileUploader",
12169        'mimeType' : ['audio/*', 'video/*', 'image/*', 'text/*', 'application/pdf']
12170    };
12171
12172})($, window, window._);
12173(function($, _) {
12174    var xfaUtil = xfalib.ut.XfaUtil.prototype;
12175    $.widget( "xfaWidget.fileUpload", $.xfaWidget.abstractWidget, {
12176
12177        _widgetName:"fileUpload",
12178        _superPrototype : $.xfaWidget.abstractWidget.prototype,
12179        getOptionsMap: function(){
12180            var parentOptionsMap = this._superPrototype.getOptionsMap.apply(this,arguments),
12181                newMap = $.extend({},parentOptionsMap, $.extend({}, this.options, {
12182                    "value" : function(value) {
12183                        this.$userControl.adobeFileAttachment("value", value);
12184                    },
12185                    "fileList": function(value){
12186                        this.$userControl.adobeFileAttachment("fileList", value);
12187                    },
12188                    "comment" : function(value){
12189                        this.$userControl.adobeFileAttachment("comment", value);
12190                    },
12191                    // "access" can be either open or readonly
12192                    "access" : function(value){
12193                        this.$userControl.adobeFileAttachment("access", value);
12194                    }
12195
12196                }));
12197
12198            return newMap;
12199
12200        },
12201        // TODO: Will need to remove this functions
12202        //  will be tracked by LC-391200
12203
12204        _initializeOptions: function () {
12205            _.each(this.optionsHandler, function (value, key) {
12206                // overriding the behaviour of _initializeOptions
12207                // only for _uuidGenerator
12208                // as we font want getUUID to be called at render time
12209                if (typeof value === "function" && key !== '_uuidGenerator' ) {
12210                        value.apply(this, [this.options[key]])
12211                }
12212            }, this)
12213        },
12214
12215        _getFileList: function(){
12216            return this.$userControl.adobeFileAttachment("fileList");
12217        },
12218
12219        _getComment: function(){
12220            return this.$userControl.adobeFileAttachment("comment");
12221        },
12222        _getFileNamePathMap: function (pathList) {
12223            return this.$userControl.adobeFileAttachment("getSetFilePathAndReturnNamePathMap", pathList);
12224        },
12225        getEventMap: function() {
12226            var parentEventMap = this._superPrototype.getEventMap.apply(this, arguments),
12227                newMap = $.extend({}, parentEventMap,
12228                    {
12229                        "change" : null,
12230                        "focusout.fileupload" : xfaUtil.XFA_EXIT_EVENT,
12231                        "focus.fileupload" : xfaUtil.XFA_ENTER_EVENT,
12232                        "change.fileupload" : xfaUtil.XFA_CHANGE_EVENT
12233                    });
12234            return newMap;
12235        },
12236        render: function() {
12237            var $el = this._superPrototype.render.apply(this,arguments);
12238            $el.adobeFileAttachment(this.getOptionsMap());
12239            return $el;
12240        },
12241        showDisplayValue: function() {
12242             //since value can't be set in file element input, leav
12242ing this fn empty
12243        },
12244        showValue: function() {
12245            //since value can't be set in file element input, leaving this fn empty
12246        },
12247        getCommitValue: function() {
12248            this.options.fileList = this._getFileList();
12249            this.options.comment = this._getComment();
12250            return this.$userControl.adobeFileAttachment("value");
12251        }
12252    });
12253})($, window._);
12254
12255/**
12256 * Adobe FilePreview Widget Plugin
12257 *
12258 * Options expected by file preview is the url
12259 *
12260 * Options Required Are:
12261 *
12262 *  iframeName: Name of the Iframe
12263 *  iframeContainer: Container of the iframe(eg Body)
12264 *  fileUploadPath: Path where the file is to be uploaded
12265 *  fileUploadServlet: Servlet where the file is to be uploaded
12266 *
12267 */
12268(function ($, _) {
12269
12270    var AdobeFileUploader = function (element, options) {
12271        this.options = options;
12272        this.$element = $(element);
12273    };
12274
12275    AdobeFileUploader.prototype = {
12276
12277        _fileIframeName: "guide-fu-iframe",
12278
12279        _filePath: "/tmp/fd/mf",
12280
12281        _iframeContainer: "body#formBody",
12282
12283
12284        fileIframe: function (name) {
12285            return $("<iframe></iframe>").attr({
12286                style: "display:none",
12287                name: name
12288            });
12289        },
12290
12291        uploadFile: function (fileObject) {
12292            var multiple = false,
12293                fileName = null,
12294                actionUrl = null,
12295                fileUploadPath = fileObject.fileUploadPath,
12296                uuid;
12297
12298            if (!fileUploadPath) {
12299                uuid = fileObject._uuidGenerator();
12300            }
12301
12302            // if uuid exists only then upload the file in the current  instance
12303            if (_.isObject(fileObject) && (fileUploadPath || uuid)) {
12304                var fileDom = fileObject.fileDom,
12305                    $form = $(this.options.iframeContainer).find(".filePreview");
12306                fileName = fileObject.fileName;
12307                multiple = fileObject.multiple;
12308                if(!fileUploadPath) {
12309                    fileUploadPath = this.options.fileUploadPath + "/" + uuid;
12310                }
12311                if (fileDom !== null) {
12312                    //prepend contextpath
12313                    actionUrl = fileObject._getUrl + fileUploadPath;
12314                    if (!multiple) {
12315                        if (!(fileUploadPath.lastIndexOf(fileObject._getUrl, 0) === 0)) {
12316                            this.fileUrl = fileObject._getUrl + fileUploadPath + "/" + fileName;
12317                        } else {
12318                            this.fileUrl = fileUploadPath + "/" + fileName;
12319                        }
12320                    } else {
12321                        this.fileUrl = actionUrl;
12322                    }
12323                    // done to solve issue LC-5835
12324                    if($form.length === 0) {
12325                        $form = $("<form method='post' enctype='multipart/form-data'/>")
12326                            .addClass("filePreview")
12327                            // create id so that it does not intercept with other forms in the page
12328                            .attr({
12329                                id : "form" + new Date().valueOf(),
12330                                action : actionUrl,
12331                                target : this.options.iframeName
12332                            })
12333                            .appendTo(this.options.iframeContainer);
12334                    } else {
12335                        /// first empty all children, using detach so that data is not clear
12336                        $form.children().detach();
12337                        // now update the new attributes
12338                        $form.attr({
12339                            action : actionUrl,
12340                            target : this.options.iframeName
12341                        });
12342                    }
12343                    // this is done so that the other events attached at some other level in DOM Tree don't interfere
12344                    $form.one("submit", function(evnt){
12345                        evnt.stopPropagation();
12346                    });
12347
12348                     var data = new FormData();
12349
12350                    if (multiple) {
12351                        _.each(fileDom, function (fileDomElement, index) {
12352                            // OOTB, this code is still used in dashboard
12353                            if(fileDomElement !== null && !_.isString(fileDomElement)) {
12354                                $(fileDomElement[0]).attr('name', fileName[index]).appendTo($form);
12355                                // fileDomElement might contain multiple files so all the files needs to be added to formdata.
12356                                var currentFileNames = fileName[index].split("\n");
12357                                for(var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
12358                                    data.append(currentFileNames[fileIndex], fileDomElement[0].files[fileIndex]);
12359                                }
12360                            }
12361                        }, this);
12362                    } else {
12363                        fileDom.attr('name', fileName).appendTo($form);
12364                        data.append(fileName, fileDom[0].files[0]);
12365                    }
12366
12367                    /* UseCase: Suppose the fileName is in other language, on click of fileName, it tries to upload the file
12368                     so that it could be preview, this change would ensure that the file is properly previewed supp
12368orting
12369                     the given UTF-8 charset */
12370                    $("<input type='hidden' name='_charset_' value='UTF-8'/>").appendTo($form);
12371                    data.append("_charset_", "UTF-8");
12372                    if (!multiple) {
12373                        this.fileMap[this.fileUrl] = this.$element;
12374                    }
12375                    var self = this;
12376                    $.ajax({
12377                        url: $form.attr("action"),
12378                        data: data,
12379                        cache: false,
12380                        contentType: false,
12381                        processData: false,
12382                        method: 'POST',
12383                        type: 'POST',
12384                        success: function(data){
12385                            if (!multiple) {
12386                                self.handleSingleFileUpload(data);
12387                            } else {
12388                                self.handleMultipleFileUpload(data);
12389                            }
12390                        },
12391                        error: function() {
12392                            this.$element.trigger("adobeFileUploader.fileUploadFailed");
12393                        }
12394                    });
12395                }
12396            }
12397            return this.fileUrl;
12398        },
12399
12400        handleMultipleFileUpload: function (data) {
12401            this.$element.trigger("adobeFileUploader.multipleFileUploaded");
12402        },
12403
12404        getFileUrl: function () {
12405            return this.fileUrl;
12406        },
12407
12408        getUrlContentsFromUploadData: function (data) {
12409            var temp;
12410            if(data != null) {
12411                temp = $(data).find("#ChangeLog").text().split("br", 2)[1];
12412            } else {
12413                var selector = this.options.iframeContainer + " iframe[name='" + this.options.iframeName + "']";
12414                temp = $(selector).contents().find("#ChangeLog").text().split("br", 2)[1];
12415            }
12416            
12417            temp = temp.substring(temp.indexOf("created") + 9, temp.indexOf(";<"));
12418            temp = temp.substring(0, temp.length - 2);
12419            var index = temp.indexOf("/jcr:content");
12420            if (index !== -1)
12421                temp = temp.substring(0, index);
12422            return temp;
12423        },
12424
12425        handleSingleFileUpload: function (data) {
12426            var url = this.getUrlContentsFromUploadData(data);
12427
12428            //prepend context path
12429            url = this.options._getUrl + url;
12430            if (url in this.fileMap) {
12431                this.fileMap[url].trigger("adobeFileUploader.fileUploaded");
12432            }
12433        },
12434
12435        initialize: function () {
12436            // Put iframe inside the iframe container
12437            // On the load of iframe, display the contents of file
12438            // since there is only one iframe for all the file attachments, there may be race condition
12439            if (this.$iframe == null || this.$iframe.length === 0) {
12440                this.$iframe = this.fileIframe(this.options.iframeName).appendTo(this.options.iframeContainer);
12441                // since there is only iframe for the preview of all file attachments
12442                // this map is added in the closure scope
12443                // map contains the url(key) vs fileDomElement(value)
12444                // it helps avoids the race condition
12445                this.fileMap = {};
12446            }
12447        }
12448    };
12449
12450    $.fn.adobeFileUploader = function (option, value) {
12451        var get = '',
12452            element = this.each(function () {
12453                // in case of input type file
12454                if ($(this).attr('type') === 'file') {
12455                    var $this = $(this),
12456                        data = $this.data('adobeFileUploader'),
12457                        options = $.extend({}, AdobeFileUploader.prototype.defaults(option, value), typeof option === 'object' && option);
12458
12459                    // Save the adobeFileAttachment data in jquery
12460                    if (!data) {
12461                        $this.data('adobeFileUploader', (data = new AdobeFileUploader(this, options)));
12462                        data.initialize();
12463                    } else {
12464                        // update elements if not equal, since sometimes one can clone too
12465                        if(data.$element.get(0) !== this) {
12466                            data.$element = $(this);
12467                        }
12468                    }
12469
12470                    // code to get and set an option
12471                    if (typeof option === 'string') {
12472                        get = data[option](value);
12473                    }
12474                }
12475            });
12476
12477        if (typeof get !== 'undefined') {
12478            return get;
12479        } else {
12480            return element;
12481        }
12482    };
12483
12484
12485    AdobeFileUploader.prototype.defaults = function (options,value)  {
12486        var propertyObject = {};
12487        if(typeof options == 'object') {
12488            propertyObject._fileIframeName = options._fileIframeName;
12489            propertyObject._filePath = options._filePath;
12490            propertyObject.actionUrl = options.actionUrl;
12491            propertyObject._getUrl = options._getUrl;
12492        }
12493        if(typeof  value == 'object') {
12494            propertyObject._fileIframeName = value._fileIframeName;
12495            propertyObject._filePath = value._filePath;
12496            propertyObject.actionUrl = value.actionUrl;
12497            propertyObject._getUrl = options._getUrl;
12498        }
12499        return {
12500            'fileUploadPath': propertyObject._filePath || AdobeFileUploader.prototype._filePath,
12501            'iframeName': AdobeFileUploader.prototype._fileIframeName + new Date().valueOf(),
12502            'fileUploadServlet': propertyObject._filePath || AdobeFileUploader.prototype._filePath,
vendor: 4,462 bytes, lines 12503-12656
12503            'iframeContainer': propertyObject._iframeContainer || AdobeFileUploader.prototype._iframeContainer,
12504            '_getUrl': propertyObject._getUrl || ""
12505        };
12506    };
12507
12508})($, window._);
12509
12510/*!
12511 * Bootstrap v3.4.1 (https://getbootstrap.com/)
12512 * Copyright 2011-2019 Twitter, Inc.
12513 * Licensed under the MIT license
12514 */
12515
12516if (typeof jQuery === 'undefined') {
12517  throw new Error('Bootstrap\'s JavaScript requires jQuery')
12518}
12519
12520+function ($) {
12521  'use strict';
12522  var version = $.fn.jquery.split(' ')[0].split('.')
12523  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
12524    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
12525  }
12526}(jQuery);
12527
12528/* ========================================================================
12529 * Bootstrap: transition.js v3.4.1
12530 * https://getbootstrap.com/docs/3.4/javascript/#transitions
12531 * ========================================================================
12532 * Copyright 2011-2019 Twitter, Inc.
12533 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12534 * ======================================================================== */
12535
12536
12537+function ($) {
12538  'use strict';
12539
12540  // CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
12541  // ============================================================
12542
12543  function transitionEnd() {
12544    var el = document.createElement('bootstrap')
12545
12546    var transEndEventNames = {
12547      WebkitTransition : 'webkitTransitionEnd',
12548      MozTransition    : 'transitionend',
12549      OTransition      : 'oTransitionEnd otransitionend',
12550      transition       : 'transitionend'
12551    }
12552
12553    for (var name in transEndEventNames) {
12554      if (el.style[name] !== undefined) {
12555        return { end: transEndEventNames[name] }
12556      }
12557    }
12558
12559    return false // explicit for ie8 (  ._.)
12560  }
12561
12562  // https://blog.alexmaccaw.com/css-transitions
12563  $.fn.emulateTransitionEnd = function (duration) {
12564    var called = false
12565    var $el = this
12566    $(this).one('bsTransitionEnd', function () { called = true })
12567    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
12568    setTimeout(callback, duration)
12569    return this
12570  }
12571
12572  $(function () {
12573    $.support.transition = transitionEnd()
12574
12575    if (!$.support.transition) return
12576
12577    $.event.special.bsTransitionEnd = {
12578      bindType: $.support.transition.end,
12579      delegateType: $.support.transition.end,
12580      handle: function (e) {
12581        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
12582      }
12583    }
12584  })
12585
12586}(jQuery);
12587
12588/* ========================================================================
12589 * Bootstrap: alert.js v3.4.1
12590 * https://getbootstrap.com/docs/3.4/javascript/#alerts
12591 * ========================================================================
12592 * Copyright 2011-2019 Twitter, Inc.
12593 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12594 * ======================================================================== */
12595
12596
12597+function ($) {
12598  'use strict';
12599
12600  // ALERT CLASS DEFINITION
12601  // ======================
12602
12603  var dismiss = '[data-dismiss="alert"]'
12604  var Alert   = function (el) {
12605    $(el).on('click', dismiss, this.close)
12606  }
12607
12608  Alert.VERSION = '3.4.1'
12609
12610  Alert.TRANSITION_DURATION = 150
12611
12612  Alert.prototype.close = function (e) {
12613    var $this    = $(this)
12614    var selector = $this.attr('data-target')
12615
12616    if (!selector) {
12617      selector = $this.attr('href')
12618      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
12619    }
12620
12621    selector    = selector === '#' ? [] : selector
12622    var $parent = $(document).find(selector)
12623
12624    if (e) e.preventDefault()
12625
12626    if (!$parent.length) {
12627      $parent = $this.closest('.alert')
12628    }
12629
12630    $parent.trigger(e = $.Event('close.bs.alert'))
12631
12632    if (e.isDefaultPrevented()) return
12633
12634    $parent.removeClass('in')
12635
12636    function removeElement() {
12637      // detach from parent, fire event then clean up data
12638      $parent.detach().trigger('closed.bs.alert').remove()
12639    }
12640
12641    $.support.transition && $parent.hasClass('fade') ?
12642        $parent
12643            .one('bsTransitionEnd', removeElement)
12644            .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
12645        removeElement()
12646  }
12647
12648
12649  // ALERT PLUGIN DEFINITION
12650  // =======================
12651
12652  function Plugin(option) {
12653    return this.each(function () {
12654      var $this = $(this)
12655      var data  = $this.data('bs.alert')
12656
vendor: 59,455 bytes, lines 12657-14643
12657      if (!data) $this.data('bs.alert', (data = new Alert(this)))
12658      if (typeof option == 'string') data[option].call($this)
12659    })
12660  }
12661
12662  var old = $.fn.alert
12663
12664  $.fn.alert             = Plugin
12665  $.fn.alert.Constructor = Alert
12666
12667
12668  // ALERT NO CONFLICT
12669  // =================
12670
12671  $.fn.alert.noConflict = function () {
12672    $.fn.alert = old
12673    return this
12674  }
12675
12676
12677  // ALERT DATA-API
12678  // ==============
12679
12680  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
12681
12682}(jQuery);
12683
12684/* ========================================================================
12685 * Bootstrap: button.js v3.4.1
12686 * https://getbootstrap.com/docs/3.4/javascript/#buttons
12687 * ========================================================================
12688 * Copyright 2011-2019 Twitter, Inc.
12689 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12690 * ======================================================================== */
12691
12692
12693+function ($) {
12694  'use strict';
12695
12696  // BUTTON PUBLIC CLASS DEFINITION
12697  // ==============================
12698
12699  var Button = function (element, options) {
12700    this.$element  = $(element)
12701    this.options   = $.extend({}, Button.DEFAULTS, options)
12702    this.isLoading = false
12703  }
12704
12705  Button.VERSION  = '3.4.1'
12706
12707  Button.DEFAULTS = {
12708    loadingText: 'loading...'
12709  }
12710
12711  Button.prototype.setState = function (state) {
12712    var d    = 'disabled'
12713    var $el  = this.$element
12714    var val  = $el.is('input') ? 'val' : 'html'
12715    var data = $el.data()
12716
12717    state += 'Text'
12718
12719    if (data.resetText == null) $el.data('resetText', $el[val]())
12720
12721    // push to event loop to allow forms to submit
12722    setTimeout($.proxy(function () {
12723      $el[val](data[state] == null ? this.options[state] : data[state])
12724
12725      if (state == 'loadingText') {
12726        this.isLoading = true
12727        $el.addClass(d).attr(d, d).prop(d, true)
12728      } else if (this.isLoading) {
12729        this.isLoading = false
12730        $el.removeClass(d).removeAttr(d).prop(d, false)
12731      }
12732    }, this), 0)
12733  }
12734
12735  Button.prototype.toggle = function () {
12736    var changed = true
12737    var $parent = this.$element.closest('[data-toggle="buttons"]')
12738
12739    if ($parent.length) {
12740      var $input = this.$element.find('input')
12741      if ($input.prop('type') == 'radio') {
12742        if ($input.prop('checked')) changed = false
12743        $parent.find('.active').removeClass('active')
12744        this.$element.addClass('active')
12745      } else if ($input.prop('type') == 'checkbox') {
12746        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
12747        this.$element.toggleClass('active')
12748      }
12749      $input.prop('checked', this.$element.hasClass('active'))
12750      if (changed) $input.trigger('change')
12751    } else {
12752      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
12753      this.$element.toggleClass('active')
12754    }
12755  }
12756
12757
12758  // BUTTON PLUGIN DEFINITION
12759  // ========================
12760
12761  function Plugin(option) {
12762    return this.each(function () {
12763      var $this   = $(this)
12764      var data    = $this.data('bs.button')
12765      var options = typeof option == 'object' && option
12766
12767      if (!data) $this.data('bs.button', (data = new Button(this, options)))
12768
12769      if (option == 'toggle') data.toggle()
12770      else if (option) data.setState(option)
12771    })
12772  }
12773
12774  var old = $.fn.button
12775
12776  $.fn.button             = Plugin
12777  $.fn.button.Constructor = Button
12778
12779
12780  // BUTTON NO CONFLICT
12781  // ==================
12782
12783  $.fn.button.noConflict = function () {
12784    $.fn.button = old
12785    return this
12786  }
12787
12788
12789  // BUTTON DATA-API
12790  // ===============
12791
12792  $(document)
12793      .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
12794        var $btn = $(e.target).closest('.btn')
12795        Plugin.call($btn, 'toggle')
12796        if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
12797          // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
12798          e.preventDefault()
12799          // The target component still receive the focus
12800          if ($btn.is('input,button')) $btn.trigger('focus')
12801          else $btn.find('input:visible,button:visible').first().trigger('focus')
12802        }
12803      })
12804      .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
12805        $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
12806      })
12807
12808}(jQuery);
12809
12810/* ========================================================================
12811 * Bootstrap: carousel.js v3.4.1
12812 * https://getbootstrap.com/docs/3.4/javascript/#carousel
12813 * ========================================================================
12814 * Copyright 2011-2019 Twitter, Inc.
12815 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12816 * ======================================================================== */
12817
12818
12819+function ($) {
12820  'use strict';
12821
12822  // CAROUSEL CLASS DEFINITION
12823  // =========================
12824
12825  var Carousel = function (element, options) {
12826    this.$element    = $(element)
12827    this.$indicators = this.$element.find('.carousel-indicators')
12828    this.options     = options
12829    this.paused      = null
12830    this.sliding     = null
12831    this.interval    = null
12832    this.$active     = null
12833    this.$items      = null
12834
12835    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
12836
12837    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
12838        .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
12839        .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
12840  }
12841
12842  Carousel.VERSION  = '3.4.1'
12843
12844  Carousel.TRANSITION_DURATION = 600
12845
12846  Carousel.DEFAULTS = {
12847    interval: 5000,
12848    pause: 'hover',
12849    wrap: true,
12850    keyboard: true
12851  }
12852
12853  Carousel.prototype.keydown = function (e) {
12854    if (/input|textarea/i.test(e.target.tagName)) return
12855    switch (e.which) {
12856      case 37: this.prev(); break
12857      case 39: this.next(); break
12858      default: return
12859    }
12860
12861    e.preventDefault()
12862  }
12863
12864  Carousel.prototype.cycle = function (e) {
12865    e || (this.paused = false)
12866
12867    this.interval && clearInterval(this.interval)
12868
12869    this.options.interval
12870    && !this.paused
12871    && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
12872
12873    return this
12874  }
12875
12876  Carousel.prototype.getItemIndex = function (item) {
12877    this.$items = item.parent().children('.item')
12878    return this.$items.index(item || this.$active)
12879  }
12880
12881  Carousel.prototype.getItemForDirection = function (direction, active) {
12882    var activeIndex = this.getItemIndex(active)
12883    var willWrap = (direction == 'prev' && activeIndex === 0)
12884        || (direction == 'next' && activeIndex == (this.$items.length - 1))
12885    if (willWrap && !this.options.wrap) return active
12886    var delta = direction == 'prev' ? -1 : 1
12887    var itemIndex = (activeIndex + delta) % this.$items.length
12888    return this.$items.eq(itemIndex)
12889  }
12890
12891  Carousel.prototype.to = function (pos) {
12892    var that        = this
12893    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
12894
12895    if (pos > (this.$items.length - 1) || pos < 0) return
12896
12897    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
12898    if (activeIndex == pos) return this.pause().cycle()
12899
12900    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
12901  }
12902
12903  Carousel.prototype.pause = function (e) {
12904    e || (this.paused = true)
12905
12906    if (this.$element.find('.next, .prev').length && $.support.transition) {
12907      this.$element.trigger($.support.transition.end)
12908      this.cycle(true)
12909    }
12910
12911    this.interval = clearInterval(this.interval)
12912
12913    return this
12914  }
12915
12916  Carousel.prototype.next = function () {
12917    if (this.sliding) return
12918    return this.slide('next')
12919  }
12920
12921  Carousel.prototype.prev = function () {
12922    if (this.sliding) return
12923    return this.slide('prev')
12924  }
12925
12926  Carousel.prototype.slide = function (type, next) {
12927    var $active   = this.$element.find('.item.active')
12928    var $next     = next || this.getItemForDirection(type, $active)
12929    var isCycling = this.interval
12930    var direction = type == 'next' ? 'left' : 'right'
12931    var that      = this
12932
12933    if ($next.hasClass('active')) return (this.sliding = false)
12934
12935    var relatedTarget = $next[0]
12936    var slideEvent = $.Event('slide.bs.carousel', {
12937      relatedTarget: relatedTarget,
12938      direction: direction
12939    })
12940    this.$element.trigger(slideEvent)
12941    if (slideEvent.isDefaultPrevented()) return
12942
12943    this.sliding = true
12944
12945    isCycling && this.pause()
12946
12947    if (this.$indicators.length) {
12948      this.$indicators.find('.active').removeClass('active')
12949      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
12950      $nextIndicator && $nextIndicator.addClass('active')
12951    }
12952
12953    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
12954    if ($.support.transition && this.$element.hasClass('slide')) {
12955      $next.addClass(type)
12956      if (typeof $next === 'object' && $next.length) {
12957        $next[0].offsetWidth // force reflow
12958      }
12959      $active.addClass(direction)
12960      $next.addClass(direction)
12961      $active
12962          .one('bsTransitionEnd', function () {
12963            $next.removeClass([type, direction].join(' ')).addClass('active')
12964            $active.removeClass(['active', direction].join(' '))
12965            that.sliding = false
12966            setTimeout(function () {
12967              that.$element.trigger(slidEvent)
12968            }, 0)
12969          })
12970          .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
12971    } else {
12972      $active.removeClass('active')
12973      $next.addClass('active')
12974      this.sliding = false
12975      this.$element.trigger(slidEvent)
12976    }
12977
12978    isCycling && this.cycle()
12979
12980    return this
12981  }
12982
12983
12984  // CAROUSEL PLUGIN DEFINITION
12985  // ==========================
12986
12987  function Plugin(option) {
12988    return this.each(function () {
12989      var $this   = $(this)
12990      var data    = $this.data('bs.carousel')
12991      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
12992      var action  = typeof option == 'string' ? option : options.slide
12993
12994      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
12995      if (typeof option == 'number') data.to(option)
12996      else if (action) data[action]()
12997      else if (options.interval) data.pause().cycle()
12998    })
12999  }
13000
13001  var old = $.fn.carousel
13002
13003  $.fn.carousel             = Plugin
13004  $.fn.carousel.Constructor = Carousel
13005
13006
13007  // CAROUSEL NO CONFLICT
13008  // ====================
13009
13010  $.fn.carousel.noConflict = function () {
13011    $.fn.carousel = old
13012    return this
13013  }
13014
13015
13016  // CAROUSEL DATA-API
13017  // =================
13018
13019  var clickHandler = function (e) {
13020    var $this   = $(this)
13021    var href    = $this.attr('href')
13022    if (href) {
13023      href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
13024    }
13025
13026    var target  = $this.attr('data-target') || href
13027    var $target = $(document).find(target)
13028
13029    if (!$target.hasClass('carousel')) return
13030
13031    var options = $.extend({}, $target.data(), $this.data())
13032    var slideIndex = $this.attr('data-slide-to')
13033    if (slideIndex) options.interval = false
13034
13035    Plugin.call($target, options)
13036
13037    if (slideIndex) {
13038      $target.data('bs.carousel').to(slideIndex)
13039    }
13040
13041    e.preventDefault()
13042  }
13043
13044  $(document)
13045      .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
13046      .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
13047
13048  $(window).on('load', function () {
13049    $('[data-ride="carousel"]').each(function () {
13050      var $carousel = $(this)
13051      Plugin.call($carousel, $carousel.data())
13052    })
13053  })
13054
13055}(jQuery);
13056
13057/* ========================================================================
13058 * Bootstrap: collapse.js v3.4.1
13059 * https://getbootstrap.com/docs/3.4/javascript/#collapse
13060 * ========================================================================
13061 * Copyright 2011-2019 Twitter, Inc.
13062 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13063 * ======================================================================== */
13064
13065/* jshint latedef: false */
13066
13067+function ($) {
13068  'use strict';
13069
13070  // COLLAPSE PUBLIC CLASS DEFINITION
13071  // ================================
13072
13073  var Collapse = function (element, options) {
13074    this.$element      = $(element)
13075    this.options       = $.extend({}, Collapse.DEFAULTS, options)
13076    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
13077        '[data-toggle="collapse"][data-target="#' + element.id + '"]')
13078    this.transitioning = null
13079
13080    if (this.options.parent) {
13081      this.$parent = this.getParent()
13082    } else {
13083      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
13084    }
13085
13086    if (this.options.toggle) this.toggle()
13087  }
13088
13089  Collapse.VERSION  = '3.4.1'
13090
13091  Collapse.TRANSITION_DURATION = 350
13092
13093  Collapse.DEFAULTS = {
13094    toggle: true
13095  }
13096
13097  Collapse.prototype.dimension = function () {
13098    var hasWidth = this.$element.hasClass('width')
13099    return hasWidth ? 'width' : 'height'
13100  }
13101
13102  Collapse.prototype.show = function () {
13103    if (this.transitioning || this.$element.hasClass('in')) return
13104
13105    var activesData
13106    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
13107
13108    if (actives && actives.length) {
13109      activesData = actives.data('bs.collapse')
13110      if (activesData && activesData.transitioning) return
13111    }
13112
13113    var startEvent = $.Event('show.bs.collapse')
13114    this.$element.trigger(startEvent)
13115    if (startEvent.isDefaultPrevented()) return
13116
13117    if (actives && actives.length) {
13118      Plugin.call(actives, 'hide')
13119      activesData || actives.data('bs.collapse', null)
13120    }
13121
13122    var dimension = this.dimension()
13123
13124    this.$element
13125        .removeClass('collapse')
13126        .addClass('collapsing')[dimension](0)
13127        .attr('aria-expanded', true)
13128
13129    this.$trigger
13130        .removeClass('collapsed')
13131        .attr('aria-expanded', true)
13132
13133    this.transitioning = 1
13134
13135    var complete = function () {
13136      this.$element
13137          .removeClass('collapsing')
13138          .addClass('collapse in')[dimension]('')
13139      this.transitioning = 0
13140      this.$element
13141          .trigger('shown.bs.collapse')
13142    }
13143
13144    if (!$.support.transition) return complete.call(this)
13145
13146    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
13147
13148    this.$element
13149        .one('bsTransitionEnd', $.proxy(complete, this))
13150        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
13151  }
13152
13153  Collapse.prototype.hide = function () {
13154    if (this.transitioning || !this.$element.hasClass('in')) return
13155
13156    var startEvent = $.Event('hide.bs.collapse')
13157    this.$element.trigger(startEvent)
13158    if (startEvent.isDefaultPrevented()) return
13159
13160    var dimension = this.dimension()
13161
13162    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
13163
13164    this.$element
13165        .addClass('collapsing')
13166        .removeClass('collapse in')
13167        .attr('aria-expanded', false)
13168
13169    this.$trigger
13170        .addClass('collapsed')
13171        .attr('aria-expanded', false)
13172
13173    this.transitioning = 1
13174
13175    var complete = function () {
13176      this.transitioning = 0
13177      this.$element
13178          .removeClass('collapsing')
13179          .addClass('collapse')
13180          .trigger('hidden.bs.collapse')
13181    }
13182
13183    if (!$.support.transition) return complete.call(this)
13184
13185    this.$element
13186        [dimension](0)
13187        .one('bsTransitionEnd', $.proxy(complete, this))
13188        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
13189  }
13190
13191  Collapse.prototype.toggle = function () {
13192    this[this.$element.hasClass('in') ? 'hide' : 'show']()
13193  }
13194
13195  Collapse.prototype.getParent = function () {
13196    return $(document).find(this.options.parent)
13197        .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
13198        .each($.proxy(function (i, element) {
13199          var $element = $(element)
13200          this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
13201        }, this))
13202        .end()
13203  }
13204
13205  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
13206    var isOpen = $element.hasClass('in')
13207
13208    $element.attr('aria-expanded', isOpen)
13209    $trigger
13210        .toggleClass('collapsed', !isOpen)
13211        .attr('aria-expanded', isOpen)
13212  }
13213
13214  function getTargetFromTrigger($trigger) {
13215    var href
13216    var target = $trigger.attr('data-target')
13217        || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
13218
13219    return $(document).find(target)
13220  }
13221
13222
13223  // COLLAPSE PLUGIN DEFINITION
13224  // ==========================
13225
13226  function Plugin(option) {
13227    return this.each(function () {
13228      var $this   = $(this)
13229      var data    = $this.data('bs.collapse')
13230      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
13231
13232      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
13233      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
13234      if (typeof option == 'string') data[option]()
13235    })
13236  }
13237
13238  var old = $.fn.collapse
13239
13240  $.fn.collapse             = Plugin
13241  $.fn.collapse.Constructor = Collapse
13242
13243
13244  // COLLAPSE NO CONFLICT
13245  // ====================
13246
13247  $.fn.collapse.noConflict = function () {
13248    $.fn.collapse = old
13249    return this
13250  }
13251
13252
13253  // COLLAPSE DATA-API
13254  // =================
13255
13256  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
13257    var $this   = $(this)
13258
13259    if (!$this.attr('data-target')) e.preventDefault()
13260
13261    var $target = getTargetFromTrigger($this)
13262    var data    = $target.data('bs.collapse')
13263    var option  = data ? 'toggle' : $this.data()
13264
13265    Plugin.call($target, option)
13266  })
13267
13268}(jQuery);
13269
13270/* ========================================================================
13271 * Bootstrap: dropdown.js v3.4.1
13272 * https://getbootstrap.com/docs/3.4/javascript/#dropdowns
13273 * ========================================================================
13274 * Copyright 2011-2019 Twitter, Inc.
13275 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13276 * ======================================================================== */
13277
13278
13279+function ($) {
13280  'use strict';
13281
13282  // DROPDOWN CLASS DEFINITION
13283  // =========================
13284
13285  var backdrop = '.dropdown-backdrop'
13286  var toggle   = '[data-toggle="dropdown"]'
13287  var Dropdown = function (element) {
13288    $(element).on('click.bs.dropdown', this.toggle)
13289  }
13290
13291  Dropdown.VERSION = '3.4.1'
13292
13293  function getParent($this) {
13294    var selector = $this.attr('data-target')
13295
13296    if (!selector) {
13297      selector = $this.attr('href')
13298      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
13299    }
13300
13301    var $parent = selector !== '#' ? $(document).find(selector) : null
13302
13303    return $parent && $parent.length ? $parent : $this.parent()
13304  }
13305
13306  function clearMenus(e) {
13307    if (e && e.which === 3) return
13308    $(backdrop).remove()
13309    $(toggle).each(function () {
13310      var $this         = $(this)
13311      var $parent       = getParent($this)
13312      var relatedTarget = { relatedTarget: this }
13313
13314      if (!$parent.hasClass('open')) return
13315
13316      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
13317
13318      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
13319
13320      if (e.isDefaultPrevented()) return
13321
13322      $this.attr('aria-expanded', 'false')
13323      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
13324    })
13325  }
13326
13327  Dropdown.prototype.toggle = function (e) {
13328    var $this = $(this)
13329
13330    if ($this.is('.disabled, :disabled')) return
13331
13332    var $parent  = getParent($this)
13333    var isActive = $parent.hasClass('open')
13334
13335    clearMenus()
13336
13337    if (!isActive) {
13338      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
13339        // if mobile we use a backdrop because click events don't delegate
13340        $(document.createElement('div'))
13341            .addClass('dropdown-backdrop')
13342            .insertAfter($(this))
13343            .on('click', clearMenus)
13344      }
13345
13346      var relatedTarget = { relatedTarget: this }
13347      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
13348
13349      if (e.isDefaultPrevented()) return
13350
13351      $this
13352          .trigger('focus')
13353          .attr('aria-expanded', 'true')
13354
13355      $parent
13356          .toggleClass('open')
13357          .trigger($.Event('shown.bs.dropdown', relatedTarget))
13358    }
13359
13360    return false
13361  }
13362
13363  Dropdown.prototype.keydown = function (e) {
13364    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
13365
13366    var $this = $(this)
13367
13368    e.preventDefault()
13369    e.stopPropagation()
13370
13371    if ($this.is('.disabled, :disabled')) return
13372
13373    var $parent  = getParent($this)
13374    var isActive = $parent.hasClass('open')
13375
13376    if (!isActive && e.which != 27 || isActive && e.which == 27) {
13377      if (e.which == 27) $parent.find(toggle).trigger('focus')
13378      return $this.trigger('click')
13379    }
13380
13381    var desc = ' li:not(.disabled):visible a'
13382    var $items = $parent.find('.dropdown-menu' + desc)
13383
13384    if (!$items.length) return
13385
13386    var index = $items.index(e.target)
13387
13388    if (e.which == 38 && index > 0)                 index--         // up
13389    if (e.which == 40 && index < $items.length - 1) index++         // down
13390    if (!~index)                                    index = 0
13391
13392    $items.eq(index).trigger('focus')
13393  }
13394
13395
13396  // DROPDOWN PLUGIN DEFINITION
13397  // ==========================
13398
13399  function Plugin(option) {
13400    return this.each(function () {
13401      var $this = $(this)
13402      var data  = $this.data('bs.dropdown')
13403
13404      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
13405      if (typeof option == 'string') data[option].call($this)
13406    })
13407  }
13408
13409  var old = $.fn.dropdown
13410
13411  $.fn.dropdown             = Plugin
13412  $.fn.dropdown.Constructor = Dropdown
13413
13414
13415  // DROPDOWN NO CONFLICT
13416  // ====================
13417
13418  $.fn.dropdown.noConflict = function () {
13419    $.fn.dropdown = old
13420    return this
13421  }
13422
13423
13424  // APPLY TO STANDARD DROPDOWN ELEMENTS
13425  // ===================================
13426
13427  $(document)
13428      .on('click.bs.dropdown.data-api', clearMenus)
13429      .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
13430      .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
13431      .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
13432      .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
13433
13434}(jQuery);
13435
13436/* ========================================================================
13437 * Bootstrap: modal.js v3.4.1
13438 * https://getbootstrap.com/docs/3.4/javascript/#modals
13439 * ========================================================================
13440 * Copyright 2011-2019 Twitter, Inc.
13441 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13442 * ======================================================================== */
13443
13444
13445+function ($) {
13446  'use strict';
13447
13448  // MODAL CLASS DEFINITION
13449  // ======================
13450
13451  var Modal = function (element, options) {
13452    this.options = options
13453    this.$body = $(document.body)
13454    this.$element = $(element)
13455    this.$dialog = this.$element.find('.modal-dialog')
13456    this.$backdrop = null
13457    this.isShown = null
13458    this.originalBodyPad = null
13459    this.scrollbarWidth = 0
13460    this.ignoreBackdropClick = false
13461    this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
13462
13463    if (this.options.remote) {
13464      this.$element
13465          .find('.modal-content')
13466          .load(this.options.remote, $.proxy(function () {
13467            this.$element.trigger('loaded.bs.modal')
13468          }, this))
13469    }
13470  }
13471
13472  Modal.VERSION = '3.4.1'
13473
13474  Modal.TRANSITION_DURATION = 300
13475  Modal.BACKDROP_TRANSITION_DURATION = 150
13476
13477  Modal.DEFAULTS = {
13478    backdrop: true,
13479    keyboard: true,
13480    show: true
13481  }
13482
13483  Modal.prototype.toggle = function (_relatedTarget) {
13484    return this.isShown ? this.hide() : this.show(_relatedTarget)
13485  }
13486
13487  Modal.prototype.show = function (_relatedTarget) {
13488    var that = this
13489    var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
13490
13491    this.$element.trigger(e)
13492
13493    if (this.isShown || e.isDefaultPrevented()) return
13494
13495    this.isShown = true
13496
13497    this.checkScrollbar()
13498    this.setScrollbar()
13499    this.$body.addClass('modal-open')
13500
13501    this.escape()
13502    this.resize()
13503
13504    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
13505
13506    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
13507      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
13508        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
13509      })
13510    })
13511
13512    this.backdrop(function () {
13513      var transition = $.support.transition && that.$element.hasClass('fade')
13514
13515      if (!that.$element.parent().length) {
13516        that.$element.appendTo(that.$body) // don't move modals dom position
13517      }
13518
13519      that.$element
13520          .show()
13521          .scrollTop(0)
13522
13523      that.adjustDialog()
13524
13525      if (transition) {
13526        that.$element[0].offsetWidth // force reflow
13527      }
13528
13529      that.$element.addClass('in')
13530
13531      that.enforceFocus()
13532
13533      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
13534
13535      transition ?
13536          that.$dialog // wait for modal to slide in
13537              .one('bsTransitionEnd', function () {
13538                that.$element.trigger('focus').trigger(e)
13539              })
13540              .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
13541          that.$element.trigger('focus').trigger(e)
13542    })
13543  }
13544
13545  Modal.prototype.hide = function (e) {
13546    if (e) e.preventDefault()
13547
13548    e = $.Event('hide.bs.modal')
13549
13550    this.$element.trigger(e)
13551
13552    if (!this.isShown || e.isDefaultPrevented()) return
13553
13554    this.isShown = false
13555
13556    this.escape()
13557    this.resize()
13558
13559    $(document).off('focusin.bs.modal')
13560
13561    this.$element
13562        .removeClass('in')
13563        .off('click.dismiss.bs.modal')
13564        .off('mouseup.dismiss.bs.modal')
13565
13566    this.$dialog.off('mousedown.dismiss.bs.modal')
13567
13568    $.support.transition && this.$element.hasClass('fade') ?
13569        this.$element
13570            .one('bsTransitionEnd', $.proxy(this.hideModal, this))
13571            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
13572        this.hideModal()
13573  }
13574
13575  Modal.prototype.enforceFocus = function () {
13576    $(document)
13577        .off('focusin.bs.modal') // guard against infinite focus loop
13578        .on('focusin.bs.modal', $.proxy(function (e) {
13579          if (document !== e.target &&
13580              this.$element[0] !== e.target &&
13581              !this.$element.has(e.target).length) {
13582            this.$element.trigger('focus')
13583          }
13584        }, this))
13585  }
13586
13587  Modal.prototype.escape = function () {
13588    if (this.isShown && this.options.keyboard) {
13589      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
13590        e.which == 27 && this.hide()
13591      }, this))
13592    } else if (!this.isShown) {
13593      this.$element.off('keydown.dismiss.bs.modal')
13594    }
13595  }
13596
13597  Modal.prototype.resize = function () {
13598    if (this.isShown) {
13599      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
13600    } else {
13601      $(window).off('resize.bs.modal')
13602    }
13603  }
13604
13605  Modal.prototype.hideModal = function () {
13606    var that = this
13607    this.$element.hide()
13608    this.backdrop(function () {
13609      that.$body.removeClass('modal-open')
13610      that.resetAdjustments()
13611      that.resetScrollbar()
13612      that.$element.trigger('hidden.bs.modal')
13613    })
13614  }
13615
13616  Modal.prototype.removeBackdrop = function () {
13617    this.$backdrop && this.$backdrop.remove()
13618    this.$backdrop = null
13619  }
13620
13621  Modal.prototype.backdrop = function (callback) {
13622    var that = this
13623    var animate = this.$element.hasClass('fade') ? 'fade' : ''
13624
13625    if (this.isShown && this.options.backdrop) {
13626      var doAnimate = $.support.transition && animate
13627
13628      this.$backdrop = $(document.createElement('div'))
13629          .addClass('modal-backdrop ' + animate)
13630          .appendTo(this.$body)
13631
13632      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
13633        if (this.ignoreBackdropClick) {
13634          this.ignoreBackdropClick = false
13635          return
13636        }
13637        if (e.target !== e.currentTarget) return
13638        this.options.backdrop == 'static'
13639            ? this.$element[0].focus()
13640            : this.hide()
13641      }, this))
13642
13643      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
13644
13645      this.$backdrop.addClass('in')
13646
13647      if (!callback) return
13648
13649      doAnimate ?
13650          this.$backdrop
13651              .one('bsTransitionEnd', callback)
13652              .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
13653          callback()
13654
13655    } else if (!this.isShown && this.$backdrop) {
13656      this.$backdrop.removeClass('in')
13657
13658      var callbackRemove = function () {
13659        that.removeBackdrop()
13660        callback && callback()
13661      }
13662      $.support.transition && this.$element.hasClass('fade') ?
13663          this.$backdrop
13664              .one('bsTransitionEnd', callbackRemove)
13665              .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
13666          callbackRemove()
13667
13668    } else if (callback) {
13669      callback()
13670    }
13671  }
13672
13673  // these following methods are used to handle overflowing modals
13674
13675  Modal.prototype.handleUpdate = function () {
13676    this.adjustDialog()
13677  }
13678
13679  Modal.prototype.adjustDialog = function () {
13680    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
13681
13682    this.$element.css({
13683      paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
13684      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
13685    })
13686  }
13687
13688  Modal.prototype.resetAdjustments = function () {
13689    this.$element.css({
13690      paddingLeft: '',
13691      paddingRight: ''
13692    })
13693  }
13694
13695  Modal.prototype.checkScrollbar = function () {
13696    var fullWindowWidth = window.innerWidth
13697    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
13698      var documentElementRect = document.documentElement.getBoundingClientRect()
13699      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
13700    }
13701    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
13702    this.scrollbarWidth = this.measureScrollbar()
13703  }
13704
13705  Modal.prototype.setScrollbar = function () {
13706    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
13707    this.originalBodyPad = document.body.style.paddingRight || ''
13708    var scrollbarWidth = this.scrollbarWidth
13709    if (this.bodyIsOverflowing) {
13710      this.$body.css('padding-right', bodyPad + scrollbarWidth)
13711      $(this.fixedContent).each(function (index, element) {
13712        var actualPadding = element.style.paddingRight
13713        var calculatedPadding = $(element).css('padding-right')
13714        $(element)
13715            .data('padding-right', actualPadding)
13716            .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
13717      })
13718    }
13719  }
13720
13721  Modal.prototype.resetScrollbar = function () {
13722    this.$body.css('padding-right', this.originalBodyPad)
13723    $(this.fixedContent).each(function (index, element) {
13724      var padding = $(element).data('padding-right')
13725      $(element).removeData('padding-right')
13726      element.style.paddingRight = padding ? padding : ''
13727    })
13728  }
13729
13730  Modal.prototype.measureScrollbar = function () { // thx walsh
13731    var scrollDiv = document.createElement('div')
13732    scrollDiv.className = 'modal-scrollbar-measure'
13733    this.$body.append(scrollDiv)
13734    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
13735    this.$body[0].removeChild(scrollDiv)
13736    return scrollbarWidth
13737  }
13738
13739
13740  // MODAL PLUGIN DEFINITION
13741  // =======================
13742
13743  function Plugin(option, _relatedTarget) {
13744    return this.each(function () {
13745      var $this = $(this)
13746      var data = $this.data('bs.modal')
13747      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
13748
13749      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
13750      if (typeof option == 'string') data[option](_relatedTarget)
13751      else if (options.show) data.show(_relatedTarget)
13752    })
13753  }
13754
13755  var old = $.fn.modal
13756
13757  $.fn.modal = Plugin
13758  $.fn.modal.Constructor = Modal
13759
13760
13761  // MODAL NO CONFLICT
13762  // =================
13763
13764  $.fn.modal.noConflict = function () {
13765    $.fn.modal = old
13766    return this
13767  }
13768
13769
13770  // MODAL DATA-API
13771  // ==============
13772
13773  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
13774    var $this = $(this)
13775    var href = $this.attr('href')
13776    var target = $this.attr('data-target') ||
13777        (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
13778
13779    var $target = $(document).find(target)
13780    var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
13781
13782    if ($this.is('a')) e.preventDefault()
13783
13784    $target.one('show.bs.modal', function (showEvent) {
13785      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
13786      $target.one('hidden.bs.modal', function () {
13787        $this.is(':visible') && $this.trigger('focus')
13788      })
13789    })
13790    Plugin.call($target, option, this)
13791  })
13792
13793}(jQuery);
13794
13795/* ========================================================================
13796 * Bootstrap: tooltip.js v3.4.1
13797 * https://getbootstrap.com/docs/3.4/javascript/#tooltip
13798 * Inspired by the original jQuery.tipsy by Jason Frame
13799 * ========================================================================
13800 * Copyright 2011-2019 Twitter, Inc.
13801 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13802 * ======================================================================== */
13803
13804+function ($) {
13805  'use strict';
13806
13807  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
13808
13809  var uriAttrs = [
13810    'background',
13811    'cite',
13812    'href',
13813    'itemtype',
13814    'longdesc',
13815    'poster',
13816    'src',
13817    'xlink:href'
13818  ]
13819
13820  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
13821
13822  var DefaultWhitelist = {
13823    // Global attributes allowed on any supplied element below.
13824    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
13825    a: ['target', 'href', 'title', 'rel'],
13826    area: [],
13827    b: [],
13828    br: [],
13829    col: [],
13830    code: [],
13831    div: [],
13832    em: [],
13833    hr: [],
13834    h1: [],
13835    h2: [],
13836    h3: [],
13837    h4: [],
13838    h5: [],
13839    h6: [],
13840    i: [],
13841    img: ['src', 'alt', 'title', 'width', 'height'],
13842    li: [],
13843    ol: [],
13844    p: [],
13845    pre: [],
13846    s: [],
13847    small: [],
13848    span: [],
13849    sub: [],
13850    sup: [],
13851    strong: [],
13852    u: [],
13853    ul: []
13854  }
13855
13856  /**
13857   * A pattern that recognizes a commonly useful subset of URLs that are safe.
13858   *
13859   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
13860   */
13861  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
13862
13863  /**
13864   * A pattern that matches safe data URLs. Only matches image, video and audio types.
13865   *
13866   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
13867   */
13868  var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
13869
13870  function allowedAttribute(attr, allowedAttributeList) {
13871    var attrName = attr.nodeName.toLowerCase()
13872
13873    if ($.inArray(attrName, allowedAttributeList) !== -1) {
13874      if ($.inArray(attrName, uriAttrs) !== -1) {
13875        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
13876      }
13877
13878      return true
13879    }
13880
13881    var regExp = $(allowedAttributeList).filter(function (index, value) {
13882      return value instanceof RegExp
13883    })
13884
13885    // Check if a regular expression validates the attribute.
13886    for (var i = 0, l = regExp.length; i < l; i++) {
13887      if (attrName.match(regExp[i])) {
13888        return true
13889      }
13890    }
13891
13892    return false
13893  }
13894
13895  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
13896    if (unsafeHtml.length === 0) {
13897      return unsafeHtml
13898    }
13899
13900    if (sanitizeFn && typeof sanitizeFn === 'function') {
13901      return sanitizeFn(unsafeHtml)
13902    }
13903
13904    // IE 8 and below don't support createHTMLDocument
13905    if (!document.implementation || !document.implementation.createHTMLDocument) {
13906      return unsafeHtml
13907    }
13908
13909    var createdDocument = document.implementation.createHTMLDocument('sanitization')
13910    createdDocument.body.innerHTML = unsafeHtml
13911
13912    var whitelistKeys = $.map(whiteList, function (el, i) { return i })
13913    var elements = $(createdDocument.body).find('*')
13914
13915    for (var i = 0, len = elements.length; i < len; i++) {
13916      var el = elements[i]
13917      var elName = el.nodeName.toLowerCase()
13918
13919      if ($.inArray(elName, whitelistKeys) === -1) {
13920        el.parentNode.removeChild(el)
13921
13922        continue
13923      }
13924
13925      var attributeList = $.map(el.attributes, function (el) { return el })
13926      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
13927
13928      for (var j = 0, len2 = attributeList.length; j < len2; j++) {
13929        if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
13930          el.removeAttribute(attributeList[j].nodeName)
13931        }
13932      }
13933    }
13934
13935    return createdDocument.body.innerHTML
13936  }
13937
13938  // TOOLTIP PUBLIC CLASS DEFINITION
13939  // ===============================
13940
13941  var Tooltip = function (element, options) {
13942    this.type       = null
13943    this.options    = null
13944    this.enabled    = null
13945    this.timeout    = null
13946    this.hoverState = null
13947    this.$element   = null
13948    this.inState    = null
13949
13950    this.init('tooltip', element, options)
13951  }
13952
13953  Tooltip.VERSION  = '3.4.1'
13954
13955  Tooltip.TRANSITION_DURATION = 150
13956
13957  Tooltip.DEFAULTS = {
13958    animation: true,
13959    placement: 'top',
13960    selector: false,
13961    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
13962    trigger: 'hover focus',
13963    title: '',
13964    delay: 0,
13965    html: false,
13966    container: false,
13967    viewport: {
13968      selector: 'body',
13969      padding: 0
13970    },
13971    sanitize : true,
13972    sanitizeFn : null,
13973    whiteList : DefaultWhitelist
13974  }
13975
13976  Tooltip.prototype.init = function (type, element, options) {
13977    this.enabled   = true
13978    this.type      = type
13979    this.$element  = $(element)
13980    this.options   = this.getOptions(options)
13981    this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
13982    this.inState   = { click: false, hover: false, focus: false }
13983
13984    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
13985      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
13986    }
13987
13988    var triggers = this.options.trigger.split(' ')
13989
13990    for (var i = triggers.length; i--;) {
13991      var trigger = triggers[i]
13992
13993      if (trigger == 'click') {
13994        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
13995      } else if (trigger != 'manual') {
13996        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
13997        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13998
13999        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
14000        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
14001      }
14002    }
14003
14004    this.options.selector ?
14005        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
14006        this.fixTitle()
14007  }
14008
14009  Tooltip.prototype.getDefaults = function () {
14010    return Tooltip.DEFAULTS
14011  }
14012
14013  Tooltip.prototype.getOptions = function (options) {
14014    var dataAttributes = this.$element.data()
14015
14016    for (var dataAttr in dataAttributes) {
14017      if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
14018        delete dataAttributes[dataAttr]
14019      }
14020    }
14021
14022    options = $.extend({}, this.getDefaults(), dataAttributes, options)
14023
14024    if (options.delay && typeof options.delay == 'number') {
14025      options.delay = {
14026        show: options.delay,
14027        hide: options.delay
14028      }
14029    }
14030
14031    if (options.sanitize) {
14032      options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
14033    }
14034
14035    return options
14036  }
14037
14038  Tooltip.prototype.getDelegateOptions = function () {
14039    var options  = {}
14040    var defaults = this.getDefaults()
14041
14042    this._options && $.each(this._options, function (key, value) {
14043      if (defaults[key] != value) options[key] = value
14044    })
14045
14046    return options
14047  }
14048
14049  Tooltip.prototype.enter = function (obj) {
14050    var self = obj instanceof this.constructor ?
14051        obj : $(obj.currentTarget).data('bs.' + this.type)
14052
14053    if (!self) {
14054      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
14055      $(obj.currentTarget).data('bs.' + this.type, self)
14056    }
14057
14058    if (obj instanceof $.Event) {
14059      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
14060    }
14061
14062    if (self.tip().hasClass('in') || self.hoverState == 'in') {
14063      self.hoverState = 'in'
14064      return
14065    }
14066
14067    clearTimeout(self.timeout)
14068
14069    self.hoverState = 'in'
14070
14071    if (!self.options.delay || !self.options.delay.show) return self.show()
14072
14073    self.timeout = setTimeout(function () {
14074      if (self.hoverState == 'in') self.show()
14075    }, self.options.delay.show)
14076  }
14077
14078  Tooltip.prototype.isInStateTrue = function () {
14079    for (var key in this.inState) {
14080      if (this.inState[key]) return true
14081    }
14082
14083    return false
14084  }
14085
14086  Tooltip.prototype.leave = function (obj) {
14087    var self = obj instanceof this.constructor ?
14088        obj : $(obj.currentTarget).data('bs.' + this.type)
14089
14090    if (!self) {
14091      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
14092      $(obj.currentTarget).data('bs.' + this.type, self)
14093    }
14094
14095    if (obj instanceof $.Event) {
14096      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
14097    }
14098
14099    if (self.isInStateTrue()) return
14100
14101    clearTimeout(self.timeout)
14102
14103    self.hoverState = 'out'
14104
14105    if (!self.options.delay || !self.options.delay.hide) return self.hide()
14106
14107    self.timeout = setTimeout(function () {
14108      if (self.hoverState == 'out') self.hide()
14109    }, self.options.delay.hide)
14110  }
14111
14112  Tooltip.prototype.show = function () {
14113    var e = $.Event('show.bs.' + this.type)
14114
14115    if (this.hasContent() && this.enabled) {
14116      this.$element.trigger(e)
14117
14118      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
14119      if (e.isDefaultPrevented() || !inDom) return
14120      var that = this
14121
14122      var $tip = this.tip()
14123
14124      var tipId = this.getUID(this.type)
14125
14126      this.setContent()
14127      $tip.attr('id', tipId)
14128      this.$element.attr('aria-describedby', tipId)
14129
14130      if (this.options.animation) $tip.addClass('fade')
14131
14132      var placement = typeof this.options.placement == 'function' ?
14133          this.options.placement.call(this, $tip[0], this.$element[0]) :
14134          this.options.placement
14135
14136      var autoToken = /\s?auto?\s?/i
14137      var autoPlace = autoToken.test(placement)
14138      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
14139
14140      $tip
14141          .detach()
14142          .css({ top: 0, left: 0, display: 'block' })
14143          .addClass(placement)
14144          .data('bs.' + this.type, this)
14145
14146      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
14147      this.$element.trigger('inserted.bs.' + this.type)
14148
14149      var pos          = this.getPosition()
14150      var actualWidth  = $tip[0].offsetWidth
14151      var actualHeight = $tip[0].offsetHeight
14152
14153      if (autoPlace) {
14154        var orgPlacement = placement
14155        var viewportDim = this.getPosition(this.$viewport)
14156
14157        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
14158            placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
14159                placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
14160                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
14161                        placement
14162
14163        $tip
14164            .removeClass(orgPlacement)
14165            .addClass(placement)
14166      }
14167
14168      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
14169
14170      this.applyPlacement(calculatedOffset, placement)
14171
14172      var complete = function () {
14173        var prevHoverState = that.hoverState
14174        that.$element.trigger('shown.bs.' + that.type)
14175        that.hoverState = null
14176
14177        if (prevHoverState == 'out') that.leave(that)
14178      }
14179
14180      $.support.transition && this.$tip.hasClass('fade') ?
14181          $tip
14182              .one('bsTransitionEnd', complete)
14183              .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
14184          complete()
14185    }
14186  }
14187
14188  Tooltip.prototype.applyPlacement = function (offset, placement) {
14189    var $tip   = this.tip()
14190    var width  = $tip[0].offsetWidth
14191    var height = $tip[0].offsetHeight
14192
14193    // manually read margins because getBoundingClientRect includes difference
14194    var marginTop = parseInt($tip.css('margin-top'), 10)
14195    var marginLeft = parseInt($tip.css('margin-left'), 10)
14196
14197    // we must check for NaN for ie 8/9
14198    if (isNaN(marginTop))  marginTop  = 0
14199    if (isNaN(marginLeft)) marginLeft = 0
14200
14201    offset.top  += marginTop
14202    offset.left += marginLeft
14203
14204    // $.fn.offset doesn't round pixel values
14205    // so we use setOffset directly with our own function B-0
14206    $.offset.setOffset($tip[0], $.extend({
14207      using: function (props) {
14208        $tip.css({
14209          top: Math.round(props.top),
14210          left: Math.round(props.left)
14211        })
14212      }
14213    }, offset), 0)
14214
14215    $tip.addClass('in')
14216
14217    // check to see if placing tip in new offset caused the tip to resize itself
14218    var actualWidth  = $tip[0].offsetWidth
14219    var actualHeight = $tip[0].offsetHeight
14220
14221    if (placement == 'top' && actualHeight != height) {
14222      offset.top = offset.top + height - actualHeight
14223    }
14224
14225    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
14226
14227    if (delta.left) offset.left += delta.left
14228    else offset.top += delta.top
14229
14230    var isVertical          = /top|bottom/.test(placement)
14231    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
14232    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
14233
14234    $tip.offset(offset)
14235    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
14236  }
14237
14238  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
14239    this.arrow()
14240        .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
14241        .css(isVertical ? 'top' : 'left', '')
14242  }
14243
14244  Tooltip.prototype.setContent = function () {
14245    var $tip  = this.tip()
14246    var title = this.getTitle()
14247
14248    if (this.options.html) {
14249      if (this.options.sanitize) {
14250        title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
14251      }
14252
14253      $tip.find('.tooltip-inner').html(title)
14254    } else {
14255      $tip.find('.tooltip-inner').text(title)
14256    }
14257
14258    $tip.removeClass('fade in top bottom left right')
14259  }
14260
14261  Tooltip.prototype.hide = function (callback) {
14262    var that = this
14263    var $tip = $(this.$tip)
14264    var e    = $.Event('hide.bs.' + this.type)
14265
14266    function complete() {
14267      if (that.hoverState != 'in') $tip.detach()
14268      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
14269        that.$element
14270            .removeAttr('aria-describedby')
14271            .trigger('hidden.bs.' + that.type)
14272      }
14273      callback && callback()
14274    }
14275
14276    this.$element.trigger(e)
14277
14278    if (e.isDefaultPrevented()) return
14279
14280    $tip.removeClass('in')
14281
14282    $.support.transition && $tip.hasClass('fade') ?
14283        $tip
14284            .one('bsTransitionEnd', complete)
14285            .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
14286        complete()
14287
14288    this.hoverState = null
14289
14290    return this
14291  }
14292
14293  Tooltip.prototype.fixTitle = function () {
14294    var $e = this.$element
14295    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
14296      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
14297    }
14298  }
14299
14300  Tooltip.prototype.hasContent = function () {
14301    return this.getTitle()
14302  }
14303
14304  Tooltip.prototype.getPosition = function ($element) {
14305    $element   = $element || this.$element
14306
14307    var el     = $element[0]
14308    var isBody = el.tagName == 'BODY'
14309
14310    var elRect    = el.getBoundingClientRect()
14311    if (elRect.width == null) {
14312      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
14313      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
14314    }
14315    var isSvg = window.SVGElement && el instanceof window.SVGElement
14316    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
14317    // See https://github.com/twbs/bootstrap/issues/20280
14318    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
14319    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
14320    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
14321
14322    return $.extend({}, elRect, scroll, outerDims, elOffset)
14323  }
14324
14325  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
14326    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
14327        placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
14328            placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
14329                /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
14330
14331  }
14332
14333  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
14334    var delta = { top: 0, left: 0 }
14335    if (!this.$viewport) return delta
14336
14337    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
14338    var viewportDimensions = this.getPosition(this.$viewport)
14339
14340    if (/right|left/.test(placement)) {
14341      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
14342      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
14343      if (topEdgeOffset < viewportDimensions.top) { // top overflow
14344        delta.top = viewportDimensions.top - topEdgeOffset
14345      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
14346        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
14347      }
14348    } else {
14349      var leftEdgeOffset  = pos.left - viewportPadding
14350      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
14351      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
14352        delta.left = viewportDimensions.left - leftEdgeOffset
14353      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
14354        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
14355      }
14356    }
14357
14358    return delta
14359  }
14360
14361  Tooltip.prototype.getTitle = function () {
14362    var title
14363    var $e = this.$element
14364    var o  = this.options
14365
14366    title = $e.attr('data-original-title')
14367        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
14368
14369    return title
14370  }
14371
14372  Tooltip.prototype.getUID = function (prefix) {
14373    do prefix += ~~(Math.random() * 1000000)
14374    while (document.getElementById(prefix))
14375    return prefix
14376  }
14377
14378  Tooltip.prototype.tip = function () {
14379    if (!this.$tip) {
14380      this.$tip = $(this.options.template)
14381      if (this.$tip.length != 1) {
14382        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
14383      }
14384    }
14385    return this.$tip
14386  }
14387
14388  Tooltip.prototype.arrow = function () {
14389    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
14390  }
14391
14392  Tooltip.prototype.enable = function () {
14393    this.enabled = true
14394  }
14395
14396  Tooltip.prototype.disable = function () {
14397    this.enabled = false
14398  }
14399
14400  Tooltip.prototype.toggleEnabled = function () {
14401    this.enabled = !this.enabled
14402  }
14403
14404  Tooltip.prototype.toggle = function (e) {
14405    var self = this
14406    if (e) {
14407      self = $(e.currentTarget).data('bs.' + this.type)
14408      if (!self) {
14409        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
14410        $(e.currentTarget).data('bs.' + this.type, self)
14411      }
14412    }
14413
14414    if (e) {
14415      self.inState.click = !self.inState.click
14416      if (self.isInStateTrue()) self.enter(self)
14417      else self.leave(self)
14418    } else {
14419      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
14420    }
14421  }
14422
14423  Tooltip.prototype.destroy = function () {
14424    var that = this
14425    clearTimeout(this.timeout)
14426    this.hide(function () {
14427      that.$element.off('.' + that.type).removeData('bs.' + that.type)
14428      if (that.$tip) {
14429        that.$tip.detach()
14430      }
14431      that.$tip = null
14432      that.$arrow = null
14433      that.$viewport = null
14434      that.$element = null
14435    })
14436  }
14437
14438  Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
14439    return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
14440  }
14441
14442  // TOOLTIP PLUGIN DEFINITION
14443  // =========================
14444
14445  function Plugin(option) {
14446    return this.each(function () {
14447      var $this   = $(this)
14448      var data    = $this.data('bs.tooltip')
14449      var options = typeof option == 'object' && option
14450
14451      if (!data && /destroy|hide/.test(option)) return
14452      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
14453      if (typeof option == 'string') data[option]()
14454    })
14455  }
14456
14457  var old = $.fn.tooltip
14458
14459  $.fn.tooltip             = Plugin
14460  $.fn.tooltip.Constructor = Tooltip
14461
14462
14463  // TOOLTIP NO CONFLICT
14464  // ===================
14465
14466  $.fn.tooltip.noConflict = function () {
14467    $.fn.tooltip = old
14468    return this
14469  }
14470
14471}(jQuery);
14472
14473/* ========================================================================
14474 * Bootstrap: popover.js v3.4.1
14475 * https://getbootstrap.com/docs/3.4/javascript/#popovers
14476 * ========================================================================
14477 * Copyright 2011-2019 Twitter, Inc.
14478 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14479 * ======================================================================== */
14480
14481
14482+function ($) {
14483  'use strict';
14484
14485  // POPOVER PUBLIC CLASS DEFINITION
14486  // ===============================
14487
14488  var Popover = function (element, options) {
14489    this.init('popover', element, options)
14490  }
14491
14492  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
14493
14494  Popover.VERSION  = '3.4.1'
14495
14496  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
14497    placement: 'right',
14498    trigger: 'click',
14499    content: '',
14500    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
14501  })
14502
14503
14504  // NOTE: POPOVER EXTENDS tooltip.js
14505  // ================================
14506
14507  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
14508
14509  Popover.prototype.constructor = Popover
14510
14511  Popover.prototype.getDefaults = function () {
14512    return Popover.DEFAULTS
14513  }
14514
14515  Popover.prototype.setContent = function () {
14516    var $tip    = this.tip()
14517    var title   = this.getTitle()
14518    var content = this.getContent()
14519
14520    if (this.options.html) {
14521      var typeContent = typeof content
14522
14523      if (this.options.sanitize) {
14524        title = this.sanitizeHtml(title)
14525
14526        if (typeContent === 'string') {
14527          content = this.sanitizeHtml(content)
14528        }
14529      }
14530
14531      $tip.find('.popover-title').html(title)
14532      $tip.find('.popover-content').children().detach().end()[
14533          typeContent === 'string' ? 'html' : 'append'
14534          ](content)
14535    } else {
14536      $tip.find('.popover-title').text(title)
14537      $tip.find('.popover-content').children().detach().end().text(content)
14538    }
14539
14540    $tip.removeClass('fade top bottom left right in')
14541
14542    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
14543    // this manually by checking the contents.
14544    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
14545  }
14546
14547  Popover.prototype.hasContent = function () {
14548    return this.getTitle() || this.getContent()
14549  }
14550
14551  Popover.prototype.getContent = function () {
14552    var $e = this.$element
14553    var o  = this.options
14554
14555    return $e.attr('data-content')
14556        || (typeof o.content == 'function' ?
14557            o.content.call($e[0]) :
14558            o.content)
14559  }
14560
14561  Popover.prototype.arrow = function () {
14562    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
14563  }
14564
14565
14566  // POPOVER PLUGIN DEFINITION
14567  // =========================
14568
14569  function Plugin(option) {
14570    return this.each(function () {
14571      var $this   = $(this)
14572      var data    = $this.data('bs.popover')
14573      var options = typeof option == 'object' && option
14574
14575      if (!data && /destroy|hide/.test(option)) return
14576      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
14577      if (typeof option == 'string') data[option]()
14578    })
14579  }
14580
14581  var old = $.fn.popover
14582
14583  $.fn.popover             = Plugin
14584  $.fn.popover.Constructor = Popover
14585
14586
14587  // POPOVER NO CONFLICT
14588  // ===================
14589
14590  $.fn.popover.noConflict = function () {
14591    $.fn.popover = old
14592    return this
14593  }
14594
14595}(jQuery);
14596
14597/* ========================================================================
14598 * Bootstrap: scrollspy.js v3.4.1
14599 * https://getbootstrap.com/docs/3.4/javascript/#scrollspy
14600 * ========================================================================
14601 * Copyright 2011-2019 Twitter, Inc.
14602 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14603 * ======================================================================== */
14604
14605
14606+function ($) {
14607  'use strict';
14608
14609  // SCROLLSPY CLASS DEFINITION
14610  // ==========================
14611
14612  function ScrollSpy(element, options) {
14613    this.$body          = $(document.body)
14614    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
14615    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
14616    this.selector       = (this.options.target || '') + ' .nav li > a'
14617    this.offsets        = []
14618    this.targets        = []
14619    this.activeTarget   = null
14620    this.scrollHeight   = 0
14621
14622    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
14623    this.refresh()
14624    this.process()
14625  }
14626
14627  ScrollSpy.VERSION  = '3.4.1'
14628
14629  ScrollSpy.DEFAULTS = {
14630    offset: 10
14631  }
14632
14633  ScrollSpy.prototype.getScrollHeight = function () {
14634    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
14635  }
14636
14637  ScrollSpy.prototype.refresh = function () {
14638    var that          = this
14639    var offsetMethod  = 'offset'
14640    var offsetBase    = 0
14641
14642    this.offsets      = []
14643    this.targets      = []
vendor: 10,384 bytes, lines 14644-15013
14644    this.scrollHeight = this.getScrollHeight()
14645
14646    if (!$.isWindow(this.$scrollElement[0])) {
14647      offsetMethod = 'position'
14648      offsetBase   = this.$scrollElement.scrollTop()
14649    }
14650
14651    this.$body
14652        .find(this.selector)
14653        .map(function () {
14654          var $el   = $(this)
14655          var href  = $el.data('target') || $el.attr('href')
14656          var $href = /^#./.test(href) && $(href)
14657
14658          return ($href
14659              && $href.length
14660              && $href.is(':visible')
14661              && [[$href[offsetMethod]().top + offsetBase, href]]) || null
14662        })
14663        .sort(function (a, b) { return a[0] - b[0] })
14664        .each(function () {
14665          that.offsets.push(this[0])
14666          that.targets.push(this[1])
14667        })
14668  }
14669
14670  ScrollSpy.prototype.process = function () {
14671    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
14672    var scrollHeight = this.getScrollHeight()
14673    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
14674    var offsets      = this.offsets
14675    var targets      = this.targets
14676    var activeTarget = this.activeTarget
14677    var i
14678
14679    if (this.scrollHeight != scrollHeight) {
14680      this.refresh()
14681    }
14682
14683    if (scrollTop >= maxScroll) {
14684      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
14685    }
14686
14687    if (activeTarget && scrollTop < offsets[0]) {
14688      this.activeTarget = null
14689      return this.clear()
14690    }
14691
14692    for (i = offsets.length; i--;) {
14693      activeTarget != targets[i]
14694      && scrollTop >= offsets[i]
14695      && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
14696      && this.activate(targets[i])
14697    }
14698  }
14699
14700  ScrollSpy.prototype.activate = function (target) {
14701    this.activeTarget = target
14702
14703    this.clear()
14704
14705    var selector = this.selector +
14706        '[data-target="' + target + '"],' +
14707        this.selector + '[href="' + target + '"]'
14708
14709    var active = $(selector)
14710        .parents('li')
14711        .addClass('active')
14712
14713    if (active.parent('.dropdown-menu').length) {
14714      active = active
14715          .closest('li.dropdown')
14716          .addClass('active')
14717    }
14718
14719    active.trigger('activate.bs.scrollspy')
14720  }
14721
14722  ScrollSpy.prototype.clear = function () {
14723    $(this.selector)
14724        .parentsUntil(this.options.target, '.active')
14725        .removeClass('active')
14726  }
14727
14728
14729  // SCROLLSPY PLUGIN DEFINITION
14730  // ===========================
14731
14732  function Plugin(option) {
14733    return this.each(function () {
14734      var $this   = $(this)
14735      var data    = $this.data('bs.scrollspy')
14736      var options = typeof option == 'object' && option
14737
14738      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
14739      if (typeof option == 'string') data[option]()
14740    })
14741  }
14742
14743  var old = $.fn.scrollspy
14744
14745  $.fn.scrollspy             = Plugin
14746  $.fn.scrollspy.Constructor = ScrollSpy
14747
14748
14749  // SCROLLSPY NO CONFLICT
14750  // =====================
14751
14752  $.fn.scrollspy.noConflict = function () {
14753    $.fn.scrollspy = old
14754    return this
14755  }
14756
14757
14758  // SCROLLSPY DATA-API
14759  // ==================
14760
14761  $(window).on('load.bs.scrollspy.data-api', function () {
14762    $('[data-spy="scroll"]').each(function () {
14763      var $spy = $(this)
14764      Plugin.call($spy, $spy.data())
14765    })
14766  })
14767
14768}(jQuery);
14769
14770/* ========================================================================
14771 * Bootstrap: tab.js v3.4.1
14772 * https://getbootstrap.com/docs/3.4/javascript/#tabs
14773 * ========================================================================
14774 * Copyright 2011-2019 Twitter, Inc.
14775 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14776 * ======================================================================== */
14777
14778
14779+function ($) {
14780  'use strict';
14781
14782  // TAB CLASS DEFINITION
14783  // ====================
14784
14785  var Tab = function (element) {
14786    // jscs:disable requireDollarBeforejQueryAssignment
14787    this.element = $(element)
14788    // jscs:enable requireDollarBeforejQueryAssignment
14789  }
14790
14791  Tab.VERSION = '3.4.1'
14792
14793  Tab.TRANSITION_DURATION = 150
14794
14795  Tab.prototype.show = function () {
14796    var $this    = this.element
14797    var $ul      = $this.closest('ul:not(.dropdown-menu)')
14798    var selector = $this.data('target')
14799
14800    if (!selector) {
14801      selector = $this.attr('href')
14802      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
14803    }
14804
14805    if ($this.parent('li').hasClass('active')) return
14806
14807    var $previous = $ul.find('.active:last a')
14808    var hideEvent = $.Event('hide.bs.tab', {
14809      relatedTarget: $this[0]
14810    })
14811    var showEvent = $.Event('show.bs.tab', {
14812      relatedTarget: $previous[0]
14813    })
14814
14815    $previous.trigger(hideEvent)
14816    $this.trigger(showEvent)
14817
14818    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
14819
14820    var $target = $(document).find(selector)
14821
14822    this.activate($this.closest('li'), $ul)
14823    this.activate($target, $target.parent(), function () {
14824      $previous.trigger({
14825        type: 'hidden.bs.tab',
14826        relatedTarget: $this[0]
14827      })
14828      $this.trigger({
14829        type: 'shown.bs.tab',
14830        relatedTarget: $previous[0]
14831      })
14832    })
14833  }
14834
14835  Tab.prototype.activate = function (element, container, callback) {
14836    var $active    = container.find('> .active')
14837    var transition = callback
14838        && $.support.transition
14839        && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
14840
14841    function next() {
14842      $active
14843          .removeClass('active')
14844          .find('> .dropdown-menu > .active')
14845          .removeClass('active')
14846          .end()
14847          .find('[data-toggle="tab"]')
14848          .attr('aria-expanded', false)
14849
14850      element
14851          .addClass('active')
14852          .find('[data-toggle="tab"]')
14853          .attr('aria-expanded', true)
14854
14855      if (transition) {
14856        element[0].offsetWidth // reflow for transition
14857        element.addClass('in')
14858      } else {
14859        element.removeClass('fade')
14860      }
14861
14862      if (element.parent('.dropdown-menu').length) {
14863        element
14864            .closest('li.dropdown')
14865            .addClass('active')
14866            .end()
14867            .find('[data-toggle="tab"]')
14868            .attr('aria-expanded', true)
14869      }
14870
14871      callback && callback()
14872    }
14873
14874    $active.length && transition ?
14875        $active
14876            .one('bsTransitionEnd', next)
14877            .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
14878        next()
14879
14880    $active.removeClass('in')
14881  }
14882
14883
14884  // TAB PLUGIN DEFINITION
14885  // =====================
14886
14887  function Plugin(option) {
14888    return this.each(function () {
14889      var $this = $(this)
14890      var data  = $this.data('bs.tab')
14891
14892      if (!data) $this.data('bs.tab', (data = new Tab(this)))
14893      if (typeof option == 'string') data[option]()
14894    })
14895  }
14896
14897  var old = $.fn.tab
14898
14899  $.fn.tab             = Plugin
14900  $.fn.tab.Constructor = Tab
14901
14902
14903  // TAB NO CONFLICT
14904  // ===============
14905
14906  $.fn.tab.noConflict = function () {
14907    $.fn.tab = old
14908    return this
14909  }
14910
14911
14912  // TAB DATA-API
14913  // ============
14914
14915  var clickHandler = function (e) {
14916    e.preventDefault()
14917    Plugin.call($(this), 'show')
14918  }
14919
14920  $(document)
14921      .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
14922      .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
14923
14924}(jQuery);
14925
14926/* ========================================================================
14927 * Bootstrap: affix.js v3.4.1
14928 * https://getbootstrap.com/docs/3.4/javascript/#affix
14929 * ========================================================================
14930 * Copyright 2011-2019 Twitter, Inc.
14931 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14932 * ======================================================================== */
14933
14934
14935+function ($) {
14936  'use strict';
14937
14938  // AFFIX CLASS DEFINITION
14939  // ======================
14940
14941  var Affix = function (element, options) {
14942    this.options = $.extend({}, Affix.DEFAULTS, options)
14943
14944    var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
14945
14946    this.$target = target
14947        .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
14948        .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
14949
14950    this.$element     = $(element)
14951    this.affixed      = null
14952    this.unpin        = null
14953    this.pinnedOffset = null
14954
14955    this.checkPosition()
14956  }
14957
14958  Affix.VERSION  = '3.4.1'
14959
14960  Affix.RESET    = 'affix affix-top affix-bottom'
14961
14962  Affix.DEFAULTS = {
14963    offset: 0,
14964    target: window
14965  }
14966
14967  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
14968    var scrollTop    = this.$target.scrollTop()
14969    var position     = this.$element.offset()
14970    var targetHeight = this.$target.height()
14971
14972    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
14973
14974    if (this.affixed == 'bottom') {
14975      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
14976      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
14977    }
14978
14979    var initializing   = this.affixed == null
14980    var colliderTop    = initializing ? scrollTop : position.top
14981    var colliderHeight = initializing ? targetHeight : height
14982
14983    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
14984    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
14985
14986    return false
14987  }
14988
14989  Affix.prototype.getPinnedOffset = function () {
14990    if (this.pinnedOffset) return this.pinnedOffset
14991    this.$element.removeClass(Affix.RESET).addClass('affix')
14992    var scrollTop = this.$target.scrollTop()
14993    var position  = this.$element.offset()
14994    return (this.pinnedOffset = position.top - scrollTop)
14995  }
14996
14997  Affix.prototype.checkPositionWithEventLoop = function () {
14998    setTimeout($.proxy(this.checkPosition, this), 1)
14999  }
15000
15001  Affix.prototype.checkPosition = function () {
15002    if (!this.$element.is(':visible')) return
15003
15004    var height       = this.$element.height()
15005    var offset       = this.options.offset
15006    var offsetTop    = offset.top
15007    var offsetBottom = offset.bottom
15008    var scrollHeight = Math.max($(document).height(), $(document.body).height())
15009
15010    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
15011    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
15012    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
15013
15014    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
15015
15016    if (this.affixed != affix) {
15017      if (this.unpin != null) this.$element.css('top', '')
15018
15019      var affixType = 'affix' + (affix ? '-' + affix : '')
15020      var e         = $.Event(affixType + '.bs.affix')
15021
15022      this.$element.trigger(e)
15023
15024      if (e.isDefaultPrevented()) return
15025
15026      this.affixed = affix
15027      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
15028
15029      this.$element
15030          .removeClass(Affix.RESET)
15031          .addClass(affixType)
15032          .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
15033    }
15034
15035    if (affix == 'bottom') {
15036      this.$element.offset({
15037        top: scrollHeight - height - offsetBottom
15038      })
15039    }
15040  }
15041
15042
15043  // AFFIX PLUGIN DEFINITION
15044  // =======================
15045
15046  function Plugin(option) {
15047    return this.each(function () {
15048      var $this   = $(this)
15049      var data    = $this.data('bs.affix')
15050      var options = typeof option == 'object' && option
15051
15052      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
15053      if (typeof option == 'string') data[option]()
15054    })
15055  }
15056
15057  var old = $.fn.affix
15058
15059  $.fn.affix             = Plugin
15060  $.fn.affix.Constructor = Affix
15061
15062
15063  // AFFIX NO CONFLICT
15064  // =================
15065
15066  $.fn.affix.noConflict = function () {
15067    $.fn.affix = old
15068    return this
15069  }
15070
15071
15072  // AFFIX DATA-API
15073  // ==============
15074
15075  $(window).on('load', function () {
15076    $('[data-spy="affix"]').each(function () {
15077      var $spy = $(this)
15078      var data = $spy.data()
15079
15080      data.offset = data.offset || {}
15081
15082      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
15083      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
15084
15085      Plugin.call($spy, data)
15086    })
15087  })
15088
15089}(jQuery);
15090
15091/*
15092 * jQuery Templating Plugin
15093 * Copyright 2010, John Resig
15094 * Dual licensed under the MIT or GPL Version 2 licenses.
15095 */
15096(function( jQuery, undefined ){
15097    var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
15098        newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];
15099
15100    function newTmplItem( options, parentItem, fn, data ) {
15101        // Returns a template item data structure for a new rendered instance of a template (a 'template item').
15102        // The content field is a hierarchical array of strings and nested items (to be
15103        // removed and replaced by nodes field of dom elements, once inserted in DOM).
15104        var newItem = {
15105            data: data || (parentItem ? parentItem.data : {}),
15106            _wrap: parentItem ? parentItem._wrap : null,
15107            tmpl: null,
15108            parent: parentItem || null,
15109            nodes: [],
15110            calls: tiCalls,
15111            nest: tiNest,
15112            wrap: tiWrap,
15113            html: tiHtml,
15114            update: tiUpdate
15115        };
15116        if ( options ) {
15117            jQuery.extend( newItem, options, { nodes: [], parent: parentItem } );
15118        }
15119        if ( fn ) {
15120            // Build the hierarchical content to be used during insertion into DOM
15121            newItem.tmpl = fn;
15122            newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem );
15123            newItem.key = ++itemKey;
15124            // Keep track of new template item, until it is stored as jQuery Data on DOM element
15125            (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;
15126        }
15127        return newItem;
15128    }
15129
15130    // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core).
15131    jQuery.each({
15132        appendTo: "append",
15133        prependTo: "prepend",
15134        insertBefore: "before",
15135        insertAfter: "after",
15136        replaceAll: "replaceWith"
15137    }, function( name, original ) {
15138        jQuery.fn[ name ] = function( selector ) {
15139            var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems,
15140                parent = this.length === 1 && this[0].parentNode;
15141
15142            appendToTmplItems = newTmplItems || {};
15143            if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
15144                insert[ original ]( this[0] );
15145                ret = this;
15146            } else {
15147                for ( i = 0, l = insert.length; i < l; i++ ) {
15148                    cloneIndex = i;
15149                    elems = (i > 0 ? this.clone(true) : this).get();
15150                    jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
15151                    ret = ret.concat( elems );
15152                }
15153                cloneIndex = 0;
15154                ret = this.pushStack( ret, name, insert.selector );
15155            }
15156            tmplItems = appendToTmplItems;
15157            appendToTmplItems = null;
15158            jQuery.tmpl.complete( tmplItems );
15159            return ret;
15160        };
15161    });
15162
15163    jQuery.fn.extend({
15164        // Use first wrapped element as template markup.
15165        // Return wrapped set of template items, obtained by rendering template against data.
15166        tmpl: function( data, options, parentItem ) {
15167            return jQuery.tmpl( this[0], data, options, parentItem );
15168        },
15169
15170        // Find which rendered template item the first wrapped DOM element belongs to
15171        tmplItem: function() {
15172            return jQuery.tmplItem( this[0] );
15173        },
15174
15175        // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.
15176        template: function( name ) {
15177            return jQuery.template( name, this[0] );
15178        },
15179
15180        domManip: function( args, table, callback, options ) {
15181            // This appears to be a bug in the appendTo, etc. implementation
15182            // it should be doing .call() instead of .apply(). See #6227
15183            if ( args[0] && args[0].nodeType ) {
15184                var dmArgs = jQuery.makeArray( arguments ), argsLength = args.length, i = 0, tmplItem;
15185                while ( i < argsLength && !(tmplItem = jQuery.data( args[i++], "tmplItem" ))) {}
15186                if ( argsLength > 1 ) {
15187                    dmArgs[0] = [jQuery.makeArray( args )];
15188                }
15189                if ( tmplItem && cloneIndex ) {
15190                    dmArgs[2] = function( fragClone ) {
15191                        // Handler called by oldManip when rendered template has been inserted into DOM.
15192                        jQuery.tmpl.afterManip( this, fragClone, callback );
15193                    };
15194                }
15195                oldManip.apply( this, dmArgs );
15196            } else {
15197                oldManip.apply( this, arguments );
15198            }
15199            cloneIndex = 0;
15200            if ( !appendToTmplItems ) {
15201                jQuery.tmpl.complete( newTmplItems );
15202            }
15203            return this;
15204        }
15205    });
15206
15207    jQuery.extend({
15208        // Return wrapped set of template items, obtained by rendering template against data.
15209        tmpl: function( tmpl, data, options, parentItem ) {
15210            var ret, topLevel = !parentItem;
15211            if ( topLevel ) {
15212                // This is a top-level tmpl call (not from a nested template using {{tmpl}})
15213                parentItem = topTmplItem;
15214                tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );
15215                wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level
15216            } else if ( !tmpl ) {
15217                // The template item is already associated with DOM - this is a refresh.
15218                // Re-evaluate rendered template for the parentItem
15219                tmpl = parentItem.tmpl;
15220                newTmplItems[parentItem.key] = parentItem;
15221                parentItem.nodes = [];
15222                if ( parentItem.wrapped ) {
15223                    updateWrapped( parentItem, parentItem.wrapped );
15224                }
15225                // Rebuild, without creating a new template item
15226                return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));
15227            }
15228            if ( !tmpl ) {
15229                return []; // Could throw...
15230            }
15231            if ( typeof data === "function" ) {
15232                data = data.call( parentItem || {} );
15233            }
15234            if ( options && options.wrapped ) {
15235                updateWrapped( options, options.wrapped );
15236            }
15237            ret = jQuery.isArray( data ) ?
15238                jQuery.map( data, function( dataItem ) {
15239                    return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null;
15240                }) :
15241                [ newTmplItem( options, parentItem, tmpl, data ) ];
15242            return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret;
15243        },
15244
15245        // Return rendered template item for an element.
15246        tmplItem: function( elem ) {
15247            var tmplItem;
15248            if ( elem instanceof jQuery ) {
15249                elem = elem[0];
15250            }
15251            while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {}
15252            return tmplItem || topTmplItem;
15253        },
15254
15255        // Set:
15256        // Use $.template( name, tmpl ) to cache a named template,
15257        // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.
15258        // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration.
15259
15260        // Get:
15261        // Use $.template( name ) to access a cached template.
15262        // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
15263        // will return the compiled template, without adding a name reference.
15264        // If templateString includes at least one HTML tag, $.template( templateString ) 
vendor: 15,878 bytes, lines 15264-15594
15264is equivalent
15265        // to $.template( null, templateString )
15266        template: function( name, tmpl ) {
15267            if (tmpl) {
15268                // Compile template and associate with name
15269                if ( typeof tmpl === "string" ) {
15270                    // This is an HTML string being passed directly in.
15271                    tmpl = buildTmplFn( tmpl )
15272                } else if ( tmpl instanceof jQuery ) {
15273                    tmpl = tmpl[0] || {};
15274                }
15275                if ( tmpl.nodeType ) {
15276                    // If this is a template block, use cached copy, or generate tmpl function and cache.
15277                    tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML ));
15278                }
15279                return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl;
15280            }
15281            // Return named compiled template
15282            return name ? (typeof name !== "string" ? jQuery.template( null, name ):
15283                (jQuery.template[name] ||
15284                    // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec)
15285                    jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null;
15286        },
15287
15288        encode: function( text ) {
15289            // Do HTML encoding replacing < > & and ' and " by corresponding entities.
15290            return ("" + text).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;");
15291        }
15292    });
15293
15294    jQuery.extend( jQuery.tmpl, {
15295        tag: {
15296            "tmpl": {
15297                _default: { $2: "null" },
15298                open: "if($notnull_1){_=_.concat($item.nest($1,$2));}"
15299                // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions)
15300                // This means that {{tmpl foo}} treats foo as a template (which IS a function).
15301                // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}.
15302            },
15303            "wrap": {
15304                _default: { $2: "null" },
15305                open: "$item.calls(_,$1,$2);_=[];",
15306                close: "call=$item.calls();_=call._.concat($item.wrap(call,_));"
15307            },
15308            "each": {
15309                _default: { $2: "$index, $value" },
15310                open: "if($notnull_1){$.each($1a,function($2){with(this){",
15311                close: "}});}"
15312            },
15313            "if": {
15314                open: "if(($notnull_1) && $1a){",
15315                close: "}"
15316            },
15317            "else": {
15318                _default: { $1: "true" },
15319                open: "}else if(($notnull_1) && $1a){"
15320            },
15321            "html": {
15322                // Unecoded expression evaluation.
15323                open: "if($notnull_1){_.push($1a);}"
15324            },
15325            "=": {
15326                // Encoded expression evaluation. Abbreviated form is ${}.
15327                _default: { $1: "$data" },
15328                open: "if($notnull_1){_.push($.encode($1a));}"
15329            },
15330            "!": {
15331                // Comment tag. Skipped by parser
15332                open: ""
15333            }
15334        },
15335
15336        // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events
15337        complete: function( items ) {
15338            newTmplItems = {};
15339        },
15340
15341        // Call this from code which overrides domManip, or equivalent
15342        // Manage cloning/storing template items etc.
15343        afterManip: function afterManip( elem, fragClone, callback ) {
15344            // Provides cloned fragment ready for fixup prior to and after insertion into DOM
15345            var content = fragClone.nodeType === 11 ?
15346                jQuery.makeArray(fragClone.childNodes) :
15347                fragClone.nodeType === 1 ? [fragClone] : [];
15348
15349            // Return fragment to original caller (e.g. append) for DOM insertion
15350            callback.call( elem, fragClone );
15351
15352            // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data.
15353            storeTmplItems( content );
15354            cloneIndex++;
15355        }
15356    });
15357
15358    //========================== Private helper functions, used by code above ==========================
15359
15360    function build( tmplItem, nested, content ) {
15361        // Convert hierarchical content into flat string array
15362        // and finally return array of fragments ready for DOM insertion
15363        var frag, ret = content ? jQuery.map( content, function( item ) {
15364            return (typeof item === "string") ?
15365                // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM.
15366                (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) :
15367                // This is a child template item. Build nested template.
15368                build( item, tmplItem, item._ctnt );
15369        }) :
15370            // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}.
15371            tmplItem;
15372        if ( nested ) {
15373            return ret;
15374        }
15375
15376        // top-level template
15377        ret = ret.join("");
15378
15379        // Support templates which have initial or final text nodes, or consist only of text
15380        // Also support HTML entities within the HTML markup.
15381        ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) {
15382            frag = jQuery( middle ).get();
15383
15384            storeTmplItems( frag );
15385            if ( before ) {
15386                frag = unencode( before ).concat(frag);
15387            }
15388            if ( after ) {
15389                frag = frag.concat(unencode( after ));
15390            }
15391        });
15392        return frag ? frag : unencode( ret );
15393    }
15394
15395    function unencode( text ) {
15396        // Use createElement, since createTextNode will not render HTML entities correctly
15397        var el = document.createElement( "div" );
15398        el.innerHTML = text;
15399        return jQuery.makeArray(el.childNodes);
15400    }
15401
15402    // Generate a reusable function that will serve to render a template against data
15403    function buildTmplFn( markup ) {
15404        return new Function("jQuery","$item",
15405            "var $=jQuery,call,_=[],$data=$item.data;" +
15406
15407                // Introduce the data as local variables using with(){}
15408                "with($data){_.push('" +
15409
15410                // Convert the template into pure JavaScript
15411                jQuery.trim(markup)
15412                    .replace( /([\\'])/g, "\\$1" )
15413                    .replace( /[\r\t\n]/g, " " )
15414                    .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" )
15415                    .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,
15416                    function( all, slash, type, fnargs, target, parens, args ) {
15417                        var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect;
15418                        if ( !tag ) {
15419                            throw "Template command not found: " + type;
15420                        }
15421                        def = tag._default || [];
15422                        if ( parens && !/\w$/.test(target)) {
15423                            target += parens;
15424                            parens = "";
15425                        }
15426                        if ( target ) {
15427                            target = unescape( target );
15428                            args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : "");
15429                            // Support for target being things like a.toLowerCase();
15430                            // In that case don't call with template item as 'this' pointer. Just evaluate...
15431                            expr = parens ? (target.indexOf(".") > -1 ? target + parens : ("(" + target + ").call($item" + args)) : target;
15432                            exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))";
15433                        } else {
15434                            exprAutoFnDetect = expr = def.$1 || "null";
15435                        }
15436                        fnargs = unescape( fnargs );
15437                        return "');" +
15438                            tag[ slash ? "close" : "open" ]
15439                                .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" )
15440                                .split( "$1a" ).join( exprAutoFnDetect )
15441                                .split( "$1" ).join( expr )
15442                                .split( "$2" ).join( fnargs ?
15443                                    fnargs.replace( /\s*([^\(]+)\s*(\((.*?)\))?/g, function( all, name, parens, params ) {
15444                                        params = params ? ("," + params + ")") : (parens ? ")" : "");
15445                                        return params ? ("(" + name + ").call($item" + params) : all;
15446                                    })
15447                                    : (def.$2||"")
15448                                ) +
15449                            "_.push('";
15450                    }) +
15451                "');}return _;"
15452        );
15453    }
15454    function updateWrapped( options, wrapped ) {
15455        // Build the wrapped content.
15456        options._wrap = build( options, true,
15457            // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.
15458            jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
15459        ).join("");
15460    }
15461
15462    function unescape( args ) {
15463        return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null;
15464    }
15465    function outerHtml( elem ) {
15466        var div = document.createElement("div");
15467        div.appendChild( elem.cloneNode(true) );
15468        return div.innerHTML;
15469    }
15470
15471    // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance.
15472    function storeTmplItems( content ) {
15473        var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m;
15474        for ( i = 0, l = content.length; i < l; i++ ) {
15475            if ( (elem = content[i]).nodeType !== 1 ) {
15476                continue;
15477            }
15478            elems = elem.getElementsByTagName("*");
15479            for ( m = elems.length - 1; m >= 0; m-- ) {
15480                processItemKey( elems[m] );
15481            }
15482            processItemKey( elem );
15483        }
15484        function processItemKey( el ) {
15485            var pntKey, pntNode = el, pntItem, tmplItem, key;
15486            // Ensure that each rendered template inserted into the DOM has its own template item,
15487            if ( (key = el.getAttribute( tmplItmAtt ))) {
15488                while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { }
15489                if ( pntKey !== key ) {
15490                    // The next ancestor with a _tmplitem expando is on a different key than this one.
15491                    // So this is a top-level element within this template item
15492                    // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment.
15493                    pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0;
15494                    if ( !(tmplItem = newTmplItems[key]) ) {
15495                        // The item is for wrapped content, and was copied from the temporary parent wrappedItem.
15496                        tmplItem = wrappedItems[key];
15497                        tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode], null, true );
15498                        tmplItem.key = ++itemKey;
15499                        newTmplItems[itemKey] = tmplItem;
15500                    }
15501                    if ( cloneIndex ) {
15502                        cloneTmplItem( key );
15503                    }
15504                }
15505                el.removeAttribute( tmplItmAtt );
15506            } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) {
15507                // This was a rendered element, cloned during append or appendTo etc.
15508                // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem.
15509                cloneTmplItem( tmplItem.key );
15510                newTmplItems[tmplItem.key] = tmplItem;
15511                pntNode = jQuery.data( el.parentNode, "tmplItem" );
15512                pntNode = pntNode ? pntNode.key : 0;
15513            }
15514            if ( tmplItem ) {
15515                pntItem = tmplItem;
15516                // Find the template item of the parent element.
15517                // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string)
15518                while ( pntItem && pntItem.key != pntNode ) {
15519                    // Add this element as a top-level node for this rendered template item, as well as for any
15520                    // ancestor items between this item and the item of its parent element
15521                    pntItem.nodes.push( el );
15522                    pntItem = pntItem.parent;
15523                }
15524                // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering...
15525                delete tmplItem._ctnt;
15526                delete tmplItem._wrap;
15527                // Store template item as jQuery data on the element
15528                jQuery.data( el, "tmplItem", tmplItem );
15529            }
15530            function cloneTmplItem( key ) {
15531                key = key + keySuffix;
15532                tmplItem = newClonedItems[key] =
15533                    (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent, null, true ));
15534            }
15535        }
15536    }
15537
15538    //---- Helper functions for template item ----
15539
15540    function tiCalls( content, tmpl, data, options ) {
15541        if ( !content ) {
15542            return stack.pop();
15543        }
15544        stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options });
15545    }
15546
15547    function tiNest( tmpl, data, options ) {
15548        // nested template, using {{tmpl}} tag
15549        return jQuery.tmpl( jQuery.template( tmpl ), data, options, this );
15550    }
15551
15552    function tiWrap( call, wrapped ) {
15553        // nested template, using {{wrap}} tag
15554        var options = call.options || {};
15555        options.wrapped = wrapped;
15556        // Apply the template, which may incorporate wrapped content,
15557        return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item );
15558    }
15559
15560    function tiHtml( filter, textOnly ) {
15561        var wrapped = this._wrap;
15562        return jQuery.map(
15563            jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ),
15564            function(e) {
15565                return textOnly ?
15566                    e.innerText || e.textContent :
15567                    e.outerHTML || outerHtml(e);
15568            });
15569    }
15570
15571    function tiUpdate() {
15572        var coll = this.nodes;
15573        jQuery.tmpl( null, null, null, this).insertBefore( coll[0] );
15574        jQuery( coll ).remove();
15575    }
15576})( jQuery );
15577/*!
15578 * jQuery Mobile 1.4.1
15579 * Git HEAD hash: 18c1e32bfc4e0e92756dedc105d799131607f5bb <> Date: Wed Feb 12 2014 22:15:20 UTC
15580 * http://jquerymobile.com
15581 *
15582 * Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors
15583 * Released under the MIT license.
15584 * http://jquery.org/license
15585 *
15586 */
15587/*!
15588 * code snippet for just swipe-right and swipe-left
15589 */
15590(function( $, window, undefined ) {
15591    var $document = $(document),
15592        TouchUtil = xfalib.ut.TouchUtil,
15593        touchStartEvent = TouchUtil.POINTER_DOWN,
15594        touchStopEvent = TouchUtil.POINTER_UP,
15595        touchMoveEvent = TouchUtil.POINTER_MOVE;
15596
15597    function triggerCustomEvent( obj, eventType, event, bubble ) {
15598        var originalType = event.type;
15599        event.type = eventType;
15600        if ( bubble ) {
15601            $.event.trigger( event, undefined, obj );
15602        } else {
15603            $.event.dispatch.call( obj, event );
15604        }
15605        event.type = originalType;
15606    }
15607
15608    $.event.special.swipe = {
15609
15610        // More than this horizontal displacement, and we will suppress scrolling.
15611        scrollSupressionThreshold: 30,
15612
15613        // More time than this, and it isn't a swipe.
15614        durationThreshold: 1000,
15615
15616        // Swipe horizontal displacement must be more than this.
15617        horizontalDistanceThreshold: 30,
15618
15619        // Swipe vertical displacement must be less than this.
15620        verticalDistanceThreshold: 30,
15621
15622        getLocation: function ( event ) {
15623            var winPageX = window.pageXOffset,
15624                winPageY = window.pageYOffset,
15625                x = event.clientX || event.originalEvent.clientX,
15626                y = event.clientY || event.originalEvent.clientY;
15627
15628            if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) ||
15629                event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) {
15630
15631                // iOS4 clientX/clientY have the value that should have been
15632                // in pageX/pageY. While pageX/page/ have the value 0
15633                x = x - winPageX;
15634                y = y - winPageY;
15635            } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) {
15636
15637                // Some Android browsers have totally bogus values for clientX/Y
15638                // when scrolling/zooming a page. Detectable since clientX/clientY
15639                // should never be smaller than pageX/pageY minus page scroll
15640                x = event.pageX - winPageX;
15641                y = event.pageY - winPageY;
15642            }
15643
15644            return {
15645                x: x,
15646                y: y
15647            };
15648        },
15649
15650        start: function( event ) {
15651            var data = event.originalEvent.touches ?
15652                    event.originalEvent.touches[ 0 ] : event,
15653                location = $.event.special.swipe.getLocation( data );
15654            return {
15655                time: ( new Date() ).getTime(),
15656                coords: [ location.x, location.y ],
15657                origin: $( event.target )
15658            };
15659        },
15660
15661        stop: function( event ) {
15662            var data = event.originalEvent.touches ?
15663                    event.originalEvent.touches[ 0 ] : event,
15664                location = $.event.special.swipe.getLocation( data );
15665            return {
15666                time: ( new Date() ).getTime(),
15667                coords: [ location.x, location.y ]
15668            };
15669        },
15670
15671        handleSwipe: function( start, stop, thisObject, origTarget ) {
15672            if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
15673                Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
15674                Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
15675                var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight";
15676
15677                triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true );
15678                return true;
15679            }
15680            return false;
15681
15682        },
15683
15684        // This serves as a flag to ensure that at most one swipe event event is
15685        // in work at any given time
15686        eventInProgress: false,
15687
15688        setup: function() {
15689            var events,
15690                thisObject = this,
15691                $this = $( thisObject ),
15692                context = {};
15693
15694            // Retrieve the events data for this element and add the swipe context
15695            events = $.data( this, "mobile-events" );
15696            if ( !events ) {
15697                events = { length: 0 };
15698                $.data( this, "mobile-events", events );
15699            }
15700            events.length++;
15701            events.swipe = context;
15702
15703            context.start = function( event ) {
15704                // If its not a touch event on IE, ignore
15705                if (event.originalEvent.pointerType !== undefined && !(event.originalEvent.pointerType === 2 || event.originalEvent.pointerType === "touch")) {
15706                    return;
15707                }
15708
15709                // Bail if we're already working on a swipe event
15710                if ( $.event.special.swipe.eventInProgress ) {
15711                    return;
15712                }
15713                $.event.special.swipe.eventInProgress = true;
15714
15715                var stop,
15716                    start = $.event.special.swipe.start( event ),
15717                    origTarget = event.target,
15718                    emitted = false;
15719
15720                context.move = function( event ) {
15721                    if ( !start ) {
15722                        return;
15723                    }
15724
15725                    stop = $.event.special.swipe.stop( event );
15726                    if ( !emitted ) {
15727                        emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget );
15728                        if ( emitted ) {
15729
15730                            // Reset the context to make way for the next swipe event
15731                            $.event.special.swipe.eventInProgress = false;
15732                        }
15733                    }
15734                    // prevent scrolling
15735                    if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
15736                        event.preventDefault();
15737                    }
15738                };
15739
15740                context.stop = function() {
15741                    emitted = true;
15742
15743                    // Reset the context to make way for the next swipe event
15744                    $.event.special.swipe.eventInProgress = false;
15745                    $document.off( touchMoveEvent, context.move );
15746                    context.move = null;
15747                };
15748
15749                $document.on( touchMoveEvent, context.move )
15750                    .one( touchStopEvent, context.stop );
15751            };
15752            $this.on( touchStartEvent, context.start );
15753        },
15754
15755        teardown: function() {
15756            var events, context;
15757
15758            events = $.data( this, "mobile-events" );
15759            if ( events ) {
15760                context = events.swipe;
15761                delete events.swipe;
15762                events.length--;
15763                if ( events.length === 0 ) {
15764                    $.removeData( this, "mobile-events" );
15765                }
15766            }
15767
15768            if ( context ) {
15769                if ( context.start ) {
15770                    $( this ).off( touchStartEvent, context.start );
15771                }
15772                if ( context.move ) {
15773                    $document.off( touchMoveEvent, context.move );
15774                }
15775                if ( context.stop ) {
15776                    $document.off( touchStopEvent, context.stop );
15777                }
15778            }
15779        }
15780    };
15781    $.each({
15782        swipeleft: "swipe",
15783        swiperight: "swipe"
15784    }, function( event, sourceEvent ) {
15785		// Ignoring mouse events, for all browsers except IE 10>, which has pointer events.
15786        if (TouchUtil.POINTER_DOWN !== "mousedown") {
15787            $.event.special[ event ] = {
15788                setup: function() {
15789                    $( this ).on( sourceEvent, $.noop );
15790                },
15791                teardown: function() {
15792                    $( this ).off( sourceEvent );
15793                }
15794            };
15795        }
15796    });
15797
15798})( jQuery, this );
15799
15800/*************************************************************************
15801 *
15802 * ADOBE CONFIDENTIAL
15803 * __________________
15804 *
15805 *  Copyright 2017 Adobe Systems Incorporated
15806 *  All Rights Reserved.
15807 *
15808 * NOTICE:  All information contained herein is, and remains
15809 * the property of Adobe Systems Incorporated and its suppliers,
15810 * if any.  The intellectual and technical concepts contained
15811 * herein are proprietary to Adobe Systems Incorporated and its
15812 * suppliers and may be covered by U.S. and Foreign Patents,
15813 * patents in process, and are protected by trade secret or copyright law.
15814 * Dissemination of this information or reproduction of this material
15815 * is strictly forbidden unless prior written permission is obtained
15816 * from Adobe Systems Incorporated.
15817 **************************************************************************/
15818
15819(function (window, $) {
15820
15821    var DefaultPanelProvider = {
15822
15823        /**
15824         * Makes an ajax call and returns an object containing the template json of the template ids
15825         * @returns {Object}
15826         * @param options {Object} This object contains the path, the list of templateIds, and success handler
15827         */
15828        getMultipleTemplateJson : function (options) {
15829            var externalizedPath = options.path,
15830                listOfTemplateIds = options.listOfTemplateIds;
15831            if (listOfTemplateIds.length > 0) {
15832                $.ajax({
15833                    url : externalizedPath,
15834                    type : "GET",
15835                    data : {
15836                        listOfTemplateIds : JSON.stringify(listOfTemplateIds),
15837                        fetchMultipleJson : true
15838                    },
15839                    async : false,
15840                    success : function (response) {
15841                        options.success.call(this, JSON.parse(response.multipleJson));
15842                    },
15843                    error : function (error) {
15844                        window.guideBridge._guide().logger().log(error);
15845                    }
15846                });
15847            }
15848        },
15849
15850        /**
15851         * Makes an ajax call and gets json and html of the lazy loaded panel
15852         * @param options {Object}
15852 This object contains the templateId, fetchJson parameter and fetchHtml parameter.
15853         *                         These can be set to true or false depending on whether the respective content
15854         *                         needs to be fetched or not. Options object also contains the success, error, and complete handler as well.
15855         * @returns {JSONObject} The JSON object has two entries, json and html.
15856         */
15857        getHtmlJson : function (options) {
15858            $.ajax({
15859                url : options.path,
15860                type : "GET",
15861                data : {
15862                    templateId : options.templateId,
15863                    fetchJSON : options.fetchJSON,
15864                    fetchHTML : options.fetchHTML,
15865                    wcmmode : "disabled"
15866                },
15867                async : false,
15868                success : options.success,
15869                error : options.error,
15870                complete : options.complete
15871            });
15872        }
15873    };
15874
15875    window.addEventListener("bridgeInitializeStart", function (evnt) {
15876        var bridge = evnt.detail.guideBridge;
15877        if (bridge) {
15878            bridge.registerPanelProvider(DefaultPanelProvider);
15879        }
15880    });
15881
15882}(window, $));
15883
15884
15885// jscs:disable requireDotNotation
15886/*************************************************************************
15887 *
15888 * ADOBE CONFIDENTIAL
15889 * __________________
15890 *
15891 *  Copyright 2014 Adobe Systems Incorporated
15892 *  All Rights Reserved.
15893 *
15894 * NOTICE:  All information contained herein is, and remains
15895 * the property of Adobe Systems Incorporated and its suppliers,
15896 * if any.  The intellectual and technical concepts contained
15897 * herein are proprietary to Adobe Systems Incorporated and its
15898 * suppliers and may be covered by U.S. and Foreign Patents,
15899 * patents in process, and are protected by trade secret or copyright law.
15900 * Dissemination of this information or reproduction of this material
15901 * is strictly forbidden unless prior written permission is obtained
15902 * from Adobe Systems Incorporated.
15903 **************************************************************************/
15904
15905(function ($, _) {
15906    Function.prototype.bind = Function.prototype.bind || function (ctx) {
15907        var that = this;
15908        return function () {
15909            that.call(ctx, arguments);
15910        };
15911    };
15912
15913    var nValidationContext = 0,
15914        /**
15915         * flag to check if adaptive forms is online or not
15916         * @type {boolean}
15917         */
15918        checkAFOffline = false,
15919        _focusedSubmitButtonModel = null,
15920        sValidationContext = "";
15921
15922    /**
15923     * Class representing the result of {@link GuideBridge} API. This class provides API to access the result of the
15924     * GuideBridge API and retrieve any error messages the API has thrown.
15925     * @class GuideResultObject
15926     * @docStatus review 2016-05-03
15927     * @since 6.0
15928     */
15929    var GuideResultObject = function () {
15930        var _message = [];
15931        var _errorCode = [];
15932        var _somExpression = [];
15933        /**
15934         * The value of this property is true if the API succeeded, otherwise false. The
15935         * {@link GuideResultObject#getNextMessage|getNextMessage} API can be used to retrieve the error messages in
15936         * case the value of this property is false.
15937         * @summary whether the API succeeded or failed.
15938         *
15939         * @type {boolean}
15940         * @member errors
15941         * @memberof GuideResultObject
15942         * @instance
15943         * @readonly
15944         * @since 6.0
15945         */
15946        this.errors = false;
15947        /**
15948         * The type of the data is specific to the API and documentation of that API provides more details about the
15949         * data
15950         * @summary data returned by GuideBridge API
15951         *
15952         * @member {*} data
15953         * @memberof GuideResultObject
15954         * @instance
15955         * @readonly
15956         * @since 6.0
15957         */
15958        this.data;
15959
15960        /**
15961         * API to add a message in the GuideResultObject
15962         * @private
15963         * @memberof GuideResultObject
15964         * @instance
15965         * @since 6.0
15966         */
15967        this.addMessage = function (code, msg, som) {
15968            this.errors = true;
15969            _message.push(msg);
15970            _somExpression.push(som);
15971            _errorCode.push(code);
15972        };
15973
15974        /**
15975         * Error Message returned by GuideBridge API
15976         * @typedef {object} GuideResultObject~ErrorMessage
15977         * @property {number} code Error Code
15978         * @property {?string} somExpression Som Expression of the GuideNode the error is related to. It can be null if
15979         * error is not related to a GuideNode. For example, server failure when submitting the form.
15980         * @property {string} message User friendly message for the error.
15981         * @see GuideNode#somExpression
15982         */
15983        /**
15984         * When a GuideBridge API fails, it throws an error message. This is indicated by the
15985         * {@link GuideResultObject#errors|errors} property. To get the errors, one has to call this API. The API can throw
15986         * multiple errors and the user has to call this API until it returns null indicating no more errors.
15987         * @summary Returns the error message thrown by the GuideBridge API.
15988         * @function getNextMessage
15989         * @memberof GuideResultObject
15990         * @instance
15991         * @return {GuideResultObject~ErrorMessage} object containing the error message
15992         * @since 6.0
15993         */
15994        this.getNextMessage = function () {
15995            if (_errorCode.length == 0) {
15996                return null;
15997            }
15998            return {
15999                code : _errorCode.pop(),
16000                somExpression : _somExpression.pop(),
16001                message : _message.pop()
16002            };
16003        };
16004    };
16005
16006    var GUIDE_BRIDGE_VERSION = "1.0";
16007    /*
16008     * Callback to accept result of asynchronous GuideBridge APIs.
16009     * @callback GuideBridge~AsyncAPIResultCallback
16010     * @param {GuideResultObject}
16010 guideResultObject object containing the result of the API
16011     */
16012    /*
16013     * Signature of the input to be passed to GuideBridge asynchronous APIs
16014     * @typedef {object} GuideBridge~AsyncAPIInput
16015     * @property {GuideBridge~AsyncAPIResultCallback} [success] callback which receives the result of the API in case of
16016     * success. The argument this callback will recieve will have its {@link GuideResultObject#errors|errors} property
16017     * as false.
16018     * @property {GuideBridge~AsyncAPIResultCallback} [error] callback which receives the result of the API in case of
16019     * failure. The argument this callback will recieve will have its {@link GuideResultObject#errors|errors} property
16020     * as true.
16021     * @param {object} [context] _this_ object inside the _success_ and _error_ callback will point to this
16022     * object
16023     */
16024    /**
16025     * GuideBridge provides an interface using which, wrapper html (page hosting/embedding adaptive forms) or external
16026     * window scripts like Parent window javascript (in case form is embedded in an iframe), can communicate with
16027     * current Adaptive Form and manipulate or query it's current state.
16028     *
16029     * Some of the use cases for using this API
16030     * * Submit Adaptive Form from a custom button present outside the Form.
16031     * * Get current Adaptive Form state and save it in local storage for restoring it later on.
16032     * * Plugging in custom widgets.
16033     * * Manipulate the Adaptive Form component properties, like value, visibility from outside the Form
16034     * * Listen to bridge events and send data to Analytics server for reporting
16035     *
16036     * ### Accessing the Instance of GuideBridge
16037     * To access the GuideBridge APIs, one needs to get hold of an instance of GuideBridge. The object is
16038     * available on the window after the GuideBridge script is loaded. One can directly access it by using
16039     * `window.guideBridge`. But
16040     * that requires the user script is written after the GuideBridge script is loaded. In certain cases, a user might
16041     * not be
16042     * aware of when their script gets loaded, in those cases the recommended approach is to listen to the
16043     * {@link GuideBridge.event:bridgeInitializeStart|bridgeInitializeStart} event which provides an instance of
16044     * GuideBridge object.
16045     *```
16046     * window.addEventListener("bridgeInitializeStart", function(evnt) {
16047     *      // get hold of the guideBridge object
16048     *      var gb = evnt.detail.guideBridge;
16049     * })
16050     * ```
16051     *
16052     * **Or**, if you are sure that your script will execute after GuideBridge Script is loaded, then you can directly
16053     * use `window.guideBridge`. In cases like your script is present at the bottom of the page or you are executing on
16054     * jquery dom ready event.
16055     * ```
16056     *    $(function () {
16057     *          // one can directly access guideBridge object here.
16058     *          window.guideBridge.connect(function () {
16059     *              //call guideBridge APIs
16060     *          })
16061     *    })
16062     * ```
16063     *
16064     * <a name="wait-form-ready"></a>
16065     * ### Wait for Form to get ready
16066     * After getting the GuideBridge object one needs to wait for the Form to get initialized. This can be done by
16067     * providing a callback to the {@link GuideBridge#connect|connect} API
16068     * ```
16069     * guideBridge.connect(function (){
16070     *    //this callback will be called after adaptive form is initialized
16071     *    // do your custom processing
16072     * })
16073     * ```
16074     *
16075     * _**Note:** There is no link between Dom ready events and the connect API. If one wants to access the HTML DOM
16076     * from inside the connect callback, the recommended approach is to listen on the jQuery
16077     * [ready](https://api.jquery.com/ready/) event or the native
16078     * [DOMContentLoaded](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event. Similarly if one
16079     * wants to access GuideBridge APIs one needs to wait for the connect callback to get fired._
16080     *
16081     * <a name="guidebridge-api-usage"></a>
16082     * ### Using the GuideBridge API
16083     * APIs are provided for external applications to connect with Adaptive Form and FormDom. The APIs can be
16084     * loosely divided into two categories, **synchronous** and **asynchronous**.
16085     *
16086     * The synchronous getter API returns a {@link GuideResultObject} which represents the result of the API whereas
16087     * each setter API throws an exception in case of error(s) and it is the responsibility of the API to catch those
16088     * exceptions. The {@link GuideResultObject} either contains error or the return value of the API and provides easy
16089     * mechanism to access each of them.
16090     *
16091     * ```
16092     * var result = guideBridge.hideGlobalToolbar()
16093     * if (result.errors) {
16094     *     console.error("Unable to hide toolbar");
16095     *     var msg = guideResultObject.getNextMessage();
16096     *     while (msg != null) {
16097     *         console.error(msg.message);
16098     *         msg = guideResultObject.getNextMessage();
16099     *    }
16100     * } else {
16101     *      console.log("toolbar hidden successfully");
16102     * }
16103     * ```
16104     *
16105     * Each asynchronous API provides callback mechanism to return the result of the API. Each API takes a Javascript
16106     * Object having success and error handlers. The success and error handlers receive {@link GuideResultObject} as input.
16107     * In the success callback, the arguments {@link GuideResultObject#data|data} property is set to the return value
16108     * of the API, while in the error callback the {@link GuideResultObject#errors|errors} property is set to _true_.
16109     * Some APIs might need extra input and that will be defined by the API
16110     * ```
16111     * guideBridge.getData({
16112     *     success : function (guideResultObject) {
16113     *          console.log("data received" + guideResultObject.data);
16114     *     }
16115     *     error : function (guideResultObject) {
16116     *          console.error("API Failed");
16117     *          var msg = guideResultObject.getNextMessage();
16118     *          while (msg != null) {
16119     *              console.error(msg.message);
16120     *              msg = guideResultObject.getNextMessage();
16121     *          }
16122     *     }
16123     * });
16124     * ```
16125     * _**Note:** Some APIs do not follow the above norm and it is mentioned in the documentation of that API_
16126     *
16127     * <a name="guidebridge-events"></a>
16128     * ### GuideBridge Events
16129     *
16130     * GuideBridge API triggers a set of events to notify the current action a user has taken. Developers can listen on
16131     * that event using the {@link GuideBridge#on|on} API and perform some tasks. For example a developer can listen on
16132     * {@link GuideBridge.event:elementFocusChanged|elementFocusChanged} and capture for how long a user spends time
16133     * on that field. All the events triggered by GuideBridge are mentioned below.
16134     *
16135     * GuideBridge provides an event object which contains extra information about the event. For
16136     * example _elementFocusChanged_ event provides information about the previous field that was in focus and the
16137     * current field that came to focus.
16138     *
16139     * The {@link GuideBridge#on|on} API takes a {@link GuideBridge~GuideBridgeEventCallback|GuideBridgeEventCallback}
16140     * as input. The callback is passed two arguments, event and payload where the extra information is passed in the
16141     * payload argument. The documentation of each event lists the values of different properties of the payload
16142     * object.
16143     *
16144     * ```
16145     * guideBridge.on(eventName, function (event, payload) {
16146     *      // access payload properties
16147     *      ...
16148     * })
16149     * ```
16150     *
16151     * @class GuideBridge
16152     * @docStatus review 2016-05-03
16153     * @since 6.0
16154     */
16155    var GuideBridge = function () {
16156        this._$target = null;
16157        this._guide = null;
16158        this._guideView = null;
16159        this._version = GUIDE_BRIDGE_VERSION;
16160        this._guideInitHandler = {};
16161        // _guideModelInitHandler is for internal use only
16162        this._guideModelInitHandler = {};
16163        $(window).on("guideModelInitialized", this._guideModelInitialized.bind(this));
16164        $(window).on("guideInitialized", this._guideInitialized.bind(this));
16165        $(window).on("guideInitializationError", this._guideError);
16166        this.userConfig = {};
16167        this.panelProvider = null;
16168        // set the host name whether it is client or server, by default it is client
16169        this.hostName = "client";
16170    };
16171
16172    var _formInstanceUUID;
16173    var GUIDE_TEMP_STORAGE_PATH = "/tmp/fd/af",
16174        FM_DAM_ROOT = "/content/dam/formsanddocuments/",
16175        FM_AF_ROOT = "/content/forms/af/",
16176        _isAutoSaveEnabled = false,
16177        LOCAL_METADATA_SELECTOR = "local";
16178    var createUUIDStorage = function (uuid) {
16179        var successFlag = true;
16180        // this is  done so that when one clicks
16181        // the disabled link anyhow
16182        // you will not be able to
16183        // send request
16184        // More over if hack this too then we
16185        // have a check to prevent formation of
16186        // UUID folder at server side too ;)
16187        if (guideBridge._disablePreview()) {
16188            return false;
16189        }
16190        $.ajax({
16191            url : guideBridge._getGuidePathUrl(".fd.tempstorageprovider.jsp"),
16192            type : "POST",
16193            async : false,
16194            data : {"uuidPath" : GUIDE_TEMP_STORAGE_PATH + "/" + uuid},
16195            error : function (message) {
16196                guideBridge._guide.logger().log(message);
16197                successFlag = false;
16198                $.proxy(guideBridge._handleSubmitError(message), guideBridge);
16199            }
16200        });
16201        return successFlag;
16202    };
16203
16204    var defaultErrorHandler = function (obj) {
16205        if (typeof(console) == "undefined") {
16206            return;
16207        }
16208        var d = obj.getNextMessage();
16209        while (d) {
16210            this._guide.logger().log(d.message);
16211            d = obj.getNextMessage();
16212        }
16213    };
16214
16215    /**
16216     *
16217     * Default function to check Validations errors after getting the data from the
16218     * server with getDataXML call.
16219     * @private
16220     */
16221    var defaultValidationChecker = function (validations, obj) {
16222        if (validations && validations.length > 0) {
16223            for (var i = 0; i < validations.length; i++) {
16224                obj.addMessage(0, validations[i], "");
16225            }
16226            return false;
16227        }
16228        return true;
16229    };
16230
16231    function getOrElse() {
16232        return xfalib.ut.XfaUtil.prototype.getOrElse.apply(null, arguments);
16233    }
16234
16235    $.extend(GuideBridge.prototype, {
16236
16237        /**
16238         * Dispatched when the instance of GuideBridge is available. The GuideBridge object
16239         * will be passed to the listener and further communication can be done using that object.
16240         *
16241         * _**Note :** bridgeInitializeStart event is dispatched at window_
16242         *
16243         * @summary Notifies when the instance of GuideBridge is available.
16244         *
16245         * @event bridgeInitializeStart
16246         * @property {Object} detail an object containing guideBridge
16247         * @property {GuideBridge} detail.guideBridge GuideBridge Instance
16248         * @memberof GuideBridge
16249         * @since 6.0
16250         * @example
16251         * window.addEventListener("bridgeInitializeStart", function(evnt) {
16252         *      // get hold of the guideBridge object
16253         *      var gb = evnt.detail.guideBridge;
16254         *      //wait for the completion of adaptive forms
16255         *      gb.connect(function (){
16256         *         //this function will be called after adaptive form is initialized
16257         *      })
16258         * })
16259         */
16260        GUIDE_BRIDGE_INITIALIZE_START : "bridgeInitializeStart",
16261
16262        /**
16263         * @summary Dispatched when the initialization of Adaptive Form is complete.
16264         *
16265         * @name  bridgeInitializeComplete
16266         * @event
16267         * @property {object} payload payload passed to the event listener
16268         * @property {object} payload.target instance of GuideBridge object
16269         * @memberof GuideBridge
16270         * @deprecated since 6.3 this event is deprecated. Please use {@link GuideBridge#connect|connect} API
16271         * @since 6.0
16272         * @example
16273         * guideBridge.on("bridgeInitializeComplete" , function(event, payload) {
16274         *      var gb = payload.target;
16275         *      assert(gb === guideBridge)
16276         * }
16277         */
16278        GUIDE_BRIDGE_INITIALIZE_COMPLETE : "bridgeInitializeComplete",
16279
16280        /**
16281         * @summary Dispatched when visibility of any Adaptive Form component(Panel or Field) changes.
16282         * @name elementVisibleChanged
16283         * @event
16284         * @property {object} payload payload containing more information about the event
16285         * @property {Scriptable} payload.target Adaptive Form component whose {@link Scriptable#visible|visible} property has
16286         * changed.
16287         * @property {boolean} payload.oldText old value of the visible property
16288         * @property {boolean} payload.newText new value of the visible property
16289         * @memberof GuideBridge
16290         * @since 6.0
16291         * @example
16292         * guideBridge.on("elementVisibleChanged" , function(event, payload) {
16293         *      var component = payload.target; // scripting model of the component whose visibility has changed
16294         *      var newValue = payload.newText;
16295         *      if (newValue) {
16296         *          console.log(component.name + " is visible now";
16297         *      } else {
16298         *          console.log(component.name + " is hidden now";
16299         *      }
16300         * }
16301         *
16302         */
16303        GUIDE_ELEMENT_VISIBLE_CHANGED : "elementVisibleChanged",
16304
16305        /**
16306         * @summary Dispatched when any Adaptive Form component is enabled/disabled, i.e.
16307         * {@link Scriptable#enabled|enabled} property of a component changes.
16308         * @name elementEnableChanged
16309         * @event
16310         * @property {object} payload payload containing more information about the event
16311         * @property {Scriptable} payload.target component whose {@link Scriptable#enabled|enabled} property has changed
16312         * @property {boolean} payload.oldText old value of the enabled property
16313         * @property {boolean} payload.newText new value of the enabled property
16314         * @memberof GuideBridge
16315         * @since 6.0
16316         * @example
16317         * guideBridge.on("elementEnableChanged" , function(event, payload) {
16318         *      var component = payload.target; // scripting model of the component whose enabled property has changed
16319         *      var newValue = payload.newText;
16320         *      if (newValue) {
16321         *          console.log(component.name + " is enabled now";
16322         *      } else {
16323         *          console.log(component.name + " is disabled now";
16324         *      }
16325         * }
16326         */
16327        GUIDE_ELEMENT_ENABLE_CHANGED : "elementEnableChanged",
16328
16329        /**
16330         * @summary Dispatched when value of any Field changes.
16331         * @name elementValueChanged
16332         * @event
16333         * @property {object} payload payload containing more information about the event
16334         * @property {Field} payload.target Field whose {@link Field#value|value} has changed
16335         * @property {string|number} payload.oldText old value of the Field
16336         * @property {string|number} payload.newText new value of the Field
16337         * @memberof GuideBridge
16338         * @since 6.0
16339         * @example
16340         * guideBridge.on("elementValueChanged" , function(event, payload) {
16341         *      var component = payload.target; // Field whose value has changed
16342         *      console.log("Value of component " + component.name + " was " + payload.oldText);
16343         *      console.log("Value of component " + component.name + " is " + payload.newText);
16344         * }
16345         */
16346        GUIDE_ELEMENT_VALUE_CHANGED : "elementValueChanged",
16347
16348        /**
16349         * In layouts like Wizard or Tabbed layout, when a user navigates from one tab to another, this event is
16350         * triggered
16351         * @summary Event to notify that the user has navigated from one Panel to another.
16352         *
16353         * @name elementNavigationChanged
16354         * @event
16355         * @property {object} payload payload containing more information about the event
16356         * @property {Panel} payload.target Panel to which the user moved to
16357         * @property {string} payload.prevText SomExpression of the panel from which user moved
16358         * @property {string} payload.newText SomExpression of the panel to which user moved
16359         * @memberof GuideBridge
16360         * @see GuideNode#somExpression
16361         * @since 6.0
16362         * @example
16363         * guideBridge.on("elementNavigationChanged" , function(event, payload) {
16364         *      var component = payload.target;
16365         *      console.log("old panel's SOM Expression: " + payload.oldText);
16366         *      console.log("new panel's SOM Expression: " + payload.newText);
16367         * }
16368         */
16369        GUIDE_ELEMENT_NAVIGATION_CHANGED : "elementNavigationChanged",
16370
16371        /**
16372         * @summary Dispatched whenever a Field/Panel gets Focus
16373         * @name elementFocusChanged
16374         * @event
16375         * @property {object} payload payload containing more information about the event
16376         * @property {Panel|Field} payload.target new focused component
16377         * @property {string} oldText SOM Expression of  component  that was previously in focus or null
16378         * @property {string} newText SOM Expression of the component that is currently in focus or null
16379         * @memberof GuideBridge
16380         * @see GuideNode#somExpression
16381         * @see {@link GuideBridge#setFocus|setFocus API}
16382         * @since 6.0
16383         * @example
16384         * guideBridge.on("elementFocusChanged" , function(event, payload) {
16385         *      var component = payload.target;
16386         *      console.log("old elements's SOM Expression: " + payload.oldText);
16387         *      console.log("new elements's SOM Expression: " + payload.newText);
16388         * }
16389         */
16390        GUIDE_ELEMENT_FOCUS_CHANGED : "elementFocusChanged",
16391
16392        /**
16393         * @summary Dispatched when a user looks at the help description of any Adaptive Form component(Panel or field)
16394         * @name elementHelpShown
16395         * @event
16396         * @property {object} payload payload containing more information about the event
16397         * @property {Panel|Field} payload.target component whose help is being shown
16398         * @property {string} payload._property what kind of help is being shown. The value can be
16399         * * shortDescription (if Short Description becomes visible)
16400         * * longDescription (if Long Description becomes visible)
16401         * @property {string} payload.prevText empty string
16402         * @property {object} payload.newText object containing the help content
16403         * @property {string} payload.newText.help help content of the component
16404         * @memberof GuideBridge
16405         * @since 6.0
16406         * @see {@link https://helpx.adobe.com/aem-forms/6-1/authoring-in-field-help.html|Help Description in Adaptive Form}
16407         * @example
16408         * guideBridge.on("elementHelpShown" , function(event, payload) {
16409         *      var component = payload.target;
16410         *      console.log("component whose help is shown " + payload.target.name);
16411         *      console.log("Help shown: " + payload._property);
16412         *      console.log("Help Content: " + payload.newText.help);
16413         * }
16414         */
16415        GUIDE_ELEMENT_HELP_SHOWN : "elementHelpShown",
16416
16417        /**
16418         * @summary Dispatched when validity of a Field changes.
16419         * @name elementValidationStatusChanged
16420         * @event
16421         * @property {object} payload payload containing more information about the event
16422         * @property {Field} payload.target Field which either became valid/invalid
16423         * @property {boolean} payload.prevText old validation status
16424         * @property {boolean} payload.newText new validation status
16425         * @memberof GuideBridge
16426         * @see Field#validate
16427         * @see Field#validationState
16428         * @since 6.0
16429         * @example
16430         * guideBridge.on("elementValidationStatusChanged" , function(event, payload) {
16431         *      var component = payload.target;
16432         *      if (payload.prevText) {
16433         *          console.log("component became invalid" );
16434         *      } else {
16435         *         console.log("component became valid" );
16436         *      }
16437         * }
16438         */
16439        GUIDE_ELEMENT_VALIDATION_STATUS_CHANGED : "elementValidationStatusChanged",
16440
16441        /**
16442         * Developers must not modify the Form Fields inside the listener. This is mostly use to update the UI outside
16443         * the Form or capture some data for analytics. If you want to modify form field value on the click of a button
16444         * please use the [Click Expression](https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_6)
16445         * provided in the Forms Authoring.
16446         *
16447         * @summary Dispatched when a Button component is clicked.
16448         *
16449         * @name elementButtonClicked
16450         * @event
16451         * @property {object} payload payload containing more information about the event
16452         * @property {Button} payload.target Button which was clicked
16453         * @memberof GuideBridge
16454         * @since 6.0
16455         * @see {@link https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_6|Click Expression in Buttons}
16456         * @example
16457         * guideBridge.on("elementButtonClicked" , function(event, payload) {
16458         *      var component = payload.target; // Button which wass clicked
16459         *      console.log("Button which was clicked " + component.name);
16460         * }
16461         */
16462        GUIDE_ELEMENT_BUTTON_CLICKED : "elementButtonClicked",
16463
16464        /**
16465         * Whenever the full form validations are run via the {@link GuideBridge#validate|val
16465idate} API, this event is triggered.
16466         * @summary Dispatched when the validation of all the Adaptive Form fields are completed.
16467         *
16468         * @name validationComplete
16469         * @event
16470         * @property {object} payload payload containing more information about the event
16471         * @property {GuideContainerNode} payload.target root Node of the Adaptive Form
16472         * @property {boolean} payload.prevText result of running the validation. true if validations are successful,
16473         * false otherwise
16474         * @property {Field~ValidationError[]} payload.newText List of objects containing error messages.
16475         * @memberof GuideBridge
16476         * @since 6.0
16477         * @example
16478         * guideBridge.on("validationComplete" , function(event, payload) {
16479         *      if (payload.prevText) {
16480         *          console.log("validation success");
16481         *      } else {
16482         *          console.log("validation failure");
16483         *          if (payload.newText.length) {
16484         *              payload.newText.forEach(function (error) {
16485         *                 console.log("validation failed for " + error.som + " with message " + error.errorText);
16486         *              })
16487         *          }
16488         *      }
16489         * }
16490         */
16491        GUIDE_VALIDATION_COMPLETE : "validationComplete",
16492
16493        /**
16494         * Adaptive Form can be configured to be saved automatically at regular intervals. This can be controlled
16495         * dynamically based on the values filled in the Form. Authors can write custom scripts which can enable/disable
16496         * auto save functionality dynamically
16497         * @summary Dispatched when auto save gets enabled in the Form
16498         * @name guideAutoSaveStart
16499         * @event
16500         * @property {object} payload payload containing more information about the event
16501         * @property {GuideContainerNode} payload.target root Node of the Adaptive Form
16502         * @memberof GuideBridge
16503         * @since 6.1
16504         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Auto Save an Adaptive Form}
16505         * @example
16506         * guideBridge.on("guideAutoSaveStart" , function(event, payload) {
16507         *      console.log("Forms is now being saved as draft automatically");
16508         * }
16509         */
16510        GUIDE_AUTO_SAVE_START : "guideAutoSaveStart",
16511
16512        /**
16513         * @summary Dispatched when save of adaptive form data has started
16514         * @name saveStarted
16515         * @event
16516         * @memberof GuideBridge
16517         * @since 6.1
16518         * @example
16519         * guideBridge.on("saveStarted" , function(event) {
16520         *      console.log("Save of Adaptive Form data is about to start");
16521         * }
16522         */
16523        GUIDE_SAVE_START : "saveStarted",
16524
16525        /**
16526         * @summary Dispatched when save of adaptive form data is completed
16527         * @name saveCompleted
16528         * @event
16529         * @memberof GuideBridge
16530         * @since 6.1
16531         * @example
16532         * guideBridge.on("saveCompleted" , function(event) {
16533         *      console.log("Save of Adaptive Form data is completed");
16534         * }
16535         */
16536        GUIDE_SAVE_COMPLETED : "saveCompleted",
16537
16538        /**
16539         * Users can add some pre submit code in the listener to this event.
16540         * @summary Dispatched when the user clicks on the submit button
16541         * @name submitStart
16542         * @event
16543         * @memberof GuideBridge
16544         * @since 6.0
16545         * @example
16546         * guideBridge.on("submitStart" , function(event) {
16547         *    // do some pre submit processing
16548         * }
16549         */
16550        GUIDE_SUBMIT_START : "submitStart",
16551        GUIDE_PATH : "guidePath",
16552        GUIDE_NAME : "guideName",
16553        GUIDE_DESC : "guideDesc",
16554        GUIDE_TYPE : "guideType",
16555
16556        /**
16557         * @summary Dispatched when an Adaptive Form fragment is lazily loaded successfully
16558         * @name elementLazyLoaded
16559         * @property {object} payload payload containing more information about the event
16560         * @property {Panel} payload.target Adaptive Form Fragment which is lazily loaded
16561         * @event
16562         * @memberof GuideBridge
16563         * @since 6.1 FP1
16564         * @see {@link https://helpx.adobe.com/aem-forms/6-1/lazy-loading-adaptive-forms.html|Lazy Loading Adaptive Form}
16565         * @example
16566         * guideBridge.on("elementLazyLoaded" , function(event, payload) {
16567         *      var component = payload.target;
16568         *      console.log("Panel " + component.name + " loaded");
16569         * }
16570         */
16571        GUIDE_ELEMENT_LAZY_LOADED : "elementLazyLoaded",
16572
16573        /**
16574         * All GuideBridge APIs (except {@link GuideBridge#connect|connect}) require Adaptive Form to be initialized.
16575         * Checking the return value of this API is not necessary if guideBridge API is called only after the
16576         * <a href="#wait-form-ready">Form is initialized</a>
16577         * @summary Whether the Adaptive Form has been initialized or not
16578         *
16579         * @method
16580         * @memberof GuideBridge
16581         * @returns {boolean} true if the Adaptive Form is ready for interaction, false otherwise
16582         * @since 6.0
16583         * @instance
16584         */
16585        isConnected : function () {
16586            if (this._guide) {
16587                return true;
16588            }
16589            return false;
16590        },
16591
16592        /**
16593         * Specify a callback function which is called/notified when Adaptive Form gets initialized. After Adaptive
16594         * Form is initialized GuideBridge is ready for interaction and one can call any API.
16595         *
16596         * The callback can also be registered after the Form gets initialized. In that case, the callback will be
16597         * called immediately.
16598         *
16599         * @summary Register a callback to be executed when the Adaptive Form gets initialized
16600         * @param handler {function} function that would be called when guideBridge is ready for interaction. The
16601         * signature of the callback should be
16602         * ```
16603         * function() {
16604         *     // app specific code here
16605         * }
16606         * ```
16607         * @param {object} [context] _this_ object in the callback function will point to context
16608         * @since 6.0
16609         * @instance
16610         * @method
16611         * @memberof GuideBridge
16612         * @example
16613         * guideBridge.connect(function() {
16614         *    console.log("Hurrah! Guide Bridge Activated");
16615         * })
16616         */
16617        connect : function (handler, context) {
16618            context = context || guideBridge;
16619            if (this.isConnected()) {
16620                // handle exceptions gracefully since it executes in our thread
16621                try {
16622                    handler.call(context);
16623                } catch (exception) {
16624                    // guide model should be initialized in bridge in connect, still adding a null check
16625                    if (this._guide) {
16626                        this._guide.logger().log(exception);
16627                    }
16628                }
16629            } else {
16630                this._guideInitHandler.handler = this._guideInitHandler.handler || [];
16631                this._guideInitHandler.handler.push(handler);
16632                this._guideInitHandler.context = this._guideInitHandler.context || [];
16633                this._guideInitHandler.context.push(context);
16634            }
16635        },
16636
16637        /**
16638         * @private
16639         * @since 6.5
16640         */
16641        _modelConnect : function (handler, context) {
16642            context = context || guideBridge;
16643            if (this.isConnected()) {
16644                // handle exceptions gracefully since it executes in our thread
16645                try {
16646                    handler.call(context);
16647                } catch (exception) {
16648                    // guide model should be initialized in bridge in connect, still adding a null check
16649                    if (this._guide) {
16650                        this._guide.logger().log(exception);
16651                    }
16652                }
16653            } else {
16654                this._guideModelInitHandler.handler = this._guideModelInitHandler.handler || [];
16655                this._guideModelInitHandler.handler.push(handler);
16656                this._guideModelInitHandler.context = this._guideModelInitHandler.context || [];
16657                this._guideModelInitHandler.context.push(context);
16658            }
16659
16660        },
16661
16662        _guideModelInitialized : function (e) {
16663            this._guide = e.guide;
16664            if (this._guideModelInitHandler.handler) {
16665                for (var i = 0; i < this._guideModelInitHandler.handler.length; i++) {
16666                    try {
16667                        this._guideModelInitHandler.handler[i].call(this._guideModelInitHandler.context[i]);
16668                    } catch (exception) {
16669                        // guide model should be initialized in bridge in connect, still adding a null check
16670                        if (this._guide) {
16671                            this._guide.logger().log(exception);
16672                        }
16673                    }
16674                }
16675            }
16676        },
16677
16678        /*
16679         *
16680         * Handler for guideInitialized event which is fired by Adaptive Form library after Adaptive Form Dom is initialized
16681         *
16682         * @private
16683         */
16684        _guideInitialized : function (e) {
16685            if (this._guideInitHandler.handler) {
16686                for (var i = 0; i < this._guideInitHandler.handler.length; i++) {
16687                    try {
16688                        this._guideInitHandler.handler[i].call(this._guideInitHandler.context[i]);
16689                    } catch (exception) {
16690                        // guide model should be initialized in bridge in connect, still adding a null check
16691                        if (this._guide) {
16692                            this._guide.logger().log(exception);
16693                        }
16694                    }
16695                }
16696            }
16697            window.guideBridge.trigger("bridgeInitializeComplete",
16698                guidelib.event.GuideModelEvent.createEvent(
16699                    "bridgeInitializeComplete",
16700                    guideBridge
16701                )
16702            );
16703        },
16704        _setGuideView : function (guideView) {
16705            this._guideView = guideView;
16706        },
16707        _guideError : function (e) {
16708            this._guide.logger().debug("AF", e);
16709        },
16710        _checkGuide : function (obj) {
16711            if (!this._guide) {
16712                obj.addMessage(1, "Guide Dom not Initialized", "");
16713                return false;
16714            }
16715            return true;
16716        },
16717        /**
16718         * @summary returns the version of GuideBridge library
16719         * @returns {string} the version of the GuideBridge library
16720         * @method getBridgeVersion
16721         * @memberof GuideBridge
16722         * @instance
16723         * @since 6.0
16724         */
16725        getBridgeVersion : function () {
16726            return this._version;
16727        },
16728
16729        /**
16730         * Callback to execute when bridgeInitializeStart is triggered.
16731         * @callback GuideBridge~postExternalCallback
16732         * @param {string} name constant string `bridgeInitializeStart`
16733         * @param {object} data object containing the GuideBridge instance
16734         * @param {GuideBridge} data.guideBridge instance of GuideBridge
16735         * @since 6.0
16736         * @deprecated since 6.3 this callback is deprecated. One must do the handling in
16737         * {@link GuideBridge.events:bridgeInitializeStart} event
16738         * @memberof GuideBridge
16739         * @see GuideBridge#registerConfig
16740         * @see GuideBridge~postExternalMessageConfig
16741         */
16742        /**
16743         * @typedef {object} GuideBridge~postExternalMessageConfig
16744         * @property {GuideBridge~postExternalCallback} postExternalHandler callback to be executed when GuideBridge
16745         * instance is available
16746         * @since 6.0
16747         * @deprecated since 6.3 this configuration is deprecated. One must do the handling in
16748         * {@link GuideBridge.events:bridgeInitializeStart} event
16749         * @memberof GuideBridge
16750         * @see GuideBridge#registerConfig
16751         */
16752        /**
16753         * @typedef {object} GuideBridge~submitConfig
16754         * @property {HTMLFormElement} form During submission Adaptive Form creates a new HTMLFormElement and puts all the
16755         * value in that Form. One can provide an existing HTMLFormElement that will be reused for submitting the Form. The
16756         * action and method property of the Form element will be ignored.
16757         * @property {boolean} useAjax submit the form via a XMLHttpRequest rather than using a HTMLFormElement
16758         * instance is available
16759         * @property {function} submitSuccessHandler success Handler to be called post submission. This option is ignored
16760         * if _useAjax_ is set to false
16761         * @since 6.0
16762         * @memberof GuideBridge
16763         * @see GuideBridge#registerConfig
16764         */
16765        /**
16766         * @typedef {object} GuideBridge~renderConfig
16767         * @property {boolean} enableFocusOnFirstField option to enable focus on first field. Default value is true.
16768         * @since 6.5
16769         * @memberof GuideBridge
16770         * @see GuideBridge#registerConfig
16771         */
16772        /**
16773         * Adaptive Form uses some default named configurations to provide its default behaviour. This configurations
16774         * can be modified by providing a new configuration.
16775         *
16776         * The API accepts the name of the configuration and updated configuration. Based on value of the new
16777         * configuration the behaviour of the Form gets changed.
16778         * Currently supported configurations are:
16779         * #### postExternalMessageConfig
16780         *
16781         * <div class="deprecated"><span class="deprecated-heading">Deprecated :</span><span> since 6.2 this
16782         * configuration is deprecated. Use the {@link GuideBridge.events:bridgeInitializeStart} event to do the same
16783         * handling</span>
16784         * </div>
16785         * In case Adaptive Form is embedded inside an iframe, this configuration allows developers to provide
16786         * GuideBridge Instance to parent or child windows.
16787         *
16788         * By default, GuideBridge instance is only available to the current window and to the parent window if it
16789         * doesn't violate the cross-origin policy. Now there may be a case when this doesn't solves the problem, then
16790         * one can take advantage of this configuration to extend this functionality.
16791         *
16792         * For the signature of the configuration see
16793         * {@link GuideBridge~postExternalMessageConfig|postExternalMessageConfig}
16794         * ##### Example
16795         * To provide the GuideBridge instance to a child window
16796         * ```
16797         * window.on("bridgeInitializeStart", function (evnt) {
16798         *      var gb = evnt.detail.guideBridge;
16799         *      gb.registerConfig("postExternalMessageConfig", {
16800         *          "postExternalHandler" : function(data) {
16801         *              // assume we have a child window with an id 'childWindowId'
16802         *              var childWindow = document.getElementById("#childWindowId").contentWindow;
16803         *              var tmpEvent = document.createEvent("CustomEvent");
16804         *              tmpEvent.initCustomEvent(data.name, true, true, data.data);
16805         *              childWindow.dispatchEvent(tmpEvent);
16806         *          }
16807         *      });
16808         * });
16809         * ```
16810         * #### widgetConfig
16811         * The configuration is used to modify the appearance of a specific Field. Adaptive Form allows developers to
16812         * [create custom widgets](http://helpx.adobe.com/aem-forms/6-1/custom-appearance-widget-adaptive-form.html) and
16813         * use them in their Forms.
16814         *
16815         * The signature of the config is
16816         * ```
16817         * { "<component-identifier> : "<widget-name>"}
16818         * ```
16819         * where `<component-identifier>` can be either the name or classname of Adaptive Form Field,
16820         * while widget name is the name of the jQuery Widget.
16821         *
16822         * #### submitConfig
16823         * To modify the default submit behaviour one can provide this configuration. The signature of the config is
16824         * defined {@link GuideBridge~submitConfig|below}
16825         * ```
16826         * guideBridge.registerConfig("submitConfig", {"useAjax" : true});
16827         * ```
16828         *
16829         * #### renderConfig
16830         * To modify the default render behaviour one can provide this configuration. The signature of the config is
16831         * defined {@link GuideBridge~renderConfig|below}
16832         * ```
16833         * guideBridge.registerConfig("renderConfig", {"enableFocusOnFirstField" : false});
16834         * ```
16835         * @summary Registers user/portal specific configurations to GuideBridge
16836         * @returns {GuideResultObject} {@link GuideResultObject} with {@link GuideResultObject#data|data} having the
16837         * old configuration against the same _key_
16838         *
16839         * @param key {string} configuration name. one of the following
16840         * * postExternalMessageConfig
16841         * * widgetConfig
16842         * * submitConfig
16843         * * renderConfig
16844         * @param {widgetConfig|GuideBridge~submitConfig|GuideBridge~renderConfig|GuideBridge~postExternalMessageConfig} [config] configuration object for the configuration
16845         * @method
16846         * @memberof GuideBridge
16847         * @since 6.0
16848         * @instance
16849         */
16850        registerConfig : function (key, config) {
16851            var obj = new GuideResultObject();
16852            obj.data = this.userConfig[key];
16853            this.userConfig[key] = config;
16854            obj.completed = true;
16855            return obj;
16856        },
16857
16858        /**
16859         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16860         * fileAttachmentMap key should be present in the map.
16861         * @name customContextProperty
16862         * @param value {object} object to be replaced with the current customPropertyMap.
16863         * @memberof GuideBridge
16864         * @method
16865         * since 6.0
16866         */
16867
16868        /**
16869         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16870         * fileAttachmentMap key should be present in the map.
16871         * @name customContextProperty
16872         * @param property {string} object to be replaced with the current customPropertyMap.
16873         * @method
16874         * @memberof GuideBridge
16875         * since 6.0
16876         */
16877
16878        /**
16879         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16880         * fileAttachmentMap key should be present in the map.
16881         * @param property {string} property to update in the custom property map
16882         * @param value {*} value of the property
16883         * @return {*} old value of the property
16884         * since 6.0
16885         */
16886        customContextProperty : function (property, value) {
16887            var customPropertyMap = getOrElse(guidelib, "__runtime__.guideContext.customPropertyMap", {});
16888            // use both the customContextProperty map since customers also access that
16889            var newCustomPropertyMap = _.extend({}, customPropertyMap, getOrElse(this._guide, "runtime.guideContext.customPropertyMap", {}));
16890            if (_.isUndefined(value)) {
16891                if (_.isObject(property)) {
16892                    guideBridge._modelConnect((function (newCustomPropertyMap, property) {
16893                        return function () {
16894                            var localMap = _.extend({}, guideBridge._guide.runtime.guideContext.customPropertyMap, newCustomPropertyMap);
16895                            _.extend(localMap, property);
16896                            guideBridge._guide.runtime.guideContext.customPropertyMap = localMap;
16897                        };
16898                    })(newCustomPropertyMap, property));
16899                } else {
16900                    return newCustomPropertyMap[property];
16901                }
16902            } else {
16903                var oldValue = newCustomPropertyMap[property];
16904                guideBridge._modelConnect((function (property, value, newCustomPropertyMap) {
16905                    return function () {
16906                        var localMap = _.extend({}, guideBridge._guide.runtime.guideContext.customPropertyMap, newCustomPropertyMap);
16907                        localMap[property] = value;
16908                        guideBridge._guide.runtime.guideContext.customPropertyMap = localMap;
16909                    };
16910                })(property, value, newCustomPropertyMap));
16911                return oldValue;
16912            }
16913        },
16914
16915        getNavigablePanel : function (somExpression) {
16916            return this._guideView.getSomOnNavigableAncestor(somExpression);
16917        },
16918
16919        /**
16920         * Sets the value of a property for a set of {@link GuideNode} to a different value. Property must be a valid
16921         * writable property for that Node
16922         *
16923         * Each entry in _somList_ should have a corresponding entry in the _valueList_. Mismatch in the length of these
16924         * two arguments will make the function do nothing
16925         * @summary Modify a property for a set of Nodes
16926         * @method setProperty
16927         * @param {string[]} somList an array having someExpression for the nodes. Invalid SomExpressions and
16928         * the corresponding value in the _valueList_ are ignored.
16929         * @param {string} propertyName name of the property which has to be modified
16930         * @param {Array.<*>} valueList an array containing value of the _propertyName_ for each element in _somList_
16931         *
16932         * @memberof GuideBridge
16933         * @instance
16934         * @since 6.0
16935         * @see GuideNode#somExpression
16936         * @example <caption>Modifying the value of a set of fields</caption>
16937         * guideBridge.setProperty(["SOM_OF_FIELD_1", "SOM_OF_FIELD_2"...... "SOM_OF_FIELD_N"]
16938         *                          "value"
16939         *                          [VALUE_1, VALUE_2 .... VALUE_N]);
16940         * @example <caption>Hiding a single field</caption>
16941         * guideBridge.setProperty(["SOM_OF_FIELD_1"]
16942         *                          "visibility"
16943         *                          [false]);
16944         */
16945        setProperty : function (somList, propertyName, valueList) {
16946            if (!propertyName) {
16947                return;
16948            }
16949            if (!_.isArray(somList) || !_.isArray(valueList)) {
16950                return;
16951            }
16952            if (somList.length !== valueList.length) {
16953                return;
16954            }
16955            var gb = this;
16956            _.each(somList, function (som, index) {
16957                var node = gb.resolveNode(som);
16958                if (node) {
16959                    node[propertyName] = valueList[index];
16960                } else {
16961                    gb._guide.logger().log("som not valid:" + som);
16962                }
16963            });
16964            if (!this._guide._currentContext) {
16965                this._guide.runPendingExpressions();
16966            }
16967        },
16968
16969        /**
16970         * Used to retrieve the Form data as XML. The API gets the data xml synchronously/asynchronously based on the
16971         * _async_ option and invokes the success/error handlers passed in the arguments upon completion.
16972         *
16973         * In the success callback the {@link GuideResultObject#data|data} parameter contains the xml string.
16974         *
16975         * The success and error handlers receive {@link GuideResultObject} as input.
16976         * @summary Return Form data as XML.
16977         *
16978         * @param {object} options input to the getDataXML API
16979         * @param {function} [options.success] callback which receives the result of the API
16980         * in case of success.
16981         * @param {function} [options.error] callback which receives the result of the API in
16982         * case of failure.
16983         * {@link GuideResultObject#errors|errors} property as true.
16984         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
16985         * object
16986         * @param {boolean} [options.async=true] whether to make the server call asynchronously or not. If false, the
16987         * browser will wait for the server to return the XML and then execute the success or error callbacks object
16988         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
16989         * @method
16990         * @memberof GuideBridge
16991         * @since 6.0
16992         * @instance
16993         * @example
16994         * guideBridge.getDataXML({
16995         *     success : function (guideResultObject) {
16996         *          console.log("xml data received" + guideResultObject.data);
16997         *     }
16998         *     error : function (guideResultObject) {
16999         *          console.error("API Failed");
17000         *          var msg = guideResultObject.getNextMessage();
17001         *          while (msg != null) {
17002         *              console.error(msg.message);
17003         *              msg = guideResultObject.getNextMessage();
17004         *          }
17005         *     }
17006         * });
17007         *
17008         * @deprecated since 6.3 this API is deprecated. Use getData API instead.
17009         * @param options
17010         */
17011        getDataXML : function (options) {
17012            guideBridge.getData(options);
17013        },
17014
17015        /**
17016         * Used to retrieve the Form data as XML or JSON depending on the Schema Type. Only for JSON Schema based Forms
17017         * and Form Data Model based forms, the data will be in JSON format while for others, the data will be in XML format.
17018         * The API gets the data synchronously/asynchronously based on the
17019         * _async_ option and invokes the success/error handlers passed in the arguments upon completion.
17020         *
17021         * In the success callback the {@link GuideResultObject#data|data} parameter contains the data string.
17022         *
17023         * The success and error handlers receive {@link GuideResultObject} as input.
17024         * @summary Return Form data as XML or JSON depending on the Schema Type.
17025         *
17026         * @param {object} options input to the getData API
17027         * @param {function} [options.success] callback which receives the result of the API
17028         * in case of success.
17029         * @param {function} [options.error] callback which receives the result of the API in
17030         * case of failure.
17031         * {@link GuideResultObject#errors|errors} property as true.
17032         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
17033         * object
17034         * @param {boolean} [options.async=true] whether to make the server call asynchronously or not. If false, the
17035         * browser will wait for the server to return the data (XML or JSON) and then execute the success or error callbacks object
17036         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
17037         * @method
17038         * @memberof GuideBridge
17039         * @since 6.3
17040         * @instance
17041         * @example
17042         * guideBridge.getData({
17043         *     success : function (guideResultObject) {
17044         *          console.log("data received" + guideResultObject.data);
17045         *     }
17046         *     error : function (guideResultObject) {
17047         *          console.error("API Failed");
17048         *          var msg = guideResultObject.getNextMessage();
17049         *          while (msg != null) {
17050         *              console.error(msg.message);
17051         *              msg = guideResultObject.getNextMessage();
17052         *          }
17053         *     }
17054         * });
17055         * @deprecated use {@link GuideBridge#getFormDataString} instead
17056         */
17057        getData : function (options) {
17058            options = options || {};
17059
17060            /* Earlier this API would support boundData for getting data tro be merged in PDF. Now that flag has been renamed to dorData
17061             *  Earlier, boundData flag now maps to boundData for backward compatibility.
17062             * */
17063            options.dorData = options.dorData || options.boundData;
17064
17065            var resultObject = new GuideResultObject();
17066            if (!options.guideState && !this._checkGuide(resultObject)) {
17067                options.error.call(options.context, resultObject);
17068                return;
17069            }
17070
17071            this._submitInternal({
17072                success : function (data) {
17073                    var resultJson = data || {};
17074                    resultObject.completed = true;
17075                    if (options.dorData) {
17076                        resultObject.data = resultJson["dorDataXml"];
17077                    } else {
17078                        resultObject.data = resultJson["data"];
17079                    }
17080                    if (_.isFunction(options.success)) {
17081                        options.success.call(options.context, resultObject);
17082                    }
17083                },
17084                error : function (xhr, txtStatus, errorThrown) {
17085                    var msg = "Error in getData API";
17086                    resultObject.completed = false;
17087                    resultObject.addMessage(2, msg, "");
17088                    if (_.isFunction(options.error)) {
17089                        options.error.call(options.context, resultObject);
17090                    }
17091                },
17092                guideState : options.guideState,
17093                async : options.async,
17094                fileUploadPath : options.fileUploadPath,
17095                excludeFormState : options.excludeFormState || false,
17096                dorData : options.dorData || false
17097            });
17098        },
17099
17100
17101        /**
17102         * returns form data object {@link FormData}
17103         * @returns {*}
17104         * @private
17105         */
17106        _getFormDataObj : function() {
17107            guideBridge._updateAFSubmissionInfo();
17108            guideBridge._guide.internal.liveDataUtils.updateLiveData(null, true); // fetching client side data
17109            guideBridge._guide.internal.liveDataUtils.insertSubmissionInfo(guideBridge._guide.runtime.guideContext.afSubmissionInfo);
17110            var data =  guideBridge._guide.internal.liveDataUtils.getLiveDataStr();
17111            var contentType = "application/xml";
17112            if (guideBridge._guide.internal.liveDataUtils instanceof guidelib.model.LiveJsonUtils) {
17113                contentType = "application/json";
17114            }
17115            return new guidelib.model.FormData({
17116                "data": data,
17117                "contentType" : contentType,
17118                "attachments": guideBridge.getFileAttachmentWrapper()
17119            });
17120        },
17121
17122        /**
17123         * invoked inside server-side-validation to return excludeFromDor data.
17124         * @param  {Object} guide input to _getExcludeFromDorData API
17125         * @returns {Array} containing excludeFromDoR info
17126         * */
17127        _getExcludeFromDorData : function (guide) {
17128            var newGuide = guide ? guide : guideBridge._guide;
17129            var excludeFromDorData = null;
17130            window.guideBridge._updateAFSubmissionInfo(newGuide);
17131            var afSubmissionInfo = newGuide.runtime.guideContext.afSubmissionInfo;
17132            if(afSubmissionInfo.excludeFromDoR) {
17133                excludeFromDorData = afSubmissionInfo.excludeFromDoR;
17134            }
17135            return excludeFromDorData;
17136        },
17137
17138
17139        /**
17140         * returns FormData object {@link FormData} containing form data xml or json and attachments
17141         * @param {object} options input to the getData API
17142         * @param {function} [options.success] callback which receives the result of the API
17143         * in case of success.
17144         * @method
17145         * @memberof GuideBridge
17146         * @since 6.5
17147         * @instance
17148         */
17149        getFormDataObject : function (options) {
17150            var formDataObj = guideBridge._getFormDataObj();
17151            var resultObject = new GuideResultObject();
17152            resultObject.data = formDataObj;
17153            if (options && typeof options.success === 'function') {
17154                options.success(resultObject);
17155            }
17156        },
17157
17158        /**
17159         * returns string representation of form data xml or json
17160         * @param {object} options input to the getData API
17161         * @param {function} [options.success] callback which receives the result of the API
17162         * in case of success.
17163         * @method
17164         * @memberof GuideBridge
17165         * @since 6.5
17166         * @instance
17167         */
17168        getFormDataString : function (options) {
17169            var formDataObj = guideBridge._getFormDataObj();
17170            var resultObject = new GuideResultObject();
17171            resultObject.data = formDataObj.data;
17172            if (options && typeof options.success === 'function') {
17173                options.success(resultObject);
17174            }
17175        },
17176
17177        /**
17178         * @summary Hides all the submit buttons present in the Adaptive Form
17179         *
17180         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17181         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors|errors} property.
17182         * @memberof GuideBridge
17183         * @instance
17184         * @since 6.0
17185         */
17186        hideSubmitButtons : function () {
17187            return this._hideElements("guideButton", "submit");
17188        },
17189
17190        /**
17191         * This API is designed to evaluate the expression entered by the author.
17192         * This API is given only to enable Auto Save meta information use case.
17193         * @returns value obtained after executing the expression.
17194         * @method
17195         * @private
17196         * @memberof GuideBridge
17197         * @deprecated since 6.3 this API is deprecated
17198         */
17199        _evaluateExpression : function (expression) {
17200            if (this._guide) {
17201                var compiledExpression = this._guide._compileExpression(expression, null);
17202                return compiledExpression.apply(this._guide);
17203            }
17204        },
17205
17206        /**
17207         * Adaptive Form can be configured to save draft automatically. This property indicates whether Adaptive Form is
17208         * configured to save draft automatically or not.
17209         *
17210         * Enabling auto save doesn't mean that AF will create the draft when the Form is loaded. Based on the result of
17211         * **Auto save start expression** the draft will be created. Once the expression returns true, drafts will be
17212         * saved at regular interval or at specific events as configured.
17213         *
17214         * @summary Whether autoSave is enabled for this Adaptive Form or not
17215         * @returns {boolean} true if auto save is enabled otherwise false.
17216         * @method
17217         * @memberof GuideBridge
17218         * @instance
17219         * @since 6.1 FP1
17220         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Saving an adaptive Form}
17221         */
17222        getAutoSaveEnabledStatus : function () {
17223            var _isAutoSaveEnable = false;
17224            // check if form is loaded or not, if loaded then check for auto save
17225            if (this.isConnected()) {
17226                _isAutoSaveEnable = this._guide.enableAutoSave;
17227            }
17228            return _isAutoSaveEnable;
17229        },
17230
17231        /**
17232         * This API indicates that auto save is enabled and draft is being saved at the configured location.
17233         * @summary Whether Adaptive Form data is being saved as draft or not.
17234         * @returns {Boolean} whether autoSave has started.
17235         * @method
17236         * @memberof GuideBridge
17237         * @instance
17238         * @since 6.1 FP1
17239         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Saving an adaptive Form}
17240         **/
17241        hasAutoSaveStarted : function () {
17242            return this._guide && this._guide.enableAutoSave && this._guide.autoSaveStart;
17243        },
17244
17245        /**
17246         * @summary the autoSaveinfo that is stored at the guideContainer.
17247         * @returns {object} object contains the additional meta information stored along with form data
17248         * @method
17249         * @memberof GuideBridge
17250         * @instance
17251         * @since 6.1 FP1
17252         * @deprecated since 6.3
17253         */
17254        getAutoSaveInfo : function () {
17255            return this._guide.autoSaveInfo;
17256        },
17257
17258        /**
17259         * The API is used to provide extra information to be saved in Final data XML. It can also be used to retrieve
17260         * that information.
17261         *
17262         * If _value_ is null then the value of the _property_ is returned
17263         * @summary store or retrieve submission related information
17264         * @param {string} property name of the property against which to save the value or retrieve the value of
17265         * property
17266         * @param {string} [value] value to save.
17267         * @returns {*} old value of the property
17268         * @method
17269         * @since 6.1 FP1
17270         * @memberof GuideBridge
17271         * @instance
17272         * @deprecated since 6.3
17273         */
17274        afSubmissionInfo : function (property, value) {
17275            var afSubmissionInfo = guideBridge._guide.runtime.guideContext.afSubmissionInfo || {};
17276            if (_.isUndefined(value)) {
17277                return afSubmissionInfo[property];
17278            } else {
17279                var oldValue = afSubmissionInfo[property];
17280                afSubmissionInfo[property] = value;
17281                guideBridge._guide.runtime.guideContext.afSubmissionInfo = afSubmissionInfo;
17282                return oldValue;
17283            }
17284        },
17285
17286        /**
17287         * @summary returns the globalMetaInfo object after all the computation. This object will be set in guideContext for submission
17288         * @returns {object} In a format {"key 1": computation result of registered expression, "key 2":...}
17289         * @method
17290         * @since 6.1 FP1
17291         * @memberof GuideBridge
17292         * @instance
17293         * @example
17294         * {
17295         *   "key 1": computation result of registered expression,
17296         *   ...
17297         * }
17298         * @deprecated since 6.3
17299         */
17300        getComputedSubmissionMetadata : function () {
17301            var computedMetadata = {},
17302                currentMetadata = null,
17303                compiledExpression = null,
17304                metadata = this.getSubmissionMetadataInfo();
17305            if (metadata) {
17306                if (_.isObject(metadata)) {
17307                    for (var key in metadata) {
17308                        try {
17309                            currentMetadata = JSON.parse(metadata[key]);
17310                            compiledExpression = this._guide._compileExpression(currentMetadata["value"]);
17311                            computedMetadata[currentMetadata["key"]] = compiledExpression.apply(this._guide);
17312                        } catch (exception) {
17313                            if (this._guide) {
17314                                this._guide.logger().log(exception);
17315                            }
17316                        }
17317                    }
17318                } else if (_.isString(metadata)) {
17319                    try {
17320                        currentMetadata = JSON.parse(metadata);
17321                        compiledExpression = this._guide._compileExpression(currentMetadata["value"]);
17322                        computedMetadata[currentMetadata["key"]] = compiledExpression.apply(this._guide);
17323                    } catch (exception) {
17324                        if (this._guide) {
17325                            this._guide.logger().log(exception);
17326                        }
17327                    }
17328                }
17329            }
17330            return computedMetadata;
17331        },
17332
17333        /**
17334         * @summary this API returns the globalMetaInfo stored in global context (in globalMetaInfo tab).
17335         * @returns {object}
17336         * @method
17337         * @memberof GuideBridge
17338         * @instance
17339         * @deprecated since 6.3
17340         */
17341        getGlobalMetaInfo : function () {
17342            return this._guide.globalMetaInfo;
17343        },
17344
17345        /**
17346         * @summary this API returns the metadata configured for submission. Value depends on the selection of metadata
17347         * type, local or global.
17348         * @returns {Object}
17349         * @method
17350         * @since 6.1 FP1
17351         * @memberof GuideBridge
17352         * @instance
17353         * @deprecated since 6.3
17354         */
17355        getSubmissionMetadataInfo : function () {
17356            if (this._guide.submissionMetaInfo && this._guide.submissionMetaInfo.metadataselector === LOCAL_METADATA_SELECTOR) {
17357                // In order to maintain backward compatibility, this piece of code will always be here.
17358                // For the cases where metadata selection is being configured for submit actions
17359                return getOrElse(this._guide, "submissionMetaInfo.metadata", null);
17360            } else {
17361                //From 6.2 onwards, we are asking author to provide metadata only at one place, which is global to whole form
17362                // In case, metadataselector's value is "global" or not configured at all, this block will get executed
17363                return getOrElse(this._guide, "globalMetaInfo.metadata", null);
17364            }
17365        },
17366
17367        /**
17368         * The API enables auto save in Adaptive Form
17369         * @summary  enable auto save in Adaptive Form.
17370         * @param value {boolean} true to enable auto save otherwise false.
17371         * @method
17372         * @memberof GuideBridge
17373         * @instance
17374         * @since 6.1 FP1
17375         * @see {@link GuideBridge#getAutoSaveEnabledStatus|getAutoSaveEnabledStatus}
17376         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Auto Save an Adaptive Form}
17377         */
17378        setEnabledAutoSave : function (value) {
17379            this._guide.enableAutoSave = value;
17380        },
17381
17382        /**
17383         * @summary Hides all the file attachment listing buttons present in the Adaptive Form
17384         *
17385         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17386         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17387         * @memberof GuideBridge
17388         * @instance
17389         * @since 6.0
17390         */
17391        hideFileAttachmentListingButtons : function () {
17392            return this._hideElements("guideListFileAttachmentButton");
17393        },
17394
17395        /**
17396         * @todo: Function can change as per usecase, it can behave as a wrapper
17397         * where it can use the configuration provided through registerConfig and invoke any callback if required
17398         *
17399         * @returns {boolean} boolean indicating whether Adaptive Form is offline
17400         * @private
17401         */
17402        isOffline : function () {
17403            return checkAFOffline;
17404        },
17405
17406        /**
17407         * function to set the status of Adaptive Form (online or offline)
17408         * @type {boolean}
17409         * @private
17410         */
17411        setIsOffline : function (value) {
17412            checkAFOffline = value;
17413        },
17414
17415        /**
17416         * @summary Hide all the File Attachment component present in the Adaptive Form
17417         *
17418         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17419         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17420         * @memberof GuideBridge
17421         * @instance
17422         * @since 6.0
17423         */
17424        hideFileAttachments : function () {
17425            return this._hideElements("guideFileUpload");
17426        },
17427
17428        /**
17429         * @summary Hides the global toolbar of the Adaptive Form.
17430         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17431         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17432         * @memberof GuideBridge
17433         * @instance
17434         * @since 6.0
17435         */
17436        hideGlobalToolbar : function () {
17437            var resultObject = new GuideResultObject(),
17438                $toolbar;
17439
17440            // If guide dom not initialized, return
17441            if (!this._checkGuide(resultObject)) {
17442                return resultObject;
17443            }
17444
17445            if (guideBridge._guide.toolbar) {
17446                $toolbar = this._getGuideDomElement(guideBridge._guide.toolbar.somExpression);
17447                if ($toolbar && $toolbar.length > 0) {
17448                    $toolbar.hide();
17449                }
17450            }
17451
17452            resultObject.completed = true;
17453            return resultObject;
17454        },
17455
17456        /*
17457         *
17458         * This API is designed to return all the toolbar buttons present in the Adaptive Form(except submit, save, reset and file attachment listing)
17459         *
17460         * @returns {GuideResultObject} data contains an array of all the tool bar buttons available(except submit, save, reset and file attachment listing)
17461         * Each element of data property is an object holding model and html property.
17462         * The html string does not contain any script tags, this is to avoid crosss site scripting attacks
17463         */
17464        /*
17465         getToolbarButtons : function(){
17466         var resultObject = new GuideResultObject(),
17467         resultData = [],
17468         $elem = null;
17469         // If guide dom not initialized, return
17470         if (!this._checkGuide(resultObject)) {
17471         return resultObject;
17472         }
17473         resultObject.completed = true;
17474         this.visit(function(node){
17475         // Check if this node is a guide button and if it resides inside a guideToolBar
17476         if(node.className === "guideButton" && node.parent.className === "guideToolbar"){
17477         if(node.type !== "submit" && node.type !== "save" && node.type !== "fileattachmentlisting" && node.type !== "next" && node.type !=="prev") {
17478         $elem =  this._getGuideDomElement(node.somExpression);
17479         // Remove the script tag from the $html, we don't support execution of Adaptive Form Scripts in parent or other domain
17480         // This is to avoid cross site scripting attacks
17481         $elem.find("script").remove();
17482         resultData.push({
17483         "model" : node,
17484         "html"  : $elem.html()
17485         });
17486         }
17487         }
17488         });
17489         resultObject.data = resultData;
17490         return resultObject;
17491         }, */
17492
17493        /**
17494         * @summary Hides all the save buttons present in the Adaptive Form
17495         *
17496         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17497         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17498         * @memberof GuideBridge
17499         * @instance
17500         * @since 6.0
17501         */
17502        hideSaveButtons : function () {
17503            return this._hideElements("guideButton", "save");
17504        },
17505
17506        /**
17507         * @summary Hides all the reset buttons present in the Adaptive Form
17508         *
17509         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17510         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17511         * @memberof GuideBridge
17512         * @instance
17513         * @since 6.3
17514         */
17515        hideResetButtons : function () {
17516            return this._hideElements("guideButton", "reset");
17517        },
17518
17519        /**
17520         * The API can be used to retrieve the value of a specific property for a list of AF components. If the property
17521         * doesn't exists for a component then the corresponding value in the resulting array will be null.
17522         *
17523         * The {@link GuideResultObject#data|data} element of the return object will be an array containing the values
17524         * of the _property_ for each component in the list of components
17525         *
17526         * The API fails if the Form is not initiailzed
17527         *
17528         * **_Note:_** If a somExpression provided doesn't points to a valid {@link GuideNode} null is returned for
17529         * that element and an error message is added in the returned object
17530         * @summary returns the value of a specific property for a set of Adaptive Form Components
17531         *
17532         * @param {object} options input object containing the propertyName and the list of components
17533         * @param {string} options.propertyName name of the property whose value has to be returned
17534         * @param {string[]} options.somExpression list of somExpression of the components for which the value is to be
17535         * returned.
17536         *
17537         * @returns {GuideResultObject} The {@link GuideResultObject#data|data} member of the object contains the property
17538         * values
17539         * @method
17540         * @memberof GuideBridge
17541         * @since 6.0
17542         * @instance
17543         * @deprecated since 6.3
17544         * @see GuideNode#somExpression
17545         * @example
17546         * var result = guideBridge.getElementProperty({
17547         *    propertyName: "value",
17548         *   somExpression: ["somExpression1", "somExpression2"]
17549         * });
17550         * if (result.errors) {
17551         *      console.log("some som expressions were invalid");
17552         *      var err = result.getNextMessage();
17553         *     while(err != null) {
17554         *          //err.somExpression will point to the invalid somExpression in the Field.
17555         *          console.log(err.message);
17556         *     }
17557         * }
17558         * for(var i = 0; i< result.data.length; i++) {
17559         *      console.log(result.data[i]);
17560         * }
17561         */
17562        getElementProperty : function (options) {
17563            var somExpressions = options.somExpressions;
17564            var propertyName = options.propertyName;
17565            var resultObject = new GuideResultObject();
17566            if (!this._checkGuide(resultObject)) {
17567                return resultObject;
17568            }
17569            resultObject.data = [];
17570            for (var i = 0; i < somExpressions.length; i++) {
17571                var element = this.resolveNode(somExpressions[i]);
17572                if (element == null) {
17573                    resultObject.addMessage(0, "No element " + somExpressions[i] + " exists", somExpressions[i]);
17574                    resultObject.data.push(null);
17575                } else {
17576                    resultObject.completed = true;
17577                    resultObject.data.push(element[propertyName]);
17578                }
17579            }
17580            return resultObject;
17581        },
17582
17583        _getGuideDomElement : function (somExpression, option) {
17584            if (this._guideView) {
17585                return this._guideView._getGuideDomElement(somExpression, option);
17586            } else {
17587                return null;
17588            }
17589        },
17590
17591        getTempPath : function () {
17592            return "/tmp/fd/af/" + this._getUUID();
17593        },
17594
17595        /**
17596         * File Attachment object
17597         * @typedef {object} GuideBridge~FileAttachementObject
17598         * @property {string} name name of the uploaded File
17599         * @property {string} path path of the uploaded File
17600         * @memberof GuideBridge
17601         * @since 6.0
17602         */
17603        /**
17604         * Success callback that is called from {@link GuideBridge#getFileAttachmentsInfo} with the list of File
17605         * Attachments
17606         * @callback GuideBridge~FileAttachmentInfoHandler
17607         * @param {GuideBridge~FileAttachementObject[]} fileAttachementList list of file attachement objects uploaded
17608         * in the Form
17609         */
17610        /**
17611         * The API provides a list containing File Names and File URLS for the Files Attached by the user using the
17612         * File Attachment component. The API is a asynchronous API and takes success handler which is called with
17613         * the list of File Names and URLs.
17614         *
17615         * @param {object} options Object containing the callback which will be invoked with the result of this API
17616         * @param {function} options.success success callback which will be invoked. The signature of the callback should
17617         * match the signature of {@link GuideBridge~FileAttachmentInfoHandler|FileAttachmentInfoHandler}
17618         * @param {object} [options.context] _this_ parameter in the success handler will point to this object
17619         *
17620         * @example  <caption>Example usage of the getFileAttachmentsInfo API</caption>
17621         * guideBridge.getFileAttachmentsInfo({
17622         *        success:function(list) {
17623         *             for(var i = 0; i< list.length; i++) {
17624         *                  console.log(list[i].name + " "+ list[i].path);
17625         *             }
17626         *        }
17627         * });
17628         * @method
17629         * @memberof GuideBridge
17630         * @since 6.0
17631         * @instance
17632         */
17633        getFileAttachmentsInfo : function (options) {
17634            var fileAttachmentsList = this._getFileAttachmentsList(),
17635                list;
17636
17637            function collectFileUrls(event) {
17638                list = [];
17639                //TODO: need to modularize collectFileUrs()
17640                // here this is the context of the function who calls it
17641                _.each(this.attachments, function (att) {
17642                    list.push({name : att.split("/")[1], path : this.fileUrl + "/" + att});
17643                }, this);
17644                if (this.options.success) {
17645                    this.options.success.call(this.options.context, list);
17646                }
17647            }
17648            var optionArgument = {"options" : options,
17649                "fileAttachmentsList" : fileAttachmentsList,
17650                "fileUploadPath" : this.getTempPath(),
17651                "callback" : collectFileUrls
17652            };
17653            this._getGuideAttachments(optionArgument);
17654        },
17655
17656        /**
17657         * Syntax - argObject : {"options" : options to be passed to the callback,
17658         *                   "fileAttachmentsList" : fileAttachmentsList,
17659         *                    "fileUploadPath" :fileUploadPath
17660         *                     "callback" :callback, "errorCallback" :errorCallback}
17661         * @param {object}
17661 argObject Input object containing the callbacks that will be invoked
17662         * to provide the result of the API
17663         * @private
17664         * @memberof GuideBridge
17665         * @since 6.0
17666         */
17667        _getGuideAttachments : function (argObject) {
17668            var fileDoms = [],
17669                fileNames = [],
17670                fileUrl = null,
17671                didSubmit = false,
17672                contextRoot = this._getContextRoot(),
17673                options = argObject.options,
17674                fileAttachmentsList = argObject.fileAttachmentsList,
17675                fileUploadPath = argObject.fileUploadPath,
17676                callback = argObject.callback,
17677                errorCallback = argObject.errorCallback,
17678                fileNameDomMap;
17679
17680            // In the case of draft, url comes with context root. Need to remove it so that correct
17681            // value gets stored in model
17682            if (contextRoot) {
17683                if (fileUploadPath.indexOf(contextRoot) === 0) {
17684                    fileUploadPath = fileUploadPath.substring(contextRoot.length);
17685                }
17686            }
17687            // File attachment list is an array containing the list of file attachments
17688            // We need to fetch the fileNameDomMap even when there's no fileAttachmentsList as there can be
17689            // lazy loaded file attachment models as well.
17690            fileNameDomMap = this._juiceOutNameAndFileDomMap(fileAttachmentsList);
17691            fileDoms = fileNameDomMap.fileDom;
17692            fileNames = fileNameDomMap.fileName;
17693            if (fileDoms.length > 0) {
17694                // since there can be a dom element which is null, in case of draft reload, get the first
17695                // non null file dom
17696                var firstNonNullFileDom = _.indexOf(fileDoms, _.find(fileDoms, function (item) {
17697                    return item !== null && !_.isString(item);
17698                }));
17699                // fileUploadPath doesn't contain the context path and hence we need to to pass the baseURL
17700                // FileUploader takes a _getUrl option which is baseUrl/contextPath
17701                if (firstNonNullFileDom !== -1 && fileUploadPath) {
17702                    var uploaderPluginName = guideBridge.userConfig.uploaderPluginName || "adobeFileUploader";
17703                    fileUrl = fileDoms[firstNonNullFileDom][uploaderPluginName]("uploadFile", {
17704                        'fileName' : fileNames,
17705                        'fileDom' : fileDoms,
17706                        'fileUploadPath' : fileUploadPath,
17707                        'multiple' : true,
17708                        _getUrl : guideBridge._getUrl("")
17709                    });
17710
17711                    // The file url returned by file upload widget can contain context root.
17712                    // Remove it so that correct value gets stored in model.
17713                    if (contextRoot) {
17714                        if (fileUrl.indexOf(contextRoot) === 0) {
17715                            fileUrl = fileUrl.substring(contextRoot.length);
17716                        }
17717                    }
17718
17719                    fileDoms[firstNonNullFileDom].one("adobeFileUploader.multipleFileUploaded",
17720                        $.proxy(callback, {
17721                            "attachments" : fileNames,
17722                            "fileUrl" : fileUrl,
17723                            "fileAttachmentsList" : fileAttachmentsList,
17724                            "options" : options
17725                        })
17726                    );
17727                    if (errorCallback) {
17728                        fileDoms[firstNonNullFileDom].one("adobeFileUploader.fileUploadFailed",
17729                            $.proxy(errorCallback, {
17730                                "attachments" : fileNames,
17731                                "fileUrl" : fileUrl,
17732                                "fileAttachmentsList" : fileAttachmentsList,
17733                                "options" : options
17734                            })
17735                        );
17736                    }
17737                    didSubmit = true;
17738                }
17739                // if fileUrl is not yet set, default it to fileUploadPath
17740                if (fileUrl === null && fileUploadPath) {
17741                    fileUrl = fileUploadPath;
17742                }
17743            }
17744            if (!didSubmit) {
17745                // if there are no files attached, still call the callback to submit the json contents
17746                // if there is only one file attachment component with no files, in this case else is 
17746important
17747                callback.apply({
17748                    "attachments" : fileNames,
17749                    "fileUrl" : fileUrl,
17750                    "fileAttachmentsList" : fileAttachmentsList,
17751                    "options" : options
17752                });
17753            }
17754        },
17755        /**
17756         * Iterates over all the components in the Adaptive Form and invokes its {@link GuideNode#visit|visit} method
17757         * passing the _callback_ to the API.
17758         *
17759         * @summary Traverse all the components in the Adaptive Form and invoke callback function for each of the
17760         * component
17761         * @param {function} callback Function to be called for every Adaptive Form Component present
17762         * in the Form. The signature of the callback matches the signature of
17763         * {@link GuideNode~VisitorCallback|VisitorCallback}
17764         * @param {object} [context=window] _this_ object in the callback will point to this object
17765         *
17766         * @example <caption>Creating a list of all components having name <i>testName</i></caption>
17767         * var myList = []
17768         * guideBridge.visit(function(cmp) {
17769         *     if(cmp.name === "testName") {
17770         *          myList.push[cmp];
17771         *     }
17772         * }};
17773         * @method
17774         * @memberof GuideBridge
17775         * @since 6.0
17776         * @instance
17777         */
17778        visit : function (callback, context) {
17779            this._guide.visit(callback, context || window);
17780        },
17781
17782        /**
17783         *
17784         * Hides the elements of the specified class name.
17785         * In case of guideButton, it checks for type too, if no type is specified in "guideButton", then that button
17786         * cannot be made hidden
17787         *
17788         * @param className String representing the classname of the node
17789         * @param type [optional] type will be used only if the classname is "guideButton"
17790         * @private
17791         */
17792        _hideElements : function (className, type) {
17793            var resultObject = new GuideResultObject();
17794            // If guide dom not initialized, return
17795            if (!this._checkGuide(resultObject)) {
17796                return resultObject;
17797            }
17798            resultObject.completed = true;
17799            this.visit(function (node) {
17800                // if the class name is guide button only the use the type
17801                if (node.className === "guideButton") {
17802                    if (node.type === type) {
17803                        node.visible = false;
17804                    }
17805                } else {
17806                    // else just compare the classname and hide it
17807                    if (node.className === className) {
17808                        node.visible = false;
17809                    }
17810                }
17811            });
17812            return resultObject;
17813        },
17814
17815        /**
17816         * In Adaptive Form there is a summary component to show the summary of submission. This API hides the parent
17817         * panel of the summary component. If the component is not present inside the Form, this operation doesn't do
17818         * anything
17819         * @summary Hides the panel that contains the summary component.
17820         *
17821         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17822         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17823         * @memberof GuideBridge
17824         * @instance
17825         * @since 6.0
17826         */
17827        hideSummaryPanel : function () {
17828            var resultObject = new GuideResultObject();
17829            // If guide dom not initialized, return
17830            if (!this._checkGuide(resultObject)) {
17831                return resultObject;
17832            }
17833            resultObject.completed = true;
17834            this.visit(function (node) {
17835                if (node.className === "guideNode" && node.jsonModel['sling:resourceType'] === "fd/afaddon/components/summary") {
17836                    node.panel.visible = false;
17837                }
17838            });
17839            return resultObject;
17840        },
17841
17842        _getFileAttachmentsList : function () {
17843            var fileAttachmentsList = [];
17844            this.visit(function (node) {
17845                if (node.className === "guideFileUpload") {
17846                    fileAttachmentsList.push(node);
17847                }
17848            });
17849            return fileAttachmentsList;
17850        },
17851
17852        /**
17853         * @summary the captchaData which will be submitted to server for validation purposes.
17854         * @param captchaModel
17855         * @returns {object}
17855 object contains the captchaData which includes captcha service provider name, its SOM exp and
17856         * data coming from OOTB/third-party captcha widget.
17857         * @method
17858         * @memberof GuideBridge
17859         * @instance
17860         * @since 6.3
17861         */
17862        _getCaptchaData : function (captchaModel) {
17863            if (captchaModel) {
17864                return {
17865                    serviceType : captchaModel.captchaService,
17866                    somExpression : captchaModel.somExpression,
17867                    validationMessage : captchaModel.validateExpMessage,
17868                    mandatoryMessage : captchaModel.mandatoryMessage,
17869                    data : captchaModel.value
17870                };
17871            }
17872            return {};
17873        },
17874
17875        /**
17876         * This function returns the additional action Field information that is required during submit.
17877         *
17878         * @returns {object} object having the action Field information.
17879         * @memberof GuideBridge
17880         */
17881        _getAdditionalSubmitInfo : function () {
17882            var additionalSubmitInfo = {},
17883                actionFieldDiv = $("#actionField");
17884            var thankYouPage = this._getThankYouPageFromConfig();
17885            if (typeof thankYouPage === "string") {
17886                document.getElementById(":redirect").value = thankYouPage;
17887            }
17888            var actionFields = actionFieldDiv.find('input')
17889                .each(function () {
17890                    additionalSubmitInfo[$(this).attr("name")] = $(this).val();
17891                    if ($(this).attr("name") == "_guideValueMap" && $(this).val() == "yes") {
17892                        var guideKeyValue = {};
17893                        window.guideBridge._guide._collectValues(guideKeyValue);
17894                        additionalSubmitInfo['_guideValuesMap'] = JSON.stringify(guideKeyValue);
17895                    }
17896                });
17897            return additionalSubmitInfo;
17898        },
17899
17900        /**
17901         * Gets the guideDom based on whether reducedJSON option is true or not.
17902         * If reducedJSON is true, only the white-listed properties are included.
17903         *
17904         * @returns {object} guideDom
17905         * @memberof GuideBridge
17906         */
17907
17908        _getGuideDom : function (options) {
17909            var guideDom;
17910            if (options.reducedJSON) {
17911                guideDom = guideBridge._guide._getReducedJSON();
17912            } else {
17913                guideDom = guideBridge._guide.jsonModel;
17914            }
17915            return guideDom;
17916        },
17917
17918        /**
17919         * Creates the guideState and the liveXml.
17920         *
17921         * @param options {object} options should contain a GuideResultObject [{obj:"<GuideResultObject type>"}]
17922         * @memberof GuideBridge
17923         * Steps performed by the function -
17924         * 1) creates the xfaState
17925         * 2) creates the guideState that consists of guideDom, guideContext and additionalSubmitInfo
17926         * 3) creates guideLiveData
17927         * 4) adds xfaState and guideLiveData to the guideState
17928         *
17929         * @private
17930         */
17931        _createGuideStateAndLiveXml : function (options) {
17932            var obj = new GuideResultObject();
17933            // add the guideResultObject to options so that it can be passed to the success handler
17934            options.obj = obj;
17935
17936            if (!this._checkGuide(obj)) {
17937                return;
17938            }
17939
17940            var saveXfaXml = function (xfaResultObj) {
17941                if (!xfaResultObj.errors && xfaResultObj.completed) {
17942                    xfaState.currentContext = {'data' : xfaResultObj.data};
17943                }
17944            };
17945
17946            obj.data = {};
17947            var xfaState = null;
17948            if (this._isXfaGuide() && this._isValidXFAGuide()) {
17949                var xfaResultObject = null;
17950                if (options.reducedJSON) {
17951                    //If reduceJson is asked, then xfaState should also be reduced by passing the diff and bSubmit flag to true
17952                    xfaResultObject = window.formBridge.getFormState(true, true);
17953                } else {
17954                    xfaResultObject = window.formBridge.getFormState();
17955                }
17956                if (xfaResultObject.errors) {
17957                    guideBridge._guide.logger().log("Error in getting Xfa State:" + JSON.stringify(xfaResultObject.getNextMessage()));
17958                    alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-001"]));
17959                }
17960                xfaState = xfaResultObject.data;
17961            }
17962
17963            var guideDom = guideBridge._getGuideDom(options);
17964
17965            //adding additionalSubmitInfo in the guideState.
17966            //additionalSubmitInfo contains the information about action fields.
17967            var additionalSubmitInfo = guideBridge._getAdditionalSubmitInfo();
17968            //set the updated file attachment map in the customPropertyMap
17969            guideBridge.customContextProperty("fileAttachmentMap", JSON.stringify(this.getFileAttachmentMap()));
17970            var guideState = {
17971                guideDom : guideDom,
17972                //save renderContext in guide state to enable deferred submit even if guide is not open
17973                guideContext : guideBridge._guide.runtime.guideContext,
17974                additionalSubmitInfo : additionalSubmitInfo
17975            };
17976
17977            if (guideBridge._guide.allLazyChildren.length > 0) {
17978                guideBridge._guide.internal.liveDataUtils.updateLiveData();
17979                var listOfDirtyPanels = guideBridge._guide.internal.GuideDirtyMarkerAndVisitor.flatten
17979DirtyPanelMapToCSV();
17980                if (listOfDirtyPanels.length > 0) {
17981                    this.afSubmissionInfo("afDraft", listOfDirtyPanels);
17982                }
17983                // save live xml & xfa state as xml for restoration of lazy model on 'restore'
17984                guideState.guideLiveData = guideBridge._guide.internal.liveDataUtils.getLiveDataStr();
17985                if (this._isXfaGuide() && this._isValidXFAGuide()) {
17986                    formBridge.getDataXML({"success" : saveXfaXml}); // currently xfa restore relies on formBridge.getDataXML being sync
17987                }
17988            }
17989            obj.data.guideState = guideState;
17990            if (xfaState) {
17991                obj.data.guideState.xfaState = xfaState;
17992            }
17993
17994        },
17995
17996        _updateAFSubmissionInfo : function (guide) {
17997            if (guideBridge.isGuideLoaded(true) && !guide) {
17998                var previousFocusSom = this._guideView._previousFocusItemSom;
17999                var previousItemModel = guideBridge.resolveNode(this._guideView._previousFocusItemSom);
18000                if (getOrElse(previousItemModel, "parent.className", undefined) === "guideToolbar") {
18001                    previousFocusSom = previousItemModel.parent.parent.somExpression;
18002                }
18003                this.afSubmissionInfo("lastFocusItem", this._guideView.getSomOnNavigableAncestor(previousFocusSom));
18004            }
18005            this.afSubmissionInfo("computedMetaInfo", guideBridge.getComputedSubmissionMetadata());
18006            var newGuide = guide ? guide : guideBridge._guide;
18007            this.afSubmissionInfo("excludeFromDoR", newGuide._getExcludeFromDorMap());
18008            // send state override on in cases when we have dor
18009            var stateOverrides = {};
18010            if (newGuide.dorType && "none" !== newGuide.dorType) {
18011                stateOverrides = newGuide._getStateOverrideMap();
18012            }
18013            this.afSubmissionInfo("stateOverrides", stateOverrides);
18014            // Add signers to af submission info
18015            this.afSubmissionInfo("signers", newGuide._getSigners());
18016
18017        },
18018
18019
18020        /**
18021         * Adaptive Form stores its state in the form of JSON. The Files attached in the component are uploaded
18022         * onto the server and their paths are returned in the JSON state except in certain conditions mentioned below.
18023         * The API is an asynchronous call which calls the success and error handlers with the data.
18024         *
18025         * In the below mentioned scenarios the file will not be uploaded
18026         * * User doesn't have **write permissions** on the _fileUploadPath_ provided
18027         * * The _fileUploadPath_ property doesn't point to a node of type _**sling:Folder**_
18028         *
18029         * @summary Retrieve the current state of Adaptive Form as json string
18030         * @param {object} options Input object containing the callbacks that will be invoked
18031         * to provide the result of the API
18032         * @param {function} [options.success] callback which receives the result of the API
18033         * in case of success.
18034         * {@link GuideResultObject#errors|errors} property as false.
18035         * @param {function} [options.error] callback which receives the result of the API in
18036         * case of failure.
18037         * {@link GuideResultObject#errors|errors} property as true.
18038         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18039         * object
18040         * @param {string} [options.fileUploadPath] controls whether the files in the File Attachment component have to be
18041         * uploaded or not. If _fileUploadPath_ is non null, only then file gets uploaded and the model's value is
18042         * updated with the file url
18043         *
18044         * @method
18045         * @memberof GuideBridge
18046         * @since 6.0
18047         * @instance
18048         */
18049        getGuideState : function (options) {
18050
18051            var fileAttachmentsList = [];
18052
18053            // walk through the model to get the list of file attachment components
18054            // do this only and only if login!= anonymous
18055            if (!guideBridge._disablePreview()) {
18056                fileAttachmentsList = this._getFileAttachmentsList();
18057            }
18058
18059            guideBridge._updateAFSubmissionInfo();
18060
18061            if (!guidelib.runtime.progressive && guideBridge.isGuideLoaded(true)) {
18062                this.customContextProperty("lastFocusItem", this._guideView.getSomOnNavigableAncestor(this._guideView._previousFocusItemSom));
18063            }
18064
18065            // Walk through the list of file Attachment components
18066            // and update the value of every item
18067            // Get the list of file Attachments
18068            if (options.fileUploadPath && !guideBridge._disablePreview()) {
18069                var optionArgument = {"options" : options,
18070                    "fileAttachmentsList" : fileAttachmentsList,
18071                    "fileUploadPath" : options.fileUploadPath,
18072                    "callback" : window.guideBridge._collectFileUrls,
18073                    "errorCallback" : window.guideBridge._fileUploadFailed};
18074
18075                this._getGuideAttachments(optionArgument);
18076            } else {
18077                this._createGuideStateAndLiveXml(options);
18078                if (options.success) {
18079                    options.success.call(options.context, options.obj);
18080                }
18081            }
18082
18083        },
18084
18085        /**
18086         * Validates the Adaptive Form or it's specific panel and return the validation status. The API also moves
18087         * focus to first invalid element
18088         * @summary validate the entire Form or a component in Adaptive Form
18089         * @param  {Field~ValidationError[]} errorList Input must be an empty array. The array will be filled with list
18090         * of Adaptive Form Components that failed validation.
18091         * @param  {string}
18091 [somExpression] SOM Expression of the Guide Node for which validation should be triggered.
18092         * If not provided, it would validate the entire Adaptive Form
18093         * @param {boolean} [setFocus=true] If true, set focus to the first invalid element.
18094         * @returns {boolean} true if the component/form was valid, false otherwise
18095         * @method
18096         * @memberof GuideBridge
18097         * @since 6.0
18098         * @instance
18099         * @see Field#validate
18100         * @see Panel#validate
18101         */
18102        validate : function (errorList, somExpression, setFocus, guide) {
18103            // guide parameter is not to be documented and it is meant for internal use only
18104            var guideNode = null,
18105                isFocusEnabled = _.isUndefined(setFocus) ? true : setFocus,
18106                ec = guidelib.util.ErrorConstants,
18107                validationContext,
18108                afContainer = guide ? guide : this._guide; // done, to keep this thread safe
18109            //  get Json of all the dirty , non visited (templateJson missing from cache)
18110            if (afContainer.allLazyChildren.length > 0) {
18111                afContainer.guideLazyUtil.putDirtyToTemplateCacheIfMissing(afContainer);
18112            }
18113            if (somExpression) {
18114                guideNode = this.resolveNode(somExpression);
18115                // how to know if the panel is navigable from the model. We do not bring the nonNavigable property ?
18116                if (guideNode instanceof guidelib.model.GuidePanel) {
18117                    validationContext = ec.CONTEXT_NAVIGATION;
18118                }
18119            } else {
18120                guideNode = afContainer;
18121                validationContext = ec.CONTEXT_SUBMISSION;
18122            }
18123            this.setValidationContext(validationContext);
18124            var status = false;
18125            if (!errorList) {
18126                errorList = [];
18127            }
18128            status = guideNode.validate(errorList);
18129
18130            try {
18131                // there can be errors in the user script, hence handling the exception gracefully, and resetting the global error state properly
18132                this._guide._triggerOnBridge("validationComplete", this._guide, status, "", errorList);
18133                if (!status && isFocusEnabled) {
18134                    var errorSom = errorList[0]["som"];
18135
18136                    guideBridge._guide.on(guidelib.event.GuideModelEvent.LAZY_LOADED, function () {
18137                        var errorField = guideBridge.resolveNode(errorSom);
18138                        if (errorField) {
18139                            errorField.validate();
18140                        }
18141                    }, {});
18142
18143                    this.setFocus(errorSom);
18144
18145                    guideBridge._guide.off(guidelib.event.GuideModelEvent.LAZY_LOADED);
18146                }
18147
18148            } catch (exception) {
18149                this._guide.logger().log(exception);
18150            } finally {
18151                // since the errors have been published reset the state back to normal
18152                //guidelib.runtime.errorManager.setGlobalError(false);
18153                this.unsetValidationContext(validationContext);
18154                return status;
18155            }
18156
18157        },
18158
18159        // todo: submit behaviour should make sure that if the value of file upload
18160        /**
18161         * Adaptive Form can be restore in three ways
18162         * * by passing the JSON data obtained from {@link GuideBridge#getGuideState}. This can be done by setting
18163         * _**data**_ property .
18164         * * by passing a URL pointing to a resource that returns JSON/XML data that should be used. This can be done by setting
18165         * _**dataRef**_ property. The data can be obtained by calling the
18166         * {@link GuideBridge#getData|getData} API.
18167         * * by passing a URL pointing to a resource that returns JSON data obtained from {@link GuideBridge#getGuideState}.
18168         * This can be done by setting _**guideStatePathRef**_ property .
18169         *
18170         * When restoring from dataRef, only values and other properties, that are dependant on value, are restored. For
18171         * example, If a Field was hidden based on the click of a Button then
18172         * when restoring from data XML/JSON the Field will not remain hidden.
18173         *
18174         * **NOTE:** The _data_, _dataRef_ and _guideStatePathRef_ must not be null simultaneously and only one property
18175         * must be specified. Specifying more than one can lead to undesired results.
18176         * @summary restore/prepopulate the state of Adaptive Form from an earlier saved state
18177         * @param {object}
18177 options object containing the callbacks to be invoked on
18178         * success/failure and data from where to restore the object.
18179         * @param {function} [options.success] callback which receives the result of the API
18180         * in case of success
18181         * {@link GuideResultObject#errors|errors} property as false.
18182         * @param {function} [options.error] callback which receives the result of the API in
18183         * case of failure.
18184         * {@link GuideResultObject#errors|errors} property as true.
18185         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18186         * object.
18187         * @param {object} [options.data] It must be the value of the {@link GuideResultObject#data|data} property passed to
18188         * the _success_ handler of {@link GuideBridge#getGuideState|getGuideState} API.
18189         * @param {string} [options.dataRef] URL pointing to the data XML/JSON.
18190         * @param {string} [options.guideStatePathRef] URL pointing to the JSON state of Adaptive Form.
18191         *
18192         * @method
18193         * @memberof GuideBridge
18194         * @since 6.0
18195         * @instance
18196         * @example <caption>Restoring from JSON data</caption>
18197         * var jsonData;
18198         * guideBridge.getGuideState({
18199         *      success : function (guideResultObj) {
18200         *          jsonData = guideResultObj.data;
18201         *      },
18202         *      error : function (guideResultObj) {
18203         *          // log error
18204         *      }
18205         * });
18206         *
18207         * // after some time or on click of a button or reloading the page
18208         * guideBridge.restoreGuideState({
18209         *      guideState : jsonData.guideState,
18210         *      error : function (guideResultObject) {
18211         *          // log the errors
18212         *      }
18213         * })
18214         *
18215         * @example <caption>Restoring from data XML/JSON</caption>
18216         * guideBridge.getData({
18217         *      success : function (guideResultObj) {
18218         *          var data = guideResultObj.data;
18219         *          //post the data to a server that saves it at say http://abc.com/my/data.xml
18220         *          //or http://abc.com/my/data.json
18221         *      },
18222         *      error : function (guideResultObj) {
18223         *          // log the errors
18224         *      }
18225         * });
18226         *
18227         * // after some time or on click of a button or reloading the page
18228         * guideBridge.restoreGuideState({
18229         *      dataRef : "http://abc.com/my/data.xml",
18230         *      error : function (guideResultObject) {
18231         *          // log the errors
18232         *      }
18233         * })
18234         *
18235         * @example <caption>Restoring from URL to a JSON</caption>
18236         * guideBridge.getGuideState({
18237         *      success : function (guideResultObj) {
18238         *          var json = guideResultObj.data;
18239         *          //post the JSON to a server that saves it at say http://abc.com/my/data.json
18240         *      },
18241         *      error : function (guideResultObj) {
18242         *          // log the errors
18243         *      }
18244         * });
18245         *
18246         * // after some time or on click of a button or reloading the page
18247         * guideBridge.restoreGuideState({
18248         *      guideStatePathRef : "http://abc.com/my/data.json",
18249         *      error : function (guideResultObject) {
18250         *          // log the errors
18251         *      }
18252         * })
18253         **/
18254        restoreGuideState : function (options) {
18255            var parameters,
18256                path;
18257            if (options && options.dataRef) {
18258                parameters = {"dataRef" : options.dataRef};
18259            } else if (options && options.guideStatePathRef) {
18260                parameters = {"guideStatePathRef" : options.guideStatePathRef};
18261            }
18262            // if parameters have DataRef or guideStatePathRef, a recursive call is made to restoreGuideState.
18263            if (parameters) {
18264                path = window.guideBridge.getGuidePath();
18265                path = path + ".guidejson";
18266                $.ajax({
18267                    url : path,
18268                    type : "GET",
18269                    async : false,
18270                    cache : false,
18271                    data : parameters,
18272                    success : function (response) {
18273                        //case where section information exist in guideState
18274                        if (response.guideState && response.guideState.guideContext
18275                            && response.guideState.guideContext.customPropertyMap
18276                            && response.guideState.guideContext.customPropertyMap.sections
18277                            && response.guideState.guideContext.customPropertyMap.sections.length > 0) {
18278                            // todo: add safe check for string vs array
18279                            window.guideBridge.customContextProperty.sections = response.guideState.guideContext.customPropertyMap.sections;
18280                        }
18281                        //passing the options again, but with DataRef or guideStatePathRef removed from it.
18282                        window.guideBridge.restoreGuideState(_.extend(
18283                            {},
18284                            options,
18285                            {
18286                                guideState : response.guideState,
18287                                dataRef : undefined,
18288                                guideStatePathRef : undefined
18289                            }
18290                        ));
18291                        if (guidelib.runtime.progressive) {
18292                            // Initialize the progressive
18293                            // We are not directly playing json on the model, since may be the json of entire progressive is not brought upfront
18294                            // Only in case of static service, we bring the entire json, hence creating model if not present
18295                            guidelib.runtime.progressive._initializeSectionModelAndPlayJson(window.guideBridge.customContextProperty.sections);
18296
18297                            // Now render the last section
18298                            guidelib.runtime.progressive.renderLastSection();
18299                        }
18300                    },
18301                    error : function (response) {
18302                        window.guideBridge._guide.logger().log("Error: " + response);
18303                    }
18304                });
18305                return;
18306            }
18307
18308            /*
18309             * We have to merge the runtime guideContext with the guideContext passed in the guideState
18310             * so that no custom properties that were set in the guideState.guideContext are ignored.
18311             */
18312            guidelib.__runtime__.guideContext = guidelib.__runtime__.guideContext || {};
18313            if (guideBridge.isGuideLoaded()) {
18314                guideBridge._guide.runtime.guideContext = guideBridge._guide.runtime.guideContext || {};
18315            }
18316            var gc = getOrElse(options, "guideState.guideContext", undefined);
18317            if (!_.isUndefined(options.guideState.guideContext)) {
18318                /* Runtime custom property map is set by external application and hence, shallow copy will set the value
18319                 * as set externally. If no value was set, the guideState custom property map keys stay.
18320                 */
18321                _.extend(gc.customPropertyMap, guidelib.__runtime__.guideContext.customPropertyMap);
18322                if (guideBridge.isGuideLoaded()) {
18323                    _.extend(gc.customPropertyMap, guideBridge._guide.runtime.guideContext.customPropertyMap);
18324                }
18325            }
18326            // not setting at guidelib runtime, but honoring if anyone has set customPropertyMap
18327            // through guidelib.runtime.guideContext directly
18328            if (guideBridge.isGuideLoaded()) {
18329                _.extend(guideBridge._guide.runtime.guideContext, gc);
18330            }
18331
18332            if (!this._guide) {
18333                this.storage = {};
18334                this.storage.guideState = options.guideState;
18335                //NOCHECKMARX - This is error callback to be provided by the user of this API.
18336                this.storage.error = options.error;
18337                this.storage.success = options.success;
18338                this.storage.context = options.context;
18339            } else {
18340                this._playGuideJson(options);
18341                // Trigger the event
18342                // If guide has restore state, call sync guide node to html
18343                // Case 1: If this is called before view gets initialized, there would be no listener present, hence nothing would happen
18344                // Case 2: If it is called after view gets initialized(using restore guide state in mobile workspace), then the model would sync to view
18345                // using this event
18346                // If view is initialized, which means a listener would to MODEL_REFRESH would be set, hence just trigger the event for execution
18347                if (this._guideView) {
18348                    this._guide._triggerEvent(guidelib.event.GuideModelEvent.MODEL_REFRESH, "jsonModel", null, null);
18349                }
18350            }
18351
18352        },
18353
18354        /**
18355         * Adaptive Form can set data in three ways:
18356         * * by passing the JSON data obtained from {@link GuideBridge#getGuideState}. This can be done by setting
18357         * _**data**_ property .
18358         * * by passing a URL pointing to a resource that returns data JSON/XML that should be used. This can be done by setting
18359         * _**dataRef**_ property. The data can be obtained by calling the
18360         * {@link GuideBridge#getData|getData} API.
18361         * * by passing a URL pointing to a resource that returns JSON data obtained from {@link GuideBridge#getGuideState}.
18362         * This can be done by setting _**guideStatePathRef**_ property .
18363         *
18364         * When setting data from dataRef, only values and other properties, that are dependant on value, are set. For
18365         * example, If a Field was hidden based on the click of a Button in the data passed then
18366         * when setting data from XML/JSON the Field will not remain hidden.
18367         *
18368         * **NOTE:** The _data_, _dataRef_ and _guideStatePathRef_ must not be null simultaneously and only one property
18369         * must be specified. Specifying more than one can lead to undesired results.
18370         * @summary Populate the Adaptive Form from the data.
18371         * @param {object}
18371 options object containing the callbacks to be invoked on
18372         * success/failure and data from where to restore the object.
18373         * @param {function} [options.success] callback which receives the result of the API
18374         * in case of success
18375         * {@link GuideResultObject#errors|errors} property as false.
18376         * @param {function} [options.error] callback which receives the result of the API in
18377         * case of failure.
18378         * {@link GuideResultObject#errors|errors} property as true.
18379         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18380         * object.
18381         * @param {object} [options.data] It must be the value of the {@link GuideResultObject#data|data} property passed to
18382         * the _success_ handler of {@link GuideBridge#getGuideState|getGuideState} API.
18383         * @param {string} [options.dataRef] URL pointing to the data JSON/XML.
18384         * @param {string} [options.guideStatePathRef] URL pointing to the JSON state of Adaptive Form.
18385         *
18386         * @method
18387         * @memberof GuideBridge
18388         * @since 6.3
18389         * @instance
18390         * @example <caption>Setting data from JSON data</caption>
18391         * var jsonData;
18392         * guideBridge.getGuideState({
18393         *      success : function (guideResultObj) {
18394         *          jsonData = guideResultObj.data;
18395         *      },
18396         *      error : function (guideResultObj) {
18397         *       // log the errors
18398         *      }
18399         * });
18400         *
18401         * guideBridge.setData({
18402         *      guideState : jsonData,
18403         *      error : function (guideResultObject) {
18404         *          // log the errors
18405         *      }
18406         * })
18407         *
18408         * @example <caption>Setting data from XML/JSON</caption>
18409         * guideBridge.getData({
18410         *      success : function (guideResultObj) {
18411         *          var data = guideResultObj.data;
18412         *          //post the XML/JSON to a server that saves it at say http://abc.com/my/data.xml
18413         *          //or http://abc.com/my/data.json
18414         *      },
18415         *      error : function (guideResultObj) {
18416         *          // log the errors
18417         *      }
18418         * });
18419         *
18420         * guideBridge.setData({
18421         *      dataRef : "http://abc.com/my/data.xml",
18422         *      error : function (guideResultObject) {
18423         *          // log the errors
18424         *      }
18425         * })
18426         *
18427         * @example <caption>Setting data from URL to a JSON</caption>
18428         * guideBridge.getGuideState({
18429         *      success : function (guideResultObj) {
18430         *          var json = guideResultObj.data;
18431         *          //post the JSON to a server that saves it at say http://abc.com/my/data.json
18432         *      },
18433         *      error : function (guideResultObj) {
18434         *          // log the errors
18435         *      }
18436         * });
18437         *
18438         * guideBridge.setData({
18439         *      guideStatePathRef : "http://abc.com/my/data.json",
18440         *      error : function (guideResultObject) {
18441         *          // log the errors
18442         *      }
18443         * })
18444         **/
18445        setData : function (options) {
18446            guideBridge.restoreGuideState(options);
18447        },
18448
18449        /*
18450         * @private
18451         */
18452        _getStorage : function () {
18453            var storage = null;
18454            if (this.storage) {
18455                // Get the storage
18456                storage = this.storage;
18457                this.storage = null;
18458            }
18459            return storage;
18460        },
18461
18462        getGuideContext : function () {
18463            var obj = new GuideResultObject();
18464            obj.data = jQuery.extend(true, {}, (this._guide ? this._guide.runtime.guideContext : null));
18465            return obj;
18466        },
18467
18468        _getContextRoot : function () {
18469            return this.userConfig["contextPath"];
18470        },
18471
18472        _getEnableFocusOnFirstField : function () {
18473            var renderConfig = this.userConfig.renderConfig || {},
18474                enableFocusOnFirstField = renderConfig.enableFocusOnFirstField === undefined ? true : renderConfig.enableFocusOnFirstField,
18475                // convert "true"/"false" strings to boolean too
18476                enableFocusOnFirstFieldAsBoolean = enableFocusOnFirstField === 'true' || (enableFocusOnFirstField === 'false' ? false : enableFocusOnFirstField);
18477            // default value is true
18478            return enableFocusOnFirstFieldAsBoolean;
18479        },
18480
18481        _updateAjaxUrl : function (baseUrl) {
18482            if (this.hostName === "server") {
18483                $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
18484                    // 'Rebase' the URL if required.
18485                    var thisUrl = options.url;
18486                    if ((thisUrl.lastIndexOf('http://', 0) !== 0) && (thisUrl.lastIndexOf('https://', 0) !== 0)) {
18487                        // thisUrl is relative.
18488                        // thisUrl may or may not begin with slash
18489                        // encoding taken care by the ajax call
18490                        if (thisUrl.indexOf("/") === 0) {
18491                            // if begins with slash
18492                            thisUrl = baseUrl + thisUrl;
18493                        } else {
18494                            thisUrl = baseUrl + "/" + thisUrl;
18495                        }
18496                        options.url = thisUrl;
18497                    }
18498                });
18499
18500                // Native XHR Wrapper
18501                var originalOpen = XMLHttpRequest.prototype.open;
18502                XMLHttpRequest.prototype.open = function(method, url) {
18503                    if ((url.lastIndexOf('http://', 0) !== 0) && (url.lastIndexOf('https://', 0) !== 0)) {
18504                        // url is relative
18505                        if (url.indexOf("/") === 0) {
18506                            url = baseUrl + url;
18507                        } else {
18508                            url = baseUrl + "/" + url;
18509                        }
18510                    }
18511                    originalOpen.apply(this, arguments);
18512                };
18513            }
18514        },
18515
18516        _getUrl : function (url) {
18517            var baseUrl = this.userConfig["baseUrl"],
18518                contextPath = this.userConfig["contextPath"];
18519            if (baseUrl) {
18520                return baseUrl + url;
18521            } else if (contextPath && contextPath !== "/" && url.indexOf(contextPath) !== 0 && (url.length === 0 || url.indexOf("/") === 0)) {
18522                //if url does not have contextPath and starts with /, pre-pend contextPath
18523                // Also url.length check because I need to pass "" to getUrl and get context path
18524                return contextPath + url;
18525            }
18526            return url;
18527        },
18528
18529        _getGuidePathUrl : function (urlSuffix, guidePath) {
18530            // guidePath here refers to the path got from json state of guide
18531            // we use this path, if there is no guidePath set in guidelib.runtime.guideContext, cases where guide is not initialized but
18532            // guideBridge is present
18533            var path = guidePath || this.getGuidePath(),
18534                url = path + (urlSuffix || "");
18535            return this._getUrl(url);
18536        },
18537
18538        /**
18539         * @summary Returns the path which refers to the location of
18540         * the content resource of adaptive form container
18541         * @returns {String} Path to the content resource of the adaptive form container
18542         * @method
18543         * @memberof GuideBridge
18544         * @since 6.5
18545         * @instance
18546         */
18547        getGuidePath : function () {
18548            var guideContext = this.getGuideContext().data;
18549            if (guideContext && guideContext.hasOwnProperty("guidePath")) {
18550                return guideContext["guidePath"];
18551            }
18552            return null;
18553        },
18554
18555        /**
18556         * @summary Given a somExpression, return the {@link GuideNode} having the same somExpression.
18557         * @param {string} somExpression somExpression of the Adaptive Form component
18558         * @returns {GuideNode} GuideNode matching the som expression or null if not found
18559         * @method
18560         * @memberof GuideBridge
18561         * @since 6.0
18562         * @instance
18563         * @see GuideNode#somExpression
18564         */
18565        resolveNode : function (somExpression) {
18566            return this._guide.resolveNode(somExpression);
18567        },
18568        /*
18569         * Internal API. Should be used carefully.
18570         */
18571        _resolveId : function (id) {
18572            var node = this._guide._modelTemplateCacheStore.getModel(id);
18573            return node;
18574        },
18575
18576        /**
18577         * Helper method for accesibility announcements
18578         * Is part of the fix for FORMS-7071 (CQ-4276669)
18579         */
18580        _ariaLiveAnnouncement : function (text) {
18581            var ariaLiveElement = $("#ariaLiveElement");
18582            setTimeout(function() {
18583                $(ariaLiveElement).text(text);
18584                return (setTimeout(function() {
18585                    $(ariaLiveElement).text("");
18586                }, 2000))
18587            }, 500);
18588        },
18589
18590        /**
18591         * Invokes {@link Field#resetData}
18591 API for all the Fields inside the Form to reset their values to default
18592         * @summary Reset the values of all the Fields to their default values.
18593         *
18594         * @method
18595         * @memberof GuideBridge
18596         * @instance
18597         * @since 6.0
18598         */
18599        reset : function () {
18600            if (window.xfalib && window.xfalib.runtime && window.xfalib.runtime.xfa) {
18601                var xfa = window.xfalib.runtime.xfa;
18602                xfa.host.resetData();
18603            }
18604            this._guide.resetData();
18605
18606            if (this._guide.internal.liveDataUtils.isLiveDataInitialized()) {
18607                this._guide.internal.liveDataUtils.updateLiveData();
18608            }
18609
18610            var guideDirtyMarkerAndVisitor = this._guide.internal.GuideDirtyMarkerAndVisitor;
18611            guideDirtyMarkerAndVisitor.visitMap = guidelib.model.util.CommonUtils.createMap(this._guide.allLazyChildren, 0);
18612
18613            this._ariaLiveAnnouncement(guidelib.i18n.strings["formHasBeenReset"]);
18614        },
18615
18616        _getPreviousFocus : function () {
18617            return this._guideView._previousFocusItemSom;
18618        },
18619
18620        /**
18621         * Returns the somExpression of the current {@link Panel} or current {@link Field} in Focus. The API can also
18622         * be used to get the somExpression of the Navigable Panel that contains the current Element in Focus.
18623         *
18624         * @summary return the somExpression of the {@link Panel} or {@link Field} that is currently in focus
18625         * @param {object} options configuration to be passed to the API to get the desired result
18626         * @param {?string} [options.focusOption] Currently the following value of this option are supported
18627         * * `navigablePanel`: if one wants to get the somExpression of the Navigable Panel
18628         * @returns {string} somExpression of Adaptive Form component representing the field or panel.
18629         * @method
18630         * @memberof GuideBridge
18631         * @instance
18632         * @since 6.0
18633         * @see {GuideNode#somExpression}
18634         * @example
18635         * guideBridge.getFocus({"focusOption": "navigablePanel"})
18636         */
18637        getFocus : function (options) {
18638            var focusOption;
18639            if (_.isUndefined(options)) {
18640                return this._guideView.currentFocusItemSom;
18641            }
18642            if ((focusOption = getOrElse(options, "focusOption", null)) === "navigablePanel") {
18643                return this._guideView._lastFocussedPanelForNonActionFields;
18644            }
18645            this._guide.logger().log("Invalid Focus option.", focusOption);
18646        },
18647
18648        /**
18649         * The API is equivalent to calling
18650         * `guideBridge.setFocus(options.somExpression, options.focusOption, options.runCompletionScript)`
18651         * @summary An alternate signature to the {@link GuideBridge#setFocus|setFocus} API
18652         * @method setFocus
18653         * @memberof GuideBridge
18654         * @instance
18655         * @since 6.1 FP1
18656         * @param {object} options options passed to the API
18657         * @param {string} options.somExpression somExpression to set the focus to
18658         * @param {string} options.focusOption item inside the Panel to focus to
18659         * @param {string} options.runCompletionScript whether to run the completion script or not.
18660         * @return {boolean} true if the focus was set successfully otherwise false.
18661         */
18662
18663        /**
18664         * In Adaptive Form one can focus a Field/Panel. Setting focus on a Panel means setting focus to its first
18665         * child. This can be controlled using the _focusOption_ provided in this API.
18666         *
18667         * The API provides two mechanism to focus a Field/Panel.
18668         * * **Direct** : By providing the somExpression of the Field/Panel. If the somExpression of Panel is provided,
18669         * then based on the focusOption one of its child (or their child) is set to Focus
18670         * * **Indirect** : By providing an item's relative position inside a Panel, first or last item inside of a
18671         * Panel, sibling of current focussed Item of a Panel, etc. If the item is a Panel then the First Item of
18672         * that Panel (if that is again a Panel, this process continues until a Field is found) is activated.
18673         *
18674         * The first way is trivial, by providing the _somExpression_ of a {@link Field} to the API, the focus will be
18675         * set to the Field.
18676         *
18677         * If that Field is inside a Panel that is not currently open because of tabbed/wizard navigation, then that tab
18678         * would be opened and focus would be set to the Field/Panel.
18679         *
18680         * The API can also execute the
18681         * [completion expression](https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_8)
18682         * of the current Panel and only if the expression returns true set focus to the required element.
18683         *
18684         * **Note:**
18685         * * If _focusOption_ is either of nextItemDeep or prevItemDeep then _somExpression_ parameter must not be
18686         * passed. Otherwise the API will throw an exception
18687         * * If _somExpression_ points to a {@link Field} and _focusOption_ is not _nextItemDeep_ or _prevItemDeep_ then
18688         * _focusOption_ is ignored.
18689         *
18690         * @summary Sets focus to a {@link Field} or {@link Panel}
18691         * @param {?string} somExpression SOM Expression of the Adaptive Form Field or Panel which has to be activated.
18692         * @param {string} [focusOption=firstItem] The option provides the mechanism to focus onto an sibling of the
18693         * current active item.
18694         * * **_firstItem_** - Focuses to the first focusable item of the Panel whose _SOM Expression_ is provided
18695         * * **_lastItem_** - Focuses to the last focusable item of the Panel whose _SOM Expression_ is provided
18696         *
18697         * If either the _firstItem_ or _lastItem_ is a Panel, then the _firstItem_ of that Panel (until a Field is
18698         * found) is set to Focus.
18699         *
18700         * * **_nextItem_** - Next sibling component of the current active Item of the Panel whose _somExpression_ is
18701         * provided. It is equivalent to the result of `panel.navigationContext.nextItem` API.
18702         * * **prevItem** - Previous sibling component of the current active Item of the Panel show _somExpression_ is
18703         * provided. It is equivalent to the result of `panel.navigationContext.prevItem` API.
18704         *
18705         * * **_nextItemDeep_** - Focus is set to the next Navigable Panel of root Panel in DFS Order
18706         * * **_prevItemDeep_** - Focus is set to the next Navigable Panel of root Panel in DFS Order
18707         * @param {boolean} [runCompletionScript=false] indicating whether to execute the completion expression or not.
18708         * @returns {boolean} true if the focus was set to requested field successfully otherwise false
18709         * @method
18710         * @memberof GuideBridge
18711         * @since 6.0
18712         * @instance
18713         * @example
18714         * setFocus(somExpression); // Focus is set to the specified somExpression.
18715         * setFocus(this.panel.somExpression,'nextItem',true); // Focus is set to next item in the Panel.
18716         * setFocus(null,'nextItemDeep',true); // Focus is set to next navigable Panel in rootPanel
18717         */
18718        setFocus : function (somExpression, focusOption, runCompletionScript) {
18719            var options,
18720                focusDone,
18721                originalSkipFieldFocus;
18722            if (_.isObject(somExpression)) {
18723                options = somExpression;
18724            } else {
18725                options = {
18726                    somExpression : somExpression,
18727                    focusOption : focusOption,
18728                    runCompletionScript : runCompletionScript
18729                };
18730            }
18731            try {
18732                originalSkipFieldFocus = this._guideView.skipFieldFocus;
18733                /**
18734                 * Setting of this._guideView.skipFieldFocus was added for issue LC-3911361
18735                 * Here we set a skipFieldFocus property for gudeContainerView, which prevents
18736                 * actual 'input' / widget focus. This was done to prevent opening of keyboard or dropdown spinner
18737                 * or date picker.. in case of swipe and use of deep navigators in mobile view of Adaptive Form.
18738                 *
18739                 * when user validates Adaptive Form, skipFieldFocus is set to  options.skipFieldFocus based on somExpression
18740                 * which has default value of'undefined' else the skipFieldFocus set to the negated value of global variable
18741                 * enableFocusOnFirstField to enable/disable focus on first field of Adaptive Form.
18742                 */
18743                var fallbackSkipFieldFocus = !this._guide.enableFocusOnFirstField;
18744                if (!fallbackSkipFieldFocus) {
18745                    fallbackSkipFieldFocus = !guideBridge._getEnableFocusOnFirstField();
18746                }
18747                this._guideView.skipFieldFocus = options.somExpression ? options.skipFieldFocus : fallbackSkipFieldFocus;
18748                focusDone = this._guideView.setFocus(options);
18749            } finally {
18750                this._guideView.skipFieldFocus = originalSkipFieldFocus; //moving back to original state
18751            }
18752            //TODO: need a more common place to do that.
18753            if (!this._guide._currentContext) {
18754                this._guide.runPendingExpressions();
18755            }
18756            return focusDone;
18757        },
18758
18759        /**
18760         * Loads the lazy fragment specified by somExpression
18761         * @param {string} somExpression somexpression of the lazy loaded fragment
18762         * @param {object} options options to control the behaviour of loadLazyFragment API.
18763         * @param {function} [options.error] callback which receives the result of the API in
18764         * case of failure.
18765         * @method
18766         * @memberof GuideBridge
18767         * @since 6.4
18768         * @instance
18769         * @example <caption>Loading a lazy loaded fragment with somexpression x[0].y[0].z[0]. If both y and z form objects are lazy loaded, this API
18770         * would load both</caption>
18771         * guideBridge.loadLazyFragment("x[0].y[0].z[0]");
18772         *
18773         */
18774        loadLazyFragment : function (somExpression, options) {
18775            if (!_.isUndefined(somExpression)) {
18776                var relativeSom = guidelib.util.GuideUtil.relativeSom(this._guide.rootPanel.somExpression, somExpression);
18777                if (relativeSom) {
18778                    var somTokens = relativeSom.split(".");
18779                    var currItem = this._guide.rootPanel;
18780                    _.each(somTokens, function (qName) {
18781                        if (currItem != null) {
18782                            var arr = currItem._findChildren(qName, false);
18783                            if (arr.length > 0) {
18784                                var node = arr[0];
18785                                if (node && node._lazyReference && !node._itemsLoaded) {
18786                                    this._guide.internal.liveDataUtils.updateLiveData();
18787                                    node._loadLazyFragment(options);
18788                                }
18789                                currItem = node;
18790                            } else {
18791                                currItem = null;
18792                            }
18793                        }
18794                    }, this);
18795                }
18796            }
18797        },
18798
18799        /*
18800         * Get the download link of signed document set by signing service.
18801         * @return: url from where the signed document can be accessed, empty in case its not set by signing service.
18802         */
18803        getSignedDocDownloadLink : function () {
18804            var url = "";
18805            if (!_.isUndefined(FD)
18806                && !_.isUndefined(FD.AFaddon)
18807                && !_.isUndefined(FD.AFaddon.Signing)
18808                && !_.isUndefined(FD.AFaddon.Signing.signedDocDownloadLink)) {
18809                url = FD.AFaddon.Signing.signedDocDownloadLink;
18810            }
18811            return url;
18812        },
18813
18814        /*
18815         If true is passed to the function then it checks for model and view both,
18816         if false or no parameter is passed, then it checks the model only.
18817         */
18818        isGuideLoaded : function (complete) {
18819            if (complete) {
18820                return !_.isEmpty(window.guideBridge._guide && window.guideBridge._guideView);
18821            }
18822            return !_.isEmpty(window.guideBridge._guide);
18823        },
18824
18825        _doInternalSubmit : function (options) {
18826            if (options.excludeFormState) {
18827                var submissionInfo = options.guideState.data.guideState.guideContext.afSubmissionInfo;
18828                if (submissionInfo && submissionInfo.hasOwnProperty('lastFocusItem')) {
18829                    submissionInfo.lastFocusItem = undefined;
18830                }
18831            }
18832            // Make a clone of options so that original options are not modified.
18833            // Remove additionalSubmitInfo from the guideState so that no extra information
18834            // is sent to the server.
18835            var clonedGuideState = JSON.parse(JSON.stringify(options.guideState));
18836            if (!_.isEmpty(clonedGuideState.data.guideState.additionalSubmitInfo)) {
18837                clonedGuideState.data.guideState.additionalSubmitInfo = {};
18838            }
18839            var guideState = clonedGuideState,
18840                strContent = this.getMultipartData({
18841                    guideState : JSON.stringify(guideState.data),
18842                    dorData : options.dorData || false,
18843                    _charset_ : "UTF-8"
18844                }),
18845                // check if guide state is present, if yes get guide path from guide state
18846                // Specifically written for mobile workspace to getDataXML from current json state
18847                guidePath = ((guideState && guideState.data) ? guideState.data.guideState.guideContext.guidePath : null);
18848
18849            $.ajax({
18850                url : this._getGuidePathUrl(".af.internalsubmit.jsp", guidePath),
18851                type : "POST",
18852                async : options.async || false,
18853                contentType : "multipart/form-data; charset=UTF-8; boundary=" + strContent[0],
18854                data : strContent[1],
18855                success : options.success,
18856                error : options.error
18857            });
18858        },
18859
18860        _submitInternal : function (options) {
18861            var self = this;
18862            options = options || {};
18863            if (!options.guideState) {
18864                this.getGuideState({
18865                    "diff" : "diff",
18866                    "fileUploadPath" : options.fileUploadPath,
18867                    "success" : function (guideState) {
18868                        self._doInternalSubmit({
18869                            guideState : guideState,
18870                            success : options.success,
18871                            error : options.error,
18872                            async : options.async,
18873                            excludeFormState : options.excludeFormState,
18874                            dorData : options.dorData
18875                        });
18876                    },
18877                    "error" : options.error,
18878                    reducedJSON : true
18879                });
18880            } else {
18881                this._doInternalSubmit({
18882                    guideState : options.guideState,
18883                    success : options.success,
18884                    error : options.error,
18885                    async : options.async,
18886                    excludeFormState : options.excludeFormState,
18887                    dorData : options.dorData
18888                });
18889            }
18890        },
18891
18892        getMultipartData : function (data) {
18893            //Start multipart formatting
18894            var initBoundary = this.randomString();
18895            var strBoundary = "--" + initBoundary;
18896            var strMultipartBody = "";
18897            var strCRLF = "\r\n";
18898
18899            //Create multipart for each element of the form
18900            for (var key in data) {
18901                if (data.hasOwnProperty(key)) {
18902                    var value = _.isObject(data[key]) ? JSON.stringify(data[key]) : data[key];
18903                    strMultipartBody +=
18904                        strBoundary +
18905                        strCRLF +
18906                        "Content-Disposition: form-data; name=\"" + key + "\"" +
18907                        strCRLF +
18908                        strCRLF +
18909            
18909            value +
18910                        strCRLF;
18911                }
18912            }
18913            //End the body by delimiting it
18914            strMultipartBody += strBoundary + "--" + strCRLF;
18915            //Return boundary without -- and the multipart content
18916            return [initBoundary, strMultipartBody];
18917        },
18918
18919        randomString : function () {
18920            var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
18921            var string_length = 8;
18922            var randomstring = '';
18923            for (var i = 0; i < string_length; i++) {
18924                var rnum = Math.floor(Math.random() * chars.length);
18925                randomstring += chars.substring(rnum, rnum + 1);
18926            }
18927            return randomstring;
18928        },
18929
18930        /*
18931         * Get the file Attachment map that contains a mapping of som expression vs path when files have been uploaded
18932         * and som expression vs name when the files have not yet been uploaded .
18933         * @return: map of som expression and paths.
18934         * @private
18935         */
18936        getFileAttachmentMap : function () {
18937            var fileAttachmentMap = {},
18938                fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
18939            for (var i = 0; i < fileAttachmentsList.length; i++) {
18940                var node = fileAttachmentsList[i];
18941                if (!_.isEmpty(node.fileAttachment.value)) {
18942                    fileAttachmentMap[node.somExpression] = node.fileAttachment.value;
18943                }
18944            }
18945
18946            var lazyAttachmentMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap();
18947            _.each(lazyAttachmentMap, function (mapObject, key) {
18948                fileAttachmentMap[key] = mapObject.value;
18949            });
18950            return fileAttachmentMap;
18951        },
18952
18953        /*
18954         * sets the value of the file attachment component based on the map that is passed.
18955         * @private
18956         */
18957        putFileAttachmentMap : function (fileAttachmentMap) {
18958            _.each(fileAttachmentMap, function (value, som) {
18959                var node = guideBridge.resolveNode(som);
18960                node.fileAttachment.value = value;
18961            });
18962        },
18963
18964        _appendFileAttachmentsToFormData : function(dataForm, fileNameDomMap, fileAttachmentsList) {
18965            var fileNamesIndex,
18966                fileDoms = fileNameDomMap.fileDom,
18967                fileNames = fileNameDomMap.fileName,
18968                faPromise = {},
18969                rejectedFileNames = [],
18970                isIOS = guidelib.util.GuideUtil._isIOS(),
18971                createUnorderedList = function(list, bulletChar) {
18972                    var result = "";
18973                    for (var i = 0; i<list.length; ++i) {
18974                        result += bulletChar + " " + list[i] + "\n";
18975                    }
18976                    return "\n" + result;
18977                },
18978                throwException = function(fileNames) {
18979                    if (fileNames && fileNames.length > 0) {
18980                        throw guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-024"], [createUnorderedList(fileNames, "•")]);
18981                    }
18982                };
18983            for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
18984                // multiple files inside one filedom element & draft save case is handled.
18985                var currentFileNames = fileNames[fileNamesIndex].split("\n");
18986                for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
18987                    if (currentFileNames[fileIndex] && _.isString(fileDoms[fileNamesIndex])) {
18988                        //handle draft save scenario when fileDoms[fileNamesIndex] is string(URL) & currentFileNames[fileIndex] is a url
18989                        dataForm.append("_guideFileAttachment." + guideBridge._getRelativeFilePath(currentFileNames[fileIndex]), fileDoms[fileNamesIndex]);
18990                    }
18991                }
18992            }
18993            dataForm.append("_guideAttachments", fileNames.toString());
18994            if (isIOS) {
18995                var allFAPromises = [];
18996                _.each(fileAttachmentsList, function (fileAttachmentModel, index) {
18997                    var fileAttachmentWrapperPromises = fileAttachmentModel._fileAttachmentWrapperIOS;
18998                    if (fileAttachmentWrapperPromises) {
18999                        allFAPromises.push.apply(allFAPromises, fileAttachmentWrapperPromises);
19000                    }
19001                });
19002                faPromise = Promise.allSettled(allFAPromises).then(function(results){
19003                    for (var pIndex = 0; pIndex < results.length; pIndex++) {
19004                        // if status rejected, fail submission
19005                        if (results[pIndex].status === "rejected") {
19006                            rejectedFileNames.push(results[pIndex].reason);
19007                        } else {
19008                            var resultValue = results[pIndex].value;
19009                            var completeNameOfFile = resultValue.formElementName + "/" + resultValue.name;
19010                            dataForm.append(completeNameOfFile, resultValue.dataURLtoBlob(), resultValue.name);
19011                        }
19012                    }
19013                    // to fail this promise, throw an exception here
19014                    throwException(rejectedFileNames);
19015                    return dataForm;
19016                });
19017            } else {
19018                var allFileAccessPromise = [];
19019                for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
19020                    // multiple files inside one filedom element & draft save case is handled.
19021                    var currentFileNames = fileNames[fileNamesIndex].split("\n");
19022                    for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
19023                        // in case of IOS, file binary is from file object, we use the in-memory data
19024                        if (fileDoms[fileNamesIndex] && !_.isString(fileDoms[fileNamesIndex]) && fileDoms[fileNamesIndex].length > 0) {
19025                            // promise is not supported in IE11
19026                            // for IE11, we don't read file bytes
19027                            if (window.Promise) {
19028                                var fileAccessPromise = guidelib.util.GuideUtil._checkIfFileIsAccessible(currentFileNames[fileIndex], fileDoms[fileNamesIndex][0].files[fileIndex]);
19029                                allFileAccessPromise.push(fileAccessPromise);
19030                            } else {
19031                                // append each file of input file element to formdata
19032                                dataForm.append(currentFileNames[fileIndex], fileDoms[fileNamesIndex][0].files[fileIndex]);
19033                            }
19034
19035                        }
19036                    }
19037                }
19038                // promise is not supported in IE11
19039                if (window.Promise) {
19040                    faPromise = Promise.allSettled(allFileAccessPromise).then(function (results) {
19041                        for (var pIndex = 0; pIndex < results.length; pIndex++) {
19042                            // if status rejected, fail submission
19043                            if (results[pIndex].status === "rejected") {
19044                                rejectedFileNames.push(results[pIndex].reason);
19045                            } else {
19046                                var resultValue = results[pIndex].value;
19047                                dataForm.append(resultValue.fileName, resultValue.file);
19048                            }
19049                        }
19050                        throwException(rejectedFileNames);
19051                        return dataForm;
19052                    });
19053                } else {
19054                    faPromise = $.Deferred().resolve(dataForm);
19055                }
19056            }
19057            return faPromise;
19058        },
19059
19060        doAjaxSubmitWithFileAttachment : function (actionUrl, submitData, options, fileAttachmentsList) {
19061            var _options = options || {},
19062                self = this,
19063                dataForm = new FormData(),
19064                fileNameDomMap = this._juiceOutNameAndFileDomMap(fileAttachmentsList),
19065                faPromise = this._appendFileAttachmentsToFormData(dataForm, fileNameDomMap, fileAttachmentsList);
19066
19067            var _submitForm = function () {
19068                $.ajax({
19069                    url : actionUrl,
19070                    type : "POST",
19071                    processData : false,
19072                    cache : false,
19073                    contentType : false,
19074                    dataType : 'json',
19075                    data : dataForm,
19076                    success : function (data) {
19077                        self.doAjaxSubmitSuccess(data, _options);
19078                    },
19079                    error : function (data) {
19080                        self.doAjaxSubmitError(data, _options);
19081                    }
19082                });
19083            };
19084            faPromise.then(function (dataForm) {
19085                $.each(submitData, function (key, val) {
19086                    if (typeof val == "object") {
19087                        val = JSON.stringify(val);
19088                    }
19089                    dataForm.append(key, val);
19090                });
19091                _submitForm();
19092            })
19093                .catch(function (e) {
19094                    // handle errors here
19095                    console.error("Error while reading file bytes in IOS");
19096                    self.doAjaxSubmitError(data, _options);
19097                });
19098        },
19099
19100
19101        doAjaxSubmit : function (actionUrl, submitData, options) {
19102            var _options = options || {},
19103                self = this,
19104                asyncSubmit = _options.async !== false,
19105                strContent = this.getMultipartData(submitData);
19106            $.ajax({
19107                url : actionUrl,
19108                type : "POST",
19109                traditional : true,
19110                async : asyncSubmit,
19111                contentType : "multipart/form-data; charset=UTF-8; boundary=" + strContent[0],
19112                data : strContent[1],
19113                success : function (data) {
19114                    self.doAjaxSubmitSuccess(data, _options);
19115                },
19116                error : function (data) {
19117                    self.doAjaxSubmitError(data, _options);
19118                }
19119            });
19120        },
19121
19122        KEY_AF_SUCCESS_PAYLOAD : "afSuccessPayload",
19123
19124        doAjaxSubmitSuccess : function (data, options) {
19125            var guideResultObject = new GuideResultObject();
19126            guideResultObject.data = data;
19127            guideResultObject.completed = true;
19128            // remove the submitting message too after success of ajax submit
19129            guideBridge._showGuideLoading(false);
19130            if (_.isFunction(options.success)) {
19131                options.success.call(options.context, guideResultObject);
19132            } else {
19133                if (data.hasOwnProperty("signingURL")) {
19134                    // Adobe sign : FormFiller enabled case.
19135                    window.location.href = data.signingURL;
19136                } else {
19137                    var payload = {};
19138                    if (data.hasOwnProperty(guideBridge.KEY_AF_SUCCESS_PAYLOAD)) {
19139                        try {
19140                            payload = JSON.parse(data[guideBridge.KEY_AF_SUCCESS_PAYLOAD]);
19141                            payload.data = this._guide.internal.afdata;
19142                            var schemaType = this._guide.runtime.guideContext.schemaType;
19143                            if (!schemaType) {
19144                                //TODO define a constant for schema Type.
19145                                schemaType = "xmlschema";
19146                            }
19147                            payload.contentType = schemaType;
19148                        } catch (e) {
19149                            guideBridge._guide.logger().log("Error while parsing AF Success Payload: " + e);
19150                        }
19151                    }
19152                    guideBridge._guide.executeExpression("submitSuccess", payload); // Executing Rule Editor code for submit success.
19153                }
19154            }
19155        },
19156
19157        doAjaxSubmitError : function (data, options) {
19158            var guideResultObject = new GuideResultObject();
19159            guideResultObject.data = data;
19160            guideResultObject.completed = false;
19161            guideResultObject.addMessage(2, "Error in Async Submit", "");
19162            guideBridge._showGuideLoading(false);
19163            if (_.isFunction(options.error)) {
19164                options.error.call(options.context, guideResultObject);
19165            } else {
19166                var errorPayload = {};
19167                try {
19168                    errorPayload = JSON.parse(data.responseText);
19169                } catch (e) {
19170                    guideBridge._guide.logger().log("Error while parsing errorPayload." + e);
19171                }
19172                guideBridge._guide.executeExpression("submitError", errorPayload); //Executing Rule Editor code for submitError
19173            }
19174        },
19175
19176        handleUpload : function () {
19177            self = this.self;
19178            this.submitData['_guideAttachments'] = this.attachments.toString();
19179            _.each(this.attachments, function (att) {
19180                this.submitData["_guideFileAttachment." + att] = this.submitData['fileUrl'] + "/" + att;
19181            }, this);
19182            delete this.submitData['fileUrl'];
19183            self.doAjaxSubmit(this.actionUrl, this.submitData, this.options);
19184        },
19185
19186        _handleSubmitError : function (data, message) {
19187            // case: show message if it exists, for example, there could be client side errors during submit
19188            if (message) {
19189                alert(message);
19190            } else {
19191                var status = Number(data.status);
19192                switch (status) {
19193                    case 502:
19194                        alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-003"]));
19195                        break;
19196                    default:
19197                        alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-004"]));
19198                        break;
19199                }
19200            }
19201            guideBridge._showGuideLoading(false);
19202        },
19203
19204        updateSubmitData : function (fileAttachmentsList, submitData, fileList) {
19205            var fileCount = 0,
19206                attachments = [],
19207                name;
19208            if (fileList.length === 0 && fileAttachmentsList.length > 0 && !guideBridge._disablePreview()) {
19209                _.each(fileAttachmentsList, function (fileUploadComponentId, index) {
19210                    var currentCount = 0;
19211                    var componentInModel = window.guideBridge._resolveId(fileUploadComponentId);
19212                    var fileNameList = componentInModel["fileAttachment"].value;
19213                    if (fileNameList) {
19214                        var fileNames = fileNameList.split("\n");
19215                        _.each(fileNames, function (fileUrl, index) {
19216                            name = componentInModel.name + "/" + fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
19217                            if (name) {
19218                                attachments[fileCount++] = name;
19219                                submitData["_guideFileAttachment." + name] = fileUrl;
19220                            }
19221                        }, this);
19222                    }
19223                }, this);
19224                submitData['_guideAttachments'] = attachments;
19225            } else if (fileList.length > 0) {
19226                _.each(fileList, function (file, index) {
19227                    name = guideBridge._getRelativeFilePath(file);
19228                    attachments[fileCount++] = name;
19229                    submitData["_guideFileAttachment." + name] = file;
19230                }, this);
19231                submitData['_guideAttachments'] = attachments;
19232            }
19233        },
19234
19235        _collectFileUrls : function (event) {
19236            var list = [],
19237                fileUploadError = false;
19238
19239            // Populate list to have path of all the uploaded files. The file Attachment component whose model was
19240            // loaded would have their fileNames first followed by the list of file names of unloaded file upload components.
19241            _.each(this.attachments, function (attachment) {
19242                _.each(attachment.split("\n"), function (att) {
19243                    // check if att is a url and hence push it directly to list
19244                    if (_.isString(att) && att.match(/\//g).length > 1) {
19245                        list.push(att);
19246                    } else {
19247                        list.push(this.fileUrl + "/" + att);
19248                    }
19249                }, this);
19250            }, this);
19251
19252            var options = {
19253                fileUrlList : list,
19254                fileUploadModelsList : this.fileAttachmentsList,
19255                lazyAttachmentMap : guideBridge._guide.internal.liveDataUtils._getLazyAttachmentMap()
19256            };
19257            guidelib.util.GuideUtil._updateFileModelsAndLazyMap(options);
19258
19259            var submitOptions = this.options.ajaxSubmitObject;
19260            if (submitOptions && submitOptions.ajaxSubmitDataHandler) {
19261                submitOptions.ajaxSubmitDataHandler.call(this.options.context, submitOptions.fileAttachmentsList, submitOptions.submitData, list);
19262                window.guideBridge.doAjaxSubmit(submitOptions.actionUrl, submitOptions.submitData, this.options);
19263            } else if (this.options.success) {
19264                //create the guideState now as the model has been updated with the latest values.
19265                //do this only during getGuideState and not on ajax submit
19266                guideBridge._createGuideStateAndLiveXml(this.options);
19267                this.options.success.call(this.options.context, this.options.obj);
19268            }
19269
19270        },
19271
19272        _fileUploadFailed : function (event) {
19273            $.proxy(guideBridge._handleSubmitError({
19274                "status" : "500"
19275            }), guideBridge);
19276        },
19277
19278        // This function extracts the form name from the guideContainerPath.
19279        _getFormName : function (guidePath) {
19280            var formName = "";
19281            if (guidePath) {
19282                var index = guidePath.indexOf("/jcr:content/guideContainer");
19283                guidePath = guidePath.substring(0, index);
19284                formName = guidePath.substring(guidePath.lastIndexOf("/") + 1);
19285            }
19286            return formName;
19287        },
19288
19289        // This function creates a UUID that is used for ajax submit
19290        _getUUIDForAjaxSubmit : function () {
19291            var uuidSuffix = Math.floor((Math.random() * 10000) + 1),
19292                uuidCurrentTime = new Date().getTime(),
19293                successFlag = true;
19294            var guidePath = window.guideBridge.getGuidePath();
19295            this._formInstanceUUID = window.guideBridge._getFormName(guidePath) + uuidCurrentTime + uuidSuffix;
19296            successFlag = createUUIDStorage(this._formInstanceUUID);
19297            if (successFlag) {
19298                return this._formInstanceUUID;
19299            } else {
19300                return null;
19301            }
19302        },
19303
19304        /**
19305         * returns the form element to be used for submission in case of non-ajax
19306         * submit.
19307         * The function looks in the submitConfig for a form and if not present,
19308         * creates a new form
19309         * @returns {object} jQuery object for form element
19310         * @private
19311         */
19312        _getFormForSubmission : function () {
19313            var submitConfig = this.userConfig.submitConfig || {},
19314                form = submitConfig.form || $("<form method='post' enctype='multipart/form-data'></form>").appendTo($("body"));
19315            return $(form);
19316        },
19317
19318        _getThankYouPageFromConfig : function () {
19319            var submitConfig = this.userConfig.submitConfig || {};
19320            return submitConfig.thankyouPage;
19321        },
19322
19323        /**
19324         * This function prepare the guideValueMap and returns it.
19325         * @returns A map consisting of name and value for all the unbound components
19326         * @private
19327         */
19328        _prepareGuideValueMap : function () {
19329            var guideValueMap = {}, visitedMap = {};
19330            this.visit(function (node) {
19331                if (!node.bindRef && !visitedMap[node.somExpression]) {
19332                    if (node instanceof guidelib.model.Field && node.value) {
19333                        visitedMap[node.somExpression] = true;
19334                        guideValueMap[node.getAttribute("name")] = node.value;
19335                    } else if (node instanceof guidelib.model.GuideCompositeField) {
19336                        var obj = guideValueMap[node.getAttribute("name")] = {};
19337                        _.each(node.items, function (childNode, index) {
19338                            visitedMap[childNode.somExpression] = true;
19339                            if (childNode.value) {
19340                                obj[childNode.getAttribute("name")] = childNode.value;
19341                            }
19342                        }, this);
19343                    }
19344                }
19345            });
19346            return guideValueMap;
19347        },
19348
19349        _showGuideLoading : function (flag, msg) {
19350            if(!flag){
19351                if(_focusedSubmitButtonModel){
19352                    _focusedSubmitButtonModel.enabled = true;
19353                    _focusedSubmitButtonModel = null;
19354                }
19355            }
19356            var util = guidelib.util.GuideUtil;
19357            if (util) {
19358                util.showGuideLoading(flag);
19359                if (msg !== undefined) {
19360                    util.showMessages(msg);
19361                } else {
19362                    util.removeAllMessages();
19363                }
19364            }
19365        },
19366
19367        _submitAfterValidation : function (options, submitSuccess, submitError) {
19368            var self = this;
19369            if (guidelib.util.GuideUtil) {
19370                var msg = guidelib.i18n.strings.submittingForm;
19371                if (options && options.submissionSelector === 'agreement') {
19372                    msg = guidelib.i18n.strings.generatingSignAgreement;
19373                }
19374                guidelib.util.GuideUtil.showMessages(msg);
19375            }
19376            // Trigger submitStart before calling internal submit.
19377            if (guideBridge.isGuideLoaded() && self._guide._triggerOnBridge) {
19378                self._guide._triggerOnBridge("submitStart", "", "", "", "");
19379            }
19380            var excludeFormState = true;
19381            if (options && options.hasOwnProperty("excludeFormState")) {
19382                excludeFormState = options.excludeFormState;
19383            }
19384            try {
19385                var guideState = getOrElse(options, "guideState", null);
19386                if (guideState || guideBridge.isGuideLoaded()) {
19387                    var twoStepSubmission = getOrElse(options, "twoStepSubmission", true);
19388                    if (guideState || self._guide.xdpRef || twoStepSubmission) {
19389                        self._submitInternal({
19390                            guideState : guideState,
19391                            success : function () {
19392                                try {
19393                                    submitSuccess.apply(self, arguments);
19394                                } catch (e) {
19395                                    self._handleInternalSubmitError(submitError, self, arguments);
19396                                }
19397                            },
19398                            error : function () {
19399                                self._handleInternalSubmitError(submitError, self, arguments);
19400                            },
19401                            async : true,
19402                            excludeFormState : excludeFormState
19403                        });
19404                    } else {
19405                        self.getFormDataString({
19406                            success : function () {
19407                                try {
19408                                    submitSuccess.apply(self, arguments);
19409                                } catch (e) {
19410                                    self._handleInternalSubmitError(submitError, self, arguments);
19411                                }
19412                            }
19413                        });
19414                    }
19415                } else {
19416                    console.error("Form Submission failed as the form doesn't exist on the page")
19417                }
19418            } catch (e) {
19419                self._showGuideLoading(false);
19420                if (console && console.error) {
19421                    console.error(e);
19422                }
19423            }
19424        },
19425
19426        _handleCaptchaTimeout : function () {
19427            window.alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-025"]));
19428            window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
19429            guideBridge._showGuideLoading(false);
19430            return;
19431        },
19432
19433        /**
19434         * Validate and submits the data of the Adaptive Form to the pre-configured submit action.
19435         *
19436         * The success handler provided in the argument is executed only if the Adaptive Form is configured to use AJAX
19437         * for submission using {@link GuideBridge#registerConfig|registerConfig} API
19438         * @summary submits the Adaptive Form
19439         * @param {object} options options to control the behaviour of submit API.
19440         * @param {string} [options.submissionSelector] url selector governs the submission behaviour at server
19441         * Default value is "submit", other options are "agreement", "signSubmit"
19442         * @param {function} [options.success] callback which receives the result of the API
19443         * in case of success.
19444         * {@link GuideResultObject#errors|errors} property as false.
19445         * @param {function} [options.error] callback which receives the result of the API in
19446         * case of failure.
19447         * {@link GuideResultObject#errors|errors} property as true.
19448         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
19449         * object
19450         * @param {boolean} [options.validate=true] whether to validate the form before submission or not
19451         * @method
19452         * @memberof GuideBridge
19453         * @since 6.0
19454         * @instance
19455         * @example <caption>Submitting the form without validation</caption>
19456         * guideBridge.submit({
19457         *    validate: false,
19458         *    error : function (guideResultObject) {//log message}
19459         * });
19460         * @example <caption>Submitting the form and showing a success message</caption>
19461         * guideBridge.registerConfig("submitConfig" : {"useAjax" : true});
19462         * guideBridge.submit({
19463         *   validate: false,
19464         *   error : function (guideResultObject) {//log message}
19465         *   success : function (guideResultObject) {alert("data submitted successfully")
19466         * });
19467         */
19468
19469        submit : function (options) {
19470            // Disabling the submit button
19471            if (this._guideView) {
19472                var focusedElementSOM = guideBridge.getFocus();
19473                if (focusedElementSOM) {
19474                    _focusedSubmitButtonModel = guideBridge.resolveNode(focusedElementSOM);
19475                    _focusedSubmitButtonModel.enabled = false;
19476                }
19477            }
19478            _isAutoSaveEnabled = window.guideBridge.getAutoSaveEnabledStatus();
19479            //Disable auto save till submission is not completed
19480            if (_isAutoSaveEnabled) {
19481                window.guideBridge.setEnabledAutoSave(false);
19482            }
19483            var self = this;
19484            var guideContextFromOptions,
19485                runtimeGuideContext = getOrElse(this._guide, "runtime.guideContext", {});
19486            if (getOrElse(options, "guideState", "")) {
19487                guideContextFromOptions = options.guideState.data.guideState.guideContext;
19488            }
19489            var localGuideContext = guideContextFromOptions || runtimeGuideContext;
19490            // to submit guideContainerForm  which will be stopped so that autocomplete values can be remembered
19491            $(".guideContainerFormSubmitButton").click();
19492
19493            window.guideBridge._populateBindRefToSomMap();
19494
19495            function submitError(data) {
19496                self._ariaLiveAnnouncement(guidelib.i18n.strings["formSubmitFail"]);
19497                if (options && options.error) {
19498                    options.error.call(options.context || this, data);
19499                } else {
19500                    $.proxy(guideBridge._handleSubmitError(data), guideBridge);
19501                }
19502            }
19503
19504            function submitSuccess(result) {
19505                var isAjaxSubmit = false;
19506
19507                if (options) {
19508                    isAjaxSubmit = options.success ? true : false;
19509                }
19510                options = options || {};
19511                options.success = options.success || (self.userConfig.submitConfig || {}).submitSuccessHandler;
19512                isAjaxSubmit = isAjaxSubmit || (self.userConfig.submitConfig || {useAjax : false}).useAjax || guideBridge._guide.enableAsyncSubmission;
19513                var submitData = {};
19514
19515                if (this.isGuideLoaded()) {
19516                    var guideCaptchaList = [];
19517                    this.visit(function (node) {
19518                        if (node.className === "guideCaptcha") {
19519                            guideCaptchaList.push(node);
19520                        }
19521                    });
19522                    var captchaModel = guideCaptchaList[0];
19523                    if (captchaModel) {
19524                        var captchaData = window.guideBridge._getCaptchaData(captchaModel);
19525                        submitData['captchaData'] = captchaData;
19526                    }
19527                }
19528
19529                // check if guide state is present, if yes get guide path from guide state
19530                var guidePath = getOrElse(options, "guideState.data.guideState.guideContext.guidePath", ""),
19531                    guideContainerPath = guidePath || window.guideBridge.getGuidePath(),
19532                    aemFormComponentPath = this.userConfig.submitConfig ? this.userConfig.submitConfig.aemFormComponentPath : "",
19533                    submissionSelector = options.submissionSelector || "submit",
19534                    actionUrl = window.guideBridge._getGuidePathUrl(".af." + submissionSelector + ".jsp", guideContainerPath);
19535
19536                submitData['guideContainerPath'] = guideContainerPath;
19537                submitData['aemFormComponentPath'] = aemFormComponentPath;
19538                submitData['_asyncSubmit'] = isAjaxSubmit;
19539                submitData['_charset_'] = "UTF-8";
19540                var customPropMap = localGuideContext.customPropertyMap || {};
19541                // need to remove lastFocusItem from being sent as a different property
19542                // as it being sent in xml and with afSubmissionInfo as well.
19543                var whiteListedProperties = ["lastFocusItem"];
19544                for (var prop in customPropMap) {
19545                    if (customPropMap.hasOwnProperty(prop) && whiteListedProperties.indexOf(prop) < 0) {
19546                        submitData[prop] = customPropMap[prop];
19547                    }
19548                }
19549                // todo: Have to remove the excludeFromDor map from the submission info, is this required ?
19550                if (this.isGuideLoaded()) {
19551                    submitData['afSubmissionInfo'] = this._guide.runtime.guideContext.afSubmissionInfo || {};
19552                }
19553                var resultJson = result,
19554                    guideJson,
19555                    data,
19556                    fileAttachmentsList,
19557                    attachments = [],
19558                    fileCount = 0;
19559                if (resultJson.hasOwnProperty("guideValue")) {
19560                    guideJson = resultJson.guideValue;
19561                } else if (!_.isUndefined(options.guideValueMap)) {
19562                    guideJson = options.guideValueMap;
19563                } else {
19564                    // todo: why is this required in client ?
19565                    guideJson = window.guideBridge._prepareGuideValueMap();
19566                }
19567                if (resultJson.hasOwnProperty("data")) {
19568                    data = resultJson["data"];
19569                }
19570
19571                if (resultJson.hasOwnProperty("fileAttachmentsList")) {
19572                    fileAttachmentsList = resultJson["fileAttachmentsList"];
19573                }
19574
19575                for (var key in guideJson) {
19576                    if (guideJson.hasOwnProperty(key)) {
19577                        submitData[key] = guideJson[key];
19578                    }
19579                }
19580
19581                if (data) {
19582                    submitData['jcr:data'] = data;
19583                    submitData['jcr:data@TypeHint'] = "Binary";
19584                    if (self.isGuideLoaded()) {
19585                        self._guide.internal.afdata = data;
19586                    }
19587                }
19588                if (!_.isUndefined(options.fileAttachmentMap)) {
19589                    submitData.fileAttachmentMap = options.fileAttachmentMap;
19590                } else {
19591                    //send the fileAttachmentMap through submit data to restore submission attachments for read only viewing
19592                    submitData.fileAttachmentMap = JSON.stringify(guideBridge._getFileAttachmentMapForSubmit());
19593                }
19594                // read the additional information from the guideState if it is passed in options
19595                // otherwise get the additional information from the DOM
19596                var additionalSubmitInfo = {};
19597                if (options.guideState && options.guideState.data.guideState.additionalSubmitInfo) {
19598                    additionalSubmitInfo = options.guideState.data.guideState.additionalSubmitInfo;
19599                } else {
19600                    additionalSubmitInfo = guideBridge._getAdditionalSubmitInfo();
19601                }
19602                // append additionalSubmitInfo to the submitData
19603                $.extend(true, submitData, additionalSubmitInfo);
19604
19605                if (isAjaxSubmit && isAjaxSubmit === true) {
19606                    // if the fileAttachmentMap is passed in the options, then we don't need to upload the files as the map contains the uploaded path only.
19607                    // we just update the submitData with the attachment information
19608                    if (options.fileAttachmentMap) {
19609                        var attachmentMap = JSON.parse(options.fileAttachmentMap);
19610                        var keys = _.keys(attachmentMap);
19611                        for (var i = 0; i < keys.length; i++) {
19612                            if (attachmentMap[keys[i]]) {
19613                                var fileNames = attachmentMap[keys[i]].split("\n");
19614                                for (var j = 0; j < fileNames.length; j++) {
19615                                    var name = guideBridge._getRelativeFilePath(fileNames[j]);
19616                                    attachments[fileCount++] = name;
19617                                    submitData["_guideFileAttachment." + name] = fileNames[j];
19618                                }
19619                            }
19620                        }
19621                        submitData['_guideAttachments'] = attachments;
19622                        self.doAjaxSubmit(actionUrl, submitData, options);
19623                    } else {
19624                        var attachedFilesList = [];
19625                        var currentCount = 0;
19626                        // need to check if the guide is loaded, as it is not available for mobile workspace app use case
19627                        if (guideBridge.isGuideLoaded()) {
19628                            attachedFilesList = window.guideBridge._getFileAttachmentsList();
19629                        }
19630                        _.each(attachedFilesList, function (object) {
19631                            var fileNameList = object["fileAttachment"].value;
19632                            if (fileNameList) {
19633                                currentCount++;
19634                            }
19635                        });
19636                        // If a file has been attached and isAjaxSubmit is true, then a UUID is generated and
19637                        // the files are uploaded at temp storage path.
19638                        // The submit data is updated with the attached files and then
19639                        // doAjaxSubmit is called.
19640                        if (currentCount > 0) {
19641                            self.doAjaxSubmitWithFileAttachment(actionUrl, submitData, options, attachedFilesList);
19642                        } else {
19643                            self.doAjaxSubmit(actionUrl, submitData, options);
19644                        }
19645                    }
19646                } else {
19647                    var $form = self._getFormForSubmission();
19648                    $form.attr('action', actionUrl);
19649                    $form.attr('data-name', 'afSubmissionForm');
19650                    for (var fields in submitData) {
19651                        if (submitData.hasOwnProperty(fields)) {
19652                            var value = submitData[fields];
19653                            $("<input>").attr("type", "hidden")
19654                                .attr("name", fields)
19655                                .val(_.isObject(value) ? JSON.stringify(value) : value)
19656                                .appendTo($form);
19657                        }
19658                    }
19659                    /*
19660                     * This means we did not do any preprocessing
19661                     * for file attachments so fileAttachment list won't be present
19662                     * so posting DOM for the files.
19663                     * */
19664                    var attachmentNameDomMap = guideBridge._getFileNameFileDomMap(),
19665                        fileNameList = [],
19666                        _guideAttachments = "";
19667                    // A string containing the names of all the files that are attached is stored in the variable _guideAttachments.
19668                    // For all the files that have been uploaded already and don't have a dom element are
19669                    // added to $form with prefix "_guideFileAttachment."
19670                    if (attachmentNameDomMap && attachmentNameDomMap.fileDom) {
19671                        fileNameList = attachmentNameDomMap.fileName;
19672                        _.each(attachmentNameDomMap.fileDom, function (file, index) {
19673                            if (!_.isString(file)) {
19674                                file.attr("name", fileNameList[index].split["\n"])
19675                                    .attr("class", "hidden")
19676                                    .appendTo($form);
19677                                _guideAttachments += fileNameList[index] + ",";
19678                            } else {
19679                                if (fileNameList[index]) {
19680                                    var name = guideBridge._getRelativeFilePath(fileNameList[index]);
19681                                    $("<input>").attr("type", "hidden")
19682                                        .attr("name", "_guideFileAttachment." + name)
19683                                        .attr("value", file)
19684                                        .appendTo($form);
19685                                    _guideAttachments += name + ",";
19686                                }
19687                            }
19688                        });
19689                    }
19690                    $("<input>").attr("type", "hidden")
19691                        .attr("name", "_guideAttachments")
19692                        .attr("value", _guideAttachments)
19693                        .appendTo($form);
19694
19695                    $form.submit();
19696                }
19697            }
19698
19699            self._showGuideLoading(true, guidelib.i18n.strings.val
19699idatingForm);
19700            // since validate is synchronous call, putting this in timeout
19701            // so that html changes can be display
19702            setTimeout(function () {
19703                // update the snapshot just before validating
19704                // so that we get true state of play before loading panels
19705                if (guideBridge.isGuideLoaded() && guideBridge._guide.allLazyChildren && guideBridge._guide.allLazyChildren.length > 0) {
19706                    self._guide.internal.liveDataUtils.updateLiveData();
19707                }
19708                var isValid = false;
19709                try {
19710                    isValid = self._performConditionalValidation(options);
19711                } catch (e) {
19712                    isValid = false;
19713                } finally {
19714                    self._showGuideLoading(true);
19715                }
19716                if (isValid) {
19717                    /* Handle Invisible Recaptcha on form submission */
19718                    var recaptchaInvisibleElement = FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) ?
19719                        $("#captchaInvisible") : $("#recaptchaInvisible");
19720                    if (recaptchaInvisibleElement != undefined && recaptchaInvisibleElement.attr("af-recaptcha-execute") == "") {
19721                        recaptchaInvisibleElement.trigger({
19722                            type: "recaptchaExecution",
19723                            submitParameters: {
19724                                options: options,
19725                                success: submitSuccess,
19726                                error: submitError
19727                            },
19728                            triggerPostSubmission: true
19729                        });
19730                        return;
19731                    }
19732                    guideBridge._submitAfterValidation(options, submitSuccess, submitError);
19733                } else {
19734                    window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
19735                    self._showGuideLoading(false);
19736                    return;
19737                }
19738            }, 1);
19739        },
19740        /**
19741         * @private
19742         */
19743        _handleInternalSubmitError : function (submitError, selfVar, args) {
19744            try {
19745                submitError.apply(selfVar, args);
19746            } catch (e) {
19747                //ignoring the error
19748            } finally {
19749                guideBridge._showGuideLoading(false);
19750
19751            }
19752        },
19753        /**
19754         * @private
19755         */
19756        _getFileAttachmentMapForSubmit : function () {
19757            var fileAttachmentMap = {},
19758                fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
19759            for (var i = 0; i < fileAttachmentsList.length; i++) {
19760                var node = fileAttachmentsList[i];
19761                if (!_.isUndefined(node.value) && node.value.length > 0) {
19762                    var attachmentList = node.value.split("\n");
19763                    for (var j = 0; j < attachmentList.length; j++) {
19764                        attachmentList[j] = node.name + "/" + attachmentList[j];
19765                    }
19766                    fileAttachmentMap[node.somExpression] = attachmentList.join('\n');
19767                }
19768            }
19769
19770            var lazyAttachmentMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap();
19771            _.each(lazyAttachmentMap, function (mapObject, key) {
19772                var attachmentList = mapObject.value.split("\n");
19773                for (var j = 0; j < attachmentList.length; j++) {
19774                    attachmentList[j] = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + attachmentList[j];
19775                }
19776                fileAttachmentMap[key] = attachmentList.join('\n');
19777            });
19778            return fileAttachmentMap;
19779        },
19780
19781        ERROR_CAUSED_BY : {
19782            CAPTCHA_VALIDATION : "CAPTCHA_VALIDATION",
19783            SERVER_SIDE_VALIDATION : "SERVER_SIDE_VALIDATION",
19784            FORM_SUBMISSION : "FORM_SUBMISSION",
19785            AGREEMENT_CREATION : "AGREEMENT_CREATION",
19786            AGREEMENT_CREATION : "AGREEMENT_CREATION",
19787            SERVICE_INVOCATION_FAILURE: "SERVICE_INVOCATION_FAILURE"
19788        },
19789
19790        /**
19791         * This API displays validation error messages at the field level corresponding to the input errorJson object
19792         * @summary Displays validation error messages at field level
19793         * @memberof GuideBridge
19794         * @instance
19795         * @param {object}
19795 errorJson json object containing the error messages in the [standard format](https://helpx.adobe.com/experience-manager/6-5/forms/using/custom-validation-message-adaptive-forms.html)
19796         * @see {@link https://helpx.adobe.com/experience-manager/6-5/forms/using/custom-validation-message-adaptive-forms.html%7CCustom validation message in adaptive form}
19797         */
19798        handleServerValidationError : function (errorJson) {
19799            var self = this;
19800            if (errorJson) {
19801                var errors = errorJson.errors;
19802                if (errors && errors.length > 0) {
19803                    var firstFocusableSom;
19804                    _.each(errors, function (object, i) {
19805                        var errMsg;
19806                        if (object.errorMessages) {
19807                            errMsg = object.errorMessages.join("\n");
19808                        } else {
19809                            errMsg = object.errorMessage;
19810                        }
19811                        var som = (object.somExpression) ? object.somExpression : self._guide._bindRefMap[object.bindRef];
19812                        var node = self.resolveNode(som);
19813
19814                        if (node) {
19815                            if (!firstFocusableSom) {
19816                                firstFocusableSom = som;
19817                            }
19818                            node.markAsInvalid(errMsg);
19819                        }
19820                    });
19821                    // set focus to first invalid node
19822                    if (firstFocusableSom) {
19823                        self.setFocus(firstFocusableSom);
19824                    }
19825                }
19826            }
19827        },
19828
19829        /* Handle the server side validation failure in case of submission fails.
19830         * This function handles Captcha validation as well as server side validation.
19831         * @private
19832         */
19833        _handleServerValidationError : function (errorJson) {
19834            var self = this;
19835            window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
19836            if (errorJson) {
19837                if (errorJson.errorCausedBy && errorJson.errorCausedBy === this.ERROR_CAUSED_BY.CAPTCHA_VALIDATION) {
19838                    var errors = errorJson.errors,
19839                        firstFocusableSom = errors[0].somExpression;
19840                    _.each(errors, function (object, i) {
19841                        var somExpression = object.somExpression,
19842                            errorMessage = object.errorMessage,
19843                            guideCaptcha;
19844                        /*Setting focus to load captcha's view.
19845                         This is required when panel's children get loaded later.
19846                         Setting focus ensures that view is loaded properly so that model can throw
19847                         'guide.errorChanged' event and view can listen the same.
19848                         */
19849                        self.setFocus(somExpression);
19850                        guideCaptcha = self.resolveNode(somExpression);
19851                        if (guideCaptcha) {
19852                            guideCaptcha.showCaptchaError(errorMessage);
19853                        }
19854                    });
19855                    //Setting focus to the first captcha element.
19856                    self.setFocus(firstFocusableSom);
19857                } else if (errorJson.errorCausedBy && errorJson.errorCausedBy === this.ERROR_CAUSED_BY.FORM_SUBMISSION
19858                    || errorJson.errorCausedBy === this.ERROR_CAUSED_BY.AGREEMENT_CREATION) {
19859                    if (errorJson.errors && errorJson.errors.length > 0) {
19860                        window.guideBridge.handleServerValidationError(errorJson);
19861                    } else {
19862                        var statusCode = errorJson.originCode ? Number(errorJson.originCode) : 500,
19863                            errorMessage = statusCode === 400 ? (errorJson.errorMessage ? errorJson.errorMessage : "") : "";
19864                        // show the message returned by server only if if the HTTP status code is 400
19865                        // this is done so that users could act upon the error and re-submit the form
19866                        $.proxy(guideBridge._handleSubmitError({
19867                            "status" : statusCode
19868                        }, errorMessage), guideBridge);
19869                    }
19870                } else {
19871                    //Everything else is "SERVER_SIDE_VALIDATION". Calling this as it was being called.
19872                    window.guideBridge.handleServerValidationError(errorJson);
19873                }
19874            }
19875        },
19876
19877        /*
19878         * Populates bindRefToSomMap.
19879         * This function is called during submission and during unloading of a lazy fragment
19880         * @param {node} is equal to the lazy loaded fragment model if this is called during lazy fragment unloading
19881         * @private
19882         */
19883        _populateBindRefToSomMap : function (node) {
19884
19885            /*
19886             * While populating bindRefToSomMap we basically check if any panel is repeatable panel.
19887             * If a panel is repeatable, in that node and its desce
19887ndant nodes we replace the bindRef
19888             * by corresponding json-pointer in the map.
19889             * parameter {jsonp} refers to the json-pointer of the parent node. It is valid if
19890             * some ancestor of current node in the hierarchy was a repeatable panel
19891             */
19892            var bindRefToSomMapper = function (node, map, jsonp) {
19893                var path, bindref;
19894                if (node.bindRef) {
19895                    if (node.repeatable) { // current node is a repeatable panel
19896                        if (jsonp) { // some ancestor panel in the hierarchy was a repeatable panel
19897                            path = jsonp + "/" + node.bindRef.split("/").slice(-1)[0] + "/" + node.index;
19898                            bindref = path;
19899                        } else { // current node is the first repeatable panel in the hierarchy
19900                            path = node.bindRef + "/" + node.index;
19901                            bindref = path;
19902                        }
19903                    } else {
19904                        if (jsonp) { // some panel in the upper level was a repeatable panel
19905                            path = jsonp + "/" + node.bindRef.split("/").slice(-1)[0];
19906                            bindref = path;
19907                        } else { // no repeatable panel till now
19908                            bindref = node.bindRef;
19909                        }
19910                    }
19911                    map[bindref] = node.somExpression;
19912                }
19913
19914                if (node._children) {
19915                    node._children.forEach(function (element) {
19916                        bindRefToSomMapper(element, map, path);
19917                    });
19918                }
19919            };
19920            var jsonp;
19921
19922            // since we support lazy-loading for a fragment upto only two level deep, the immediate parent panel
19923            // of a lazy-loaded fragment can atmost be a repeatable panel. so we only check the repeatability for the parent
19924            if (node && node.parent && node.parent.repeatable && node.parent.bindRef) {
19925                jsonp = node.parent.bindRef + "/" + node.parent.index;
19926            }
19927
19928            if (!node) {
19929                node = window.guideBridge._guide;
19930            }
19931
19932            if (window.guideBridge.isGuideLoaded()) {
19933                if (!window.guideBridge._guide._bindRefMap) {
19934                    window.guideBridge._guide._bindRefMap = {};
19935                }
19936                bindRefToSomMapper(node, window.guideBridge._guide._bindRefMap, jsonp);
19937            }
19938        },
19939
19940        SELECTOR_FORM_CONTAINER : "#guideContainerForm",
19941
19942        THANK_YOU_OPTION : {
19943            PAGE : "page",
19944            MESSAGE : "message"
19945        },
19946        /*
19947         *  default Submit Success Handler.
19948         *  This function handles the Thank You Page/Message
19949         */
19950        _defaultSubmitSuccessHandler : function (successPayload) {
19951            if (successPayload) {
19952                if (successPayload.thankYouOption === this.THANK_YOU_OPTION.MESSAGE) {
19953                    var tyMessage = $("<div class='tyMessage'>" + successPayload.thankYouContent + "</div>");
19954                    $(this.SELECTOR_FORM_CONTAINER).replaceWith(tyMessage);
19955                    tyMessage.attr({'tabindex': '-1',
19956                        'role': 'alertdialog'});
19957                    tyMessage.focus();
19958                } else if (successPayload.thankYouOption === this.THANK_YOU_OPTION.PAGE) {
19959                    window.location.href = encodeURI(successPayload.thankYouContent);
19960                }
19961            }
19962        },
19963
19964        // This function gets the relative path of the file.
19965        // Suppose the component Name is attachment and the file name is a.jpg,
19966        // then it will return "attachment/a.jpg" as the path
19967        _getRelativeFilePath : function (fileName) {
19968            var relPath = fileName;
19969            if (fileName.indexOf("/") !== -1) {
19970                var splitPath = fileName.split("/");
19971                if (splitPath.length > 2) {
19972                    relPath = splitPath[splitPath.length - 2] + "/" + splitPath[splitPath.length - 1];
19973                }
19974            }
19975            return relPath;
19976        },
19977
19978        // We do not need to validate if options.validate = false.
19979        // This function makes sure that validations are not performed when validate flag is false.
19980        // Validation is performed in all the other cases.
19981        _performConditionalValidation : function (options) {
19982            if (getOrElse(options, "validate", true)) {
19983                return guideBridge.validate(null, null, true, false);
19984            }
19985            return true;
19986        },
19987
19988        /**
19989         * This API returns the HTML content of another Adaptive Form and optionally load the Form inside an HTML
19990         * element
19991         *
19992         * The {@link GuideResultObject#data|data}
19992 property of the result passed to success handler will contain the HTML of
19993         * the Form
19994         * @summary load an Adaptive Form given its path
19995         * @param {object} options object to pass to the API
19996         * @param {function} [options.success] callback which receives the result of the API
19997         * in case of success.
19998         * {@link GuideResultObject#errors|errors} property as false.
19999         * @param {function} [options.error] callback which receives the result of the API in
20000         * case of failure.
20001         * {@link GuideResultObject#errors|errors} property as true.
20002         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
20003         * object
20004         * @param {string} options.path Path of the Adaptive Form whose HTML is required. If sever is running at a
20005         * context path, this parameter must have the context path
20006         * @param {string} [options.dataRef] URL of the resource that returns the XML. The protocol of the URL must
20007         * match the supported URL protocols
20008         * @param {string} [options.containerSelector] jquery Selector of the HTML element where to insert the HTML
20009         * of the form.
20010         * @method
20011         * @memberof GuideBridge
20012         * @since 6.1 FP1
20013         * @instance
20014         * @example
20015         * guideBridge.loadAdaptiveForm({
20016         *      success : function (guideResultObj) {console.log("html is " + guideResultObj.data)},
20017         *      error : function (guideResultObj) { //log errors},
20018         *      dataRef : "http://url/of/the/dataRef",
20019         *      path : "/contextpath/content/dam/formsanddocuments/form1"
20020         * })
20021         * @see {@link https://api.jquery.com/category/selectors/|jQuery selectors}
20022         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
20023         */
20024        loadAdaptiveForm : function (options) {
20025            if (options && options.path) {
20026                // Let's covert the adaptive form asset path or af path
20027                // @todo: add notion of channel type in the options to load adaptive form
20028                var path = options.path.replace(FM_DAM_ROOT, FM_AF_ROOT);
20029                path += "/jcr:content/guideContainer.html";
20030                $.ajax({
20031                    url : path,
20032                    type : "GET",
20033                    data : {
20034                        // lets set the wcmmode to disabled
20035                        wcmmode : "disabled",
20036                        // Set the data reference
20037                        "dataRef" : options.dataRef
20038                    },
20039                    async : false,
20040                    success : function (data) {
20041                        // Get the container selector and do a replaceWith HTML
20042                        // not using jquery since jquery create a separate array objects for script, link etc
20043                        if (options.containerSelector) {
20044                            //NOCHECKMARX - data is coming from serverside preventing Reflective XSS All Clients.
20045                            $(options.containerSelector).html(data);
20046                        }
20047                        var guideResultObject = new GuideResultObject();
20048                        // data would here be html
20049                        guideResultObject.data = data;
20050                        guideResultObject.completed = true;
20051                        if (options.success && _.isFunction(options.success)) {
20052                            options.success.call(options.context, guideResultObject);
20053                        }
20054                    },
20055                    error : function (data) {
20056                        var guideResultObject = new GuideResultObject();
20057                        // data is an object containing xhr request, status and error
20058                        guideResultObject.data = data;
20059                        guideResultObject.completed = false;
20060                        guideResultObject.addMessage(2, "Error in getting HTML of Adaptive Form: " + options.path, "");
20061                        if (options.error && _.isFunction(options.error)) {
20062                            options.error.call(options.context, guideResultObject);
20063                        }
20064                    }
20065                });
20066            } else {
20067                if (typeof(console) !== "undefined") {
20068                    console.log("Path of Adaptive Form not specified to loadAdaptiveForm API");
20069                }
20070            }
20071        },
20072
20073        /**
20074         * Unloads the Form loaded using the {@link GuideBridge#loadAdaptiveForm|loadAdaptiveForm} API
20075         * @summary Unloads an adaptive Form from the browser, removing all the existing event listeners, data, html.
20076         * @param containerSelector jQuery Selector of the container, which contains the HTML of the Adaptive Form
20077         * @method
20078         * @memberof GuideBridge
20079         * @since 6.1 FP1
20080         * @instance
20081         * @see {@link https://api.jquery.com/category/selectors/|jQuery selectors}
20082         */
20083        unloadAdaptiveForm : function (containerSelector) {
20084            // Let's clear all intervals
20085            // Never make intervals, which are not cleared
20086            if (window.guidelib && window.guidelib.intervals) {
20087                // check for null safe
20088                window.clearInterval(window.guidelib.intervals.intId);
20089            }
20090            // Remove all the child present in the container
20091            $(containerSelector).children().remove();
20092            // Clean the date picker html
20093            // todo: clean other HTML which we add outside Adaptive Form
20094            $('body').find(".datePickerTarget").remove();
20095
20096            // todo: what are the even listeners to clean ?
20097            $(window).off("guideModelInitialized");
20098            $(window).off("guideInitialized");
20099            $(window).off("guideInitializationError");
20100            // todo: What if there is an existing load, scroll or resize listener already present in page ?
20101            $(window).off("load scroll resize");
20102            $(window).off("keydown.guides");
20103
20104            $('.guideContainerWrapperNode').off("swiperight");
20105            $('.guideContainerWrapperNode').off("swipeleft");
20106
20107            // Remove all delegated event listeners
20108            $(document).off('click.guidetab.data-api');
20109            $(document).off('click.guideAddRemove.data-api');
20110
20111            // Remove date picker event listeners
20112            $(window).off("touchstart.datetimepicker mousedown.datetimepicker");
20113
20114            if (window.guidelib) {
20115                // Start cleaning data
20116                window.guidelib.runtime = {
20117                    guide : null,
20118                    af : null, // not sure if making it null would impact, since this namespace hold's public functions
20119                    guideContext : null,
20120                    _private : {},
20121                    errorManager : null
20122                };
20123
20124                window.guidelib.internal = {
20125                    liveModel : null,
20126                    liveDataUtils : null,
20127                    GuideDirtyMarkerAndVisitor : null
20128                };
20129            }
20130
20131            if (window.guideBridge) {
20132                // Unload all guideBridge references
20133                window.guideBridge._guide = null;
20134                window.guideBridge._guideView = null;
20135                window.guideBridge._$target = null;
20136                window.guideBridge._guideDoc = null;
20137            }
20138            if (window.xfalib) {
20139                // We always load ut for logger
20140                window.xfalib.ut = null;
20141            }
20142            // If form bridge exist's call form bridge to destroy form
20143            if (window.formBridge) {
20144                window.formBridge.destroyForm();
20145            }
20146            // Clear any jquery cache, this should avoid memory leak
20147            if (window.jQuery) {
20148                // note: repeatable template marker div was held by jquery fragment
20149                // Before converting the HTML string to a DOM subtree, there is a lot of process involved
20150                // To make the process faster there is a "fragment cache" that saves the processed string as DOM nodes
20151                // Let's clean the fragment cache
20152                window.jQuery.fragments = {};
20153            }
20154
20155            if (window.guidelib && window.guidelib.model) {
20156                // Clean accessible objects
20157                window.guidelib.model.GuideNode.guideUtil = null;
20158            }
20159
20160            // Lets clean all guidelib object's at first level
20161            // Let's hope there are no closure objects created or any reference of objects inside guidelib
20162            _.each(window.guidelib, function (obj, key) {
20163                // "util", "event", "model", "view", "runtime", "author", "log", "i18n", "guideReplaced" get's cleaned here
20164                window.guidelib[key] = undefined;
20165            });
20166
20167            if ($) {
20168                // Lets clean all jquery plugin's created
20169                //window.$.Widget = undefined;
20170                //window.$.widget = undefined;
20171                $.xfaWidget = undefined;
20172                // May be required if we want to unload the entire page.
20173                // window.$.fn = undefined;
20174                $.prototype.abstractWidget = undefined;
20175                $.prototype.adobeDateTimePicker = undefined;
20176                $.prototype.adobeFileAttachment = undefined;
20177                $.prototype.adobeFileUploader = undefined;
20178                $.prototype.dateTimeEdit = undefined;
20179                $.prototype.dropDownList = undefined;
20180                $.prototype.defaultWidget = undefined;
20181                $.prototype.fileUpload = undefined;
20182                $.prototype.imageField = undefined;
20183                $.prototype.listBox = undefined;
20184                $.prototype.nwkListBox = undefined;
20185                $.prototype.numericInput = undefined;
20186                $.prototype.signatureField = undefined;
20187                $.prototype.ScribbleImageField = undefined;
20188                $.prototype.textField = undefined;
20189                $.prototype.xfaButton = undefined;
20190                $.prototype.XfaCheckBox = undefined;
20191            }
20192        },
20193
20194        /**
20195         * Disables all the fields and global toolbar
20196         * @private
20197         */
20198        _disableForm : function () {
20199            var rootPanel = guideBridge.resolveNode("guide[0].guide1[0].guideRootPanel[0]"),
20200                globalToolbar = guideBridge.resolveNode("guide[0].guide1[0].toolbar[0]");
20201
20202            // The following API disables the loaded fields
20203            rootPanel.disableAllFields();
20204            // The following API disables the form toolbar
20205            if (globalToolbar) {
20206                globalToolbar.disableAllFields();
20207            }
20208        },
20209
20210        /**
20211         * @summary Disables the adaptive form, i.e. it disables all the fields and buttons, including toolbar's button
20212         * @method
20213         * @memberof GuideBridge
20214         * @since 6.3
20215         */
20216        disableForm : function () {
20217            guideBridge._disableForm();
20218            //Listening on guideBridge for "elementLazyLoaded" event to disable lazily loaded fields
20219            guideBridge.on("elementLazyLoaded", guideBridge._disableForm);
20220        },
20221
20222        _playGuideJson : function (options) {
20223            this._guide.setGuideState(guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_PROGRESS);
20224            /*
20225             * no need to check here since merged json will not have xfaState if
20226             * xdp is invalid
20227             */
20228            if (this._isXfaGuide() && options.guideState.xfaState && options.guideState.xfaState.xfaDom) {
20229                var that = this;
20230                window.formBridge.restoreFormState({
20231                    formState : options.guideState.xfaState,
20232                    context : this,
20233                    //NOCHECKMARX - This is error callback to be provided by the user of this API.
20234                    error : options.error || defaultErrorHandler,
20235                    success : function () {
20236                        that._playNonXfaJson(options);
20237                    }
20238                });
20239            } else {
20240                this._playNonXfaJson(options);
20241            }
20242        },
20243
20244        _playNonXfaJson : function (options) {
20245            // try to  get xml-s from restore state 1st as they will be more relevant than the prefill state
20246            var xmlStr = getOrElse(options, "guideState.guideLiveData", null)
20247                    || getOrElse(options, "guideState.guidePrefillXml", null),
20248                xfaXmlStr = getOrElse(options, "guideState.xfaState.currentContext.data", null)
20249                    || JSON.parse(getOrElse(options, "guideState.xfaState.xfaRenderContext", "{}")).data,
20250                jsonStr = getOrElse(options, "guideState.guidePrefillJson", null);
20251            if (xmlStr || xfaXmlStr) {
20252                this._guide.internal.liveDataUtils.initLiveData(xmlStr, xfaXmlStr,
20253                    _.isString(this._guide.xdpRef), _.isString(this._guide.xsdRef),
20254                    this._guide.getAttribute("xsdRootElement"));
20255                this._guide.internal.liveModel.prefillCrossFragFields(this._guide);
20256                this._guide.internal.liveDataUtils.dropXfaXml();
20257            } else if (jsonStr) {
20258                this._guide.internal.liveDataUtils.initLiveData(jsonStr, this._guide.runtime.guideContext);
20259            } else {
20260                this._guide.internal.liveDataUtils.initLiveData(null, null,
20261                    _.isString(this._guide.xdpRef), _.isString(this._guide.xsdRef),
20262                    this._guide.getAttribute("xsdRootElement"));
20263            }
20264
20265            // If the restore state is not stored in local storage,then use it from the json passed from the server
20266            if (options.guideState.guideDom) {
20267                this._guide.playJson(options.guideState.guideDom, options.attachments);
20268            }
20269            if (options.guideState.unboundDataMap && options.guideState.unboundDataMap.data) {
20270                this.visit(function (node) {
20271                    // Fileupload value should not be set again, as it replaces the url with the file name
20272                    if (!(node instanceof guidelib.model.GuideFileUpload) && (node instanceof guidelib.model.Field || node instanceof guidelib.model.GuideCompositeField)
20273                        && !node.getAttribute("bindRef") && options.guideState.unboundDataMap.data[node.name]) {
20274                        var nodeValue = options.guideState.unboundDataMap.data[node.name];
20275                        //If the xml had empty tag, an empty object will come in the map, so set to null.
20276                        if (_.isObject(nodeValue) && _.isEmpty(nodeValue)) {
20277                            node._setGuideValue(null);
20278                        } else {
20279                            node._setGuideValue(nodeValue);
20280                        }
20281
20282                        if (node.className === "guideRadioButton") {
20283                            node.prevOnItem = node.getSelectedIndex(node.jsonModel._value);
20284                        }
20285                    }
20286                });
20287            }
20288            this._guide.setGuideState(guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_COMPLETE);
20289            this._guide.prepare();
20290
20291            if (options.success) {
20292                options.success.call(this);
20293            }
20294        },
20295
20296        _postExternalMessage : function (message) {
20297            if (this.userConfig["postExternalMessageConfig"] && _.isFunction(this.userConfig["postExternalMessageConfig"]["postExternalHandler"])) {
20298                var externalHandler = this.userConfig["postExternalMessageConfig"]["postExternalHandler"];
20299                externalHandler(message);
20300            }
20301        },
20302
20303        _isXfaGuide : function () {
20304            if (this._guide.xdpRef) {
20305                return true;
20306            } else {
20307                return false;
20308            }
20309        },
20310        _readRuntimeLocale : function (runtimeLocale) {
20311            return this.customContextProperty("runtimeLocale", runtimeLocale);
20312
20313        },
20314
20315        /*
20316         * checks whether xdp present in Adaptive Form is valid or not
20317         * This is verified by checking the xdpRef property in guideContext
20318         */
20319        _isValidXFAGuide : function () {
20320            return !_.isUndefined(this._guide.runtime.guideContext.xdpRef);
20321        },
20322
20323        _isEditDesignMode : function () {
20324            if (window.CQ && window.CQ.WCM && (window.CQ.WCM.isEditMode() || window.CQ.WCM.isDesignMode())) {
20325                return true;
20326            } else {
20327                return false;
20328            }
20329        },
20330
20331        /**
20332         *
20333         * This function does following:
20334         * a) On first call, it creates the uuid storage and returns the UUID
20335         * b) On subsequent calls, it just returns the uuid
20336         * c) if uuid is not created then it returns null
20337         *
20338         * @private
20339         */
20340        _getUUID : function () {
20341            if (this._formInstanceUUID) {
20342                return this._formInstanceUUID;
20343            }
20344            //Generate the UUID for the form instance on client side
20345            var successFlag = true;
20346            this._formInstanceUUID = guideBridge._produceUUID();
20347            successFlag = createUUIDStorage(this._formInstanceUUID);
20348            if (!successFlag) {
20349                var message = "Could not create UUID storage";
20350                guideBridge._guide.logger().log(message);
20351            }
20352            return this._formInstanceUUID;
20353        },
20354
20355        /**
20356         * This will produce new UUID
20357         * @returns {string}
20358         * @private
20359         */
20360        _produceUUID : function () {
20361            var uuid = $('div.guideContainerWrapperNode').data("tmproot"),
20362                uuidSuffix = Math.floor((Math.random() * 10000) + 1),
20363                uuidCurrentTime = new Date().getTime();
20364            return uuid + "_" + uuidCurrentTime + uuidSuffix;
20365        },
20366
20367        /**
20368         * Signature of the callback for the GuideBridgeEvent Listener. It must be passed as handler in the
20369         * {@link GuideBridge#on|on} API.
20370         * @callback GuideBridge~GuideBridgeEventCallback
20371         * @param {jQuery.Event} event jQuery Event Object with target property being the instance of GuideBridge
20372         * @param {Object} payload Payload containing extra information in the API
20373         * @see {@link http://api.jquery.com/category/events/event-object/|jQuery.Event}
20374         * @since 6.0
20375         */
20376        /**
20377         * The API can be used to add an event listener for events triggered by GuideBridge object
20378         *
20379         * @summary add a listener on a GuideBridge Event.
20380         * @param eventName {string} name of the event for which listener has to be added. It must be one of the
20381         * following events
20382         * * bridgeInitializeComplete
20383         * * elementEnableChanged
20384         * * elementFocusChanged
20385         * * elementHelpShown
20386         * * elementLazyLoaded
20387         * * elementNavigationChanged
20388         * * elementValidationStatusChanged
20389         * * elementValueChanged
20390         * * elementVisibleChanged:
20391         * * guideAutoSaveStart
20392         * * submitStart
20393         * * validationComplete
20394         * @param {function} handler callback to be invoked whenever the event is triggered. The signature of the
20395         * callback is {@link GuideBridge~GuideBridgeEventCallback|GuideBridgeEventCallback}
20396         * @param {object} [context] The _this_ object in the _handler_ will point to _context_
20397         *
20398         * @method on
20399         * @memberof GuideBridge
20400         * @instance
20401         * @since 6.0
20402         */
20403        on : function (eventName, handler, context) {
20404            this._$target.on(eventName, handler, context);
20405        },
20406
20407        /**
20408         * Unregister the event registered using the {@link GuideBridge#on|on} function
20409         *
20410         * @param eventName {string} name of the event to un-register.
20411         * @param [selector] {string} selector which should match the one originally passed to guideBridge's on() while registering handlers
20412         * @param [handler] {function} handler which needs to un-registered. If not provided all the event listeners
20413         * will be unregistered
20414         *
20415         * @method off
20416         * @memberof GuideBridge
20417         * @instance
20418         * @since 6.0
20419         */
20420
20421        off : function (eventName, selector, handler) {
20422            this._$target.off(eventName, selector, handler);
20423        },
20424
20425        /**
20426         * Internal API
20427         * @param extraParamerts
20428         * @param eventName
20429         * @private
20430         */
20431        trigger : function (eventName, extraParamerts) {
20432            this._$target.trigger(eventName, extraParamerts);
20433        },
20434
20435        /**
20436         * This will  return information
20437         * weather the the file attachment preview
20438         * needs to be enabled or not
20439         * @private
20440         * */
20441        _disablePreview : function () {
20442            if (this._guide && this._guide.runtime && this._guide.runtime.guideContext) {
20443                return this._guide.runtime.guideContext.disablePreview;
20444            }
20445        },
20446        /**
20447         * If the name of the file attachments have to be made unique then the
20448         * vaule of this function would be true else false
20449         * @returns {*}
20450         * @private
20451         */
20452        _makeFileNameUnique : function () {
20453            if (this._guide && this._guide.runtime && this._guide.runtime.guideContext) {
20454                return this._guide.runtime.guideContext.makeFileNameUnique;
20455            }
20456        },
20457        /*this function is used to mince out
20458         * file attachmenemts name and dom in case of
20459         * anonymous user
20460         * */
20461        _getFileNameFileDomMap : function () {
20462            var fileAttachmentsList = this._getFileAttachmentsList();
20463            return this._juiceOutNameAndFileDomMap(fileAttachmentsList);
20464        },
20465
20466        /**
20467         * Returns a list of file attachment wrapper object represeting all file binaries
20468         * @returns reference of {@link guidelib.model.FileAttachmentWrapper}
20469         * @method
20470         * @memberof GuideBridge
20471         * @since FaaCS
20472         * @instance
20473         */
20474        getFileAttachmentWrapper : function() {
20475            var fileNameDomBindRefMap = this._getFileNameFileDomMap(),
20476                attachments = [],
20477                fileDoms = fileNameDomBindRefMap.fileDom,
20478                fileNames = fileNameDomBindRefMap.fileName,
20479                bindRefs = fileNameDomBindRefMap.fileBindRef,
20480                contentTypes = fileNameDomBindRefMap.fileContentType,
20481                _getFileName = function (fileName, componentName) {
20482                    // if file name contains component name
20483                    if (fileName.indexOf(componentName) !== -1) {
20484                        return fileName.replace(componentName + "/", "");
20485                    } else if (fileName.indexOf("/") !== -1) {
20486                        // if file name is a URL
20487                        return fileName.substring(fileName.lastIndexOf('/') + 1);
20488                    }
20489                };
20490
20491            var fileNamesIndex;
20492            for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
20493                // multiple files inside one filedom element & draft save case is handled.
20494                var currentFileNames = fileNames[fileNamesIndex].split("\n");
20495                for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
20496                    if (fileDoms[fileNamesIndex] && !_.isString(fileDoms[fileNamesIndex]) && fileDoms[fileNamesIndex].length > 0) {
20497                        // append each file of input file element
20498                        attachments.push(new guidelib.model.FileAttachmentWrapper({
20499                            name : _getFileName(currentFileNames[fileIndex], bindRefs[fileNamesIndex]),
20500                            data : fileDoms[fileNamesIndex][0].files[fileIndex],
20501                            contentType : fileDoms[fileNamesIndex][0].files[fileIndex].type,
20502                            bindRef : bindRefs[fileNamesIndex]
20503                        }));
20504                    } else if (currentFileNames[fileIndex]) {
20505                        //handle draft save scenario when fileDoms[fileNamesIndex] is null & currentFileNames[fileIndex] is a url
20506                        attachments.push(new guidelib.model.FileAttachmentWrapper({
20507                            name : _getFileName(guideBridge._getRelativeFilePath(currentFileNames[fileIndex]), bindRefs[fileNamesIndex]),
20508                            data : fileDoms[fileNamesIndex],
20509                            contentType : contentTypes[fileNamesIndex],
20510                            bindRef : bindRefs[fileNamesIndex]
20511                        }));
20512
20513                    }
20514                }
20515            }
20516            return attachments;
20517        },
20518
20519        /**
20520         * Returns the file attachment name and dom (input type=file) element
20521         * The returned object contains a list of file Doms and a list of corresponding file Names.
20522         * If the file is already uploaded, then the file DOM is null and file Name contains the URL.
20523         * @param fileAttachmentsList object list of file attachment models
20524         * @returns {{fileName: Array, fileDom: Array}}
20525         * @private
20526         */
20527        _juiceOutNameAndFileDomMap : function (fileAttachmentsList) {
20528            var fileDoms = [],
20529                fullFileNames = [],
20530                fullContentTypes = [],
20531                fileBindRefs = [],
20532                fileContentTypes = [],
20533                fileCount = 0,
20534                loadedFileDoms = [],
20535                loadedBindRefs = [],
20536                loadedContentTypes = [],
20537                loadedFileNames = [];
20538
20539            _.each(fileAttachmentsList, function (fileAttachmentModel, index) {
20540                var fileName = fileAttachmentModel._getFileAttachmentNames(),
20541                    fileAttachmentModelValue = fileAttachmentModel.value,
20542                    effectiveBindRef = fileAttachmentModel._getEffectiveBindRef(),
20543                    fileNameList = fileName; // even in case of makeFileNameUnique context set, fileName has the correct unique value
20544                if (fileNameList) {
20545                    var fileNames = fileNameList.split("\n");
20546                    var fileList = $.extend(true, [], fileAttachmentModel.fileList);
20547                    var fileNamesIndex = 0;
20548
20549                    _.each(fileList, function (inputFileDOM, currIndex) {
20550                        var fileNamesOfFileDom = null;
20551
20552                        // case: if there is a file dom
20553                        if (!_.isString(inputFileDOM)) {
20554                            _.each(inputFileDOM[0].files, function (file) {
20555                                var fileName = fileNames[fileNamesIndex++];
20556                                if (fileName) {
20557                                    if (fileNamesOfFileDom) {
20558                                        fileNamesOfFileDom += "\n" + fileAttachmentModel.name + "/" + fileName;
20559                                    } else {
20560                                        fileNamesOfFileDom = fileAttachmentModel.name + "/" + fileName;
20561                                    }
20562                                }
20563                            });
20564                            if (fileNamesOfFileDom != null) {
20565                                // Check if the value exist in the file, this is done because in IE9 and IE10 the list
20566                                // will have an extra empty dom
20567                                if ($(inputFileDOM).val().length > 0) {
20568                                    $(inputFileDOM).attr('name', fileNamesOfFileDom);
20569                                    loadedFileNames[fileCount] = fileNamesOfFileDom;
20570                                    loadedBindRefs[fileCount] = effectiveBindRef;
20571                                    // since the api is internal, we are not setting this
20572                                    loadedContentTypes[fileCount] = null; // we don't set "\n" separated content type here
20573                                    loadedFileDoms[fileCount++] = $(inputFileDOM);
20574                                }
20575                            }
20576                        } else {
20577                            // these values are nothing but field present as part of guidelib.model.FileAttachmentWrapper
20578                            // @note: to minimize the refactoring, not reusing the same model
20579                            // since there is no file dom in case of draft reload, make it null
20580                            loadedFileNames[fileCount] = fileAttachmentModel.name + "/" + fileNames[currIndex];
20581                            loadedBindRefs[fileCount] = effectiveBindRef;  // we add effective bindRef here
20582                            loadedContentTypes[fileCount] = fileAttachmentModel._getContentType(fileList[currIndex]);  // we add effective bindRef here
20583                            loadedFileDoms[fileCount++] = fileList[currIndex]; // we add the file URL in fileDom
20584                            fileNamesIndex++;
20585                        }
20586                    }, this);
20587
20588                }
20589            }, this);
20590
20591            // create the dom and name map for lazy file upload components as well
20592            var lazyFileMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap(),
20593                lazyFileDom = [],
20594                lazyFileBindRef = [],
20595                lazyFileContentType = [],
20596                lazyFileName = [];
20597            _.each(lazyFileMap, function (mapObject, key) {
20598                var fileList = mapObject.fileList;
20599                var fileUploadValue = mapObject.value.split("\n");
20600                var fileUploadBindRef = mapObject.bindRef;
20601                var fileNames = mapObject.fileNames.split("\n");
20602                var fileNamesIndex = 0;
20603                _.each(fileList, function (value) {
20604                    if (!_.isString(value)) {
20605                        var fileNamesOfFileDom = null;
20606                        _.each(value[0].files, function (file) {
20607                            var fileName = fileUploadValue[fileNamesIndex++];
20608                            if (fileName) {
20609                                var fullName = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + fileName;
20610                                if (fileNamesOfFileDom) {
20611                                    fileNamesOfFileDom += "\n" + fullName;
20612                                } else {
20613                                    fileNamesOfFileDom = fullName;
20614                                }
20615                            }
20616                        });
20617
20618                        lazyFileDom.push(value);
20619                        lazyFileName.push(fileNamesOfFileDom);
20620                    } else {
20621                        var fullName = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + fileNames[fileNamesIndex];
20622                        lazyFileDom.push(value);
20623                        lazyFileName.push(fullName);
20624                        fileNamesIndex++;
20625                    }
20626                    lazyFileBindRef.push(fileUploadBindRef);
20627                    lazyFileContentType.push(null); // todo: check if this use-case would ever hit
20628                });
20629            });
20630
20631            // concatenate the arrays for loaded and unloaded file doms and names
20632            fileDoms = loadedFileDoms.concat(lazyFileDom);
20633            fullFileNames = loadedFileNames.concat(lazyFileName);
20634            fileBindRefs = loadedBindRefs.concat(lazyFileBindRef);
20635            fileContentTypes = loadedContentTypes.concat(lazyFileContentType);
20636
20637            return {
20638                "fileName" : fullFileNames,
20639                "fileDom" : fileDoms,
20640                "fileBindRef" : fileBindRefs,
20641                "fileContentType" : fileContentTypes
20642            };
20643        },
20644
20645        setValidationContext : function (context) {
20646            var ec = guidelib.util.ErrorConstants;
20647            if (typeof ec[context] === "number") {
20648                var nContext = ec[context];
20649                if (nValidationContext < nContext) {
20650                    nValidationContext = nContext;
20651                    sValidationContext = context;
20652                }
20653            }
20654        },
20655
20656        unsetValidationContext : function (context) {
20657            if (context === sValidationContext) {
20658                nValidationContext = 0;
20659                sValidationContext = "";
20660            }
20661        },
20662
20663        getValidationContext : function () {
20664            return sValidationContext;
20665        },
20666
20667        /**
20668         * @summary Enable/Disable the swipe gesture for navigation on touch devices.
20669         * @param swiptLeft boolean flag to enable(true)/disable(false) the swipe left gesture to perform next item navigation
20670         * @param swipeRight boolean flag to enable(true)/disable(false) the swipe right gesture to perform previous item navigation
20671         * @method
20672         * @memberof GuideBridge
20673         * @instance
20674         * @since 6.3
20675         */
20676        enableSwipeGesture : function (swiptLeft, swipeRight) {
20677            $guideWrapperNode = $('.guideContainerWrapperNode');
20678            $guideWrapperNode.off('swipeleft', window.guideBridge._performItemDeepNavigationNext);
20679            $guideWrapperNode.off('swiperight', window.guideBridge._performItemDeepNavigationPrevious);
20680            if (swiptLeft) {
20681                $guideWrapperNode.on('swipeleft', window.guideBridge._performItemDeepNavigationNext);
20682            }
20683            if (swipeRight) {
20684                $guideWrapperNode.on('swiperight', window.guideBridge._performItemDeepNavigationPrevious);
20685            }
20686        },
20687
20688        /**
20689         * Enable the next item navigation (deep) using swipe left gesture
20690         * @private
20691         */
20692        _performItemDeepNavigationNext : function () {
20693            window.guideBridge.setFocus({
20694                somExpression : null,
20695                focusOption : 'nextItemDeep',
20696                runCompletionScript : true,
20697                skipFieldFocus : true
20698            });
20699        },
20700
20701        /**
20702         * Enable the previous item navigation (deep) using swipe right gesture
20703         * @private
20704         */
20705        _performItemDeepNavigationPrevious : function () {
20706            window.guideBridge.setFocus({
20707                somExpression : null,
20708                focusOption : 'prevItemDeep',
20709                runCompletionScript : true,
20710                skipFieldFocus : true
20711            });
20712        },
20713
20714        /**
20715         * Update the model popup that appears at click of file attachment listing button
20716         * This function is currently run of the clickExp of fileAttachmentListingButton
20717         * @param node
20718         * @private
20719         */
20720        _updateFileListing : function (node) {
20721            var somExpression = node.somExpression,
20722                viewOfListingButton = guideBridge._guideView.getView(somExpression);
20723            viewOfListingButton._clearFileListing();
20724            guideBridge.visit($.proxy(viewOfListingButton._updateFileListing, viewOfListingButton));
20725
20726        },
20727
20728        registerPanelProvider : function (panelProvider) {
20729            var resultObj = new GuideResultObject();
20730            if (this.panelProvider == null) {
20731                resultObj.data = panelProvider;
20732                this.panelProvider = panelProvider;
20733                return resultObj;
20734            }
20735            resultObj.addMessage(2, "registrationError: PanelProvider already registered", "");
20736            return resultObj;
20737        }
20738    });
20739
20740    window.guideBridge = new GuideBridge();
20741    window.guideBridge._$target = $(window.guideBridge);
20742
20743    window.guideBridge.on("af.invisibleMandatoryRecaptchaInitialization", function (event, data) {
20744        var model = data.jsonModel.target.jsonModel;
20745        var formContainerSelector = guidelib.util.GuideUtil.GUIDE_CONTAINER_FORM_CLASS;
20746        if(FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)) {
20747            $(formContainerSelector).append('<div id="captchaInvisible"></div>');
20748            var captchaInvisibleElement = $("#captchaInvisible"), captchaElement = $("[data-captchaservice]");
20749
20750            captchaInvisibleElement.attr({
20751                "modelId" : model.id || model.templateId,
20752                "af-recaptcha-execute" : "",
20753                "data-locale" : captchaElement.attr("data-locale")
20754            });
20755
20756            if (model.captchaService === 'turnstile') {
20757                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.CaptchaUtil.captchaExecution);
20758                var turnstileParameters = {
20759                    'sitekey' : model.siteKey,
20760                    'theme' : model.theme || 'light',
20761                    'size' : model.size,
20762                    'language' : captchaElement.attr('data-locale'),
20763                    'execution' : 'execute'
20764                };
20765                guidelib.util.CaptchaUtil.renderCaptcha(captchaInvisibleElement, model,
20766                    model.clientJsUrl, 'cf-turnstile-response', turnstileParameters);
20767            } else if (model.captchaService === 'hcaptcha') {
20768                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.CaptchaUtil.captchaExecution);
20769                var hcaptchaParameters = {
20770                    'sitekey' : model.siteKey,
20771                    'theme' : model.theme || 'light',
20772                    'size' : model.size,
20773                };
20774                guidelib.util.CaptchaUtil.renderCaptcha(captchaInvisibleElement, model,
20775                    model.clientJsUrl, 'h-captcha-response', hcaptchaParameters);
20776            } else {
20777                captchaInvisibleElement.attr({
20778                    "data-externaldomain" : captchaElement.attr("data-externaldomain")
20779                });
20780                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.RecaptchaUtil.recaptchaExecution);
20781                guidelib.util.RecaptchaUtil.renderRecaptcha(captchaInvisibleElement, model);
20782            }
20783        } else {
20784            $(formContainerSelector).append('<div id="recaptchaInvisible"></div>');
20785            var recaptchaInvisibleElement = $("#recaptchaInvisible"), captchaElement = $("[data-captchaservice]");
20786
20787            recaptchaInvisibleElement.attr({
20788                "modelId" : model.id || model.templateId,
20789                "af-recaptcha-execute" : "",
20790                "data-externaldomain" : captchaElement.attr("data-externaldomain"),
20791                "data-locale" : captchaElement.attr("data-locale")
20792            });
20793            recaptchaInvisibleElement.on("recaptchaExecution", guidelib.util.RecaptchaUtil.recaptchaExecution);
20794            guidelib.util.RecaptchaUtil.renderRecaptcha(recaptchaInvisibleElement, model);
20795        }
20796    });
20797
20798    try {
20799        var evnt = document.createEvent("CustomEvent");
20800        evnt.initCustomEvent("bridgeInitializeStart", true, true, {"guideBridge" : window.guideBridge});
20801        window.dispatchEvent(evnt);
20802    } catch (exception) {
20803        // written for env rhino to execute(for server side validation)
20804        // todo: once env rhino implements CustomEvent and initCustomEvent remove this
20805        // this._guide.logger().log(exception);
20806    }
20807
20808    if (!window.guideBridge.userConfig["postExternalMessageConfig"]) {
20809        if (window !== window.parent) {
20810            try {
20811                window.parent.document.getElementById(window.name);
20812                //We are here means no cross domain issue. So if user has not defined custom postExternalMessageConfig and
20813                // then we'll create one which would just send event on parent.
20814                window.guideBridge.registerConfig("postExternalMessageConfig", {
20815                    "postExternalHandler" : function (message) {
20816                        try {
20817                            var tmpEvent = document.createEvent("CustomEvent");
20818                            tmpEvent.initCustomEvent(message.name, true, true, message.data);
20819                            window.parent.dispatchEvent(tmpEvent);
20820                        } catch (exception) {
20821                            // written for env rhino to execute
20822                            //this._guide.logger().log(exception);
20823                        }
20824                    }
20825                });
20826            } catch (e) {
20827                //ignore the error
20828            }
20829        }
20830    }
20831
20832    window.guideBridge._postExternalMessage({
20833        name : "bridgeInitializeStart",
20834        data : {
20835            "guideBridge" : window.guideBridge
20836        }
20837    });
20838})($, _);
20839/**
20840 * @package guidelib.model.DataNode
20841 * @version 0.0.1
20842 */
20843
20844(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
20845
20846    var LiveDataUtils = guidelib.model.LiveDataUtils = xfalib.ut.Class.extend({
20847
20848        constants : {
20849            SKELETON_XML : '<afData><afUnboundData><data/></afUnboundData><afBoundData><data xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"/></afBoundData></afData>',
20850            SKELETON_JSON : '{"afData":{"afUnboundData":{"data":{}},"afBoundData":{"data":{}}}}',
20851            UNBOUND_SKELETON : '<unBound></unBound>',
20852            UNBOUND_JSON_SKELETON : '{"afUnboundData":{}}',
20853            INDEXED_XPATH_PAT : new RegExp(/\/[^\/]+\[\d+\]/),
20854            INDEXED_XPATH_PAT_JSON : new RegExp(/\/[^\/]+\/\d+/),
20855            XFA_DATA_NODE_ATTR_NAME : "xfa:dataNode",
20856            XFA_DATA_NODE_ATTR_VALUE : "dataGroup",
20857            UNKNOWN_XSD_ROOT_ELEMENT : "?",
20858            AF_ROOT_TAG : "afData",
20859            BOUND_TAG : "afBoundData",
20860            UNBOUND_TAG : "afUnboundData",
20861            XFA_TAG : "xfa",
20862            DATA_TAG : "data",
20863            BOUND_DATA_XPATH : "afBoundData/data",
20864            UNBOUND_DATA_XPATH : "afUnboundData/data",
20865            AF_DRAFT_TAG : "afSubmissionInfo/afDraft"
20866        },
20867
20868        initialize : function () {
20869            LiveDataUtils._super.initialize.call(this);
20870            this._boundDataRoot = null;
20871            this._unboundDataRoot = null;
20872            this._xfaDataRoot = null;
20873            this._fetchingClientSideData = false; // this state indicates that we are fetching client side data, its not use-case to fetch lazy data
20874            this.lazyAttachmentMap = {};
20875            this.attachments = [];
20876        },
20877
20878        /**
20879         * This function updates the lazy attachment Map from
20880         * the map passed
20881         * @param fileAttachmentMap
20882         * @private
20883         */
20884        _updateLazyAttachmentMap : function(fileAttachmentMap) {
20885            _.each(fileAttachmentMap, function (value, key) {
20886                this.lazyAttachmentMap[key] = {};
20887                this.lazyAttachmentMap[key].fileList = value.split("\n");
20888                this.lazyAttachmentMap[key].value = value;
20889            }, this);
20890        },
20891
20892        /**
20893         * This function updates the lazy attachment Map from the model.
20894         * It gets the value and fileList from the model and updates the map.
20895         * If the fileUpload component is not in a lazy panel then it removes
20896         * its entry form the map(if the entry is already there).
20897         * @param model
20898         * @private
20899         */
20900        _updateLazyAttachmentMapFromModel : function (model) {
20901            // add the component in the map only when its in a lazy panel
20902            // add the entry in map only when its not not empty
20903            if (model.parent._selfOrAncestorIsLazyReference && model.value && model.fileList && !this._fetchingClientSideData) {
20904                this.lazyAttachmentMap[model.somExpression] = {
20905                    value : model.value,
20906                    fileList : model.fileList,
20907                    bindRef : model._getEffectiveBindRef(),
20908                    fileNames : model._getFileAttachmentNames()
20909                };
20910            } else {
20911                if (this.lazyAttachmentMap[model.somExpression]) {
20912                    delete this.lazyAttachmentMap[model.somExpression];
20913                }
20914            }
20915        },
20916
20917        /**
20918         * This function returns the value in the lazy attachment map for the model.
20919         * It removes the entry from the map as well. This is required so that the map gets
20920         * updated with the new values when the panel unloads.
20921         * @param model
20922         * @returns {*}
20923         * @private
20924         */
20925        _getAttachmentDataForModel : function (model) {
20926            var effectiveBindRef = model._getEffectiveBindRef();
20927            if (model.somExpression && !_.isEmpty(this.lazyAttachmentMap)) {
20928                var data = this.lazyAttachmentMap[model.somExpression];
20929                delete this.lazyAttachmentMap[model.somExpression];
20930                return data;
20931            }
20932            if (effectiveBindRef && !_.isEmpty(this.attachments)) {
20933                var data = model._getCurrentFileAttachmentWrapper(this.attachments);
20934                return data;
20935            }
20936        },
20937
20938        _getLazyAttachmentMap : function () {
20939            return this.lazyAttachmentMap;
20940        },
20941
20942        dropXfaXml : function () {
20943            this._xfaDataRoot = null;
20944        },
20945
20946        // only called from test framework
20947        destroy : function () {
20948            this._liveDataDoc = null;
20949            this._boundDataRoot = null;
20950            this._unboundDataRoot = null;
20951            this._xfaDataRoot = null;
20952        },
20953
20954        initLiveData : function (prefillDataStr, xfaPrefillDataStr, isXdp, isXsd, xsdRootElement, attachments) {
20955            this.attachments = attachments;
20956        },
20957
20958        isLiveDataInitialized : function () {
20959        },
20960
20961        getLiveDataStr : function () {
20962        },
20963
20964        getLiveDataDoc : function () {
20965            return this._liveDataDoc;
20966        },
20967
20968        _isNonNaked : function () {
20969        },
20970
20971        _getNameAndIndex : function (xpathPart) {
20972        },
20973
20974        isIndexedPath : function (xpath) {
20975        },
20976
20977        _createElements : function (contextNode, xpathParts) {
20978        },
20979
20980        _createRepeatedElements : function (contextNode, xpathParts) {
20981        },
20982
20983        _createChildElement : function (parentElement, elemName) {
20984        },
20985
20986        _createAttributeNode : function (parentElement, attrName) {
20987        },
20988
20989        getContextNode : function (schemaPath, dataSection, createMissingNodes, lastNodeValue) {
20990        },
20991
20992        addIndexToPath : function (path, index) {
20993        },
20994
20995        _getElement : function (node, xpath, options) {},
20996
20997        hasChildNodes : function (node) {
20998        },
20999
21000        /**
21001         * Removes a child node from its parent
21002         * @param parentNode {Node} Parent Node from which to remove the child node
21003         * @param targetNode {String} Node name of the child to remove
21004         * @param index Index of the child node to remove
21005         */
21006        removeChild : function (parentNode, targetNodeName, index) {
21007        },
21008
21009        insertNode : function (parentNode, childNodeName, index) {
21010        },
21011
21012        _getDataContext : function (model, bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
21013            var bindRef = model.bindRef,
21014                liveDataUtils = this,
21015                xmlSec,
21016                indexedXpath;
21017
21018            if (model._isXfaNode()) {
21019                xmlSec = liveDataUtils.constants.XFA_TAG;
21020                indexedXpath = xfalib.ut.XMLUtils.dataSom2xpath(model.dataSom);
21021            } else if (_.isEmpty(bindRef)) {
21022                xmlSec = liveDataUtils.constants.UNBOUND_TAG;
21023                indexedXpath = unBound_indexedXpathSoFar + '/' + model.getAttribute("name").replace(/\s+/g, '');
21024                // use attr 'name' here, as schema might have an elem called 'name'
21025            } else {
21026                xmlSec = liveDataUtils.constants.BOUND_TAG;
21027
21028                var xpathMatch = liveDataUtils.getMatchingXpathHierarchy(bou
21028nd_indexedXpathSoFar, bindRef);
21029                if (xpathMatch.isCrossHierarchy) {
21030                    indexedXpath = bindRef;
21031                } else {
21032                    indexedXpath = bound_indexedXpathSoFar;
21033                    if (!_.isEmpty(xpathMatch.suffixParts)) {
21034                        indexedXpath += '/' + xpathMatch.suffixParts.join('/');
21035                    }
21036                }
21037            }
21038
21039            return {
21040                'xmlSec' : xmlSec,
21041                'indexedXpath' : indexedXpath
21042            };
21043        },
21044
21045        /**
21046         * return true if both xpath parts have same element name and indices
21047         * absence of index in the templateName is ignored
21048         * @param indexedName
21049         * @param templateName
21050         * @returns {boolean}
21051         * @private
21052         * @memberof LiveDataUtils
21053         */
21054        _cmpXpathParts : function (indexedName, templateName) {
21055          },
21056
21057        /**
21058         * get a partition of the matching xpath part hierarchy
21059         * the matching parts have same element names and agreeable indices
21060         * @param parentXpath
21061         * @param currentXpath
21062         * @returns {{prefixParts: Array, suffixParts: (*|Array.<T>|list), isCrossHierarchy: boolean}}
21063         * @memberof LiveDataUtils
21064         */
21065        getMatchingXpathHierarchy : function (parentXpath, currentXpath) {
21066            var isCrossHierarchy = false,
21067                prefixParts = [],
21068                suffixParts = this._sanitizedXpathParts(currentXpath);
21069
21070            _.find(this._sanitizedXpathParts(parentXpath), function (parentPart) {
21071                if (this._cmpXpathParts(parentPart, suffixParts[0])) {
21072                    prefixParts.push(parentPart);
21073                    suffixParts.shift();
21074                } else {
21075                    isCrossHierarchy = true;
21076                    return true;
21077                }
21078            }, this);
21079
21080            return {
21081                'prefixParts' : prefixParts,
21082                'suffixParts' : suffixParts,
21083                'isCrossHierarchy' : isCrossHierarchy
21084            };
21085        },
21086
21087        _getXpathContext : function (targetPanel) {
21088            var boundXpath = '',
21089                unBoundXpath = '',
21090                ancestors = [],
21091                panel = targetPanel.parent;
21092
21093            while (panel instanceof guidelib.model.GuidePanel) {
21094                if (panel._preserveLazyValue()) {
21095                    ancestors.unshift(panel);
21096                }
21097                panel = panel.parent;
21098            }
21099
21100            _.each(ancestors, function (ancestor) {
21101                var xmlContext = ancestor._syncModelAndData(boundXpath, unBoundXpath);
21102                boundXpath = xmlContext.bound;
21103                unBoundXpath = xmlContext.unBound;
21104            });
21105
21106            return {
21107                'bound' : boundXpath,
21108                'unBound' : unBoundXpath
21109            };
21110        },
21111
21112        _applyOnLiveData : function (action, targetPanel) {
21113            if (_.isString(targetPanel)) {
21114                targetPanel = guideBridge.resolveNode(targetPanel);
21115            }
21116
21117            if (targetPanel instanceof guidelib.model.GuidePanel) {
21118                var indexedXpathsFromRoot = targetPanel._guide().internal.liveDataUtils._getXpathContext(targetPanel);
21119                targetPanel[action](indexedXpathsFromRoot.bound, indexedXpathsFromRoot.unBound);
21120            } else {
21121                guideBridge._guide.rootPanel[action]('', '');
21122            }
21123        },
21124
21125        /**
21126         * will capture the currently loaded model hierarchy in a xml doc to be referred to later by lazily loaded panels
21127         * @private
21128         * @memberof LiveDataUtils
21129         */
21130        updateLiveData : function (targetPanel, fetchingClientSideData) {
21131            this._fetchingClientSideData = !_.isUndefined(fetchingClientSideData);
21132            this._applyOnLiveData('_updateLiveData', targetPanel);
21133            this._fetchingClientSideData = false;
21134        },
21135
21136        /**
21137         * will replay the model hierarchy from the live xml, for the supplied panel
21138         * @param targetPanel
21139         * @private
21140         * @memberof LiveDataUtils
21141         */
21142        playLiveData : function (targetPanel) {
21143            this._applyOnLiveData('_playLiveData', targetPanel);
21144        },
21145
21146        getListOfDirtyPanels : function (dataString) {
21147            return [];
21148        },
21149
21150        addDataNodeInfo : function (contextNode) {
21151        },
21152
21153        /**
21154         * Set the value of the node referred by xpath in the bounded/unbounded
21155         * section as specified by section. This optionally creates the data nodes
21156         * if they are not present
21157         * @param xpath
21158         * @param section
21159         * @param createMissingNodes
21160         * @param value
21161         */
21162        setDataValue : function (xpath, section, createMissingNodes, value) {
21163        },
21164
21165        /**
21166         * Set the rich text(html) value of the node referred by xpath in the bounded/unbounded
21167         * section as specified by section. This optionally creates the data nodes
21168         * if they are not present
21169         * @param xpath
21170         * @param xmlSection
21171         * @param createMissingNodes
21172         * @param value
21173         */
21174        setRichTextValue : function (xpath, xmlSection, createMissingNodes, value) {
21175            this.setDataValue(xpath, xmlSection, createMissingNodes, value);
21176        },
21177
21178        /**
21179         * Returns the value of the node referred by xpath in the bounded/unbounded
21180         * section as specified by section. It returns undefined if the node doesn't
21181         * exist
21182         * @param xpath
21183         * @param section
21184         */
21185        getDataValue : function (xpath, section) {
21186        },
21187
21188        _convertModelIndexToDataIndex : function (index) {
21189        },
21190
21191        getParentRef : function (path) {
21192        },
21193
21194        /**
21195         * returns the parent data node for the context specified by dataNodeContext
21196         * @param dataNodeContext {object} containing xpath and section
21197         * @param createIfMissing
21198         * @returns {*}
21199         * @param parentNodeValue
21200         */
21201        getParentDataNode : function (dataNodeContext, createIfMissing, parentNodeValue) {
21202            var parentRef = this.getParentRef(dataNodeContext.indexedXpath),
21203                parentNode;
21204            if (_.isEmpty(parentRef)) {
21205                parentNode = this.getContextNode("", dataNodeContext.xmlSec, false);
21206            } else {
21207                parentNode = this.getContextNode(parentRef, dataNodeContext.xmlSec, createIfMissing, parentNodeValue);
21208            }
21209            return parentNode;
21210        },
21211
21212        /**
21213         * Insert submission Info in the data
21214         * @param submissionInfo {object} object containing the properties to be added as submission info in data
21215         */
21216        insertSubmissionInfo : function (submissionInfo) {
21217
21218        }
21219
21220    });
21221
21222}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
21223
21224/**
21225 * @package guidelib.model.DataNode
21226 * @version 0.0.1
21227 */
21228
21229(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
21230    var getOrElse = xfalib.ut.XfaUtil.prototype.getOrElse;
21231
21232    var LiveJsonUtils = guidelib.model.LiveJsonUtils = guidelib.model.LiveDataUtils.extend({
21233
21234        initialize : function () {
21235            LiveJsonUtils._super.initialize.call(this);
21236            this._liveDataDoc = null;
21237        },
21238
21239        initLiveData : function (prefillDataStr, guideContext) {
21240            LiveJsonUtils._super.initLiveData.apply(this, arguments);
21241            prefillDataStr = prefillDataStr || getOrElse(guideContext, "guidePrefillJson", null);
21242
21243            if (_.isString(prefillDataStr) && prefillDataStr.length > 0) {
21244                var prefillDataDoc = JSON.parse(prefillDataStr);
21245
21246                if (this._isNonNaked(prefillDataDoc)) {
21247                    // non naked json, assuming full hierarchy afdata/afbounddata/data
21248                    this._liveDataDoc = prefillDataDoc;
21249                    this._boundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.BOUND_DATA_XPATH);
21250                    this._unboundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.UNBOUND_DATA_XPATH);
21251
21252                } else {
21253                    // naked json start from prefill data root
21254                    this._boundDataRoot = prefillDataDoc;
21255                    this._unboundDataRoot = JSON.parse(this.constants.UNBOUND_JSON_SKELETON)[this.constants.UNBOUND_TAG];  // need this for unbound data fill across lazy
21256                    this._liveDataDoc = prefillDataDoc;
21257                }
21258            } else {
21259                // init default skeleton for no prefill cases
21260                this._liveDataDoc = JSON.parse(this.constants.SKELETON_JSON);
21261                this._boundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.BOUND_DATA_XPATH);
21262                this._unboundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.UNBOUND_DATA_XPATH);
21263            }
21264            if (this._boundDataRoot == null && this._isNonNaked(prefillDataDoc)) {
21265                this._liveDataDoc.afData.afBoundData = this._liveDataDoc.afData.afBoundData || {};
21266                this._liveDataDoc.afData.afBoundData.data = this._liveDataDoc.afData.afBoundData.data || {};
21267                this._boundDataRoot = this._liveDataDoc.afData.afBoundData.data;
21268            }
21269        },
21270
21271        /*
21272         * This API gets the element w.r.t to the node.
21273         * Eg - path is a/b/c, then it converts the path to a.b.c and then searches for c.
21274         */
21275        _getElement : function (node, path, options) {
21276            if (!(node instanceof Object)) {
21277                return null;
21278            }
21279
21280            if (_.isEmpty(path) || !_.isString(path)) {
21281                return node;
21282            }
21283            options = options || {};
21284            var index = options.index;
21285            var convertedPath = path.split('/').join('.');
21286            if (!(_.isUndefined(index) || _.isNull(index))) {
21287                convertedPath = convertedPath + "." + index;
21288            }
21289            return getOrElse(node, convertedPath, null);
21290        },
21291
21292        /**
21293         * This function checks if the data contains naked or non naked json
21294         * @returns {boolean} returns true if there exists a afData node inside data
21295         * @private
21296         * @memberof LiveJsonUtils
21297         * @param prefillData
21298         */
21299        _isNonNaked : function (prefillData) {
21300            prefillData = prefillData || this.getLiveDataDoc();
21301            if (prefillData) {
21302                return prefillData.hasOwnProperty("afData");
21303            } else {
21304                return false;
21305            }
21306        },
21307
21308        isLiveDataInitialized : function () {
21309            return (this.getLiveDataDoc() instanceof Object);
21310        },
21311
21312        getLiveDataStr : function () {
21313            if (this.isLiveDataInitialized()) {
21314                return JSON.stringify(this.getLiveDataDoc());
21315            } else {
21316                return '';
21317            }
21318        },
21319
21320        /*
21321         * This API will remove the spaces,"\" from the path.
21322         * It will return an array after splitting the path.
21323         * Eg - for a/0/b/c, it will return ["a/0","b","c"]
21324         */
21325        _sanitizedXpathParts : function (path) {
21326            var pathParts = (path || '').replace(/^\//, '').replace(/\s+/g, '');
21327            pathParts = this._splitForIndex(pathParts);
21328
21329            return _.filter(pathParts, function (xpathPart) {
21330                return this._getNameAndIndex(xpathPart) !== null;
21331            }, this);
21332        },
21333
21334        _splitForIndex : function (path) {
21335            var pathArray = [];
21336            var pathParts = path.split('/');
21337            for (var i = 0; i < pathParts.length; i++) {
21338                var str = pathParts[i];
21339                if ((i + 1) < pathParts.length && !isNaN(pathParts[i + 1]) && !_.isEmpty(pathParts[i + 1])) {
21340                    str = str + "/" + pathParts[i + 1];
21341                    i = i + 1;
21342                }
21343                pathArray.push(str);
21344            }
21345            return pathArray;
21346        },
21347
21348        /**
21349         * Returns the index associated with the pathPart.
21350         * Eg - if pathPart is 'a/1', then it returns {name : a, index : 1}
21351         * @param pathPart
21352         * @returns {*}
21353         * @private
21354         */
21355        _getNameAndIndex : function (pathPart) {
21356            if (pathPart) {
21357                var elName = pathPart.match(/^([^\s\/]+)(?:\/(\d+))?$/);  // match the whole string
21358                if (elName !== null) {
21359                    return {
21360                        name : elName[1],
21361                        index : elName[2] ? parseInt(elName[2]) : -1
21362                        // -1 index for depicting non repeatable element
21363                    };
21364                }
21365            }
21366            return null;
21367        },
21368
21369        _cmpXpathParts : function (indexedName, templateName) {
21370            if (indexedName && templateName) {
21371                var match1 = this._getNameAndIndex(indexedName),
21372                    match2 = this._getNameAndIndex(templateName);
21373                return !_.isEmpty(match1 && match2)
21374                    && match1.name === match2.name
21375                    && (match2.index === -1 || match1.index === match2.index);
21376            }
21377            return false;
21378        },
21379
21380        /**
21381         * This function gets or creates the node if its not there. The node can be any valid JSON Value
21382         * null, string, object, array, number, boolean.
21383         * @param schemaPath
21384         * @param dataSection
21385         * @param createMissingNodes
21386         * @param lastNodeValue
21387         * @returns {*}
21388         */
21389        getContextNode : function (schemaPath, dataSection, createMissingNodes, lastNodeValue) {
21390            var contextNode,
21391                baseContextNode,
21392                basePath = "",
21393                pathParts = this._sanitizedXpathParts(schemaPath);
21394            if (dataSection == this.constants.BOUND_TAG) {
21395                baseContextNode = this._boundDataRoot;
21396                if (this._isNonNaked(this._liveDataDoc)) {
21397                    basePath = "afData/" + this.constants.BOUND_DATA_XPATH + "/";
21398                }
21399            } else if (dataSection === this.constants.UNBOUND_TAG) {
21400                baseContextNode = this._unboundDataRoot;
21401                if (this._isNonNaked(this._liveDataDoc)) {
21402                    basePath = "afData/" + this.constants.UNBOUND_DATA_XPATH + "/";
21403                }
21404            }
21405            if (!_.isEmpty(pathParts)) {
21406                var path = (basePath + pathParts.join('/'));
21407
21408                // return baseContextNode for naked json. path can be "" only for naked json.
21409                if (path == "" && !this._isNonNaked(this._liveDataDoc)) {
21410                    return baseContextNode;
21411                }
21412
21413                contextNode = this._getElement(this._liveDataDoc, path);
21414                if (!contextNode && createMissingNodes) {
21415                    contextNode = this._createElements(baseContextNode, pathParts, lastNodeValue);
21416                }
21417            } else {
21418                contextNode = baseContextNode;
21419            }
21420            return contextNode;
21421        },
21422
21423        /**
21424         * This function creates the node at the path.
21425         *
21426         * @param contextNode
21427         * @param pathParts
21428         * @returns {*}
21429         * @private
21430         * @param lastNodeValue
21431         */
21432        _createElements : function (contextNode, pathParts, lastNodeValue) {
21433            if (!(contextNode instanceof Object)) {
21434                return null;
21435            }
21436
21437            if (_.isEmpty(pathParts)) {
21438                return contextNode;
21439            }
21440
21441            // recurse and create one level of tags at a time
21442            contextNode = this._createRepeatedElements(contextNode, pathParts, lastNodeValue);
21443            return contextNode;
21444        },
21445
21446        // it will always return the parent node after checking the last token
21447        _createRepeatedElements : function (contextNode, pathParts, lastNodeValue) {
21448            var childContextNode = contextNode,
21449                xpathPart = this._getNameAndIndex(pathParts[0]),
21450                elemName = xpathPart.name,
21451                index = xpathPart.index || 0,
21452                i,
21453                isLastToken = (pathParts.length == 1),
21454                elementNode = contextNode[elemName];
21455            // -1 signifies non repeating element
21456            if (index === -1) {
21457                if (elementNode == null) {
21458                    childContextNode = this._createChildElement(contextNode, elemName, isLastToken, lastNodeValue);
21459                } else {
21460                    childContextNode = elementNode;
21461                }
21462                // if its the last token, then stop recursion here and return the created node
21463                if (isLastToken) {
21464                    return childContextNode;
21465                }
21466            } else {
21467                if (elementNode != null) {
21468                    var numOfChildren = elementNode.length;
21469                    if (numOfChildren < index + 1) {
21470                        // create immediate 'extra' children
21471                        for (i = numOfChildren; i < index + 1; ++i) {
21472                            childContextNode = {};
21473                            contextNode[elemName].push(childContextNode);
21474                        }
21475                    } else {
21476                        childContextNode = elementNode[index];
21477                    }
21478                } else {
21479                    contextNode[elemName] = [];
21480                    for (i = 0; i < index + 1; ++i) {
21481                        childContextNode = {};
21482                        contextNode[elemName].push(childContextNode);
21483                    }
21484                }
21485            }
21486            // recursively create descendants
21487            return this._createElements(childContextNode, pathParts.slice(1), lastNodeValue);
21488        },
21489
21490        _createChildElement : function (parentElement, elemName, isLastToken, nodeValue) {
21491            if (parentElement instanceof Object) {
21492                if (isLastToken) {
21493                    parentElement[elemName] = nodeValue;
21494                } else {
21495                    parentElement[elemName] = {};
21496                }
21497                return parentElement[elemName];
21498            }
21499        },
21500
21501        isIndexedPath : function (xpath) {
21502            return (xpath || "").match(this.constants.INDEXED_XPATH_PAT_JSON) !== null;
21503        },
21504
21505        /**
21506         * This function sets the value of the field in the live data document.
21507         * @param xpath
21508         * @param xmlSection
21509         * @private
21510         * @param createMissingNodes
21511         * @param value
21512         */
21513        setDataValue : function (xpath, xmlSection, createMissingNodes, value) {
21514            var lastSlash = xpath.lastIndexOf("/"),
21515                parentPath = xpath.substring(0, lastSlash),
21516                name = xpath.substring(lastSlash + 1),
21517                parent = this.getContextNode(parentPath, xmlSection, createMissingNodes, {});
21518            if (parent instanceof Object) {
21519                if (createMissingNodes || parent.hasOwnProperty(name)) {
21520                    parent[name] = value;
21521                }
21522            }
21523        },
21524
21525        /**
21526         * This function sets the value in the model from the live data document.
21527         * @param node
21528         * @param field
21529         * @private
21530         */
21531        getDataValue : function (xpath, xmlSection) {
21532            var lastSlash = xpath.lastIndexOf("/"),
21533                parentPath = xpath.substring(0, lastSlash),
21534                name = xpath.substring(lastSlash + 1),
21535                parent = this.getContextNode(parentPath, xmlSection, false);
21536            if (parent instanceof Object) {
21537                return parent[name] === undefined ? null : parent[name];
21538            }
21539            return null;
21540        },
21541
21542        getRichTextValue : function (xpath, xmlSection) {
21543            return this.getDataValue(xpath, xmlSection);
21544        },
21545
21546        addIndexToPath : function (path, index) {
21547            if (path.match(/\/\d+$/) === null) { // only add repeat index if it doesn't already end in one
21548                path += '/' + (index);
21549            } else {
21550                this.logger().debug("AF", "Tried to add index to already indexed JSON path :" + path);
21551            }
21552            return path;
21553        },
21554
21555        hasChildNodes : function (node) {
21556            return !_.isEmpty(node);
21557        },
21558
21559        removeChild : function (parentNode, targetNodeName, index) {
21560            parentNode[targetNodeName].splice(index, 1);
21561        },
21562
21563        insertNode : function (parentNode, childNodeName, index) {
21564            if (parentNode[childNodeName] == null) {
21565                parentNode[childNodeName] = [];
21566            }
21567            for (var i = 0; i < index; i++) {
21568                if (parentNode[childNodeName][i] == null) {
21569                    parentNode[childNodeName][i] = {};
21570                }
21571            }
21572            parentNode[childNodeName].splice(index, 0, {});
21573            return parentNode[childNodeName][index];
21574        },
21575
21576        getDataInstances : function (dataContext, dataNodeName) {
21577            return this.getContextNode(dataContext.indexedXpath, dataContext.xmlSec);
21578        },
21579
21580        _convertModelIndexToDataIndex : function (index) {
21581            if (index < 0) {
21582                return 0;
21583            }
21584            return index;
21585        },
21586
21587        getParentRef : function (path) {
21588            return path.replace(/\/[^\/]+(?:\/\d+)?$/, "");
21589        },
21590
21591        insertSubmissionInfo : function (submissionInfo, rootNode) {
21592            if (this._isNonNaked()) {
21593                var node = rootNode,
21594                    self = this,
21595                    finalValue, insert, keyNode;
21596                if (node == null) {
21597                    node = this._liveDataDoc.afData.afSubmissionInfo;
21598                }
21599                if (node == null && this._liveDataDoc.afData.afSubmissionInfo == null) {
21600                    node = {};
21601                    this._liveDataDoc.afData.afSubmissionInfo = node;
21602                }
21603                _.each(submissionInfo, function (value, key) {
21604                    if (value instanceof Array) {
21605                        // we only support string items in json array
21606                        finalValue = [];
21607                        insert = true;
21608                        _.each(value, function (arrItem, index) {
21609                            if (typeof arrItem === "string") {
21610                                finalValue.push(arrItem);
21611                            } else {
21612                                //ignore this. we currently do not support anything other than string
21613                            }
21614                        });
21615                        if (insert) {
21616                            node[key] = finalValue.join(',');
21617                        }
21618                    } else if (typeof (value) === "object" && value != null) {
21619                        keyNode = node[key];
21620                        if (keyNode == null) {
21621                            keyNode = {};
21622                            node[key] = keyNode;
21623                        }
21624                        self.insertSubmissionInfo(value, keyNode);
21625                    } else {
21626                        node[key] = value;
21627                    }
21628                });
21629            }
21630        }
21631
21632    });
21633
21634}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
21635
21636/**
21637 * @package guidelib.model.DataNode
21638 * @version 0.0.1
21639 */
21640
21641(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
21642    var isXdp, isXsd, isNone;
21643
21644    var LiveXmlUtils = guidelib.model.LiveXmlUtils = guidelib.model.LiveDataUtils.extend({
21645
21646        initialize : function () {
21647            LiveXmlUtils._super.initialize.call(this);
21648
21649            if (_.isUndefined(document.evaluate)) {
21650                wgxpath.install();
21651            }
21652            this._liveDataDoc = null;
21653        },
21654
21655        initLiveData : function (prefillXmlStr, xfaPrefillXmlStr, isXdp, isXsd, xsdRootElement) {
21656            LiveXmlUtils._super.initLiveData.apply(this, arguments);
21657            isXdp = isXdp || false;
21658            isXsd = isXsd || false;
21659            isNone = !(isXdp || isXsd);
21660            this.xsdRootElement = xsdRootElement;
21661            // init default skeleton for no pefill cases
21662            this._liveDataDoc = $.parseXML(this.constants.SKELETON_XML);
21663            this._boundDataRoot = this._getElement(this._liveDataDoc.documentElement, this.constants.BOUND_DATA_XPATH);
21664            this._unboundDataRoot = this._getElement(this._liveDataDoc.documentElement, this.constants.UNBOUND_DATA_XPATH);
21665
21666            if (_.isString(prefillXmlStr) && prefillXmlStr.length > 0) {
21667                var prefillXmlDoc = $.parseXML(prefillXmlStr);
21668
21669                // find data root
21670                if (this._isNonNaked(prefillXmlDoc)) {
21671                    // non naked xml, assuming full hierarchy afdata/afbounddata/data
21672
21673                    var prefillBoundDataRoot,
21674                        prefillUnBoundDataRoot,
21675                        newDataNode;
21676
21677                    if (!isXdp) { //capture bound data from prefill, for both none(may contain bound form/frag) and xsd
21678                        prefillBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.BOUND_DATA_XPATH);
21679                        if (null == prefillBoundDataRoot) {
21680                            prefillBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.BOUND_TAG +
21681                                                                        "/" + guideBridge._guide.jsonModel.xsdRootElement);
21682                        }
21683                        if (prefillBoundDataRoot) {
21684                            newDataNode = this._liveDataDoc.importNode(prefillBoundDataRoot, true);
21685                            this._boundDataRoot.parentNode.replaceChild(newDataNode, this._boundDataRoot);
21686                            this._boundDataRoot = newDataNode;
21687                        }
21688                    }
21689
21690                    prefillUnBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.UNBOUND_DATA_XPATH);
21691                    if (prefillUnBoundDataRoot) {
21692                        newDataNode = this._liveDataDoc.importNode(prefillUnBoundDataRoot, true);
21693                        this._unboundDataRoot.parentNode.replaceChild(newDataNode, this._unboundDataRoot);
21694                        this._unboundDataRoot = newDataNode;
21695                    }
21696
21697                } else {
21698                    // naked xml start from prefill data root
21699
21700                    if (isNone) {
21701                        this._unboundDataRoot = prefillXmlDoc.documentElement;
21702                        this._boundDataRoot = null;
21703                    } else {
21704                        if (isXsd) {
21705                            this._boundDataRoot = prefillXmlDoc.documentElement;
21706                        }
21707
21708                        var unBoundXmlDoc = $.parseXML(this.constants.UNBOUND_SKELETON);
21709                        this._unboundDataRoot = unBoundXmlDoc.documentElement;  // need this for unbound data fill across lazy
21710                    }
21711                    this._liveDataDoc = prefillXmlDoc;
21712                }
21713            }
21714
21715            if (isXdp) { // don't need the bound data sec, model is always loaded & server will fill during submission
21716                if (_.isString(xfaPrefillXmlStr) && xfaPrefillXmlStr.length > 0) {
21717                    this._xfaDataRoot = xfalib.ut.XMLUtils.getXFARootFormElementFromXML($.parseXML(xfaPrefillXmlStr));
21718                }
21719                this._boundDataRoot.parentNode.parentNode.removeChild(this._boundDataRoot.parentNode);
21720                this._boundDataRoot = null;
21721            }
21722        },
21723
21724        isLiveDataInitialized : function () {
21725            return (this.getLiveDataDoc() instanceof Node);
21726        },
21727
21728        getLiveDataStr : function () {
21729            if (this.isLiveDataInitialized()) {
21730                return (new XMLSerializer()).serializeToString(this.getLiveDataDoc());
21731            } else {
21732                return '';
21733            }
21734        },
21735
21736        _ignoreXpathRoot : function (xpathRoot) {
21737            return this.xsdRootElement === this.cons
21737tants.UNKNOWN_XSD_ROOT_ELEMENT
21738                || this.xsdRootElement === xpathRoot;
21739        },
21740
21741        /**
21742         * will return the apt node, in the AF xml, based on the xml context passed in.
21743         * Will create nodes if it doesn't exist and createMissingNodes is passed as true
21744         * @param schemaPath
21745         * @param dataSection
21746         * @param createMissingNodes
21747         * @returns {*}
21748         * @memberof LiveXmlUtils
21749         */
21750        getContextNode : function (schemaPath, dataSection, createMissingNodes) {
21751            var contextNode,
21752                baseContextNode,
21753                xpathParts = this._sanitizedXpathParts(schemaPath);
21754            if (dataSection === this.constants.BOUND_TAG) {
21755                baseContextNode = this._boundDataRoot;
21756            } else if (dataSection === this.constants.UNBOUND_TAG) {
21757                baseContextNode = this._unboundDataRoot;
21758            } else if (dataSection === this.constants.XFA_TAG) {
21759                baseContextNode = this._xfaDataRoot;
21760            }
21761            if (!_.isEmpty(xpathParts)) {
21762                if (dataSection === this.constants.BOUND_TAG) {
21763                    if (this._ignoreXpathRoot(xpathParts[0])) {
21764                        xpathParts = xpathParts.slice(1);   // discard xsd schema root
21765                        if (xpathParts.length === 0) {
21766                            return baseContextNode;
21767                        }
21768                    }
21769                }
21770
21771                contextNode = this._getElement(baseContextNode, xpathParts.join('/'));
21772
21773                if (!contextNode && createMissingNodes) {
21774                    contextNode = this._createElements(baseContextNode, xpathParts);
21775                }
21776            } else if (_.isEmpty(schemaPath)) {
21777                contextNode = baseContextNode;
21778            }
21779            return contextNode;
21780        },
21781
21782        addIndexToPath : function (path, index) {
21783            if (path.match(/\[\d+\]$/) === null) { // only add repeat index if it doesn't already end in one
21784                path += '[' + (index + 1) + ']'; // indices in xpath 1 based}
21785            } else {
21786                this.logger().debug("AF", "Tried to add index to already indexed xpath :" + path);
21787            }
21788            return path;
21789        },
21790
21791        getDataInstances : function (dataContext, dataNodeName) {
21792            var node = this.getContextNode(dataContext.indexedXpath, dataContext.xmlSec);
21793            if (node != null) {
21794                return _.filter(node.parentNode.childNodes, function (child) {
21795                    return (child instanceof Element) && child.nodeName === dataNodeName;
21796                }, this);
21797            }
21798            return null;
21799        },
21800
21801        _findLastDataNode : function (parentContextNode, dataNodeName) {
21802            var xmlUtils = xfalib.ut.XMLUtils,
21803                iterator = xmlUtils.evaluateXPath(dataNodeName, parentContextNode, null, null, null),
21804                result = xmlUtils.iteratorToArray(iterator);
21805            if (result.length > 0) {
21806                return result[result.length - 1];
21807            }
21808            return null;
21809        },
21810
21811        hasChildNodes : function (node) {
21812            return node.hasChildNodes();
21813        },
21814
21815        removeChild : function (parentNode, targetNodeName, index) {
21816            var childNode = this._getElement(parentNode, targetNodeName + "[" + (index + 1) + "]", null);
21817            if (childNode) {
21818                parentNode.removeChild(childNode);
21819            }
21820        },
21821
21822        insertNode : function (parentNode, childNodeName, index) {
21823            var childNode = this._getElement(parentNode, childNodeName + "[" + (index + 1) + "]", null),
21824                node = parentNode.ownerDocument.createElement(childNodeName);
21825            if (childNode) {
21826                parentNode.insertBefore(node, childNode);
21827            } else {
21828                var lastNode = this._findLastDataNode(parentNode, childNodeName);
21829                if (lastNode && lastNode.nextSibling) {
21830                    parentNode.insertBefore(node, lastNode.nextSibling);
21831                } else if (lastNode && !lastNode.nextSibling) {
21832                    // for the case when the last node is there but there is no next sibling.
21833                    // we don't need to create all the nodes for this scenario.
21834                    parentNode.appendChild(node);
21835                } else {
21836                    // we need to create all the nodes till the count reaches the index.
21837                    for (var i = 0; i <= index; i++) {
21838                        var newNode = parentNode.ownerDocument.createElement(childNodeName);
21839                        parentNode.appendChild(newNode);
21840                    }
21841                }
21842            }
21843            return node;
21844        },
21845
21846        /**
21847         * Form an xpath part returns the index as well as the tagName.
21848         * Index returned is 0 if not present
21849         * @param xpathName
21850         * @returns {*}
21851         * @private
21852         * @memberof LiveXmlUtils
21853         */
21854        _getNameAndIndex : function (xpathPart) {
21855            if (xpathPart) {
21856                var elName = xpathPart.match(/^([^[\s\/]+)(?:\[(\d+)\])?$/);  // match the whole string
21857                if (elName !== null) {
21858                    return {
21859                        name : elName[1],
21860                        index : elName[2] ? parseInt(elName[2]) : 0
21861                    };
21862                }
21863            }
21864            return null;
21865        },
21866
21867        _cmpXpathParts : function (indexedName, templateName) {
21868            if (indexedName && templateName) {
21869                var match1 = this._getNameAndIndex(indexedName),
21870                    match2 = this._getNameAndIndex(templateName);
21871                return !_.isEmpty(match1 && match2)
21872                    && match1.name === match2.name
21873                    && (match2.index === 0 || match1.index === match2.index);
21874            }
21875            return false;
21876        },
21877
21878        /**
21879         * Will split an xpath string into an array containing one xml element/node per part
21880         * This expects only the simple xpath syntax allowed in bindRefs of xsd bound fields
21881         * of the form /a/b/c/@d
21882         * @param xpath
21883         * @returns {*|Array.<T>|list}
21884         * @private
21885         * @memberof LiveXmlUtils
21886         */
21887        _sanitizedXpathParts : function (xpath) {
21888            var xpathParts = (xpath || '').replace(/^\//, '').replace(/\s+/g, '').split('/');
21889
21890            if (_.last(xpathParts) === "text()") { // ignore "/text()" appended to bindRef for SimpleType schema element
21891                xpathParts.splice(-1, 1); // drop last element
21892            }
21893
21894            return _.filter(xpathParts, function (xpathPart) {
21895                return this._getNameAndIndex(xpathPart) !== null;
21896            }, this);
21897        },
21898
21899        /**
21900         * returns true if the xpath uses indices
21901         * @param xpath
21902         * @returns {boolean}
21903         * @memberof LiveXmlUtils
21904         */
21905        isIndexedPath : function (xpath) {
21906            return (xpath || "").match(this.constants.INDEXED_XPATH_PAT) !== null;
21907        },
21908
21909        _createElements : function (contextNode, xpathParts) {
21910            if (!(contextNode instanceof Node)) {
21911                return null;
21912            }
21913
21914            if (_.isEmpty(xpathParts)) {
21915                return contextNode;
21916            }
21917
21918            if (xpathParts[0][0] === '@') { // xpath parts having '@' as 1st char must be and attr
21919                var attrName = xpathParts[0].slice(1);
21920                // in bindrefs attributes are the last xpath part, so no need to recurse
21921                contextNode = this._createAttributeNode(contextNode, attrName);
21922            } else {
21923                // recurse and create one level of tags at a time
21924                contextNode = this._createRepeatedElements(contextNode, xpathParts);
21925            }
21926
21927            return contextNode;
21928        },
21929
21930        /**
21931         * This will update the xml with the required tags,
21932         * and return the context node matching the xpath query.
21933         * Further if xml has lesser number of tags than the index in each part,
21934         * it'll fill those gaps with empty tags.
21935         * @param contextNode node beneath which tags are to be created
21936         * @param xpathParts
21937         * @returns {*}
21938         * @private
21939         * @memberof LiveXmlUtils
21940         */
21941        _createRepeatedElements : function (contextNode, xpathParts) {
21942            var childContextNode = contextNode,
21943                xpathPart = this._getNameAndIndex(xpathParts[0]),
21944                elemName = xpathPart.name,
21945                index = xpathPart.index || 1,
21946                i,
21947                children = _.filter(contextNode.childNodes, function (child) {
21948                    return (child instanceof Element) && child.nodeName === elemName;
21949                });
21950
21951            if (children.length < index) {
21952                // create immediate 'extra' children
21953                for (i = children.length; i < index; ++i) {
21954                    childContextNode = this._createChildElement(contextNode, elemName);
21955                }
21956            } else {
21957                childContextNode = children[index - 1]; // indices are 1 based in xml
21958            }
21959            // recursively create descendants
21960            return this._createElements(childContextNode, xpathParts.slice(1));
21961        },
21962
21963        _createChildElement : function (parentElement, elemName) {
21964            if (parentElement instanceof Element) {
21965                var childElem = parentElement.ownerDocument.createElement(elemName);
21966                parentElement.appendChild(childElem);
21967                return childElem;
21968            }
21969        },
21970
21971        _createAttributeNode : function (parentElement, attrName) {
21972            if (parentElement instanceof Element) {
21973                var attrNode = parentElement.ownerDocument.createAttribute(attrName);
21974                parentElement.setAttributeNode(attrNode);
21975                return attrNode;
21976            }
21977        },
21978
21979        /**
21980         * finds xml node/element based on current context node and xpath
21981         * @param node
21982         * @param xpath
21983         * @param options
21984         * @returns {*}
21985         * @private
21986         * @memberof LiveXmlUtils
21987         */
21988        _getElement : function (node, xpath, options) {
21989            if (!(node instanceof Node)) {
21990                return null;
21991            }
21992
21993            if (_.isEmpty(xpath) || !_.isString(xpath)) {
21994                return node;
21995            }
21996            options = options || {};
21997            var nsResolver = options.nsResolver;
21998            var index = options.index;
21999            // in IE singleNodeValue maybe null for attribute queries,
22000            // so find parent element of attribute, and then explicitly check for attribute node's presence
22001
22002            var xpathParts = xpath.split('/@'),
22003                checkAttr = false,
22004                attributeName;
22005
22006            if (xpathParts.length > 2) { // more than 1 attr unsupported
22007                xfalib.ut.XfaUtil.prototype.getLogger().error("BindRefs must be Xpaths ending in atmost one attribute"); // TODO localize
22008                return null;
22009            } else if (xpathParts.length === 2) {
22010                xpath = xpathParts[0]; // find parent el and seek attribute there
22011                attributeName = xpathParts[1]; // attr can only be in the last part
22012                checkAttr = true;
22013            }
22014            if (!(_.isUndefined(index) || _.isNull(index))) {
22015                xpath = xpath + "[" + index + "]";
22016            }
22017            if (!window.XPathResult) {
22018                document.evaluate = undefined;
22019                wgxpath.install(window, true);
22020            }
22021            var result = xfalib.ut.XMLUtils.evaluateXPath(xpath, node, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null),
22022                el;
22023
22024            if (result && result.resultType === XPathResult.FIRST_ORDERED_NODE_TYPE) {
22025                el = result.singleNodeValue;
22026                if (el instanceof Node) {
22027                    if (!checkAttr) {
22028                        return el;
22029                    } else if (el.hasAttribute(attributeName)) {
22030                        el = el.getAttributeNode(attributeName);
22031                        if (el instanceof Node) {
22032                            return el;
22033                        }
22034                    }
22035                }
22036            }
22037        },
22038
22039        /**
22040         * This function checks if the document was naked or non naked xml
22041         * @param doc
22042         * @returns {boolean} returns true if there exists a afData node inside data false otherwise
22043         * @private
22044         * @memberof LiveXmlUtils
22045         */
22046        _isNonNaked : function (doc) {
22047            doc = doc || this.getLiveDataDoc();
22048            if (doc) {
22049                return doc.documentElement.tagName === this.constants.AF_ROOT_TAG;
22050            } else {
22051                return false;
22052            }
22053        },
22054
22055        /**
22056         * Returns list of panels touched by the end user before saving the draft
22057         * @param dataString
22058         */
22059        getListOfDirtyPanels : function (dataString) {
22060            if (dataString == null || dataString === "") {
22061                return [];
22062            }
22063            var livePrefillXmlDoc = $.parseXML(dataString),
22064                draftDoc = this._getElement(livePrefillXmlDoc.documentElement, this.constants.AF_DRAFT_TAG);
22065            if (_.isUndefined(draftDoc) || draftDoc.childNodes.length === 0) {
22066                return [];
22067            }
22068            var draftStr = draftDoc.firstChild.textContent.replace(/\"/g, ""),
22069                retVal = [];
22070            // not using filter here explicitly, due to ES4 syntax
22071            if (draftStr) {
22072                retVal = draftStr.split(",");
22073            }
22074            return retVal;
22075        },
22076
22077        /**
22078         * This function sets the rich text value of the field in the live data.
22079         * @param xpath
22080         * @param xmlSection
22081         * @param createMissingNodes
22082         * @param value
22083         * @private
22084         */
22085        setRichTextValue : function (xpath, xmlSection, createMissingNodes, value) {
22086            var node = this.getContextNode(xpath, xmlSection, createMissingNodes);
22087            if (node instanceof Node) {
22088                var richTextNode = $.parseXML(value);
22089				// clear the text content before appending child
22090                node.textContent = "";
22091                node.appendChild(richTextNode.documentElement);
22092            }
22093        },
22094
22095        setDataValue : function (xpath, xmlSection, createMissingNodes, value) {
22096            var node = this.getContextNode(xpath, xmlSection, createMissingNodes);
22097            if (node instanceof Node) {
22098                node.textContent = value;
22099            }
22100        },
22101
22102        getDataValue : function (xpath, xmlSection) {
22103            var node = this.getContextNode(xpath, xmlSection, false);
22104            if (node instanceof Node) {
22105                return node.textContent || null;
22106            }
22107            return undefined;
22108        },
22109
22110        getRichTextValue : function (xpath, xmlSection) {
22111            var node = this.getContextNode(xpath, xmlSection, false);
22112            if (node instanceof Node) {
22113                return node.innerHTML.trim();
22114            }
22115            return undefined;
22116        },
22117
22118        _convertModelIndexToDataIndex : function (index) {
22119            if (index < 0) {
22120                return 1;
22121            }
22122            return index + 1;
22123        },
22124
22125        getParentRef : function (path) {
22126            return path.substring(0, path.lastIndexOf("/"));
22127        },
22128
22129        insertSubmissionInfo : function (submissionInfo, rootNode) {
22130            if (this._isNonNaked()) {
22131                var xmlutils = xfalib.ut.XMLUtils,
22132                    node = rootNode === undefined
22133                        ? xmlutils.findOrCreateElement("afSubmissionInfo", this._liveDataDoc.documentElement)
22134                        : rootNode,
22135                    self = this;
22136                _.each(submissionInfo, function (value, key) {
22137                    var keyNode;
22138                    if (value instanceof Array) {
22139                        // we only support string items in json array
22140                        var finalValue = [], insert = true;
22141                        _.each(value, function (arrItem, index) {
22142                            if (typeof arrItem === "string") {
22143                                finalValue.push(arrItem);
22144                            } else if (arrItem instanceof Object && arrItem != null) {
22145                                insert = false;
22146                                var el = node.ownerDocument.createElement(key);
22147                                node.appendChild(el);
22148                                self.insertSubmissionInfo(arrItem, el);
22149                            }
22150                        });
22151                        if (insert) {
22152                            keyNode = xmlutils.findOrCreateElement(key, node);
22153                            keyNode.textContent = finalValue.join(',');
22154                            node.appendChild(keyNode);
22155                        }
22156                    } else if (typeof (value) === "object" && value != null) {
22157                        keyNode = xmlutils.findOrCreateElement(key, node);
22158                        self.insertSubmissionInfo(value, keyNode);
22159                        node.appendChild(keyNode);
22160                    } else {
22161                        keyNode = xmlutils.findOrCreateElement(key, node);
22162                        keyNode.textContent = value;
22163                        node.appendChild(keyNode);
22164                    }
22165                });
22166            }
22167        }
22168    });
22169
22170}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
22171
22172/*
22173 * ***********************************************************************
22174 * ADOBE CONFIDENTIAL
22175 * __________________
22176 *
22177 * Copyright 2015 Adobe Systems Incorporated
22178 * All Rights Reserved.
22179 *
22180 * NOTICE:  All information contained herein is, and remains
22181 * the property of Adobe Systems Incorporated and its suppliers,
22182 * if any.  The intellectual and technical concepts contained
22183 * herein are proprietary to Adobe Systems Incorporated and its
22184 * suppliers and may be covered by U.S. and Foreign Patents,
22185 * patents in process, and are protected by trade secret or copyright law.
22186 * Dissemination of this information or reproduction of this material
22187 * is strictly forbidden unless prior written permission is obtained
22188 * from Adobe Systems Incorporated.
22189 * ***********************************************************************
22190 */
22191
22192/**
22193 * @package guidelib.model.LiveModel
22194 * @version 0.0.1
22195 */
22196
22197(function ($, _, guideBridge, guidelib) {
22198    var LiveModel = guidelib.model.LiveModel = xfalib.ut.Class.extend({
22199        initialize : function () {
22200            LiveModel._super.initialize.call(this);
22201            this._crossFragmentFields = {}; // 2 level map: name => { bindRef => abstract model }
22202            this._dataNodes = {};
22203        },
22204
22205        // only called from test framework
22206        destroy : function () {
22207            this._crossFragmentFields = {};
22208            this._dataNodes = {};
22209        },
22210
22211        getCrossFragmentFields : function () {
22212            return this._crossFragmentFields;
22213        },
22214
22215        add : function (key, model) {
22216            if (key) {
22217                var dn = this._dataNodes[key] || new guidelib.model.DataNode();
22218                dn.addField(model);
22219                this._dataNodes[key] = dn;
22220            }
22221        },
22222
22223        isLive : function (key) {
22224            return _.isString(key) && _.has(this._dataNodes, key);
22225        },
22226
22227        remove : function (key, model) {
22228            if (this.isLive(key)) {
22229                var dn = this._dataNodes[key];
22230                dn.removeField(model);
22231            }
22232        },
22233
22234        getAllFieldModels : function (keys) {
22235            return _.flatten(_.map(keys, function (key) {
22236                var result,
22237                    dataNode = this._dataNodes[key];
22238                if (dataNode) {
22239                    result = dataNode.getFieldModels();
22240                }
22241                return result;
22242            }, this));
22243        },
22244
22245        getAllAbstractFieldModels : function (keys) {
22246            return _.flatten(_.map(keys, function (key) {
22247                return this._dataNodes[key].getAbstractFieldModels();
22248            }, this));
22249        },
22250
22251        resetData : function () {
22252            // all loaded models in data nodes dataNodes will be reset by the respective fields
22253            // just need to reset the abstract cross frag fields
22254            _.each(this._crossFragmentFields, function (fields) {
22255                _.each(fields, function (abstractField) {
22256                    abstractField.resetData();
22257                });
22258            });
22259        },
22260
22261        createDataNodes : function (duplicateBindRefs) {
22262            _.each(duplicateBindRefs, function (bindRef) {
22263                this.add(bindRef);
22264            }, this);
22265        },
22266
22267        createCrossFragFields : function (crossFragFields, guide) {
22268            _.each(crossFragFields, function (field) {
22269                var effectiveBindRef = field.bindRef || field.name,
22270                    value = field._value || null,// default value, keep null because js is quirky with operations on undefined
22271                    absModel = new guidelib.model.AbstractField({
22272                        'name' : field.name,
22273                        'className' : field.guideNodeClass,
22274                        'bindRef' : field.bindRef,
22275                        'dataSom' : field.dataSom,
22276                        'afDataSom' : field.afDataSom,
22277                        'jsonModel' : {
22278                            '_value' : value,
22279                            "{default}" : value
22280                        },
22281                        '_guideContainer' : guide
22282                    });
22283
22284                if (_.isEmpty(this._crossFragmentFields[field.name])) {
22285                    this._crossFragmentFields[field.name] = {};
22286                }
22287                this._crossFragmentFields[field.name][effectiveBindRef] = absMo
22287del;
22288
22289                this.add(effectiveBindRef, absModel); // unbound globals with same name linked together
22290
22291            }, this);
22292        },
22293
22294        prefillCrossFragFields : function (guide) {
22295            var dataUtils = guide.internal.liveDataUtils;
22296            if (dataUtils.isLiveDataInitialized()) {
22297                _.each(this._crossFragmentFields, function (fields, name) {
22298                    _.each(fields, function (absModel, bindRef) {
22299                        var dataContext = dataUtils._getDataContext(absModel, '', '');
22300                        // fill value from prefill data or saved lazy live data
22301                        absModel.value = dataUtils.getDataValue(dataContext.indexedXpath, dataContext.xmlSec);
22302                    }, this);
22303                }, this);
22304            }
22305        }
22306    });
22307}($, _, window.guideBridge, window.guidelib));
22308
22309/**
22310 * @package guidelib.model.FormData
22311 * @version 0.0.1
22312 */
22313
22314(function ($, _, guidelib) {
22315
22316    /**
22317     * JavaScript class to represent form data
22318     * @class FormData
22319     * @since 6.5.11
22320     */
22321    var AfFormData = guidelib.model.FormData = xfalib.ut.Class.extend({
22322
22323        initialize : function () {
22324            AfFormData._super.initialize.call(this);
22325        },
22326
22327        toJsObject : function() {
22328            return {
22329                "data" : this.data,
22330                "contentType" : this.contentType,
22331                "attachments" : this.attachments
22332            }
22333        },
22334
22335        /**
22336         * This returns the html form data representation of adaptive form data. This could be used to submit the adaptive form data to
22337         * external end point from the client. The HTML form data contains the following the key / value pairs:
22338         * 1. data -> contains form data represented as string
22339         * 2. contentType -> contains content type of form data (it would be application/xml or application/json)
22340         * 2. fileAttachments -> list of blobs containing the file (in case of fileUrl's the type of blob would be application/json)
22341         * 3. fileAttachmentBindRefs -> list of string containing file bindRef's, this has one to one mapping with fileAttachments
22342         * @returns {*}
22343         */
22344        toHTMLFormData : function() {
22345            // using native formData class
22346            var formData = new FormData();
22347            // appending data of adaptive form in data key
22348            // data could be JSON or XML
22349            if (this.contentType) {
22350                formData.append("contentType", this.contentType);
22351            }
22352            formData.append("data", this.data);
22353            for (var index = 0; index < this.attachments.length; index++) {
22354                var fileAttachmentWrapper = this.attachments[index];
22355                // 2nd parameter should be of blob type, hence adding an explicit check here
22356                // we could have created dataURL for all the files in the client, but this would cause the browser
22357                // to slow down since it would serialize the binary, hence following the below approach
22358                if (fileAttachmentWrapper.isFile()) {
22359                    formData.append("fileAttachments", fileAttachmentWrapper.data, fileAttachmentWrapper.name);
22360                } else {
22361                    // blob is supported on all major browsers
22362                    var urlBlob = new Blob([
22363                        JSON.stringify({
22364                            "data" : fileAttachmentWrapper.data,
22365                            "name" : fileAttachmentWrapper.name,
22366                            "contentType" : fileAttachmentWrapper.contentType
22367                        })
22368                    ], { type: 'application/json' });
22369                    formData.append("fileAttachments", urlBlob);
22370                }
22371                formData.append("fileAttachmentBindRefs", fileAttachmentWrapper.bindRef);
22372            }
22373            return formData;
22374        }
22375    });
22376
22377    AfFormData.defineProps({
22378        /**
22379         * Actual form data (could be JSON or xml)
22380         */
22381        data : {
22382            get : function () {
22383                return this.options.data;
22384            }
22385        },
22386
22387        /**
22388         * List of {FileAttachmentWrapper} {@link FileAttachmentWrapper}
22389         */
22390        attachments : {
22391            get : function () {
22392                return this.options.attachments;
22393            }
22394        },
22395
22396        /**
22397         * Content type of form data (it could be application/xml or application/json)
22398         */
22399        contentType : {
22400            get : function () {
22401                return this.options.contentType;
22402            }
22403        }
22404    });
22405
22406
22407}($, _, window.guidelib));
22408
22409/**
22410 * @package guidelib.model.FileAttachmentWrapper
22411 * @version 0.0.1
22412 */
22413
22414(function ($, _, guidelib) {
22415
22416    /**
22417     * JavaScript class to represent the each file data present in the form.
22418     * Data could be URI (URI could be a file URL or dataURL)
22419     * @class FileAttachmentWrapper
22420     * @since 6.5.10
22421     */
22422    var FileAttachmentWrapper = guidelib.model.FileAttachmentWrapper = xfalib.ut.Class.extend({
22423
22424        initialize : function () {
22425            FileAttachmentWrapper._super.initialize.call(this);
22426        },
22427
22428        /**
22429         * Converts file attachment wrapper to a javascript object
22430         * @returns {{name: *, contentType: *, bindRef: *, data: *}}
22431         */
22432        toJsObject : function () {
22433            return {
22434                name : this.name,
22435                contentType : this.contentType,
22436                bindRef : this.bindRef,
22437                data : this.data
22438            }
22439        },
22440
22441        /**
22442         * Checks if the file data is native JS File object
22443         * @returns {boolean}
22444         */
22445        isFile : function() {
22446            return this.data instanceof File;
22447        },
22448
22449
22450        /**
22451         * Returns blob for the data URL present in data
22452         * @returns {*}
22453         */
22454        dataURLtoBlob : function() {
22455            var dataurl = this.data, // data should be a data url
22456                arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
22457                bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
22458            while(n--){
22459                u8arr[n] = bstr.charCodeAt(n);
22460            }
22461            return new Blob([u8arr], {type: mime});
22462        }
22463    });
22464
22465    FileAttachmentWrapper.defineProps({
22466        /**
22467         * Actual name of the file associated with data
22468         */
22469        name : {
22470            get : function () {
22471                return this.options.name;
22472            }
22473        },
22474
22475        /**
22476         * Content type of file
22477         */
22478        contentType : {
22479            get : function () {
22480                return this.options.contentType;
22481            }
22482        },
22483
22484        /**
22485         * This would be effective bindRef meaning bindRef in case of data model or component name in case of unbound data
22486         */
22487        bindRef : {
22488            get : function () {
22489                return this.options.bindRef;
22490            }
22491        },
22492
22493        /**
22494         * This would represent the name of the form element to which the file binary is associated.
22495         * In case of unbound form, bindRef and component name would be the same
22496         */
22497        formElementName : {
22498            get : function () {
22499                return this.options.formElementName || this.options.bindRef;
22500            }
22501        },
22502
22503        /**
22504         * Data could be URI (URI could be file URL or dataURL) or native JavaScript File object
22505         */
22506        data : {
22507            get : function () {
22508                return this.options.data;
22509            }
22510        }
22511    });
22512
22513
22514}($, _, window.guidelib));
22515/*************************************************************************
22516 *
22517 * ADOBE CONFIDENTIAL
22518 * __________________
22519 *
22520 *  Copyright 2014 Adobe Systems Incorporated
22521 *  All Rights Reserved.
22522 *
22523 * NOTICE:  All information contained herein is, and remains
22524 * the property of Adobe Systems Incorporated and its suppliers,
22525 * if any.  The intellectual and technical concepts contained
22526 * herein are proprietary to Adobe Systems Incorporated and its
22527 * suppliers and may be covered by U.S. and Foreign Patents,
22528 * patents in process, and are protected by trade secret or copyright law.
22529 * Dissemination of this information or reproduction of this material
22530 * is strictly forbidden unless prior written permission is obtained
22531 * from Adobe Systems Incorporated.
22532 **************************************************************************/
22533
22534
22535(function (_, guidelib) {
22536
22537    
22538    var GuideModelEvent = guidelib.event.GuideModelEvent = xfalib.ut.Class.extend({
22539        msClassName : "guideModelEvent"
22540    });
22541
22542    GuideModelEvent.defineProps({
22543        
22544        "prevText" : {
22545            get : function () {
22546                return this.jsonModel.prevText;
22547            }
22548        },
22549        
22550        "newText" : {
22551            get : function () {
22552                return this.jsonModel.newText;
22553            }
22554        },
22555        
22556        "name" : {
22557            get : function () {
22558                return this.jsonModel.name;
22559            }
22560        },
22561        "keyDown" : {
22562            get : function () {
22563                return this.jsonModel.keyDown;
22564            }
22565        },
22566        "modifier" : {
22567            get : function () {
22568                return this.jsonModel.modifier;
22569            }
22570        },
22571        
22572        "target" : {
22573            get : function () {
22574                return this.jsonModel.target;
22575            }
22576        },
22577        "shift" : {
22578            get : function () {
22579                return this.jsonModel.shift;
22580            }
22581        },
22582        "change" : {
22583            get : function () {
22584                return this.jsonModel.change;
22585            },
22586            set : function (value) {
22587                this.jsonModel.change = value;
22588            }
22589        },
22590        
22591        "_property" : {
22592            get : function () {
22593                return this.jsonModel._property;
22594            }
22595        }
22596    });
22597
22598    GuideModelEvent.createEvent = function (nm, tgt, prop, oldVal, newVal) {
22599        var evnt = {
22600            name : nm,
22601            target : tgt,
22602            _property : prop,
22603            prevText : oldVal,
22604            newText : newVal
22605        };
22606        return new GuideModelEvent({"jsonModel" : evnt});
22607    };
22608
22609    GuideModelEvent.MODEL_REFRESH = "guide.modelRefresh";
22610    GuideModelEvent.CHILD_CHANGED = "guide.childChanged";
22611    GuideModelEvent.MULTIPLE_CHILD_ADDED = "guide.multipleChildAdded";
22612    GuideModelEvent.MODEL_CHANGED = "guide.modelChanged";
22613    GuideModelEvent.VALUE_CHANGED = "guide.valueChanged";
22614    GuideModelEvent.ERROR_CHANGED = "guide.errorChanged";
22615    GuideModelEvent.ERROR_RESET = "guide.errorReset";
22616    GuideModelEvent.VISIBLE_CHANGED = "guide.visibleChanged";
22617    GuideModelEvent.ENABLED_CHANGED = "guide.enabledChanged";
22618    GuideModelEvent.ITEMS_CHANGED   = "guide.itemsChanged";
22619    GuideModelEvent.OBJECT_DESTROYED = "guide.objectDestroyed";
22620    GuideModelEvent.NAVIGATE_SECTION = "guide.navigateSection";
22621    GuideModelEvent.LAZY_LOADED = "guide.lazyLoaded";
22622}(_, guidelib));
22623(function ($, _, guidelib) {
22624    var GuideViewRegistry = guidelib.view.GuideViewRegistry = xfalib.ut.Class.extend({
22625
22626        
22627        _findWidget : function (config, name, className) {
22628            var result = _.find(config, function (widgetName, identifier) {
22629                return name === identifier;
22630            });
22631            if (result === undefined) {
22632                result = _.find(config, function (widgetName, identifier) {
22633                    return className === identifier;
22634                });
22635            }
22636            return result;
22637        },
22638
22639        
22640        _findWidgetNameFromCSS : function (cssClasses) {
22641            var result = null;
22642            if (_.isString(cssClasses)) {
22643                _.find(cssClasses.split(" "),
22644                    function (cssClass, index) {
22645                        var match = cssClass.match(/^widget_([\w\W]+)$/);
22646                        if (match && match.length === 2) {
22647                            result = match[1];
22648                            return true;
22649                        }
22650                        return false;
22651                    });
22652            }
22653            return result;
22654        },
22655
22656        createView : function (element, parentView) {
22657            var $element = $(element);
22658            var options = {
22659                    'element' : $element.get(0),
22660                    'widgetName' : $element.data("guideViewWidget"),
22661                    'parentView' : parentView
22662                };
22663            var guideViewBind = $element.data("guideViewBind");
22664            var model = window.guideBridge._resolveId(guideViewBind);
22665            
22666            
22667            if (model) {
22668                options.model = model;
22669                var clsName = model.className;
22670                var nodeClass = clsName.charAt(0).toUpperCase() + clsName.substr(1) + "View";
22671                var viewClass = guidelib.view[nodeClass],
22672                    widgetConfig = window.guideBridge.userConfig.widgetConfig;
22673                if (model instanceof guidelib.model.Field || model instanceof guidelib.model.GuideCompositeField) {
22674                    options.widgetName = this._findWidgetNameFromCSS(model.cssClassName)
22675                        || this._findWidget(widgetConfig, model.name, model.className);
22676                }
22677                if (!viewClass && model instanceof guidelib.model.GuideContainerNode) {
22678                    viewClass = guidelib.view.GuideContainerView;
22679                }
22680                if (!viewClass && model instanceof guidelib.model.Field) {
22681                    viewClass = guidelib.view.GuideFieldView;
22682                }
22683                if (!viewClass && model instanceof guidelib.model.GuidePanel) {
22684                    viewClass = guidelib.view.GuidePanelView;
22685                }
22686                if (!viewClass && model instanceof guidelib.model.GuideItemsContainer) {
22687                    viewClass = guidelib.view.GuideItemsView;
22688                }
22689                if (!viewClass) {
22690                    viewClass = guidelib.view.GuideBaseView;
22691                }
22692                
22693                var bindView = new viewClass(options);
22694                return bindView;
22695            }
22696        }
22697    });
22698
22699})($, _, guidelib);
22700(function (_, guidelib, xfalib) {
22701    var DataNode = guidelib.model.DataNode = xfalib.ut.Class.extend({
22702        initialize : function () {
22703            this.linkedFields = [];
22704            this.isUpdateInProgress = false;
22705        },
22706
22707        addField : function (model) {
22708            if (!_.isEmpty(model) && !_.contains(this.linkedFields, model)) {
22709                this.linkedFields.push(model);
22710                model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this);
22711            }
22712        },
22713
22714        removeField : function (model) {
22715            if (!_.isEmpty(model)) {
22716                model.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, this);
22717                this.linkedFields = _.without(this.linkedFields, model);
22718            }
22719        },
22720
22721        getFieldModels : function () {
22722            return _.filter(this.linkedFields, function (field) {
22723                return (field instanceof guidelib.model.Field);
22724            });
22725        },
22726
22727        getAbstractFieldModels : function () {
22728            return _.filter(this.linkedFields, function (field) {
22729                return (field instanceof guidelib.model.AbstractField);
22730            });
22731        },
22732
22733        handleEvent : function (event) {
22734            switch (event.name) {
22735            case guidelib.event.GuideModelEvent.VALUE_CHANGED:
22736                if (!_.contains(['guideButton', 'guideTextDraw', 'guideAdobeSignBlock'], event.target.className)) {
22737                    this.updateLinkedFieldsValue(event);
22738                }
22739                break;
22740            default:
22741                event.target.logger().warn("AF", "Unexpected Event type on Data Node", event);
22742            }
22743        },
22744
22745        updateLinkedFieldsValue : function (event) {
22746            if (this.isUpdateInProgress) {
22747                return;
22748            }
22749
22750            this.isUpdateInProgress = true;
22751            var newValue = event.target._getValue();
22752
22753            try {
22754                _.each(this.linkedFields, function (field) {
22755                    if (field !== event.target) {
22756                        field.value = newValue;
22757                    }
22758                }, this);
22759            } catch (ex) {
22760                event.target.logger().error("AF", "Unable to set Linked Field value" + ex);
22761            } finally {
22762                this.isUpdateInProgress = false;
22763            }
22764        }
22765    });
22766
22767}(_, guidelib, xfalib));
22768(function ($, guidelib, _) {
22769    var GuideBaseView = guidelib.view.GuideBaseView = xfalib.ut.Class.extend({
22770        guideUtil : guidelib.util.GuideUtil,
22771        _triggerOnBridge : function (eventName, target, property, oldVal, newVal) {
22772            var evnt = guidelib.event.GuideModelEvent.createEvent(eventName, target,
22773                                                    property, oldVal, newVal);
22774            window.guideBridge.trigger(eventName, evnt);
22775        },
22776
22777        initialize : function () {
22778            GuideBaseView._super.initialize.call(this);
22779            this.$element = $(this.options.element);
22780            this.id = this.$element.attr("id");
22781            this._model = this.options.model;
22782            this.parentView = this.options.parentView;
22783            this.$element.data("guideView", this);
22784            this._$item = null;
22785            this._$itemNav = null;
22786            
22787            if (this._model && this._model != null) {
22788                this._model.on(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
22789            }
22790            this._syncPending = true; 
22791            this._visibleHelpElement = "none";
22792            this._polyfills();
22793        },
22794
22795        _polyfills: function () {
22796            var IEpolyfillForObjectDotEntries = function() {
22797                if(!Object.entries) {
22798                    Object.entries = function (obj) {
22799                        var ownProps = Object.keys(obj),
22800                            i = ownProps.length,
22801                            resArray = new Array(i); 
22802                        while (i--)
22803                            resArray[i] = [ownProps[i], obj[ownProps[i]]];
22804
22805                        return resArray;
22806                    };
22807                }
22808            };
22809
22810            var polyfills = [IEpolyfillForObjectDotEntries];
22811
22812            for (var i = 0; i < polyfills.length; ++i) {
22813                polyfills[i](); 
22814            }
22815        },
22816
22817        postInitialize : function () {
22818        },
22819
22820        _unloadView : function () {
22821            
22822            this._model.off(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
22823            
22824            this.$element = null;
22825            this.$widget = null;
22826            this._model = null;
22827            this._$item = null;
22828            this._$itemNav = null;
22829            this.parentView = null;
22830        },
22831
22832        handleVisibleChanged : function (event) {
22833            
22834            
22835            if (!event.newText) {
22836                this.$item.addClass("hidden");
22837                this.$itemNav.addClass("hidden");
22838                if (this.parentView.currentActiveItemView == this) {
22839                    this.parentView.setActive("nextItem");
22840                }
22841                if (event.prevText) {
22842                    this.announceVisibilityChanged("HIDDEN");
22843                }
22844            }   else {
22845                
22846                this.$item.removeClass("hidden");
22847                this.$itemNav.removeClass("hidden");
22848                if (!event.prevText) {
22849                    this.announceVisibilityChanged("VISIBLE");
22850                }
22851            }
22852        },
22853
22854        announceVisibilityChanged : function (visible) {
22855            var $statusAnnounceElement = this.parentView.$element.find('.guideGridFluidLayout2ContainerStatus');
22856            var $elementLabel = this.$item.find('.guideFieldLabel label');
22857            if ($statusAnnounceElement && $elementLabel) {
22858                var newStatus = visible === "VISIBLE" ? 
22859                    this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.showingField, [$elementLabel.text()])
22860                    :
22861                    this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.hidingField, [$elementLabel.text()]);
22862                $statusAnnounceElement.attr('aria-label', newStatus);
22863            }
22864        },
22865
22866        handleModelChanged : function (event) {
22867            switch (event._property) {
22868                case "viewVisited":
22869                    if (event.newText) {
22870                        this.$item.addClass("stepped");
22871                        this.$itemNav.addClass("stepped");
22872                    }else {
22873                        this.$item.removeClass("stepped");
22874                        this.$itemNav.removeClass("stepped");
22875                    }
22876                    break;
22877
22878                case "visible":
22879                    this.handleVisibleChanged(event);
22880                    break;
22881            }
22882        },
22883
22884        setActive : function (activeItemToken, focus, muteScripts) {
22885            if (focus && (this._model.className === "guideNode" || this._model.forceElementFocusChange)) {
22886                if (this.$element !== null && typeof this.$element.focus === "function" && !this._guideView.skipFieldFocus) {
22887                    
22888                    this.$element.focus();
22889                    
22890                    this._guideView.currentFocusItemSom = this._model.somExpression;
22891                }
22892            }
22893            return true;
22894        },
22895
22896        focusable : function () {
22897            return this._model.visible;
22898        },
22899
22900        _find : function (selector) {
22901            return this._guideView.$element.find(selector);
22902        },
22903
22904        _syncGuideNodeToHtml : function (deepSync) {
22905            this._syncPending = false;
22906            
22907            
22908            this.handleVisibleChanged(guidelib.event.GuideModelEvent.createEvent(
22909                guidelib.event.GuideModelEvent.MODEL_CHANGED,
22910                this,
22911                "visible",
22912                this._model.visible,
22913                this._model.visible
22914            ));
22915        },
22916
22917        _updateIds : function ($el, oldId, newId) {
22918            if (oldId == newId) {
22919                return;
22920            }
22921            
22922            var idSelector = "#" + oldId,
22923                modelBindSelector = this.guideUtil.modelElSelector(oldId),
22924                attrSelector = '[id^="' + oldId + '"]',
22925                longDescriptionSelector = '[data-guide-longDescription^="' + oldId + '"]',
22926                labelSelector = 'label[for^="' + oldId + '"]',
22927                targetIdSelector = "[data-guide-id^='" + oldId + "']",
22928                $elById = $el.find(idSelector).addBack(idSelector),
22929                selectorAttrObject  = {
22930                    "id" : attrSelector ,
22931                    "for" : labelSelector,
22932                    "data-guide-longDescription" : longDescriptionSelector,
22933                    "data-guide-id" : targetIdSelector
22934                };
22935            
22936            
22937            
22938            if ($elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM_CONTAINER) !== undefined) {
22939                $elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM_CONTAINER, newId + guidelib.util.GuideUtil.GUIDE_ITEM_CONTAINER_SUFFIX);
22940            }
22941            
22942            if ($elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM) !== undefined) {
22943                $elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM, newId + guidelib.util.GuideUtil.GUIDE_ITEM_SUFFIX);
22944            }
22945            $elById.attr("id", newId);
22946            $el.find(modelBindSelector).addBack(modelBindSelector).attr(this.guideUtil.GUIDE_VIEW_BIND_ATTR, newId);
22947            
22948            _.each(_.keys(selectorAttrObject), function (item, index) {
22949                var selector = selectorAttrObject[item];
22950                $el.find(selector).addBack(selector).each(function () {
22951                    
22952                    var $this = $(this),
22953                        prevId = $this.attr(item),
22954                        nextId = newId + prevId.substring(oldId.length);
22955                    $this.attr(item, nextId);
22956                });
22957            }, this);
22958        },
22959
22960        getSiblingItemView : function (siblingType) {
22961            if (this.parentView instanceof guidelib.view.GuidePanelView) {
22962                var siblingItem = this.parentView._model.navigationContext.getItemForNav(siblingType);
22963                if (siblingItem) {
22964                    return this.parentView.getQualifiedNamedView(siblingItem._escapeQualifiedName());
22965                }
22966            }
22967            return null;
22968        }
22969    });
22970
22971    GuideBaseView.defineProps({
22972        _guideView : {
22973            get : function () {
22974                return window.guideBridge._guideView;
22975            }
22976        },
22977
22978        _guide : {
22979            get : function () {
22980                return window.guideBridge._guide;
22981            }
22982        },
22983
22984        $item : {
22985            get : function () {
22986                if (!this._$item || this._$item.length == 0) {
22987                    var itemSelector = this.guideUtil.itemSelector(this._model.id, this._model);
22988                    this._$item = this._find(itemSelector);
22989                    
22990                    
22991                    if (this._$item && this._$item.length == 0) {
22992                        return this.$element;
22993                    }
22994                }
22995                return this._$item;
22996            }
22997        },
22998
22999        $itemNav : {
23000            get : function () {
23001                if (!this._$itemNav) {
23002                    var itemNavSelector = this.guideUtil.itemNavSelector(this._model.id);
23003                    this._$itemNav = this._find(itemNavSelector);
23004                }
23005                return this._$itemNav;
23006            }
23007        },
23008        visibleHelpElement :  {
23009            get : function () {
23010                return this._visibleHelpElement;
23011            },
23012            set : function (helpType) {
23013                this._visibleHelpElement = helpType;
23014            }
23015        },
23016
23017        
23018        isItem : {
23019            get : function () {
23020                return this._model._isItem;
23021            }
23022        },
23023
23024        qualifiedName : {
23025            get : function () {
23026                return this._model._escapeQualifiedName();
23027            }
23028        }
23029
23030    });
23031}($, guidelib, _));
23032(function ($, guidelib, _) {
23033
23034    var xfaUtil = xfalib.ut.XfaUtil.prototype,
23035        GuideFieldView = guidelib.view.GuideFieldView = guidelib.view.GuideBaseView.extend({
23036            _defaultWidgetName : "defaultWidget",
23037
23038            
23039            autofillFieldKeywordToName  : {
23040                "name" : "name",
23041                "given-name" : "fname",
23042                "additional-name" : "mname",
23043                "family-name" : "lname",
23044                "email" : "email",
23045                "street-address" : "address",
23046                "address-line1" : "address",
23047                "address-line2" : "address",
23048                "address-level1" : "state",
23049                "address-level2" : "city",
23050                "postal-code" : "zip",
23051                "country" : "country",
23052                "tel" : "phone",
23053                "cc-name" : "ccname",
23054                "cc-number" : "cardnumber",
23055                "cc-csc" : "cvc",
23056                "cc-exp-month" : "ccmonth",
23057                "cc-exp-year" : "ccyear",
23058                "cc-exp" : "exp-date",
23059                "cc-type" : "card-type"
23060            },
23061
23062            initialize : function () {
23063                GuideFieldView._super.initialize.call(this);
23064                this._initializeWidget();
23065                this._defineModelEvents();
23066                this._markMandatory();
23067                this._updateEmptyStatus();
23068                this.oldValue = null;
23069            },
23070
23071            postInitialize : function () {
23072                this._syncGuideNodeToHtml(true);
23073            },
23074
23075            createWidgetOptions : function () {
23076                return {
23077                    name : this._model.getAttribute("autocomplete") ? this.autofillFieldKeywordToName[this._model.getAttribute("autofillFieldKeyword")] : this._model.id + "_jqName",
23078                    value : this._model.value,
23079                    displayValue : this._model.formattedValue,
23080                    commitEvent : this.getCommitEvent(),
23081                    access : this._model.enabled ? "open" : "readOnly",
23082                    screenReaderText : this._model._getScreenReaderText(),
23083                    mandatory : this._model.mandatory
23084                };
23085            },
23086
23087            getCommitEvent : function () {
23088                return xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT;
23089            },
23090
23091            getWidgetName : function () {
23092                var widgetName;
23093                if (this.$widget) {
23094                    var $elem = this.$widget.find('[data-af-widgetname]').addBack('[data-af-widgetname]');
23095                    
23096                    if ($elem && $elem.length > 0) {
23097                        widgetName = $elem.attr("data-af-widgetname");
23098                    }
23099                }
23100                if (!widgetName) {
23101                    this.logger().warn("AF", "widget name is not specified for field " + this._model.somExpression +
23102                        ", falling back to other widget");
23103                }
23104                return widgetName || this.options.widgetName || this._defaultWidgetName;
23105            },
23106
23107            _unloadView : function () {
23108                if (this._model) {
23109                    this._model.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
23110                    this._model.off(guidelib.event.GuideModelEvent.ERROR_CHANGED, this.handleErrorChanged, this);
23111                    this._model.off(guidelib.event.GuideModelEvent.ERROR_RESET, this.handleErrorReset, this);
23112                }
23113                
23114                this.jqwidget = null;
23115                GuideFieldView._super._unloadView.apply(this, arguments);
23116            },
23117
23118            _initializeWidget : function () {
23119                if (this.$element.find('div.guideFieldWidget').length) {
23120                    this.$widget = this.$element.find('div.guideFieldWidget');
23121                } else {
23122                    this.$widget = null;
23123                }
23124
23125                
23126                if (this.$widget) {
23127                    $(this.$widget).on(this.getCommitEvent(), $.proxy(this.handleCommit, this))
23128                        .on(xfaUtil.XFA_CLICK_EVENT, $.proxy(this.handleClick, this))
23129                        .on(xfaUtil.XFA_EXIT_EVENT, $.proxy(this.handleFocusOut, this))
23130                        .on(xfaUtil.XFA_ENTER_EVENT, $.proxy(this.handleEnter, this));
23131                }
23132            },
23133
23134            _defineModelEvents : function () {
23135                if (this._model) {
23136                    
23137                    
23138                    this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
23139                    
23140                    this._model.on(guidelib.event.GuideModelEvent.ERROR_CHANGED, this.handleErrorChanged, this);
23141                    this._model.on(guidelib.event.GuideModelEvent.ERROR_RESET, this.handleErrorReset, this);
23142
23143                }
23144            },
23145
23146            _syncGuideNodeToHtml : function (deepSync) {
23147                GuideFieldView._super._syncGuideNodeToHtml.apply(this, arguments);
23148                if (this._model) {
23149                    var propsToSync = {                  
23150                        "visible" : this._model.visible, 
23151                        "jcr:title" : this._model.title
23152                    };
23153                    _.each(propsToSync, function (value, key, list) {
23154                        this.handleModelChanged(guidelib.event.GuideModelEvent.createEvent(
23155                            guidelib.event.GuideModelEvent.MODEL_CHANGED, this, key, value, value
23156                        ));
23157                    }, this);
23158                    this.$element.attr("data-disabled", !this._model.enabled + "");
23159                }
23160                if (this.$widget) {
23161                    var widgetOptions = this.createWidgetOptions();
23162                    if (!this.jqwidget) {
23163                        this.createWidget(this.getWidgetName(), widgetOptions);
23164                    } else {
23165                        this.setWidgetOptions(widgetOptions);
23166                    }
23167                }
23168                
23169                if (this._model.forceErrorShow && this._model._errorText) {
23170                    this.handleErrorChanged({prevText : this._model.validationState, newText : this._model._errorText});
23171                }
23172
23173                
23174                
23175                
23176                
23177                if (this._guide.jsonModel.textReplacementMap) {
23178                    var footnoteArr = Object.entries(this._guide.jsonModel.textReplacementMap);
23179                    var tempArray = [];
23180                    for (var i = 0; i < footnoteArr.length; i++) {
23181                        
23182                        
23183                        
23184                        if(!tempArray[footnoteArr[i][1]]){
23185                            tempArray[footnoteArr[i][1]] = footnoteArr[i][0];
23186                        }
23187                        var selector = $("span[data-af-footnote-id=" + "\"" + footnoteArr[i][0] + "\"]");
23188                        for (var j = 0; j < $(selector).length; j++) {
23189                            var supTag = document.createElement("sup");
23190                            var anchorTag = document.createElement("a");
23191                            anchorTag.setAttribute("href", "#" + tempArray[footnoteArr[i][1]] + "_ftn");
23192                            anchorTag.setAttribute("data-footnote-id", tempArray[footnoteArr[i][1]]);
23193                            anchorTag.setAttribute("title", $('#' + tempArray[footnoteArr[i][1]]).text());
23194                            anchorTag.innerHTML = footnoteArr[i][1];
23195                            supTag.appendChild(anchorTag);
23196                            $($(selector)[j]).html(supTag.outerHTML);
23197                        }
23198                    }
23199                }
23200            },
23201
23202            setWidgetOptions : function (widgetOptions) {
23203                this.jqwidget.option(widgetOptions);
23204
23205            },
23206
23207            
23208            _markMandatory : function (value) {
23209                if (this._model.mandatory && this.$element) {
23210                    this.$element.attr("data-mandatory", "true");
23211                } else {
23212                    this.$element.removeAttr("data-mandatory");
23213                    
23214                    if (this._model._failedTest === this.guideUtil.MANDATORY_TEST) {
23215                        this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
23216                    }
23217                }
23218                if (this.jqwidget) {
23219                    this.setWidgetOptions({
23220                        "mandatory" : value
23221                    });
23222                }
23223            },
23224
23225            
23226            _updateEmptyStatus : function (event) {
23227                var val = event ? event.newText : this._model.value;
23228                if (val == null || typeof val === 'string' && val.length == 0) {
23229                    this.$element.removeClass("af-field-filled").addClass("af-field-empty");
23230                } else {
23231                    this.$element.removeClass("af-field-empty").addClass("af-field-filled");
23232                }
23233            },
23234
23235            handleValueChanged : function (event) {
23236                switch (event._property) {
23237                case "value":
23238                    this.jqwidget.option("value", event.prevText);
23239                    this.jqwidget.option("displayValue", event.newText);
23240                    break;
23241                }
23242                this._updateEmptyStatus(event);
23243            },
23244
23245            handleErrorChanged : function (event) {
23246                var value = event.prevText,
23247                    errorMessage = event.newText;
23248                if (value === true) {
23249                    this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
23250                    this.$element.addClass("validation-success").removeClass("validation-failure");
23251                    this.updateWidgetOption("isValid", true);
23252                } else {
23253                    this._model._guide().runtime.errorManager.markError(errorMessage, this.$element, this._model.somExpression,
23254                        guideBridge.getValidationContext());
23255                    this.$element.addClass("validation-failure").removeClass("validation-success");
23256                    this.updateWidgetOption("isValid", false);
23257                }
23258            },
23259
23260            handleErrorReset : function (event) {
23261                this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
23262                this.$element.removeClass("validation-failure").removeClass("validation-success");
23263                this.updateWidgetOption("isValid", undefined);
23264            },
23265
23266            handleCommit : function () {
23267                if (this._model.enabled) {
23268                    this.commitValue(this.jqwidget.option("value"));
23269                }
23270            },
23271
23272            handleClick : function (event) {
23273                window.guideBridge.clickedOnWindow = false;
23274            },
23275
23276            handleFocusOut : function (event) {
23277                var gb = window.guideBridge;
23278
23279                if (this.getCommitEvent() !== xfaUtil.XFA_EXIT_EVENT) {
23280                    this._model.executeExpression("exit");
23281                }
23282                if (gb && gb.clickedOnWindow) {
23283                    this._guideView.currentFocusItemSom = null;
23284                }
23285                gb.clickedOnWindow = false;
23286                if (!(this._model.className === 'guideRadioButton'  || this._model.className === 'guideCheckBox' || this._model.className === 'guideButton')) {
23287                    this._triggerOnBridge("elementFocusOut", "", "", "", "");
23288                }
23289                
23290                if ((this.oldValue !== this._model.value) && this._model._errorText) {
23291                    this.handleErrorChanged({prevText : this._model.validationState, newText : this._model._errorText});
23292                }
23293                this.$element.removeClass('guideActiveField');
23294            },
23295
23296            handleModelChanged : function (event) {
23297                switch (event._property) {
23298                    case "enabled":
23299                        
23300                        
23301                        var prop = event.newText ? "open" : "readOnly";
23302                        if (this.jqwidget) {
23303                            this.jqwidget.option("access", prop);
23304                        }
23305                        this.$element.attr("data-disabled", !event.newText + "");
23306                        break;
23307                    case "mandatory":
23308                        
23309                        this._markMandatory(this._model.mandatory);
23310                        break;
23311                    case "validateExpMessage":
23312                        var newText = event.jsonModel.newText;
23313                        this._changeValidationMessage(newText);
23314                        break;
23315                    case "jcr:title":
23316                        
23317                        var newText = event.jsonModel.newText;
23318                        this._changeTitle(newText);
23319                        break;
23320                    default:
23321                        GuideFieldView._super.handleModelChanged.apply(this, arguments);
23322                }
23323            },
23324
23325            
23326            _changeTitle : function (newText) {
23327                var $field = $("#" + this.id),
23328                    $guideFieldLabelDiv = $field.children(".guideFieldLabel"),
23329                    $labelDiv = $guideFieldLabelDiv.children("label");
23330                if ($labelDiv) {
23331                    newText =  DOMPurify.sanitize(newText);
23332                    $labelDiv.html(newText);
23333                }
23334            },
23335
23336            
23337            _changeValidationMessage : function (newText) {
23338                var $fieldNode = $("#" + this.id),
23339                    $errorDiv = $fieldNode.children(".guideFieldError");
23340                $errorDiv.html(newText);
23341            },
23342
23343            
23344            commitValue : function (value) {
23345                this._model.value = value;
23346                var _version = this._model._guide().version;
23347                if (!(_version.isOn(_version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE))) {
23348                    this._model.executeExpression("valueCommitScript");
23349                }
23350                
23351                
23352                if (this.getCommitEvent() === xfaUtil.XFA_CHANGE_EVENT) {
23353                    this._model.executeExpression("change");
23354                } else {
23355                    this._model.executeExpression("exit");
23356                }
23357            },
23358
23359            
23360            tempXfaFixes : function () {
23361                
23362                
23363                
23364                if (this.$element) {
23365                    this.$element.find("input").css("position", "relative");
23366                }
23367                this.handleAccessibility();
23368            },
23369
23370            handleAccessibility : function () {
23371                
23372                if (this._model.mandatory) {
23373                    this.$widget.find("input,textarea,select,button").attr("aria-required", true);
23374                }
23375                if(this._model._getToolTip())  {
23376                    this.$element.find("input,textarea,select,button").attr("aria-labelledby",this._model.id + "_widget" + " " + this._model.id + "_guideFieldShortDescription");
23377                }
23378                if (this._model._getScreenReaderText() === this._model._getToolTip()) {
23379                    this.$element.find("input,textarea,select,button").removeAttr("aria-label");
23380                    this.$element.find("input,textarea,select,button").attr("aria-labelledby",this._model.id + "_guideFieldShortDescription");
23381                }
23382            },
23383
23384            
23385            _getWidgetInitialOptions : function ($widget) {
23386                var $elem = $widget.find('[data-af-widgetname]').addBack('[data-af-widgetname]');
23387                if ($elem.length > 0) {
23388                    this.logger().info("AF", "Getting widget options for " + this._model.somExpression);
23389                    var optionsMap = $elem.data('af-widgetoptions') || {};
23390                    _.each($elem[0].attributes, function (attr) {
23391                        var nm = attr.name.match(/data-af-widgetoption-([^-]+)$/);
23392                        if (nm != null && nm.length > 1) {
23393                            this.logger().info("AF", "adding option " + nm[1] + " with value " + " ");
23394                            optionsMap[nm[1]] = attr.value;
23395                        }
23396                    }, this);
23397                    return optionsMap;
23398                }
23399                return {};
23400            },
23401
23402            _newWidget : function (widgetname, options, $widgetElem) {
23403                var jqwidget = null,
23404                    fixesRequired = widgetname == this._defaultWidget
23404Name;
23405                try {
23406                    
23407                    $widgetElem[widgetname](options);
23408                    
23409                    
23410                    jqwidget = $widgetElem.data(widgetname) || $widgetElem.data('xfaWidget-' + widgetname);
23411                } catch (e) {
23412                    this.logger().error("AF", "widget " + widgetname + " doesn't exists. Falling back to default widget");
23413                    fixesRequired = true;
23414                    jqwidget = $widgetElem[this._defaultWidgetName](options).data('xfaWidget-' + widgetname);
23415                }
23416                
23417                if (fixesRequired) {
23418                    this.tempXfaFixes();
23419                }
23420                return jqwidget;
23421            },
23422
23423            createWidget : function (widgetname, options) {
23424                var initialOptions = this._getWidgetInitialOptions(this.$widget);
23425                var _options = $.extend({}, options, initialOptions);
23426                this.jqwidget = this._newWidget(widgetname, _options, this.$widget);
23427            },
23428
23429            handleEnter : function () {
23430                this._guideView.currentFocusItemSom = this._model.somExpression;
23431                var gb = window.guideBridge;
23432                if (gb) {
23433                    gb.clickedOnWindow = false;
23434                }
23435                if (!(this._model.className === 'guideRadioButton' || this._model.className === 'guideCheckBox' || this._model.className === 'guideButton')) {
23436                    this._triggerOnBridge("elementFocus", "", "", "", "");
23437                }
23438                this.oldValue = this._model.value;
23439                this.$element.addClass('guideActiveField');
23440            },
23441
23442            handleChange : function () {
23443
23444            },
23445
23446            setActive : function (activeItemToken, focus, muteScripts) {
23447                GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
23448                if (focus) {
23449                    
23450                    if (!this._guideView.skipFieldFocus && this.jqwidget && this.jqwidget.focus) {
23451                        this.jqwidget.focus();
23452                        this._guideView.currentFocusItemSom = this._model.somExpression;
23453                    }
23454                }
23455                return true;
23456            },
23457
23458            updateWidgetOption : function (optionName, optionValue) {
23459                
23460                if (this.jqwidget) {
23461                    this.jqwidget.option(optionName, optionValue);
23462                }
23463            }
23464
23465        });
23466}($, guidelib, _));
23467(function ($, guidelib) {
23468    var GuideCaptchaView = guidelib.view.GuideCaptchaView = guidelib.view.GuideFieldView.extend({
23469        
23470        _defaultWidgetName : "afcaptcha",
23471
23472        syncGuideNodeToHtml : true,
23473
23474        initialize : function () {
23475            
23476            if (!FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) || this.options.model.isWidgetRecaptcha) {
23477                if ((this.options.model.captchaEnterprise && !this.options.model.checkBoxkey) ||
23478                    (this.options.model.captchaInvisible && this.options.model.mandatory)) {
23479                    this._model = this.options.model;
23480                    this.syncGuideNodeToHtml = false;
23481                    return;
23482                } else if (this.options.model.captchaInvisible) {
23483                    this.options.element.classList.add("af-hideRecaptchaView");
23484                    this.options.model.captchaValidate = false;
23485                }
23486            } else if ((this.options.model.isWidgetTurnstile || this.options.model.isWidgetHcaptcha) && this.options.model.captchaInvisible) {
23487                this._model = this.options.model;
23488                this.syncGuideNodeToHtml = false;
23489                return;
23490            }
23491
23492            GuideCaptchaView._super.initialize.apply(this, arguments);
23493            if (this._model.captchaWidget) {
23494                
23495                this._defaultWidgetName = this._model.captchaWidget;
23496            }
23497        },
23498
23499        _initializeWidget : function () {
23500            GuideCaptchaView._super._initializeWidget.apply(this, arguments);
23501            if (this.$widget.length > 0) {
23502                this.$widget.on("tokenChange.captcha", $.proxy(this.handleTokenChange, this));
23503            }
23504        },
23505
23506        _syncGuideNodeToHtml : function (deepSync) {
23507            if(!this.syncGuideNodeToHtml)
23508                return;
23509            GuideCaptchaView._super._syncGuideNodeToHtml.call(this, deepSync);
23510        },
23511
23512        handleTokenChange : function (event) {
23513            this._model.value = event.token;
23514        },
23515
23516        createWidgetOptions : function () {
23517            var options = GuideCaptchaView._super.createWidgetOptions.apply(this, arguments);
23518            return $.extend({}, options, {
23519                "captchaConfigData" : this.options.model.jsonModel
23520            });
23521        },
23522
23523        handleErrorChanged : function (event) {
23524                var value = event.prevText,
23525                    errorMessage = event.newText;
23526                if (value === false) {
23527                    this._model._guide().runtime.errorManager.markError(errorMessage, this.$element, this._model.somExpression,
23528                    guideBridge.getValidationContext());
23529                    this.$element.addClass("validation-failure");
23530                } else {
23531                    this.$element.removeClass("validation-failure");
23532                }
23533            }
23534    });
23535}($, guidelib));
23536(function ($, guidelib, _) {
23537    var xfaUtil = xfalib.ut.XfaUtil.prototype,
23538        GuideCompositeFieldView = guidelib.view.GuideCompositeFieldView = guidelib.view.GuideFieldView.extend({
23539            _defaultWidgetName : "defaultField",
23540
23541            
23542            getModelNameOptionsMap : function () {
23543                return {};
23544            },
23545
23546            initialize : function () {
23547                GuideCompositeFieldView._super.initialize.call(this);
23548                this._defineChildModelEvents();
23549            },
23550
23551            postInitialize : function () {
23552                GuideCompositeFieldView._super.postInitialize.call(this);
23553                var _self = this;
23554                if (this.getModelNameOptionsMap()) {
23555                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
23556                        var childModel = _self._model[modelName];
23557                        if (childModel._errorText) {
23558                            childModel._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
23559                                "validationStatus", childModel.validationState, childModel._errorText);
23560                        }
23561                    });
23562                }
23563            },
23564
23565            _unloadView : function () {
23566                var _self = this;
23567                if (this.getModelNameOptionsMap()) {
23568                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
23569                        var obj = _self._model[modelName];
23570                        
23571                        obj.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, _self.handleValueChanged, _self);
23572                        if (obj.mandatory || obj.validateExp) {
23573                            obj.off(guidelib.event.GuideModelEvent.ERROR_CHANGED, _self.handleErrorChanged, _self);
23574                            obj.off(guidelib.event.GuideModelEvent.ERROR_RESET, _self.handleErrorReset, _self);
23575                        }
23576                    });
23577
23578                }
23579                GuideCompositeFieldView._super._unloadView.call(_self);
23580            },
23581
23582            _defineChildModelEvents : function () {
23583                var _self = this;
23584                if (this.getModelNameOptionsMap()) {
23585                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
23586                        var obj = _self._model[modelName];
23587                        
23588                        obj.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, _self.handleValueChanged, _self);
23589                        
23590                        
23591                        if (obj.mandatory || obj.validateExp) {
23592                            obj.on(guidelib.event.GuideModelEvent.ERROR_CHANGED, _self.handleErrorChanged, _self);
23593                            obj.on(guidelib.event.GuideModelEvent.ERROR_RESET, _self.handleErrorReset, _self);
23594                        }
23595                    });
23596
23597                }
23598            },
23599
23600            handleCommit : function () {
23601                var _self = this;
23602                if (!_.isEmpty(this.getModelNameOptionsMap())) {
23603                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
23604                        var obj = _self._model[modelName];
23605                        if (!_.isUndefined(obj)) {
23606                            var val = _self.jqwidget.option(value);
23607                            if (_.isArray(val)) {
23608                                val = val.join("\n");
23609                            }
23610                            obj.value = val;
23611                        }
23612                    });
23613                } else {
23614                    this._model.value = this.jqwidget.option("value");
23615                }
23616                this._model.executeExpression("valueCommitScript");
23617                this.execCommitExpression();
23618            },
23619
23620            handleValueChanged : function (event) {
23621                
23622                
23623                switch (event._property) {
23624                    case "value":
23625                        var map = this.getModelNameOptionsMap();
23626                        this.jqwidget.option(map[event.target.name], event.prevText);
23627                        break;
23628                }
23629            },
23630
23631            execCommitExpression : function () {
23632                
23633                if (this.getCommitEvent() == xfaUtil.XFA_CHANGE_EVENT) {
23634                    this._model.executeExpression("change");
23635                } else {
23636                    this._model.executeExpression("exit");
23637                }
23638            }
23639        });
23640}($, guidelib, _));
23641(function ($, guidelib) {
23642    var GuideFileUploadView = guidelib.view.GuideFileUploadView = guidelib.view.GuideCompositeFieldView.extend({
23643        _defaultWidgetName : "fileUpload",
23644
23645        getModelNameOptionsMap : function () {
23646            var map = GuideFileUploadView._super.getModelNameOptionsMap.apply(this, arguments);
23647            return $.extend({}, map, {
23648                "fileAttachment" : "value",
23649                "comment" : "comment"
23650            });
23651        },
23652
23653        createWidgetOptions : function () {
23654            var options = GuideFileUploadView._super.createWidgetOptions.apply(this, arguments),
23655                fileNamesStr = this._model._getFileAttachmentNames(),
23656                fileNamesArr = [];
23657            if (fileNamesStr) {
23658                fileNamesArr = fileNamesStr.split("\n");
23659            }
23660            return $.extend({}, options, {
23661                fileList : this._model.fileList,
23662                buttonText  : this._model.buttonText,
23663                multiSelect : this._model.multiSelection,
23664                fileSizeLimit : this._model.fileSizeLimit,
23665                mimeType : this._model.getOrElse(this._model.jsonModel, "mimeType", ""),
23666                buttonClass : "button.guide-fu-attach-button",
23667                fileItemListClass : "ul.guide-fu-fileItemList",
23668                iframeContainer : "div.guideContainerWrapperNode",
23669                showComment :  this._model.showComment,
23670                value : this._model.fileAttachment.value,
23671                fileNames : fileNamesArr,
23672                comment : this._model.comment.value,
23673                _uuidGenerator : function () { return guideBridge._getUUID.apply(this); }, 
23674                _filePath : "/tmp/fd/af",           
23675                _getUrl : guideBridge._getUrl(""),  
23676                disablePreview : false, 
23677                uploaderPluginName : guideBridge.userConfig.uploaderPluginName || "adobeFileUploader"
23678            });
23679        },
23680
23681        handleCommit : function () {
23682            
23683            
23684            
23685            this._model.fileList = this.jqwidget.option("fileList");
23686            GuideFileUploadView._super.handleCommit.apply(this, arguments);
23687        },
23688
23689        handleModelChanged : function (event) {
23690            switch (event._property) {
23691                case "fileList":
23692                    this.jqwidget.option("fileList", event.prevText);
23693                    break;
23694                default:
23695                    GuideFileUploadView._super.handleModelChanged.apply(this, arguments);
23696                    break;
23697            }
23698        },
23699
23700        handleAccessibility : function () {
23701            
23702            
23703            var isBrowserIE9OrIE10 = ($.browser.msie && ($.browser.version === '9.0' || $.browser.version === '10.0'));
23704            if (isBrowserIE9OrIE10) {
23705                if (this._model.mandatory) {
23706                    this.$widget.attr("aria-required", true);
23707                }
23708                if (this._model._getScreenReaderText() === this._model._getToolTip()) {
23709                    this.$widget.removeAttr("aria-label");
23710                    this.$widget.attr("aria-labelledby", this._model.id + "_guideFieldShortDescription");
23711                }
23712            } else {
23713                GuideFileUploadView._super.handleAccessibility.apply(this, arguments);
23714            }
23715        },
23716
23717        setActive: function(activeItemToken, focus, muteScripts) {
23718            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
23719            if (focus) {
23720                this._guideView.currentFocusItemSom = this._model.somExpression;
23721                this.$element.find("button").focus();
23722            }
23723            return true;
23724        },
23725
23726        
23727        
23728        tempXfaFixes : function () {
23729            
23730            this.handleAccessibility();
23731        },
23732
23733        getCommitEvent : function () {
23734            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
23735        }
23736    });
23737}($, guidelib));
23738(function ($, guidelib) {
23739    var GuideTermsAndConditionsView = guidelib.view.GuideTermsAndConditionsView = guidelib.view.GuideCompositeFieldView.extend({
23740        _defaultWidgetName : "tnc",
23741
23742        getModelNameOptionsMap : function () {
23743            var map = GuideTermsAndConditionsView._super.getModelNameOptionsMap.apply(this, arguments);
23744            return $.extend({}, map, {
23745                "reviewDocument" : "value",
23746                "reviewStatus" : "reviewStatus"
23747            });
23748        },
23749
23750        createWidgetOptions : function () {
23751            var options = GuideTermsAndConditionsView._super.createWidgetOptions.apply(this, arguments);
23752            return $.extend({}, options, {
23753                textAreaClass : ".guide-tnc-content",
23754                checkBoxClass : ".guide-tnc-checkbox",
23755                linkClass     : ".guide-tnc-link",
23756                checkBoxDisableClass : ".guide-tnc-checkbox-disabled",
23757                checkBoxReviewedClass : ".guide-tnc-checkbox-reviewed",
23758                showLink      :  this._model.showLink,
23759                showAsPopUp   :  this._model.showAsPopUp,
23760                value : this._model.reviewDocument.value,
23761                reviewStatus : this._model.reviewStatus.value,
23762                clickStatus  : this._model.clickStatus
23763            });
23764        },
23765
23766        
23767        tempXfaFixes : function () {
23768            
23769            
23770            
23771            if (this.$widget) {
23772                this.$widget.css("position", "relative");
23773            }
23774
23775        },
23776
23777        handleCommit : function (event) {
23778            
23779            this._model.clickStatus = this.jqwidget.option("clickStatus");
23780            
23781            GuideTermsAndConditionsView._super.handleCommit.apply(this, arguments);
23782        },
23783
23784        handleModelChanged : function (event) {
23785            
23786            
23787            switch (event._property) {
23788                case "clickStatus":
23789                    this.jqwidget.option("clickStatus", event.prevText);
23790                    break;
23791                default:
23792                    GuideTermsAndConditionsView._super.handleModelChanged.apply(this, arguments);
23793                    break;
23794            }
23795        },
23796
23797        getCommitEvent : function () {
23798            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
23799        }
23800    });
23801}($, guidelib));
23802(function ($, guidelib) {
23803    var GuideTelephoneView = guidelib.view.GuideTelephoneView = guidelib.view.GuideFieldView.extend({
23804        
23805        _defaultWidgetName : "telephoneWidget",
23806
23807        createWidgetOptions : function () {
23808            var options = GuideTelephoneView._super.createWidgetOptions.apply(this, arguments);
23809            return $.extend({}, options, {
23810                placeholder : this._model.placeholderText
23811            });
23812        }
23813
23814    });
23815}($, guidelib));
23816
23817(function ($, guidelib) {
23818    var GuideTextDrawView = guidelib.view.GuideTextDrawView = guidelib.view.GuideFieldView.extend({
23819        _defaultWidgetName : "abstractWidget",
23820
23821        initialize : function () {
23822            GuideTextDrawView._super.initialize.call(this);
23823            if (this.$element && this.$element.length > 0) {
23824                $(this.$element)
23825                    .on("focus.guideTextDraw", $.proxy(this.handleEnter, this))
23826                    .on("click.guideTextDraw", $.proxy(this.handleClick, this));
23827            }
23828        },
23829
23830        _syncGuideNodeToHtml : function (deepSync) {
23831            GuideTextDrawView._super._syncGuideNodeToHtml.call(this, deepSync);
23832            
23833            
23834            var isFloatingField = this._model._isFloatingField();
23835            if (this._model.value === this._model.jsonModel._value && this.$element.html() !== this._model.value && !isFloatingField) {
23836                
23837                
23838            } else {
23839                this.handleValueChanged({
23840                    _property : "value",
23841                    newText : this._model.value ? this._model.value : ""
23842                });
23843            }
23844        },
23845
23846        handleValueChanged : function (event) {
23847            switch (event._property) {
23848                case "value":
23849                    this.$element.html(event.newText);
23850                    break;
23851            }
23852        },
23853
23854        setActive : function (activeItemToken, focus, muteScripts) {
23855            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
23856            if (focus && !this._guideView.skipFieldFocus) {
23857                if (this.$element) {
23858                    this.$element.focus();
23859                }
23860                this._guideView.currentFocusItemSom = this._model.somExpression;
23861            }
23862            return true;
23863        }
23864    });
23865}($, guidelib));
23866
23867
23868(function ($, guidelib) {
23869    var GuideAdobeSignBlockView = guidelib.view.GuideAdobeSignBlockView = guidelib.view.GuideTextDrawView.extend({
23870    });
23871}($, guidelib));
23872(function ($, guidelib) {
23873    var GuideButtonView = guidelib.view.GuideButtonView = guidelib.view.GuideFieldView.extend({
23874        _defaultWidgetName : "xfaButton",
23875
23876        handleClick : function (event) {
23877            this._triggerOnBridge("elementButtonClicked", this._model, "click", "", "");
23878            this._model.executeExpression("clickExp");
23879            GuideButtonView._super.handleClick.call(this);
23880        },
23881
23882        _changeTitle : function (newText) {
23883            var $fieldTitleSpan = $("#" + this.id + "_widget");
23884            var $buttonLabel = $fieldTitleSpan.children("[data-guide-button-label]");
23885            newText =  DOMPurify.sanitize(xfalib.ut.XfaUtil.prototype.encodeScriptableTags(newText));
23886            $buttonLabel.html(newText);
23887        },
23888
23889        tempXfaFixes : function () {
23890            
23891            
23892            
23893            if (this.$element) {
23894                this.$element.find("button").css("position", "relative");
23895            }
23896            this.handleAccessibility();
23897        }
23898
23899    });
23900}($, guidelib));
23901(function ($, guidelib, _) {
23902    var fileInputIdCounter = 0;
23903    var GuideListFileAttachmentButtonView = guidelib.view.GuideListFileAttachmentButtonView = guidelib.view.GuideButtonView.extend({
23904        
23905        _clearFileListing : function () {
23906            $('#fileAttachment .modal-list', window.document).children().remove();
23907            _.each(this._fileListViews, function (childView) {
23908                childView._unloadView();
23909            }, this);
23910            this._fileListViews = [];
23911            fileInputIdCounter = 0;
23912        },
23913        _updateFileListing : function (fileAttachmentModel) {
23914            if (fileAttachmentModel.className == "guideFileUpload") {
23915                var $htmlTemplate = this._guideView.$element.find("#" + fileAttachmentModel.id),
23916                    inputFileSelector = "#" + fileAttachmentModel.id + "_widget",
23917                
23918                
23919                
23920                
23921                
23922                    $cloneHtmlTemplate = $htmlTemplate.clone();
23923                
23924                $cloneHtmlTemplate.find(inputFileSelector).attr("id", fileAttachmentModel.id + "_widget" + (++fileInputIdCounter));
23925                this._addSuffixToHelpIds($cloneHtmlTemplate, fileInputIdCounter);
23926                var $fluidDesign = $('<div></div>').addClass("row").append('<div class="col-md-12"></div>');
23927                $('#fileAttachment .modal-list', window.document).append($cloneHtmlTemplate.appendTo($fluidDesign));
23928                var view = guidelib.view.GuideViewRegistry.prototype.createView($cloneHtmlTemplate, this);
23929                this._fileListViews.push(view);
23930                view.postInitialize();
23931
23932            }
23933        },
23934        _addSuffixToHelpIds : function ($html, suffix) {
23935            var $questionMarkElement = $html.find("[data-guide-longDescription]"),
23936                $shortHelpElement;
23937            if ($questionMarkElement.length > 0) {
23938                var idForLongHelp = $questionMarkElement.attr("data-guide-longDescription"),
23939                    $longHelpElement = $(".guideFieldDescription.long", $html);
23940                idForLongHelp = idForLongHelp + suffix;
23941                $longHelpElement.attr("id", idForLongHelp);
23942                $questionMarkElement.attr("data-guide-longDescription", idForLongHelp);
23943            }
23944            
23945
23946        },
23947
23948        
23949        _markFileListing : function () {
23950            if (this.$element) {
23951                this.$element.find("button").attr("data-guide-fileListing", true);
23952            }
23953        },
23954
23955        initialize : function () {
23956            GuideListFileAttachmentButtonView._super.initialize.apply(this, arguments);
23957            this._markFileListing();
23958            
23959            
23960            this._fileListViews = [];
23961        }
23962    });
23963}($, guidelib, _));
23964(function ($, guidelib, _) {
23965    var xfaUtil = xfalib.ut.XfaUtil.prototype,
23966        GuideDropDownListView = guidelib.view.GuideDropDownListView = guidelib.view.GuideFieldView.extend({
23967
23968            _defaultWidgetName : "dropDownList",
23969
23970            initialize : function () {
23971                GuideDropDownListView._super.initialize.apply(this, arguments);
23972                if (this._model.multiSelect) {
23973                    this._defaultWidgetName = "listBox";
23974                }
23975            },
23976
23977            _valueToArray : function (value) {
23978                var valueArray;
23979                if (value !== null && !_.isUndefined(value)) {
23980                    if (_.isString(value)) {
23981                        valueArray = value.split("\n");
23982                    } else if (_.isNumber(value)) {
23983                        valueArray = [value.toString()];
23984                    }
23985                } else {
23986                    valueArray = [null];
23987                }
23988                return valueArray;
23989            },
23990
23991            createWidgetOptions : function () {
23992                var options = GuideDropDownListView._super.createWidgetOptions.apply(this, arguments);
23993                
23994                
23995                return $.extend({}, options, {
23996                    multiSelect : this._model.multiSelect,
23997                    editable : false,
23998                    items : this._model._getOptionsArray("save", "display"),
23999                    value : this._valueToArray(this._model.value),
24000                    placeholder : this._model.placeholderText
24001                });
24002            },
24003
24004            
24005            handleCommit : function () {
24006                var val = this.jqwidget.option("value");
24007                if (_.isArray(val)) {
24008                    val = val.join("\n");
24009                }
24010                
24011                this.commitValue(val);
24012            },
24013
24014            
24015            commitValue : function (value) {
24016                var oldValue = this._model.value;
24017                this._model.value = value;
24018                
24019                
24020                
24021                var _version = this._model._guide().version;
24022                if (!(_version.isOn(_version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE))) {
24023                    this._model.executeExpression("valueCommitScript");
24024                }
24025                if (this.getCommitEvent() === xfaUtil.XFA_CHANGE_EVENT) {
24026                    
24027                    
24028                    
24029                    
24030                    
24031                    this._model.executeExpression("change", {
24032                        "prevText" : oldValue,
24033                        "newText" : this._model.value
24034                    });
24035                } else {
24036                    
24037                    this._model.executeExpression("exit");
24038                }
24039            },
24040
24041            handleValueChanged : function (event) {
24042                this.jqwidget.option("value", this._valueToArray(event.prevText));
24043                this.jqwidget.option("displayValue", this._valueToArray(event.
24043newText));
24044                this._updateEmptyStatus(event);
24045            },
24046
24047            getCommitEvent : function () {
24048                return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
24049            },
24050
24051            handleModelChanged : function (event) {
24052                if (event._property === "addItem") {
24053                    this._handleAddItem(event);
24054                }
24055                if (event._property === "clearItems") {
24056                    this._handleClearItems(event);
24057                }
24058                if (event._property === "deleteItem") {
24059                    this._handleDeleteItem(event);
24060                } else {
24061                    GuideDropDownListView._super.handleModelChanged.apply(this, arguments);
24062                }
24063            },
24064
24065            _handleAddItem : function (event) {
24066                var itemValues = {
24067                    sDisplayVal : event.newText,
24068                    sSaveVal : event.prevText
24069                };
24070                this.jqwidget.addItem(itemValues);
24071            },
24072
24073            _handleClearItems : function (event) {
24074                this.jqwidget.clearItems();
24075            },
24076
24077            _handleDeleteItem : function (event) {
24078                this.jqwidget.deleteItem(event.newText);
24079            },
24080
24081            handleItemsChanged : function (event) {
24082                var items = this._model._getOptionsArray("save", "display");
24083                this.jqwidget.option("items", items);
24084                this.jqwidget.option("value", this._valueToArray(this._model.jsonModel._value));
24085                this.jqwidget.option("displayValue", this._valueToArray(this._model.formattedValue));
24086            },
24087
24088            _defineModelEvents : function () {
24089                GuideDropDownListView._super._defineModelEvents.apply(this, arguments);
24090                if (this._model) {
24091                    
24092                    this._model.on(guidelib.event.GuideModelEvent.ITEMS_CHANGED, this.handleItemsChanged, this);
24093                }
24094            },
24095
24096            
24097            tempXfaFixes : function () {
24098                
24099                
24100                if (this.$element) {
24101                    if (!this._model.multiSelect) {
24102                        this.$element.find("select")
24103                            .css("position", "relative")
24104                            .attr("id", this._model.id + "_widget")
24105                            .attr("aria-describedby", this._model.id + "_widget_desc");
24106                    } else {
24107                        
24108                        if (this._model.height) {
24109                            this.$element.find("ol").css("max-height", "none");
24110                        }
24111                        this.$element.find("ol")
24112                            .css("position", "relative")
24113                            .attr("id", this._model.id + "_widget");
24114                    }
24115                }
24116                this.handleAccessibility();
24117            }
24118        });
24119
24120}($, guidelib, _));
24121
24122(function ($, guidelib) {
24123    var GuideNumericBoxView = guidelib.view.GuideNumericBoxView = guidelib.view.GuideFieldView.extend({
24124        _defaultWidgetName : "numericInput",
24125        createWidgetOptions : function () {
24126            var options = GuideNumericBoxView._super.createWidgetOptions.apply(this, arguments);
24127            return $.extend({}, options, {
24128                dataType : this._model.dataType,
24129                leadDigits : this._model.leadDigits,
24130                fracDigits : this._model.fracDigits,
24131                
24132                zero : guidelib.i18n.numberSymbols.zero,
24133                decimal : guidelib.i18n.numberSymbols.decimal,
24134                commitEvent : this.getCommitEvent(),
24135                placeholder : this._model.placeholderText
24136            });
24137        }
24138    });
24139
24140}($, guidelib));
24141(function ($, guidelib) {
24142    var GuidePasswordBoxView = guidelib.view.GuidePasswordBoxView = guidelib.view.GuideFieldView.extend({
24143        _defaultWidgetName : "defaultWidget",
24144
24145        createWidgetOptions : function () {
24146            var options = GuidePasswordBoxView._super.createWidgetOptions.apply(this, arguments);
24147
24148            return $.extend({}, options, {
24149                 placeholder : this._model.placeholderText
24150             });
24151        }
24152    });
24153}($, guidelib));
24154(function ($, guidelib) {
24155    var GuideTextBoxView = guidelib.view.GuideTextBoxView = guidelib.view.GuideFieldView.extend({
24156        _defaultWidgetName : "textField",
24157
24158        initialize : function () {
24159            GuideTextBoxView._super.initialize.apply(this, arguments);
24160            if (this._model.allowRichText) {
24161                this._defaultWidgetName = "richTextField";
24162            }
24163        },
24164
24165        createWidgetOptions : function () {
24166            var options = GuideTextBoxView._super.createWidgetOptions.apply(this, arguments),
24167                html5Type = this._model.getAttribute("html5Type");
24168            return $.extend({}, options, {
24169                multiLine : this._model.multiLine,
24170                minLength : this._model.allowRichText ? null : this._model.minLength,
24171                length : this._model.allowRichText ? null : this._model.length,
24172                maxChars : this._model.allowRichText ? null : this._model.maxChars,
24173                required : this._model.mandatory,
24174                
24175                html5Type : html5Type ? html5Type : "",
24176                totalLengthMessage : this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalLengthMessage, [this._model.length]),
24177                minimumLengthMessage : this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minimumLengthMessage, [this._model.minLength]),
24178                allowRichText : this._model.allowRichText,
24179                placeholder : this._model.placeholderText
24180            });
24181        },
24182
24183        
24184        
24185        
24186        tempXfaFixes : function () {
24187            if (this._model.jsonModel.multiLine) {
24188                this.$element.find("textarea").css("position", "relative");
24189                this.handleAccessibility();
24190            } else {
24191                GuideTextBoxView._super.tempXfaFixes.apply(this);
24192            }
24193        },
24194
24195        handleAccessibility : function () {
24196            GuideTextBoxView._super.handleAccessibility.apply(this);
24197            if (this._model.jsonModel.multiLine) {
24198                this.$element.find("textarea").attr("aria-multiLine", true);
24199            }
24200        }
24201    });
24202}($, guidelib));
24203(function ($, guidelib, _) {
24204    var GuideCheckBoxView = guidelib.view.GuideCheckBoxView = guidelib.view.GuideFieldView.extend({
24205        _defaultWidgetName : "XfaCheckBox",
24206        initialize : function () {
24207            GuideCheckBoxView._super.initialize.apply(this, arguments);
24208            this._setListenersForLabelClick();
24209            this._setListenersForRadioButtonKeyPress();
24210        },
24211
24212        _setListenersForRadioButtonKeyPress : function () {
24213            var self = this;
24214            this.$element
24215                .find(".guideRadioButtonItem")
24216                .each(function (index, item) {
24217                    $(item).keypress(function (e){
24218                        if(e.keyCode == "13" || e.keyCode == "32"){
24219                            e.preventDefault();
24220                            if (self._model.enabled) {
24221                                self.jqwidget[self.getJQWidgetIdentifier(index)].click();
24222                            }
24223                        }
24224                    });
24225                });
24226        },
24227
24228        _setListenersForLabelClick : function () {
24229            var self = this;
24230            this.$element
24231                .find(".guideWidgetLabel")
24232                .each(function (index, item) {
24233                    $(item).click(
24234                        (function (index) {
24235                            return function () {
24236                                
24237                                if (self._model.enabled) {
24238                                    self.jqwidget[self.getJQWidgetIdentifier(index)].click();
24239                                }
24240                            };
24241                        }(index))
24242                    );
24243                });
24244        },
24245        _syncGuideNodeToHtml : function (deepSync) {
24246            if (this._model._isStateOverridden("options")) {
24247                this._replaceGroupItemsWithNewOptions(this._model._getOptionsArray(), this._model.getAttribute("alignment"));
24248                
24249                
24250                
24251                
24252                this.jqwidget = null; 
24253
24254            }
24255            GuideCheckBoxView._super._syncGuideNodeToHtml.apply(this, arguments);
24256        },
24257        getJQWidgetIdentifier : function (index) {
24258            return index;
24259        },
24260
24261        createWidgetOptions : function () {
24262            var options = GuideCheckBoxView._super.createWidgetOptions.apply(this, arguments);
24263
24264            return $.extend({}, options, {
24265                states : 2
24266            });
24267        },
24268
24269        getCommitEvent : function () {
24270            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
24271        },
24272
24273        getStateFromValue : function (value, items) {
24274            if (value === null) {
24275                return 1;
24276            }
24277            var valuesArray = null;
24278            if (value && value.indexOf && value.indexOf("\\,") > -1) {
24279                valuesArray = this.splitOnNonEscapedCommas(value);
24280            } else {
24281                valuesArray = (value + "").split(",");
24282            }
24283            if (valuesArray && valuesArray.indexOf(items[0] + "") !== -1)  {
24284                return 0;
24285            }
24286            return 1;
24287        },
24288
24289        getOnOffValueFromModelValue : function (val, items) {
24290            return items[this.getStateFromValue(val, items)];
24291        },
24292
24293        splitOnNonEscapedCommas : function (string) {
24294            var splitArray = [];
24295            var currentSubstring = '';
24296            var escaped = false;
24297
24298            for (var i = 0; i < string.length; i++) {
24299                var char = string[i];
24300
24301                if (char === ',' && !escaped) {
24302                    splitArray.push(currentSubstring.trim());
24303                    currentSubstring = '';
24304                } else {
24305                    currentSubstring += char;
24306                    escaped = (char === '\\' && !escaped);
24307                }
24308            }
24309            splitArray.push(currentSubstring.trim()); 
24310            return splitArray;
24311        },
24312
24313        handleValueChanged : function (event) {
24314            _.each(this.jqwidget, function (jqwidget) {
24315                var setVal = this.getOnOffValueFromModelValue(event.prevText, this._escapeCommas(jqwidget.option("values")));
24316                setVal = this._unescapeCommas(setVal);
24317                jqwidget.option("value", setVal);
24318                jqwidget.option("displayValue", setVal);
24319            }, this);
24320            this.$widget.find("[checked!=checked]").parents(".guideCheckBoxItem").removeClass('guideItemSelected');
24321            this.$widget.find("[checked=checked]").parents(".guideCheckBoxItem").addClass('guideItemSelected');
24322        },
24323
24324        _escapeCommas : function (items) {
24325            var temp = _.clone(items);
24326            if(temp[0] && temp[0].indexOf && temp[0].indexOf(',') > -1 && temp[0].indexOf('\\,') === -1) {
24327                temp[0] = temp[0].replace(/,/g, "\\,"); 
24328            }
24329            return temp;
24330        },
24331
24332        _unescapeCommas : function (value) {
24333            if(value && value.indexOf && value.indexOf('\\,') > -1) {
24334                value = value.replace(/\\,/g, ','); 
24335            }
24336            return value;
24337        },
24338
24339        handleCommit : function () {
24340            var temp = "";
24341            _.each(this.jqwidget, function (jqwidget, index) {
24342                var items = this._escapeCommas(jqwidget.option("values"));
24343                if (jqwidget.option("state") === 0) {
24344                    
24345                    temp = temp + items[0] + ",";
24346                }
24347            }, this);
24348            temp = temp.substring(0, temp.length - 1);
24349            this.commitValue(this._unescapeCommas(temp));
24350        },
24351
24352        handleEnabledChanged : function (event) {
24353            
24354            if (!this.$element.hasClass("dontSyncEnabled")) {
24355                var prop = event.newText ? "open" : "readOnly";
24356                _.each(this.jqwidget, function (jqwidget) {
24357                    jqwidget.option("access", prop);
24358                });
24359            }
24360
24361            this.$element.attr("data-disabled", !this._model.enabled);
24362        },
24363
24364        handleModelChanged : function (evnt) {
24365            switch (evnt._property) {
24366            case "enabled":
24367                this.handleEnabledChanged(evnt);
24368                break;
24369            default:
24370                GuideCheckBoxView._super.handleModelChanged.apply(this, arguments);
24371            }
24372        },
24373
24374        handleItemsChanged : function (event) {
24375            this._replaceGroupItemsWithNewOptions(this._model._getOptionsArray(), this._model.jsonModel.alignment);
24376            this.createWidget(this.getWidgetName(), this.createWidgetOptions());
24377        },
24378
24379        _getGroupItemIdentifier : function () {
24380            return '.guideCheckBoxGroupItems';
24381        },
24382
24383        _getWidgetType : function () {
24384            return 'checkbox';
24385        },
24386
24387        _getItemName : function () {
24388            return "CheckBoxItem";
24389        },
24390
24391        _getItemSkeleton : function () {
24392            var guideWidgetItemName = "guide" + this._getItemName(); 
24393            var afWidgetItemName = "af" + this._getItemName(); 
24394            return '<div class="' + guideWidgetItemName + ' ' + afWidgetItemName + ' {NAME_PLACEHOLDER} {CSS_PLACEHOLDER}" data-original-title="" title="">\n' +
24395                '            <div class="guideFieldWidget left XfaCheckBox" data-id="{COUNTER_PLACEHOLDER}" data-original-title="" title="">\n' +
24396                '                <input type="' + this._getWidgetType() + '" id="{TEMPLATE_ID_PLACEHOLDER}_{COUNTER_PLACEHOLDER}_widget" name="{TEMPLATE_ID_PLACEHOLDER}_jqName" value="-100" tabindex="0" placeholder="" style="position: relative;">\n' +
24397                '            </div>\n' +
24398                '            <div class="guideWidgetLabel right">\n' +
24399                '                <label>{LABEL_PLACEHOLDER}</label>\n' +
24400                '            </div>\n' +
24401                '        </div>';
24402        },
24403
24404        _renderGroupItem : function (options) {
24405            var itemSkeleton = this._getItemSkeleton(),
24406                namePlaceHolder = "{NAME_PLACEHOLDER}",
24407                cssPlaceHolder = "{CSS_PLACEHOLDER}",
24408                counterPlaceHolder = "{COUNTER_PLACEHOLDER}" ,
24409                templateIDPlaceHolder = "{TEMPLATE_ID_PLACEHOLDER}",
24410                labelPlaceHolder = "{LABEL_PLACEHOLDER}",
24411                guideUtil = guidelib.util.GuideUtil;
24412            itemSkeleton = guideUtil.replaceAll(itemSkeleton, namePlaceHolder, options.modelName);
24413            itemSkeleton = guideUtil.replaceAll(itemSkeleton, templateIDPlaceHolder, options.modelTemplateId);
24414            itemSkeleton = guideUtil.replaceAll(itemSkeleton, cssPlaceHolder, options.cssValue);
24415            itemSkeleton = guideUtil.replaceAll(itemSkeleton, counterPlaceHolder, options.itemIndex);
24416            itemSkeleton = guideUtil.replaceAll(itemSkeleton, labelPlaceHolder, options.displayValue);
24417            return itemSkeleton;
24418        },
24419
24420        _replaceGroupItemsWithNewOptions : function (items, cssValue) {
24421            var groupItem = this.$element.find(this._getGroupItemIdentifier()),
24422                options = {},
24423                widgetName = this.getWidgetName(),
24424                self = this;
24425
24426            
24427            groupItem.empty();
24428            options.widgetType = this._getWidgetType();
24429            options.modelName = this._model.name;
24430            options.modelTemplateId = this._model.id;
24431
24432            if (this._model.css !== null && !_.isUndefined(this._model.css)) {
24433                cssValue +=  " " + this._model.css;
24434            }
24435            options.cssValue = cssValue;
24436
24437            _.each(items, function (value, index) {
24438                options.itemIndex = index;
24439                options.displayValue = value.displayValue;
24440                options.saveValue = value.saveValue;
24441                groupItem.append(self._renderGroupItem(options));
24442            });
24443            this._initializeWidget();
24444            this._setListenersForLabelClick();
24445        },
24446
24447        _replaceAll : function (stringToReplaceIn, textToReplace, replacementString) {
24448            return stringToReplaceIn.split(textToReplace).join(replacementString);
24449        },
24450
24451        _defineModelEvents : function () {
24452            GuideCheckBoxView._super._defineModelEvents.apply(this, arguments);
24453            if (this._model) {
24454                
24455                this._model.on(guidelib.event.GuideModelEvent.ITEMS_CHANGED, this.handleItemsChanged, this);
24456            }
24457        },
24458
24459        setWidgetOptions : function (options) {
24460            var index = 0;
24461            _.each(this.jqwidget, function (jqwidget, id) {
24462                this._initOrUpdateWidget(id, this._getOptions(options, index++));
24463            }, this);
24464        },
24465
24466        _getOptions : function (options, index) {
24467            var items = this._model.getOnOffValues(index),
24468                val = this.getOnOffValueFromModelValue(this._model.value, items),
24469                optionsCopy = _.extend(options, {
24470                    value : val,
24471                    displayValue : val,
24472                    values : items,
24473                    state : this.getStateFromValue(this._model.value, items),
24474                    screenReaderText : this._model._getScreenReaderText(index)
24475                });
24476            return optionsCopy;
24477        },
24478
24479        _initOrUpdateWidget : function (id, options, widgetname, $widget, initialOptions) {
24480            if (this.jqwidget[id]) {
24481                this.jqwidget[id].option(options);
24482            } else {
24483                var _options = $.extend({}, options, initialOptions);
24484                this.jqwidget[id] = this._newWidget(widgetname, _options, $widget);
24485            }
24486            this.$widget.find("[checked!=checked]").parents(".guideCheckBoxItem").removeClass('guideItemSelected');
24487            this.$widget.find("[checked=checked]").parents(".guideCheckBoxItem").addClass('guideItemSelected');
24488        },
24489
24490        initializeJqWidget : function () {
24491            this.jqwidget = [];
24492        },
24493
24494        createWidget : function (widgetname, options) {
24495            var self = this;
24496            this.initializeJqWidget();
24497            if (this.$widget) {
24498                this.$widget.each(function (index, widget) {
24499                    self._initOrUpdateWidget(self.getJQWidgetIdentifier(index),
24500                        self._getOptions(options, index),
24501                        widgetname,
24502                        $(widget),
24503                        self._getWidgetInitialOptions($(widget)));
24504                });
24505                this.tempXfaFixes();
24506            }
24507        },
24508
24509        setActive : function (activeItemToken, focus, muteScripts) {
24510            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
24511            if (focus && !this._guideView.skipFieldFocus) {
24512                if (this.jqwidget && this.jqwidget[this.getJQWidgetIdentifier(0)]) {
24513                    this.jqwidget[this.getJQWidgetIdentifier(0)].focus();
24514                }
24515                this._guideView.currentFocusItemSom = this._model.somExpression;
24516            }
24517            return true;
24518        },
24519
24520        updateWidgetOption : function (optionName, optionValue) {
24521            _.each(this.jqwidget, function (jqwidget, index) {
24522                if (optionName == "isValid") {
24523                    jqwidget.option(optionName, optionValue);
24524                }
24525            }, this);
24526        },
24527
24528        handleAccessibility : function () {
24529            GuideCheckBoxView._super.handleAccessibility.apply(this, arguments);
24530            this.$element.attr("role", "group");
24531            if (this._model.jsonModel.assistPriority && this._model.jsonModel.custom && this._model.jsonModel.assistPriority === "custom"){
24532                this.$element.attr("aria-label", this._model.jsonModel.custom[0]);
24533            } else {
24534                var $label = this.$element.find(".guideFieldLabel label"),
24535                    label = $label.get(0);
24536                if (label && label.id) {
24537                    this.$element.attr("aria-labelledby", label.id);
24538                }
24539            }
24540        }
24541
24542    });
24543}($, guidelib, window._));
24544
24545(function ($, guidelib, _) {
24546    var GuideRadioButtonView = guidelib.view.GuideRadioButtonView = guidelib.view.GuideCheckBoxView.extend({
24547
24548        _defaultWidgetName : "XfaCheckBox",
24549
24550        _prevOnWidget : null,
24551
24552        _getWidgetType : function () {
24553            return 'radio';
24554        },
24555
24556        _getItemName : function () {
24557            return "RadioButtonItem";
24558        },
24559
24560        _getGroupItemIdentifier : function () {
24561            return '.guideRadioButtonGroupItems';
24562        },
24563
24564        getJQWidgetIdentifier : function (index) {
24565            return this._model.getItemIdentifier(index);
24566        },
24567
24568        handleValueChanged : function (event) {
24569            var somExpression = event.prevText;
24570            if (this.jqwidget[somExpression]) {
24571                this.jqwidget[somExpression].option("value", event.newText);
24572                this.jqwidget[somExpression].option("displayValue", event.newText);
24573                if (event.newText === null) {
24574                    this._prevOnWidget = null;
24575                } else {
24576                    this._prevOnWidget = this.jqwidget[somExpression];
24577                }
24578            }
24579            this.$widget.find("[checked!=checked]").parents(".guideRadioButtonItem").removeClass('guideItemSelected');
24580            this.$widget.find("[checked=checked]").parents(".guideRadioButtonItem").addClass('guideItemSelected');
24581            this._updateEmptyStatus();
24582        },
24583
24584        handleCommit : function () {
24585            var jqwidgettochange = _.find(this.jqwidget, function (jqwidget) {
24586                    return jqwidget.option("state") === 0 && jqwidget !== this._prevOnWidget;
24587                }, this);
24588            this.commitValue(jqwidgettochange.option("value"));
24589            this._prevOnWidget = jqwidgettochange;
24590        },
24591
24592        _initOrUpdateWidget : function (id, options, widgetname, widget) {
24593            GuideRadioButtonView._super._initOrUpdateWidget.apply(this, arguments);
24594            if (options.state === 0) {
24595                this._prevOnWidget = this.jqwidget[id];
24596            }
24597            this.$widget.find("[checked!=checked]").parents(".guideRadioButtonItem").removeClass('guideItemSelected');
24598            this.$widget.find("[checked=checked]").parents(".guideRadioButtonItem").addClass('guideItemSelected');
24599        },
24600
24601        initializeJqWidget : function () {
24602            this.jqwidget = {};
24603            
24604            
24605            
24606            this.$widget.find("[checked]").removeAttr("checked");
24607            this.$widget.find("[checked=checked]").removeAttr("checked"); 
24608
24609        },
24610
24611        handleAccessibility : function () {
24612            GuideRadioButtonView._super.handleAccessibility.apply(this, arguments);
24613            this.$element.attr("role", "radiogroup");
24614        }
24615    });
24616}($, guidelib, _));
24617(function ($, guidelib, _) {
24618    var GuideSwitchView = guidelib.view.GuideSwitchView = guidelib.view.GuideCheckBoxView.extend({
24619        _defaultWidgetName : "guideSwitch",
24620
24621        createWidgetOptions : function () {
24622            var options = GuideSwitchView._super.createWidgetOptions.apply(this, arguments),
24623                items = this._model.jsonModel.options, checkedLabel, uncheckedLabel;
24624            
24625            if (Array.isArray(items) && items.length > 0) {
24626                checkedLabel = items[0];
24627            } else if (!_.isUndefined(items) && items.length > 0) {
24628                checkedLabel = items;
24629            } else {
24630                checkedLabel = " ";
24631            }
24632            if (Array.isArray(items) && items.length > 1) {
24633                uncheckedLabel = items[1];
24634            } else {
24635                uncheckedLabel = "    ";
24636            }
24637            return $.extend({}, options, {
24638                checkedLabel : checkedLabel.substring(checkedLabel.indexOf("=") + 1),
24639                uncheckedLabel : uncheckedLabel.substring(uncheckedLabel.indexOf("=") + 1)
24640            });
24641        },
24642
24643        handleValueChanged : function (event) {
24644            
24645            var jqwidget = this.jqwidget[0],
24646                jqwidgetOptions = jqwidget.options;
24647            var setVal = this.getOnOffValueFromModelValue(event.prevText, jqwidget.option("values"));
24648            if (jqwidgetOptions.value !== setVal) {
24649                jqwidget.option("value", setVal);
24650                
24651                var userControl = jqwidget.$userControl;
24652                var checked = jqwidgetOptions.value === jqwidgetOptions.values[0];
24653                userControl.prop("checked", checked);
24654                userControl.parent().toggleClass('ui-state-active', checked);
24655                userControl.change();
24656            }
24657        },
24658
24659        handleCommit : function () {
24660            var jqwidget = this.jqwidget[0],
24661                items = jqwidget.option("values"),
24662                state = jqwidget.option("state");
24663            this.commitValue(items[state]);
24664        }
24665    });
24666}($, guidelib, _));
24667(function ($, guidelib) {
24668    var GuideDatePickerView = guidelib.view.GuideDatePickerView = guidelib.view.GuideFieldView.extend({
24669        _defaultWidgetName : "dateTimeEdit",
24670
24671        createWidgetOptions : function () {
24672            var options = GuideDatePickerView._super.createWidgetOptions.apply(this, arguments),
24673                useNativeWidget = (this._model.displayPictureClause === null && this._model.editPictureClause == null);
24674
24675            return $.extend({}, options, {
24676                days : guidelib.i18n.calendarSymbols.abbrdayNames,
24677                months : guidelib.i18n.calendarSymbols.monthNames,
24678                zero : guidelib.i18n.numberSymbols.zero,
24679                clearText : xfalib.locale.Strings.clearText,
24680                useNativeWidget : useNativeWidget,
24681                showCalendarIcon : true,
24682                editPattern : this._model.editPictureClause,
24683                placeholder : this._model.placeholderText,
24684                minValidDate : this._model.minimum,
24685                maxValidDate : this._model.maximum,
24686                exclMaxDate :  this._model.exclusiveMaximum,
24687                exclMinDate : this._model.exclusiveMinimum,
24688                allowNonIsoValue : true
24689            });
24690        },
24691
24692        
24693        tempXfaFixes : function () {
24694            GuideDatePickerView._super.tempXfaFixes.apply(this, arguments);
24695            
24696            if (this.$widget) {
24697                this.$widget.children("not:input[type=date]").height("100%"); 
24698            }
24699        },
24700
24701        handleAccessibility : function () {
24702            GuideDatePickerView._super.handleAccessibility.apply(this, arguments);
24703            this.$widget.children("div[tabIndex]").removeAttr("tabIndex");
24704            if (this.$widget) {
24705                var $icon = this.$widget.find('.datepicker-calendar-icon');
24706                if ($icon && $icon.length) {
24707                    var localizedLabel = (guidelib && guidelib.i18n && guidelib.i18n.strings && guidelib.i18n.strings.showDatePicker)
24708                        ? guidelib.i18n.strings.showDatePicker
24709                        : 'Show date picker';
24710                    $icon.attr('role', 'button')
24711                        .attr('tabindex', '0')
24712                        .attr('aria-haspopup', 'dialog')
24713                        .attr('aria-label', localizedLabel)
24714                        .attr('title', localizedLabel);
24715                }
24716            }
24717        }
24718    });
24719}($, guidelib));
24720
24721 (function ($, guidelib) {
24722    var GuideFootnotePlaceHolderView = guidelib.view.GuideFootnotePlaceHolderView = guidelib.view.GuideTextDrawView.extend({
24723        _defaultWidgetName : "abstractWidget",
24724
24725        initialize : function () {
24726            GuideFootnotePlaceHolderView._super.initialize.call(this);
24727            var that = this;
24728            $(function () {
24729                that._renderFootnotes();
24730            })
24731            guideBridge.on("elementNavigationChanged", function(event, payload) {
24732                that._renderFootnotes();
24733            })
24734            $(window.document).on('click.guidetab.data-api', '[data-guide-toggle$="accordion-tab"]',
24735                function(e) {
24736                    that._renderFootnotes();
24737                })
24738
24739        },
24740
24741       _renderFootnotes: function () {
24742           
24743           
24744           if(!this.$element.is(":visible")) {
24745               this._model.value = "";
24746               return;
24747           }
24748
24749           var footnoteMap = this._model.footnoteMap;
24750           var footnoteArr = Object.entries(footnoteMap);
24751           if (footnoteArr.length > 0) {
24752               var value = '<div>';
24753               var nodes = new Map();
24754               for (footnoteID in footnoteMap) {
24755                   var selector = "a[data-footnote-id=\"" + footnoteID + "\"]";
24756                   var mapKey = $(selector)[0].innerHTML;
24757                   if (!nodes.has(mapKey)) {
24758                       nodes.set(mapKey, footnoteMap[footnoteID]);
24759                   }
24760               };
24761               var tupleArray = [];
24762               nodes.forEach(function(value, key) {
24763                   tupleArray.push([key, value]);
24764               });
24765               tupleArray.sort(function(a, b) {
24766                   return a[0] - b[0];
24767               });
24768               tupleArray.forEach(function(el) {
24769                   value += el[1];
24770               });
24771               value += '</div>';
24772               this._model.value = value;
24773           }
24774       },
24775
24776               setActive: function () {
24777                   this._renderFootnotes();
24778               }
24779    });
24780}($, guidelib));
24781
24782
24783
24784
24785(function ($, guidelib) {
24786    var GuideScribbleView = guidelib.view.GuideScribbleView = guidelib.view.GuideFieldView.extend({
24787        _defaultWidgetName : "ScribbleImageField",
24788
24789        createWidgetOptions : function () {
24790            var options = GuideScribbleView._super.createWidgetOptions.apply(this, arguments);
24791            return $.extend({}, options, {
24792                commitProperty : "src",
24793                geoLocMandatoryOnIpad : "false",
24794                aspectRatio : this._valueOfAspectRatioToBeUsed()
24795            });
24796        },
24797
24798        _valueOfAspectRatioToBeUsed : function () {
24799            var aspectRatio ;
24800            if (this._model.jsonModel.aspectRatio) {
24801                aspectRatio = this._model.jsonModel.aspectRatio;
24802            } else {
24803                
24804                if (!this._presenceOfHeight()) {
24805                    aspectRatio = "6.8888";
24806                }
24807            }
24808            return aspectRatio ;
24809        },
24810
24811        _presenceOfHeight : function () {
24812            return (this._model.jsonModel.hasOwnProperty('height') && this._model.jsonModel.height.toString().length > 0);
24813        },
24814
24815        postInitialize : function () {
24816            GuideScribbleView._super.postInitialize.call(this);
24817            var that = this;
24818            
24819            if (!this._presenceOfHeight()) {
24820                setTimeout(function () {guidelib.util.GuideUtil._computeHeightAndWidthForScribble(that.$widget);}, guidelib.util.GuideUtil.SCRIBBLE_RESIZE_TIME_INTERVAL);
24821                $(window).off("resize", guidelib.util.GuideUtil._resizeScribbleField);
24822                $(window).on("resize", guidelib.util.GuideUtil._resizeScribbleField);
24823            }
24824        },
24825
24826        handleAccessibility : function () {
24827            
24828            if (this._model.mandatory) {
24829                this.$widget.find("img").attr("aria-required", true);
24830            }
24831            if (this._model._getScreenReaderText() === this._model._getToolTip()) {
24832                this.$element.find("img").removeAttr("aria-label");
24833                this.$element.find("img").attr("aria-labelledby", this._model.id + "_guideFieldShortDescription");
24834            } else if (this._model._getAssistPriority() === "none") {
24835                this.$element.find("img").attr("aria-label", " ");
24836            }
24837        },
24838
24839        
24840        tempXfaFixes : function () {
24841            if (this.$widget) {
24842                this.$widget.css("position", "relative").find("img").css("position", "relative");
24843            }
24844            this.handleAccessibility();
24845        }
24846    });
24847}($, guidelib));
24848(function ($, guidelib) {
24849    var xfaUtil = xfalib.ut.XfaUtil.prototype,
24850        GuideImageView = guidelib.view.GuideImageView = guidelib.view.GuideBaseView.extend({
24851            initialize : function () {
24852                GuideImageView._super.initialize.call(this);
24853                if (this._model.value != null) {
24854                    var srcString = "data:image/*;base64," + this._model.value;
24855                    this.$element.children('img').attr('src', srcString);
24856                }
24857            },
24858
24859            postInitialize : function () {
24860                this._syncGuideNodeToHtml();
24861            },
24862
24863            setActive : function (activeItemToken, focus, muteScripts) {
24864                guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
24865                if (focus && !this._guideView.skipFieldFocus) {
24866                    if (this.$element) {
24867                        this.$element.focus();
24868                    }
24869                    this._guideView.currentFocusItemSom = this._model.somExpression;
24870                }
24871                return true;
24872            }
24873
24874        });
24875}($, guidelib));
24876
24877(function ($, guidelib) {
24878    var GuideChartView = guidelib.view.GuideChartView = guidelib.view.GuideBaseView.extend({
24879
24880        initialize : function () {
24881            GuideChartView._super.initialize.call(this);
24882            var chartView = this;
24883            $(window).on("resize orientationchange", function () {
24884                chartView.renderChart.apply(chartView);
24885            });
24886        },
24887
24888        postInitialize : function () {
24889            this._syncGuideNodeToHtml(true);
24890        },
24891
24892        handleModelChanged : function (event) {
24893            switch (event._property) {
24894                case "data":
24895                case "chartType":
24896                    this.renderChart();
24897                    break;
24898
24899                case "visible":
24900                    this.handleVisibleChanged(event);
24901                    break;
24902            }
24903        },
24904
24905        handleVisibleChanged : function (event) {
24906            
24907            
24908            if (!event.newText) {
24909                
24910                this.$element.addClass("hidden");
24911                if (this.parentView.currentActiveItemView == this) {
24912                    this.parentView.setActive("nextItem");
24913                }
24914            }   else {
24915                
24916                this.$element.removeClass("hidden");
24917            }
24918        },
24919
24920        _generateChart : function () {
24921            var $chartElement = this.$element, chartModel = this._model, isChartVisible, chart;
24922            
24923            var plottedChartSelector = chartModel.jsonModel.isInteractiveCommunicationChartResource ? '.highcharts-container'
24924                    : '.dv-chart-container';
24925            var $plottedChart = $chartElement
24926                    .find(plottedChartSelector);
24927            isChartVisible = ($chartElement.parent().width() > 0)
24928                    && ($chartElement.width() > 0) ? true : false;
24929            
24930            
24931            
24932            
24933            if ((isChartVisible || $plottedChart.length == 0)
24934                    && chartModel.repeatableItem) {
24935                try {
24936                    
24937                    $plottedChart.remove();
24938                    if (chartModel.jsonModel.isInteractiveCommunicationChartResource) {
24939                        chart = new fd.chart.ChartInstanceGenerator()
24940                                .generate(chartModel.jsonModel,
24941                                        chartModel.jsonModel.data);
24942                        Highcharts.chart($chartElement.attr('id'),
24943                                chart);
24944                    } else {
24945                        chart = guidelib.chartUtils.constructChart(
24946                                chartModel, $chartElement);
24947                        if (chart) {
24948                            chart.render();
24949                        }
24950                    }
24951                } catch (exception) {
24952                    this.logger().error("AF Chart view",
24953                            "Error while rendering chart " + exception);
24954                }
24955            }
24956        },
24957
24958        renderChart : function () {
24959            if (this._model.data) {
24960                var chartView = this;
24961                window.requestAnimationFrame(function () {
24962                    chartView._generateChart.apply(chartView);
24963                });
24964            }
24965        },
24966
24967        _syncGuideNodeToHtml : function (deepSync) {
24968            this.renderChart();
24969            guidelib.view.GuideChartView._super._syncGuideNodeToHtml.call(this, deepSync);
24970        },
24971
24972        setActive : function (activeItemToken, focus, muteScripts) {
24973            guidelib.view.GuideChartView._super.setActive.call(this, activeItemToken, focus, muteScripts);
24974            if (focus && !this._guideView.skipFieldFocus) {
24975                if (this.$element) {
24976                    this.$element.focus();
24977                }
24978                this._guideView.currentFocusItemSom = this._model.somExpression;
24979            }
24980            return true;
24981        }
24982    });
24983}($, guidelib));
24984(function ($, guidelib) {
24985    var GuideAdModuleView = guidelib.view.GuideAdModuleView = guidelib.view.GuideBaseView.extend({
24986
24987        initialize : function () {
24988            GuideAdModuleView._super.initialize.call(this);
24989            if (this._model) {
24990                
24991                this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
24992            }
24993            this.oldValue = null;
24994        },
24995
24996        postInitialize : function () {
24997            this._syncGuideNodeToHtml(true);
24998        },
24999
25000        handleValueChanged : function (event) {
25001            switch (event._property) {
25002                case "value":
25003                    this.$element.html(event.newText);
25004                    break;
25005            }
25006        },
25007
25008        handleVisibleChanged : function (event) {
25009            
25010            
25011            if (!event.newText) {
25012                
25013                this.$element.addClass("hidden");
25014                if (this.parentView.currentActiveItemView == this) {
25015                    this.parentView.setActive("nextItem");
25016                }
25017            }   else {
25018                
25019                this.$element.removeClass("hidden");
25020            }
25021        },
25022
25023        handleModelChanged : function (event) {
25024            GuideAdModuleView._super.handleModelChanged.apply(this, arguments);
25025        },
25026        _syncGuideNodeToHtml : function (deepSync) {
25027            if (this._model.value) {
25028                this.$element
25029                    .html(this._model.value)
25030                    .find('img')
25031                    .attr('src', function (idx, val) {
25032                        return Granite.HTTP.externalize(val);
25033                    });
25034            }
25035
25036            if (this._model.layoutConfigs) {
25037                var options = {
25038                                $element : this.$element,
25039                                layoutConfigs : this._model.layoutConfigs
25040                            };
25041                guidelib.util.AdUtil.applyLayouts(options);
25042            }
25043            if (this._model) {
25044                this.handleModelChanged(guidelib.event.GuideModelEvent.createEvent(
25045                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
25046                    this,
25047                    "visible",
25048                    this._model.visible,
25049                    this._model.visible
25050                ));
25051            }
25052        },
25053
25054        setActive : function (activeItemToken, focus, muteScripts) {
25055            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
25056            if (focus) {
25057                if (this.$element) {
25058                    this.$element.focus();
25059                }
25060                this._guideView.currentFocusItemSom = this._model.somExpression;
25061            }
25062            return true;
25063        }
25064    });
25065}($, guidelib));
25066(function ($, _, guidelib) {
25067    var GuideItemsView = guidelib.view.GuideItemsView = guidelib.view.GuideBaseView.extend({
25068        initialize : function () {
25069            GuideItemsView._super.initialize.call(this);
25070            this.childViews = [];
25071        },
25072
25073        
25074        _unloadView : function () {
25075            if (this._model._selfOrAncestorIsLazyReference) {
25076                var fragmentPlaceHolderSelector = "#" + this.id,
25077                    ind;
25078                
25079                $(fragmentPlaceHolderSelector).children().remove();
25080                
25081                var queueForLazyItems = this._guideView._queueViewForLazyItems;
25082                
25083                if ((ind = _.indexOf(queueForLazyItems, this)) !== -1) {
25084                    queueForLazyItems[ind] = undefined;
25085                }
25086                _.each(this.childViews, function (view) {
25087
25088                    view._unloadView();
25089                }, this);
25090                
25091                this.childViews = [];
25092                
25093                this._currentActiveItemView = null;
25094                
25095                this._guideView._domTemplateCacheStore.removeDomElement("#" + this._model.templateId);
25096                
25097                this._guideView._reInitializeGuideContainerDom();
25098            }
25099        },
25100        postInitialize : function () {
25101            this.childViews = _.reduce(this._model.children, function (childViews, childModel) {
25102                var childView = this._createNonRepeatChildView(childModel);
25103                if (childView) {
25104                    childViews.push(childView);
25105                }
25106                return childViews;
25107            }, [], this);
25108            
25109            this._syncGuideNodeToHtml(false);
25110        },
25111
25112        _createNonRepeatChildView : function (childModel) {
25113            
25114
25115            
25116            
25117            var childElSelector = this.guideUtil.modelElSelector(childModel.id);
25118            var $childEl = this.$element.find(childElSelector);
25119            if (!$childEl.length) {
25120                $childEl = this.$element.find(this.guideUtil.modelElSelector(childModel.templateId));
25121                this._updateIds($childEl, childModel.templateId, childModel.id);
25122            }
25123            if ($childEl.length) {
25124                var childView = guidelib.view.GuideViewRegistry.prototype.createView($childEl, this);
25125                childView.postInitialize();
25126                return childView;
25127            }
25128            return null;
25129        },
25130
25131        _syncGuideNodeToHtml : function (deepSync) {
25132            if (deepSync) {
25133                _.each(this.childViews, function (childView) {
25134                    childView._syncGuideNodeToHtml(true);
25135                }, this);
25136            }
25137            GuideItemsView._super._syncGuideNodeToHtml.call(this, deepSync);
25138        },
25139
25140        _findChildView : function (childModel) {
25141            var view = _.find(this.childViews, function (childView) {
25142                return childView._model == childModel;
25143            }, this);
25144            return view;
25145        }
25146    });
25147
25148    GuideItemsView.defineProps({
25149        itemsView : {
25150            get : function () {
25151                var views = _.filter(this.childViews, function (childView) {
25152                    return childView.isItem;
25153                }, this);
25154                return views;
25155            }
25156        }
25157    });
25158}($, _, guidelib));
25159
25160(function ($, _, guidelib, guideBridge) {
25161
25162    var GuideProgressiveSectionView = guidelib.view.GuideProgressiveSectionView = guidelib.view.GuideItemsView.extend({
25163
25164        initialize : function () {
25165            GuideProgressiveSectionView._super.initialize.call(this);
25166            
25167            if (this._model && this._model != null) {
25168                
25169                
25170                
25171                
25172                
25173                this._model.off(guidelib.event.GuideModelEvent.NAVIGATE_SECTION);
25174                this._model.on(guidelib.event.GuideModelEvent.NAVIGATE_SECTION, this.handleNavigateSection, this);
25175            }
25176            
25177            
25178        },
25179
25180        
25181        handleNavigateSection : function (event) {
25182            
25183            var progressive = guidelib.runtime.progressive,
25184                that = this,
25185                model = this._model,
25186                part = null;
25187            if (event.newText === "next") {
25188                model.currentActivePart++;
25189            } else if (event.newText === "prev") {
25190                model.currentActivePart--;
25191            }
25192            _.each(model._parts, function (item, index) {
25193                if (index == model.currentActivePart) {
25194                    _.each(item, function (model, id) {
25195                        
25196                        
25197                        
25198                        if (progressive.isFieldVisible(model)) {
25199                            progressive.markFieldVisible(window.guideBridge._getGuideDomElement(model.somExpression).parent());
25200                        } else {
25201                            progressive.markFieldHidden(window.guideBridge._getGuideDomElement(model.somExpression).parent());
25202                        }
25203                    });
25204                } else {
25205                    _.each(item, function (model, id) {
25206                        
25207                        progressive.markFieldHidden(window.guideBridge._getGuideDomElement(model.somExpression).parent());
25208                    });
25209                }
25210            });
25211            
25212            if (((model.currentActivePart + 1) !== 1) || model._parts.length !== 1) {
25213                
25214                
25215                if (model._parts.length > 0) {
25216                    this._updateSectionTitle();
25217                }
25218            }
25219        },
25220
25221        
25222        _updateSectionTitle : function () {
25223            var progressive = guidelib.runtime.progressive,
25224                $sectionTitle = this.$element.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_TIT
25224LE_SELECTOR),
25225                sectionTitle = this._model.sectionTitle,
25226                newSectionTile = sectionTitle + " (" + (this._model.currentActivePart + 1) + "/" + this._model._parts.length + ")";
25227            $sectionTitle.html(newSectionTile);
25228        },
25229
25230        postInitialize : function () {
25231            var that = this,
25232                $childEls,
25233                item,
25234                id = null;
25235            
25236            if (this.$element && this.$element != null) {
25237                $childEls = this.$element.find(".progressiveSectionField");
25238                $childEls.each(function (index, childEl) {
25239                    
25240                    
25241                    item = $(childEl).children("div")[0];
25242                    
25243                    id = $(item).attr("id");
25244                    
25245                    
25246                    
25247                    var childView = guidelib.view.GuideViewRegistry.prototype.createView(item, that);
25248                    childView.postInitialize();
25249                    that.childViews.push(childView);
25250                    that.childViewsToId = that.childViewsToId || {};
25251                    that.childViewsToId[id] = childView;
25252                });
25253                
25254                this._calculatePartsOfSection();
25255            }
25256        },
25257
25258        _getPdcSizeConfiguration : function () {
25259            return window.guideBridge.userConfig["progressive.pdcSize"];
25260        },
25261
25262        _calculatePartsOfSection : function () {
25263            var userConfig = window.guideBridge.userConfig,
25264                progressive = guidelib.runtime.progressive,
25265                $pdc = this.$element.parents(progressive.PROGRESSIVE_CONSTANTS.PDC_SELECTOR); 
25266            
25267            
25268            if (this._getPdcSizeConfiguration()) {
25269                if (this._getPdcSizeConfiguration() && this._getPdcSizeConfiguration().height) {
25270                    $pdc.height(this._getPdcSizeConfiguration().height);
25271                }
25272                if (this._getPdcSizeConfiguration() && this._getPdcSizeConfiguration().width) {
25273                    $pdc.width(this._getPdcSizeConfiguration().width);
25274                }
25275
25276            }
25277            
25278            if (userConfig && userConfig["calculatePartsOfSectionConfig"] && _.isFunction(userConfig["calculatePartsOfSectionConfig"]["calculatePartsOfSectionHandler"])) {
25279                var externalHandler = userConfig["calculatePartsOfSectionConfig"]["calculatePartsOfSectionHandler"],
25280                    
25281                    sectionParts = externalHandler(this._model);
25282                this._updatePartsFromArray(sectionParts);
25283            } else {
25284                var $sectionFieldContainer = this.$element.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_FIELD_CONTAINER_SELECTOR), 
25285                    pdcInnerHeight = $pdc.innerHeight(), 
25286                    pdcTitleHeight = $pdc.find(progressive.PROGRESSIVE_CONSTANTS.PDC_TITLE_SELECTOR).outerHeight(), 
25287                    pdcControlHeight = $pdc.find("[" + progressive.PROGRESSIVE_CONSTANTS.PDC_CONTROLS + "]").outerHeight(), 
25288                    sectionTitleHeight = this.$element.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_TITLE_SELECTOR).outerHeight(), 
25289                    sectionFieldContainerHeight,
25290                    $sectionRepeatableControls = $pdc.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_REPEATABLE_CONTROLS_SELECTOR),
25291                    repeatableControlsHeight = $sectionRepeatableControls.outerHeight() ? $sectionRepeatableControls.outerHeight() + progressive.heightBuffer : 0,
25292                    repeatableTitleHeight = $(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_TITLE_CONTAINER_SELECTOR).outerHeight() || 0, 
25293                    availablePanelHeight,
25294                    availableFields = this.$element.find(".progressiveSectionField"),
25295                    currentActiveFields = $sectionFieldContainer.find('.progressiveSectionField.pdcCurrentPanelField'), 
25296                    consumeHeight,
25297                    that = this,
25298                    currentPart = 0,
25299                    id,
25300                    offsetDivs = $pdc.find("[" + progressive.PROGRESSIVE_CONSTANTS.PDC_OFFSET_SELECTOR + "]"),
25301                    hasAtleastOne = false,
25302                    trunkRest = false; 
25303                $sectionFieldContainer.css('max-height', ''); 
25304                sectionFieldContainerHeight = $sectionFieldContainer.height(); 
25305                
25306                
25307                
25308                
25309                availablePanelHeight = pdcInnerHeight; 
25310                _.each(offsetDivs, function (offsetDiv) {
25311                        availablePanelHeight -= $(offsetDiv).outerHeight();
25312                    });
25313                availablePanelHeight -= guidelib.runtime.progressive.heightBuffer;
25314                
25315                $sectionFieldContainer.css('max-height', availablePanelHeight + 'px');
25316                consumeHeight = availablePanelHeight; 
25317
25318                
25319                if (sectionFieldContainerHeight > availablePanelHeight) {
25320                    
25321                    for (var i = 0; i < availableFields.length; i++) { 
25322                        var $currentField = $(availableFields[i]),
25323                            currentFieldHeight = $currentField.outerHeight() + guidelib.runtime.progressive.fieldHeightBuffer;
25324                        if (currentFieldHeight <= consumeHeight && !trunkRest) {
25325                            consumeHeight = consumeHeight - currentFieldHeight;
25326                            hasAtleastOne = true;
25327                            
25328                            
25329                            
25330                            
25331                            id = $currentField.children("div").first().attr("id");
25332                            this._updateParts(currentPart, id);
25333                        } else if (!hasAtleastOne) {
25334                            
25335                            id = $currentField.children("div").first().attr("id");
25336                            this._updateParts(currentPart, id);
25337                            hasAtleastOne = true;
25338                            trunkRest = true;
25339                        } else {
25340                            
25341                            consumeHeight = availablePanelHeight;
25342                            currentPart++;
25343                            i--;
25344                        }
25345                    }
25346                } else {
25347                    
25348                    $.each(availableFields, function (index) {
25349                            
25350                            
25351                            that._updateParts(currentPart, $(this).children("div").first().attr("id"));
25352                        });
25353                }
25354            }
25355        },
25356
25357        
25358        _updatePartsFromArray : function (sectionParts) {
25359            if (_.isArray(sectionParts)) {
25360                _.each(sectionParts, function (part, currentPart) {
25361                    if (_.isArray(part)) {
25362                        _.each(part, function (item, index) {
25363                            
25364                            this._updateParts(currentPart, item.id);
25365                        });
25366                    }
25367                });
25368            }
25369        },
25370
25371        _updateParts : function (currentPart, id) {
25372            
25373            
25374            this._model._parts[currentPart] = this._model._parts[currentPart] || {} ;
25375            this._model._parts[currentPart][id] = this._model._getChildModelFromId(id);
25376        },
25377
25378        focusable : function () {
25379            
25380            return false;
25381        },
25382
25383        setActive : function (activeItemToken, focus, muteScripts) {
25384            
25385            return true;
25386        },
25387
25388        handleChildChanged : function (event) {
25389            
25390        },
25391
25392        handleModelChanged : function (event) {
25393            
25394        },
25395
25396        handleVisibleChanged : function (event) {
25397            
25398        },
25399
25400        handleAccessibility : function () {
25401            
25402        },
25403
25404        getSiblingItemView : function (siblingType) {
25405            
25406            return null;
25407        },
25408
25409        getQualifiedNamedView : function (qName) {
25410            
25411            var view = _.find(this.childViews, function (childView) {
25412                return (childView._model._escapeQualifiedName() == qName);
25413            }, this);
25414            return view;
25415        }
25416    });
25417    GuideProgressiveSectionView.defineProps({
25418        $item : {
25419            get : function () {
25420                
25421                return null;
25422            }
25423        },
25424
25425        $itemNav : {
25426            get : function () {
25427                
25428                return null;
25429            }
25430        },
25431
25432        isItem : {
25433            get : function () {
25434                
25435                return false;
25436            }
25437        },
25438
25439        qualifiedName : {
25440            get : function () {
25441                
25442                return null;
25443            }
25444        }
25445    });
25446}($, _, guidelib, window.guideBridge));
25447
25448(function ($, _, guidelib) {
25449    var GuideProgressiveRepeatableSectionView = guidelib.view.GuideProgressiveRepeatableSectionView = guidelib.view.GuideProgressiveSectionView.extend({
25450        initialize : function () {
25451            GuideProgressiveRepeatableSectionView._super.initialize.call(this);
25452            
25453            this._$summary = null;
25454            if (this._model && this._model != null) {
25455                
25456                if (this._model && this._model.instance) {
25457                    this._model.instance.off(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
25458                    this._model.instance.on(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
25459                }
25460                this._summarySelector = this.guideUtil.summarySelector(this._model.instance.id);
25461            }
25462        },
25463
25464        postInitialize : function () {
25465            GuideProgressiveRepeatableSectionView._super.postInitialize.call(this);
25466            this.handleSummaryChanged();
25467        },
25468
25469        
25470
25471        
25472        _updateSectionTitle : function () {
25473            
25474            
25475        },
25476
25477        
25478        handleRepeatableProgressivePanel : function () {
25479            
25480            this._updateIds(this.$element, this._model.repeatablePanelId, this._model.instance.id);
25481            this.childViews = [];
25482            
25483            _.each(this._model.children, function (childModel) {
25484                    var cTemplateId = childModel.templateId,
25485                        childId = childModel.id,
25486                        $childItem = this.$element.find('#' + cTemplateId), 
25487                        view = null,
25488                        $childEl;
25489                    if (!$childItem.length) {
25490                        return;
25491                    }
25492                    
25493                    
25494                    
25495                    this._updateIds(this.$element, cTemplateId, childId);
25496                }, this
25497            );
25498        },
25499
25500        handleNavigateSection : function (event) {
25501            GuideProgressiveRepeatableSectionView._super.handleNavigateSection.apply(this, arguments);
25502
25503        },
25504
25505        
25506        _calculatePartsOfSection : function () {
25507            var userConfig = window.guideBridge.userConfig;
25508            
25509            if (userConfig && userConfig["calculatePartsOfSectionConfig"] && _.isFunction(userConfig["calculatePartsOfSectionConfig"]["calculatePartsOfSectionHandler"])) {
25510                var externalHandler = userConfig["calculatePartsOfSectionConfig"]["calculatePartsOfSectionHandler"],
25511                
25512                    sectionParts = externalHandler(this._model);
25513                this._updatePartsFromArray(sectionParts);
25514            } else {
25515                var progressive = guidelib.runtime.progressive,
25516                    $pdc = $(progressive.PROGRESSIVE_CONSTANTS.PDC_SELECTOR), 
25517                    $sectionRepeatableControls = $pdc.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_REPEATABLE_CONTROLS_SELECTOR);
25518                
25519                $sectionRepeatableControls.find(".hidden").removeClass("hidden");
25520                var $sectionFieldContainer = this.$element.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_FIELD_CONTAINER_SELECTOR), 
25521                    pdcOuterHeight = $pdc.outerHeight(), 
25522                    pdcTitleHeight = $pdc.find(progressive.PROGRESSIVE_CONSTANTS.PDC_TITLE_SELECTOR).outerHeight(), 
25523                    
25524                    
25525                    repeatableControlsHeight = $sectionRepeatableControls.outerHeight(true) ? $sectionRepeatableControls.outerHeight(true) + progressive.heightBuffer : 0,
25526                    repeatableTitleHeight = this.$element.find(progressive.PROGRESSIVE_CONSTANTS.PDC_SECTION_TIT
25526LE_CONTAINER_SELECTOR).outerHeight(true) || 0, 
25527                    availableFields = this.$element.find(".progressiveSectionField"),
25528                    id,
25529                    currentPart = 0,
25530                    availablePanelHeight;
25531                
25532                $sectionRepeatableControls.find("[data-guide-repeatable='back']").addClass("hidden");
25533                $sectionRepeatableControls.outerHeight(true) ? $sectionRepeatableControls.outerHeight(true) + progressive.heightBuffer : 0,
25534                
25535                
25536                availablePanelHeight = pdcOuterHeight - pdcTitleHeight - repeatableTitleHeight - 1.5 * guidelib.runtime.progressive.heightBuffer;
25537                
25538                $sectionFieldContainer.css('max-height', availablePanelHeight + 'px');
25539                $sectionFieldContainer.css('overflow', 'auto');
25540                for (var i = 0; i < availableFields.length; i++) { 
25541                    var $currentField = $(availableFields[i]);
25542                    
25543                    
25544                    id = $currentField.children("div").first().attr("id");
25545                    this._updateParts(currentPart, id);
25546                }
25547            }
25548        },
25549
25550        handleSummaryChanged : function () {
25551            
25552            if (this.$summary.length > 0) {
25553                var panelModel = this._model.instance;
25554                
25555                if (panelModel == null) {
25556                    panelModel = window.guideBridge._resolveId("im_" + this._model.repeatablePanelId).instances[0];
25557                }
25558                if (panelModel.summary) {
25559                    this.$summary.text(panelModel.summary);
25560                } else {
25561                    var title = panelModel.title || panelModel.name;
25562                    if (this._model.instanceIndex && panelModel.repeatable) {
25563                        title += " " + this._model.instanceIndex;
25564                    }
25565                    this.$summary.text(title);
25566                }
25567            }
25568        },
25569
25570        handleModelChanged : function (event) {
25571            switch (event._property) {
25572                case "summary":
25573                    this.handleSummaryChanged();
25574                    break;
25575                default:
25576                    GuideProgressiveRepeatableSectionView._super.handleModelChanged.apply(this, arguments);
25577            }
25578        }
25579    });
25580
25581    GuideProgressiveRepeatableSectionView.defineProps({
25582        $summary : {
25583            get : function () {
25584                if (!this._$summary) {
25585                    this._$summary = this._find(this._summarySelector);
25586                }
25587                return this._$summary;
25588            }
25589        }
25590    });
25591}($, _, guidelib));
25592
25593(function ($, guidelib) {
25594    var GuideAdModuleGroupView = guidelib.view.GuideAdModuleGroupView = guidelib.view.GuideItemsView.extend({
25595        initialize : function () {
25596            GuideAdModuleGroupView._super.initialize.call(this);
25597            if (this._model) {
25598                
25599                this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
25600            }
25601        },
25602
25603        postInitialize : function () {
25604            if (this._model.value || this._model.value === "") {
25605                this._syncGuideNodeToHtml(true);
25606            } else {
25607                GuideAdModuleGroupView._super.postInitialize.call(this);
25608            }
25609        },
25610
25611        handleValueChanged : function (event) {
25612            switch (event._property) {
25613                case "value":
25614                    this.$element.html(event.newText);
25615                    break;
25616            }
25617        },
25618
25619        _syncGuideNodeToHtml : function (deepSync) {
25620            if (this._model.value || this._model.value === "") {
25621                this.$element
25622                    .html(this._model.value)
25623                    .find('img')
25624                    .attr('src', function (idx, val) {
25625                        return Granite.HTTP.externalize(val);
25626                    });
25627            } else {
25628                GuideAdModuleGroupView._super._syncGuideNodeToHtml.call(this, deepSync);
25629            }
25630        },
25631
25632        setActive : function (activeItemToken, focus, muteScripts) {
25633            guidelib.view.GuideAdModuleGroupView._super.setActive.call(this, activeItemToken, focus, muteScripts);
25634            if (focus) {
25635                if (this.$element) {
25636                    this.$element.focus();
25637                }
25638                this._guideView.currentFocusItemSom = this._model.somExpression;
25639            }
25640            return true;
25641        }
25642
25643    });
25644}($, guidelib));
25645(function ($, _, guidelib) {
25646
25647    var GuidePanelView = guidelib.view.GuidePanelView = guidelib.view.GuideItemsView.extend({
25648        initialize : function () {
25649            GuidePanelView._super.initialize.call(this);
25650            this._currentActiveItemView = null;
25651            this._$itemsContainer = null;
25652            this._$itemsNavContainer = null;
25653            this._$summary = null;
25654            this._$title = null;
25655            
25656            this._childInitializeWaiting = true;
25657            
25658            this._model.on(guidelib.event.GuideModelEvent.CHILD_CHANGED, this.handleChildChanged, this);
25659            this._model.on(guidelib.event.GuideModelEvent.MULTIPLE_CHILD_ADDED, this.multipleChildAdded, this);
25660            this._summarySelector = this.guideUtil.summarySelector(this._model.id);
25661            this._titleSelector = this.guideUtil.propSelector("title", this._model.id);
25662        },
25663
25664        addRemoveTemplateMarker : function () {
25665            var featureToggle = FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_VALID_NAV_UL_CHILDREN) ? true : false;
25666            
25667            _.each(this._model.children, function (childModel) {
25668                if (childModel instanceof guidelib.model.GuideInstanceManager) {
25669                    
25670                    var imId = childModel.id,
25671                        instanceId = (childModel._instances[0] || {}).id || childModel.instanceTemplateId,
25672                        gTemplateMarkerPanel = '<div id="' + imId + 'panel" style="display: none" data-guide-template-marker="true"></div>',
25673                        gTemplateMarkerNav = '<'+ (featureToggle ? 'li' : 'div') +' id="' + imId + 'nav" style="display: none" data-guide-template-marker="true"></' + (featureToggle ? 'li' : 'div') + '>',
25674                        instanceItem = this.guideUtil.itemSelector(instanceId, childModel),
25675                        navItem = this.guideUtil.itemNavSelector(instanceId);
25676                    this.$itemsContainer.find(instanceItem).before(gTemplateMarkerPanel);
25677                    this.$itemsNavContainer.find(navItem).before(gTemplateMarkerNav);
25678                    if (childModel._instances && childModel._instances.length === 0) { 
25679                        $(navItem, this.$element).remove(); 
25680                        $(instanceItem, this.$element).remove(); 
25681                    }
25682
25683                }
25684            }, this);
25685
25686        },
25687
25688        postInitialize : function () {
25689
25690            
25691            
25692            
25693            this.handleSummaryChanged();
25694            this.handleTitleChanged();
25695            if (this._model.repeatable) {
25696                this._toggleAddRemoveButtons();
25697            }
25698            if (!this.parentView._model.enableLayoutOptimization) {
25699                
25700                this._postInitializeChildren();
25701            } else {
25702                
25703                
25704                
25705                
25706                
25707                
25708                this.handleVisibleChanged(guidelib.event.GuideModelEvent.createEvent(
25709                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
25710                    this,
25711                    "visible",
25712                    this._model.visible,
25713                    this._model.visible
25714                ));
25715            }
25716            
25717            
25718            
25719            
25720            
25721            this.addRemoveTemplateMarker();
25722        },
25723
25724        _postInitializeChildren : function () {
25725            this._childInitializeWaiting = false;
25726            this._syncGuideNodeToHtml(true);
25727            this.handleAccessibility();
25728            
25729            
25730            
25731            if (this.parentView.$itemsNavContainer && this.parentView.$itemsNavContainer.filter(":not(.tab-navigators-mobile)").length === 0) {
25732                this.setActive("firstItem", false, true);
25733            }
25734        },
25735
25736        _syncGuideNodeToHtml : function (deepSync, currentAddedChildIndex) {
25737            if (this._childInitializeWaiting) {
25738                return;
25739            }
25740            
25741            
25742            
25743            
25744            
25745            
25746            
25747
25748            var that = this;
25749            var htmlTemplateCache = this._guideView._domTemplateCacheStore;
25750            var oldItems = {}; 
25751            var oldNonItems = {}; 
25752            var newChildren = {};
25753
25754            
25755            _.each(this.childViews, function (childView) {
25756                if (childView.isItem) {
25757                    oldItems[childView.id] = childView;
25758                } else {
25759                    oldNonItems[childView.id] = childView;
25760                }
25761            }, this);
25762
25763            
25764            
25765            
25766            
25767            
25768            
25769            
25770            _.each(this._model.items, function (childModel) {
25771                    var cTemplateId = childModel.templateId;
25772                    var childId = childModel.id,
25773                        $childItem = null,
25774                        $childItemNav = null;
25775                    
25776                    
25777                    $childItem = this._find(this.guideUtil.itemSelector(childId, childModel));
25778                    $childItemNav = this._find(this.guideUtil.itemNavSelector(childId));
25779
25780                    
25781                    
25782                    if (!$childItem.length && !newChildren[cTemplateId] && currentAddedChildIndex !== 0) {
25783                        
25784                        
25785                        $childItem = this.$itemsContainer.find(this.guideUtil.itemSelector(cTemplateId, childModel));
25786                        $childItemNav = this.$itemsNavContainer.find(this.guideUtil.itemNavSelector(cTemplateId));
25787                    }
25788                    if (!$childItem.length) {
25789                        
25790                        $childItem = htmlTemplateCache.cloneDomElement(this.guideUtil.itemSelector(cTemplateId, childModel));
25791                        $childItemNav = htmlTemplateCache.cloneDomElement(this.guideUtil.itemNavSelector(cTemplateId));
25792                        if (!$childItem.length) {
25793                            this.logger().error("AF", "Html template could not be found. cTemplateId:" + cTemplateId + ", som:" + childModel.somExpression);
25794                            return;
25795                        }
25796                    }
25797                    this._updateIds($childItem, cTemplateId, childId);
25798                    this._updateIds($childItemNav, cTemplateId, childId);
25799                    
25800                    
25801                    $childItem.attr("data-guide-parent-id", this._model.id);
25802                    $childItemNav.attr("data-guide-parent-id", this._model.id);
25803                    var view = null;
25804                    if (oldItems.hasOwnProperty(childId)) {
25805                        view = oldItems[childId];
25806                        if (view instanceof guidelib.view.GuidePanel
25806View && view._model.instanceManager.repeatable && !_.isUndefined(that._model.bindNode)) {
25807                            
25808                            this._fixChildDom(view);
25809                        }
25810                        if (deepSync) {
25811                            view._syncGuideNodeToHtml(deepSync);
25812                        } 
25813                    } else {
25814                        var $childEl = this._find("#" + childId);
25815                        if ($childEl.length) {
25816                            view = this._createChild($childEl);
25817                        } else {
25818                            $childEl = $childItem.find("#" + childId).addBack("#" + childId);
25819                            if ($childEl.length) {
25820                                view = this._createChild($childEl, $childItem, $childItemNav);
25821                            } else {
25822                                this.logger().debug("AF", "Skip creating view. could not find el for id:" + childId);
25823                            }
25824                        }
25825                        if (this._model.repeatable) {
25826                            guidelib.util.GuideUtil._initializeShortDescription($childEl);
25827                        }
25828                    }
25829                    if (view) {
25830                        newChildren[childId] = view;
25831                    }
25832                }, this
25833            );
25834
25835            
25836            this.$itemsContainer.find('[data-guide-parent-id="' + that._model.id + '"]').each(function () {
25837                var $this = $(this);
25838                var thisId = $this.attr("id");
25839                
25840                if (thisId.indexOf(that.guideUtil.GUIDE_ITEM_SUFFIX) === -1) {
25841                    thisId = $this.attr(that.guideUtil.DATA_GUIDE_ITEM);
25842                }
25843                var childId = thisId.substring(0, thisId.length - that.guideUtil.GUIDE_ITEM_SUFFIX.length);
25844                if (!newChildren.hasOwnProperty(childId) && !window.guideBridge._resolveId(childId)) {
25845                    that.logger().log("guideView", 5, "removing element as no corresponding form dom node found. id:" + thisId + ", parent id:" + that.id);
25846                    $this.remove();
25847                    that._find(that.guideUtil.itemNavSelector(childId)).remove();
25848                }
25849            });
25850
25851            this.childViews = [];
25852            _.each(this._model.children, function (childModel) {
25853                var childIsItem = childModel._isItem;
25854                var childId = childModel.id;
25855                if (childIsItem && newChildren.hasOwnProperty(childId)) {
25856                    
25857                    this.childViews.push(newChildren[childId]);
25858                } else if (!childIsItem) {
25859                    var nonItemChildView = null;
25860                    if (oldNonItems.hasOwnProperty(childId)) {
25861                        nonItemChildView = oldNonItems[childId];
25862                    } else {
25863                        nonItemChildView = this._createNonRepeatChildView(childModel);
25864                    }
25865                    if (nonItemChildView) {
25866                        if (deepSync) {
25867                            nonItemChildView._syncGuideNodeToHtml(deepSync);
25868                        }
25869                        this.childViews.push(nonItemChildView);
25870                    }
25871                }
25872            }, this);
25873            
25874            guidelib.view.GuideBaseView.prototype._syncGuideNodeToHtml.apply(this, arguments);   
25875        },
25876
25877        _createChild : function ($childEl, $item, $itemNav) {
25878            var view = guidelib.view.GuideViewRegistry.prototype.createView($childEl, this);
25879            this._fixChildDom(view, $item, $itemNav);
25880            view.postInitialize();
25881            return view;
25882        },
25883
25884        _fixChildDom : function (view, $item, $itemNav) {
25885            
25886            
25887            
25888            var newChild = view._model;
25889            if (!(newChild instanceof guidelib.model.GuidePanel) || !newChild.repeatable) {
25890                return;
25891            }
25892            var $childItem = $item || view.$item;
25893            var $childItemNav = $itemNav || view.$itemNav;
25894            var children = this._model.children;
25895            var insertAfterId = (newChild.instanceIndex > 0) ? children[children.indexOf(newChild) - 1].id : null;
25896            
25897            var insertAfterItemSelector = insertAfterId ? this.guideUtil.itemSelector(insertAfterId, newChild) : "#" + newChild.instanceManager.id;
25898            var insertAfterNavSelector = insertAfterId ? this.guideUtil.itemNavSelector(insertAfterId) : "#" + newChild.instanceManager.id;
25899            var that = this;
25900            
25901            
25902            this.$itemsContainer.each(function (index) {
25903                var insertEl = $childItem.get(index) || $childItem.get(0),
25904                    $insertAfterItem = $(this).find(insertAfterItemSelector);
25905                
25906                if ($insertAfterItem.length == 0) {
25907                    insertAfterItemSelector = "[data-guide-template-marker=" + newChild.instanceManager.id + "]";
25908                    $insertAfterItem = $(this).find(insertAfterItemSelector);
25909                    
25910                    if(newChild.instanceIndex === 0 && $insertAfterItem.length > 0) {
25911                        $insertAfterItem.removeAttr("data-guide-template-marker");
25912                        $(insertEl).attr("data-guide-template-marker", newChild.instanceManager.id);
25913                    }
25914                }
25915                
25916                if ($insertAfterItem.get(0) !== insertEl) {
25917                    
25918                    $insertAfterItem.after($(insertEl));
25919                }
25920            });
25921            
25922            
25923            
25924            this.$itemsNavContainer.each(function (index) {
25925                var insertNavEl = $childItemNav.get(index) || $childItemNav.get(0);
25926                $(this).find(insertAfterNavSelector).after($(insertNavEl));
25927            });
25928        },
25929
25930        multipleChildAdded : function (event) {
25931            if (event.jsonModel.newText && event.jsonModel.newText.length > 0) {
25932                this._syncGuideNodeToHtml(true);
25933                this.childViews.forEach(function (childView) {
25934                    if (childView._model.repeatable) {
25935                        childView._toggleAddRemoveButtons();
25936                    }
25937                });
25938            }
25939        },
25940
25941        handleChildChanged : function (event) {
25942            var newlyCreatedInstance = null,
25943                currentAddedInstanceIndex = -1; 
25944            if (event._property == "childRemoved") {
25945                var $elementRemoved = this.$element.find("#" + event.prevText.id),
25946                    index = $elementRemoved.index();
25947            }
25948            if (event._property == "childAdded") {
25949                newlyCreatedInstance = event.newText;
25950                currentAddedInstanceIndex = newlyCreatedInstance.instanceIndex;
25951            }
25952            
25953            this._syncGuideNodeToHtml(true, currentAddedInstanceIndex);
25954            this.childViews.forEach(function (childView) {
25955                if (childView._model.repeatable) {
25956                    childView._toggleAddRemoveButtons();
25957                }
25958            });
25959            if (event._property == "childRemoved") {
25960                
25961                
25962                this.$element.trigger("panelRemoved.af", [$elementRemoved, index]);
25963                if (this.currentActiveItemView && event.prevText == this.currentActiveItemView._model) {
25964                    
25965                    this._currentActiveItemView = null;
25966                    this.setActive("nextItem");
25967                }
25968            }
25969            if (newlyCreatedInstance != null) {
25970                
25971                
25972                this.$element.trigger("panelAdded.af", [this.$element.find("#" + newlyCreatedInstance.id)]);
25973            }
25974        },
25975
25976        handleSummaryChanged : function () {
25977            if (this.$summary.length > 0) {
25978                if (this._model.summary) {
25979                    this.$summary.text(this._model.summary);
25980                } else {
25981                    var title = this._model.title;
25982                    if (this._model.instanceIndex && this._model.repeatable) {
25983                        title += " " + this._model.instanceIndex;
25984                    }
25985                    this.$summary.text(title);
25986                }
25987            }
25988        },
25989
25990        handleTitleChanged : function () {
25991            if (this.$title.length > 0) {
25992                this.$title.text(this._model.title);
25993            }
25994            
25995            var isPanelActive = $("#" + this.id + "_guide-item").hasClass("active");
25996            if (isPanelActive) {
25997                $("[data-target-guide-content]").text(this._model.title);
25998            }
25999        },
26000
26001        handleModelChanged : function (event) {
26002            switch (event._property) {
26003                case "summary":
26004                    this.handleSummaryChanged();
26005                    break;
26006                case "title":
26007                    this.handleTitleChanged();
26008                    break;
26009                default:
26010                    GuidePanelView._super.handleModelChanged.apply(this, arguments);
26011            }
26012        },
26013
26014        _createReferredView : function () {
26015            
26016            this._postInitializeChildren();
26017        },
26018
26019        _loadLazyFragment : function () {
26020            
26021            
26022            
26023            
26024            
26025            
26026            var that = this;
26027            this._model._guide().internal.liveDataUtils.updateLiveData();
26028            
26029            this._guideView._clearInactiveLazyViews(this);
26030            
26031            this._viewCreationInProgress = true;
26032
26033            this._model._loadLazyFragment({
26034                "preFetch" : function () {
26035                    $("#loadingPage").addClass("guideLoading");
26036                },
26037                "postFetch" : function () {
26038                    $("#loadingPage").removeClass("guideLoading");
26039                },
26040                "success" : function () {
26041                    
26042                    that._createReferredView();
26043                    
26044                    
26045                    that._viewCreationInProgress = undefined;
26046                    that._itemsLoaded = true;
26047                }
26048            });
26049            
26050            
26051        },
26052
26053        
26054        setActive : function (activeItemToken, focus, muteScripts) {
26055            
26056            
26057            
26058            if (this._model._lazyReference) {
26059                
26060                
26061                
26062                
26063                
26064                if (_.isUndefined(this._viewCreationInProgress) && _.isUndefined(this._itemsLoaded)
26065                    && this._guideView._currentActiveItemView !== this) {
26066                    this._loadLazyFragment();
26067                }
26068            }
26069
26070            var currentActiveItemQName = this.getOrElse(this.currentActiveItemView, "qualifiedName", null);
26071            
26072            activeItemToken = activeItemToken || currentActiveItemQName || "firstItem";
26073            if (activeItemToken != currentActiveItemQName) {
26074                var newActiveItemModel = this._model.navigationContext.getItemForNav(activeItemToken);
26075                if (!newActiveItemModel) {
26076                    this.logger().log("AF", "activeItemToken not found:" + activeItemToken + ",currentActiveItem:" +
26077                        currentActiveItemQName + ":" + this._model.somExpression);
26078                    return false;
26079                }
26080                var newActiveItemView = this.getQualifiedNamedView(newActiveItemModel._escapeQualifiedName());
26081                if (!muteScripts && this._model.completionExpReq && this.currentActiveItemView && this.currentActiveItemView.focusable() && (this.childViews.indexOf(newActiveItemView) > this.childViews.indexOf(this.currentActiveItemView))) {
26082                    var completed = true;
26083                    if (this._model.getAttribute("validateOnStepCompletion")) {
26084                        completed = window.guideBridge.validate([], this._model.panel.navigationContext.currentItem.somExpression);
26085                    }
26086                    
26087                    completed = completed && this._model.executeExpression("completionExp");
26088                    if (!completed) {
26089                        return false;
26090                    } else if (this.currentActiveItemView) {
26091                        this.currentActiveItemView.$item.addClass("completed");
26092                        this.currentActiveItemView.$itemNav.addClass("completed");
26093                    }
26094                }
26095                this.currentActiveItemView = newActiveItemView;
26096                
26097                
26098                
26099                
26100                
26101            }
26102            if (this.currentActiveItemView) {
26103                this.currentActiveItemView.setActive(null, focus, muteScripts);
26104            }
26105            return true;
26106        },
26107        
26108        _clearInactiveLazyViews : function (that) {
26109            _.each(this.childViews, function (item) {
26110                if (item && item._model.className === "guidePanel" && item._ancestorHasNavigableLayout) {
26111                    if (item._model._itemsLoaded && !that._isSelfOrAncestor(item) && !item._hasEffectiveActiveClass()
26112                        && item._model._lazyReference) {
26113                        item._model._unloadLazyReferenceModel();
26114                        item._unloadView();
26115                        
26116                        item._itemsLoaded = undefined;
26117                        
26118                        item._model._itemsLoaded = undefined;
26119                    } else {
26120                        item._clearInactiveLazyViews(that);
26121                    }
26122                }
26123            }, this);
26124        },
26125        
26126        _isSelfOrAncestor : function (panelView) {
26127
26128            var selfOrParentView = this;
26129            while (!_.isUndefined(selfOrParentView) && selfOrParentView._model.className !== "rootPanelNode") {
26130                if (panelView === selfOrParentView) {
26131                    return true;
26132                }
26133                selfOrParentView = selfOrParentView.parentView;
26134            }
26135            return false;
26136        },
26137        
26138        _hasEffectiveActiveClass : function () {
26139            var hierarchy = this;
26140            while (!_.isUndefined(hierarchy) && this._model.className !== "rootPanelNode") {
26141                if (hierarchy.$item.hasClass("active")) {
26142                    hierarchy = hierarchy.parentView;
26143                } else {
26144                    return false;
26145                }
26146            }
26147            return true;
26148        },
26149
26150        handleAccessibility : function () {
26151            var role, screenReaderText;
26152            screenReaderText = this._model._getScreenReaderText();
26153            role = this._model._getRole();
26154            if (screenReaderText) {
26155                this.$itemNav.attr("aria-label", screenReaderText);
26156            }
26157            this.$itemNav.find('a').attr("tabindex", function (index, currentValue) {
26158                return (currentValue == -1 ? currentValue : 0);
26159            });
26160        },
26161
26162        getQualifiedNamedView : function (qName) {
26163            var view = _.find(this.childViews, function (childView) {
26164                return (childView._model._escapeQualifiedName() == qName);
26165            }, this);
26166            return view;
26167        },
26168
26169        _toggleAddRemoveButtons : function () {
26170            var panelModel = this._model,
26171                instanceManager = panelModel.instanceManager;
26172            $('[data-guide-id="' + panelModel.id + '"][data-guide-addremove="remove"]').toggleClass("hidden", instanceManager.instanceCount == instanceManager.minOccur);
26173            $('[data-guide-id="' + panelModel.id + '"][data-guide-addremove="add"]').toggleClass("hidden", instanceManager.instanceCount == instanceManager.maxOccur);
26174        }
26175    });
26176
26177    GuidePanelView.defineProps({
26178        hasNavigableLayout : {
26179            get : function () {
26180                return this.$itemsNavContainer.length > 0;
26181            }
26182        },
26183        $itemsContainer : {
26184            get : function () {
26185                
26186                if (this._model._selfOrAncestorIsLazyReference || !this._$itemsContainer || this._$itemsContainer.length === 0) {
26187                    this._$itemsContainer = this._find(this.guideUtil.itemContainerSelector(this._model.id));
26188                    
26189                    if (this._$itemsContainer.length === 0) {
26190                        this._$itemsContainer = this._find(this.guideUtil.alternateItemContainerSelector(this._model.id));
26191                    }
26192                }
26193                return this._$itemsContainer;
26194            }
26195        },
26196        $itemsNavContainer : {
26197            get : function () {
26198                if (this._model._selfOrAncestorIsLazyReference || !this._$itemsNavContainer || this._$itemsNavContainer.length === 0) {
26199                    this._$itemsNavContainer = this._find(this.guideUtil.itemNavContainerSelector(this._model.id));
26200                }
26201                return this._$itemsNavContainer;
26202            }
26203        },
26204        $summary : {
26205            get : function () {
26206                if (!this._$summary) {
26207                    this._$summary = this._find(this._summarySelector);
26208                }
26209                return this._$summary;
26210            }
26211        },
26212        $title : {
26213            get : function () {
26214                if (!this._$title) {
26215                    this._$title = this._find(this._titleSelector);
26216                }
26217                return this._$title;
26218            }
26219        },
26220        currentActiveItemView : {
26221            get : function () {
26222                return this._currentActiveItemView;
26223            },
26224            set : function (value) {
26225                if (value != this._currentActiveItemView) {
26226                    if (this._currentActiveItemView) {
26227                        
26228                        this._currentActiveItemView._model.viewVisited = true;
26229                    }
26230                    if (!value) {
26231                        var itemModel = this._model.navigationContext.firstItem;
26232                        if (itemModel) {
26233                            value = this.getQualifiedNamedView(itemModel._escapeQualifiedName());
26234                        }
26235                    }
26236                    this._currentActiveItemView = value;
26237                    
26238                    this._model.navigationContext.currentItem = (this._currentActiveItemView || {})._model;
26239                    _.each(this.childViews, function (childView) {
26240                        if (childView == this._currentActiveItemView) {
26241                            childView.$item.addClass("active");
26242                            childView.$itemNav.addClass("active");
26243                            childView.$itemNav.attr("aria-selected", true);
26244                            childView.$itemNav.attr("aria-disabled", false);
26245                            childView.$itemNav.removeClass("wizard-tab-disabled");
26246                        } else {
26247                            childView.$item.removeClass("active");
26248                            childView.$itemNav.removeClass("active");
26249                            childView.$itemNav.attr("aria-selected", false);
26250                        }
26251                    }, this);
26252                    
26253                    
26254                    
26255                    
26256                    if (this._currentActiveItemView instanceof guidelib.view.GuidePanel
26256View && this._currentActiveItemView._childInitializeWaiting) {
26257                        this._currentActiveItemView._postInitializeChildren();
26258                    }
26259
26260                    if (true && _.isUndefined(this._model._ajaxCallDone)) {
26261                        
26262                        
26263                        var model = this._model;
26264                        
26265                        while (model && !(model instanceof guidelib.model.RootPanelNode)) {
26266                            if (model.toolbar) {
26267                                model.toolbar.execNavigationChangeExpression();
26268                            }
26269                            model = model.parent;
26270                        }
26271                        
26272                        if (model && model.toolbar && model instanceof  guidelib.model.RootPanelNode) {
26273                            model.toolbar.execNavigationChangeExpression();
26274                        }
26275                    }
26276                }
26277            }
26278        },
26279        
26280        _ancestorHasNavigableLayout : {
26281            get : function () {
26282                var parentView = this.parentView;
26283                while (parentView) {
26284                    if (parentView.$itemsNavContainer && parentView.$itemsNavContainer.length > 0) {
26285                        return true;
26286                    }
26287                    parentView = parentView.parentView;
26288                }
26289                return false;
26290            }
26291        }
26292    });
26293}($, _, guidelib));
26294(function ($, _, guidelib) {
26295
26296    var cloneCounter = 0;
26297
26298    var tableMobileLayoutConstants = {
26299        COLLAPSIBLE_COLUMNS : "collapsibleColumns",
26300        HEADERS_LEFT : "headersLeft",
26301        COLLAPSIBLE_COLUMNS_CONTROL_ROW_SELECTOR : "tr.child",
26302        RUNTIME_TABLE_CONTROL : "guideTableRuntimeControls",
26303        RUNTIME_TABLE_RIGHT_CONTROL : "guideTableRuntimeRightControls",
26304        RUNTIME_TABLE_LEFT_CONTROL : "guideTableRuntimeLeftControls",
26305        RUNTIME_TABLE_ADD_CONTROL : "guideTableRuntimeAddControl",
26306        RUNTIME_TABLE_DELETE_CONTROL : "guideTableRuntimeDeleteControl",
26307        RUNTIME_TABLE_EDIT_CONTROL : "guideTableRuntimeEditControl"
26308    };
26309
26310    var tableSortingComponents = {
26311        GUIDE_INSTANCE_MANAGER : "guideInstanceManager",
26312        WEB_CHANNEL_HEADER_COMPONENT : "fd/ccm/web-channel/components/tableHeader/v1/tableHeader",
26313        AF_TABLE_HEADER_COMPONENT : "fd/af/components/tableHeader",
26314        SORTING_ENABLED : "sortingEnabled"
26315    };
26316
26317    var GuideTableView = guidelib.view.GuideTableView = guidelib.view.GuidePanelView.extend({
26318
26319        
26320        TABLE_WIDTH_BUFFER : 23,
26321        
26322        _getPluginOptions : function () {
26323            var defaultOptions  = {
26324                "bAutoWidth" : this.bAutoWidth
26325            }, columnWidthArray = null,
26326                sum = 0,
26327                sWidthArray = null,
26328                numOfTableCol = this.$tableElement.find("th").length;
26329
26330            if (this.bAutoWidth === false) {
26331                columnWidthArray = this._model.columnWidth.split(",");
26332                if (columnWidthArray.length === numOfTableCol) {
26333                    
26334                    _.each(columnWidthArray, function (item) {
26335                        sum += parseInt(item, 10);
26336                    });
26337                    
26338                    sWidthArray = _.map(columnWidthArray, function (item) {
26339                        return {
26340                            "pWidth" : Math.floor((item * 100) / sum)
26341                        };
26342                    });
26343                }
26344                
26345                defaultOptions = _.extend({}, defaultOptions, {
26346                    aWidthPercentage : sWidthArray,
26347                    aWidth : columnWidthArray
26348                });
26349            }
26350            return defaultOptions;
26351
26352        },
26353
26354        
26355        setAutoWidth : function () {
26356            if (this._model.columnWidth && this._model.columnWidth.length > 0) {
26357                this.bAutoWidth = false;
26358            }  else {
26359                this.bAutoWidth = true;
26360            }
26361        },
26362
26363        
26364        createView : function (id) {
26365            var $htmlTemplate = this._guideView._domTemplateCacheStore.cloneDomElement("#" + id),
26366                formElemSelector = "#" + id + "_widget",
26367                counter = ++cloneCounter;
26368            if ($htmlTemplate.length == 0) {
26369                
26370                $htmlTemplate = this.$element.find("#" + id).clone();
26371            }
26372            
26373            $htmlTemplate.find(formElemSelector).attr("id", id + "_widget" + counter);
26374
26375            var view = guidelib.view.GuideViewRegistry.prototype.createView($htmlTemplate, this);
26376            view.postInitialize();
26377            return $htmlTemplate;
26378        },
26379
26380        initializeTableColumnWidth : function (pluginOptions) {
26381            
26382            if (this.bAutoWidth == false && this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
26383                
26384                
26385                this.$tableElement.css("table-layout", "fixed");
26386                var widthArray = pluginOptions["aWidthPercentage"],
26387                    numOfTableCol = this.$tableElement.find("th").length;
26388                if (widthArray && widthArray.length == numOfTableCol) {
26389                    
26390                    this.$tableElement.find("th").each(function (index) {
26391                        $(this).width(widthArray[index]["pWidth"] + "%");
26392                    });
26393                }
26394            }
26395        },
26396
26397        _checkIfTableSortingEnabled : function () {
26398            var jsonModel = this._model.jsonModel;
26399            return (jsonModel[tableSortingComponents.SORTING_ENABLED] === "true");
26400        },
26401
26402        
26403        handleParentVisibleChanged : function (event) {
26404            switch (event._property) {
26405                case "visible":
26406                    this.handleTableShown();
26407                    break;
26408            }
26409        },
26410
26411        
26412        _checkParentModelChanged : function() {
26413            var currentParent = this.parentView;
26414            while(currentParent != null) {
26415                currentParent._model.on(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleParentVisibleChanged, this);
26416                currentParent = currentParent.parentView;
26417            }
26418        },
26419
26420        
26421        initialize : function () {
26422            GuideTableView._super.initialize.apply(this, arguments);
26423            
26424            this._checkParentModelChanged();
26425            
26426            this.$tableElement = this.$element.find("> table");
26427            
26428            this.setAutoWidth();
26429            
26430            var widgetOptions = this._getPluginOptions(),
26431                that = this;
26432            
26433            this.initializeTableColumnWidth(widgetOptions);
26434            this._fixTableControls(true);
26435            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
26436                widgetOptions = _.extend({}, widgetOptions, {
26437                    
26438                    bControlRowHiddenCells : false,
26439
26440                    
26441                    bDisableControlRowCells : true,
26442                    
26443                    viewCallback : $.proxy(this.createView, this),
26444                    
26445                    tableRuntimeEditControlClass : tableMobileLayoutConstants.RUNTIME_TABLE_EDIT_CONTROL,
26446                    
26447                    fixTableControls : $.proxy(this._fixTableControls, this)
26448                });
26449                
26450                this.jqwidget = this.$tableElement.responsiveTablePlugin(widgetOptions).data("responsiveTablePlugin");
26451            }  else {
26452                
26453                $(window).on("resize orientationchange", function (event) {
26454                    that._fixTableControls(event);
26455                });
26456            }
26457            
26458            if (this._checkIfTableSortingEnabled()) {
26459                this.$tableElement.tableSorting = this.guideTableSorter.initialize;
26460                this.$tableElement.tableSorting({
26461                    model : this._model,
26462                    tableContext : this
26463                });
26464            }
26465        },
26466
26467        handleVisibleChanged : function (event) {
26468            GuideTableView._super.handleVisibleChanged.apply(this, arguments);
26469            
26470            this.handleTableShown();
26471            this._resetTableCellWidth();
26472        },
26473
26474        handleTableShown : function () {
26475            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
26476                
26477                this.jqwidget._initializeColumnVisibility();
26478                
26479                if (this.jqwidget.isColumnHidden()) {
26480                    
26481                    this.$tableElement.find(".guideFieldNode").addClass("dontSyncEnabled");
26482                    
26483                    this.$tableElement.find("input, select, textarea, button").attr("disabled", "disabled");
26484                }
26485            }
26486        },
26487
26488        _resetTableCellWidth : function () {
26489            var that = this,
26490                tableWidthBuffer = this.TABLE_WIDTH_BUFFER;
26491            
26492            this.$tableElement.find("." + tableMobileLayoutConstants.RUNTIME_TABLE_CONTROL).each(function () {
26493                var element = this;
26494                setTimeout(function () {
26495                    that._resetTableCell($(element), tableWidthBuffer);
26496                }, 1);
26497            });
26498        },
26499
26500        _resetTableCell : function ($element, tableWidthBuffer) {
26501            var componentWidth;
26502            
26503            if ($element.hasClass(tableMobileLayoutConstants.RUNTIME_TABLE_RIGHT_CONTROL)) {
26504                var $component = $element.prev(),
26505                    $td = $element.parent();
26506                
26507                
26508                if ($element.is(":visible")) {
26509                    
26510                    $component.css("display", "inline-block");
26511                    $component.css("float", "left");
26512                    componentWidth = $td.width() - $element.outerWidth() - tableWidthBuffer;
26513                    var percentage = ((componentWidth / $td.width()) * 100);
26514                    
26515                    
26516                    $component.width(percentage + "%");
26517                } else {
26518                    
26519                    
26520                    $component.css("display", "block");
26521                    $component.css("float", "none");
26522                    $component.width($td.width());
26523                }
26524            } else if ($element.hasClass(tableMobileLayoutConstants.RUNTIME_TABLE_LEFT_CONTROL)) {
26525                
26526                if ($element.is(":visible")) {
26527                    $element.next().css("display", "inline-block");
26528                    componentWidth = $element.parent().width() - $element.outerWidth() - tableWidthBuffer;
26529                    var percentage = ((componentWidth / $element.parent().width()) * 100);
26530                    $element.next().width(percentage + "%");
26531                } else {
26532                    
26533                    $element.next().css("display", "block");
26534                }
26535            }
26536        },
26537
26538        _fixTableControls : function (event) {
26539            
26540            
26541            
26542            if ((this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) && (this.jqwidget)) {
26543                
26544                if (this.jqwidget.isColumnHidden()) {
26545                    
26546                    this.$tableElement.find("tr:not(.child)").find(".guideFieldNode").addClass("dontSyncEnabled");
26547                    
26548                    this.$tableElement.find("tr:not(.child)").find("input, select, textarea, button").attr("disabled", "disabled");
26549                } else {
26550                    
26551                    this.$tableElement.find(".guideFieldNode").removeClass("dontSyncEnabled");
26552                    
26553                    this.$tableElement.find("input, select, textarea, button").removeAttr("disabled");
26554                }
26555            }
26556            
26557            
26558            if (event) {
26559                this._resetTableCellWidth();
26560            }
26561        },
26562
26563        
26564        _fixChildDom : function (view, $item, $itemNav) {
26565            GuideTableView._super._fixChildDom.apply(this, arguments);
26566            
26567            
26568            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
26569                
26570                this.jqwidget._fixControlRows();
26571            }
26572            
26573            this._fixTableControls();
26574            
26575            this._resetTableCellWidth();
26576        },
26577
26578        _postInitializeChildren : function () {
26579            
26580            GuideTableView._super._postInitializeChildren.call(this);
26581            
26582            
26583            
26584            
26585            
26586            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
26587                
26588                this.handleTableShown();
26589            }
26590            
26591            
26592            else if (this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
26593                this._fixTableCellForHeaderLeftLayout();
26594            }
26595            this._resetTableCellWidth();
26596        },
26597
26598        _fixTableCellForHeaderLeftLayout : function () {
26599            var that = this,
26600                guideUtil = guidelib.util.GuideUtil;
26601            this.$tableElement.find("tr td").each(function () {
26602                guideUtil._setGuideDataHeader($(this), that.$tableElement);
26603            });
26604        },
26605
26606        
26607        handleChildChanged : function (event) {
26608            GuideTableView._super.handleChildChanged.apply(this, arguments);
26609            
26610            
26611            if (this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
26612                this._fixTableCellForHeaderLeftLayout();
26613            }
26614            if (event._property == "childAdded") {
26615                this._resetTableCellWidth();
26616            }
26617        },
26618
26619        addRemoveTemplateMarker : function () {
26620            
26621            _.each(this._model.children, function (childModel) {
26622                if (childModel instanceof guidelib.model.GuideInstanceManager) {
26623                    
26624                    var imId = childModel.id,
26625                        instanceId = (childModel._instances[0] || {}).id || childModel.instanceTemplateId,
26626                        gTemplateMarker = null,
26627                        
26628                        instanceItem = this.guideUtil.itemSelector(instanceId, childModel._instances[0]),
26629                        navItem = this.guideUtil.itemNavSelector(instanceId),
26630                        $instanceItem = this.$itemsContainer.find(instanceItem);
26631                    if ($instanceItem.is("tr")) {
26632                        $instanceItem.attr("data-guide-template-marker", imId);
26633                    }
26634                    
26635                    
26636                    
26637                    
26638                    
26639                }
26640            }, this);
26641        },
26642
26643        tableSortComparator : {
26644            DATE : function (tableModelDataRows, sortList, tableContext) {
26645                    return tableModelDataRows.sort(function (a, b) {
26646                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
26647                            guideTableSorter = tableContext.guideTableSorter,
26648                            value_a = guideTableSorter.formatDateValue(guideTableSorter.getValueFromJsonModel(a, currColumn)),
26649                            value_b = guideTableSorter.formatDateValue(guideTableSorter.getValueFromJsonModel(b, currColumn));
26650                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
26651                    });
26652                },
26653            NUMBER : function (tableModelDataRows, sortList, tableContext) {
26654                    return tableModelDataRows.sort(function (a, b) {
26655                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
26656                            guideTableSorter = tableContext.guideTableSorter,
26657                            value_a = guideTableSorter.formatRegexFloatData(guideTableSorter.getValueFromJsonModel(a, currColumn)),
26658                            value_b = guideTableSorter.formatRegexFloatData(guideTableSorter.getValueFromJsonModel(b, currColumn));
26659                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
26660                    });
26661
26662                },
26663            STRING : function (tableModelDataRows, sortList, tableContext) {
26664                    return tableModelDataRows.sort(function (a, b) {
26665                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
26666                            guideTableSorter = tableContext.guideTableSorter,
26667                            value_a = guideTableSorter.formatRichTextString(guideTableSorter.getValueFromJsonModel(a, currColumn, true)),
26668                            value_b = guideTableSorter.formatRichTextString(guideTableSorter.getValueFromJsonModel(b, currColumn, true));
26669                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
26670                    });
26671                }
26672        },
26673
26674        
26675        guideTableSorter : new function () {
26676            this.initialize = function (tableSortingConfig) {
26677                return this.each(function () {
26678                    this.tableConfig = {};
26679                    var defaultSortingConfig = {sortList : [], selectorsHeaders : 'thead th',
26680                        headerCss : {asc : "asc", desc : "desc", random : "random"}
26681                    };
26682                    if (!this.tHead || !this.tBodies) {return;}
26683                    var table = $(this), tableConfig = {};
26684                    tableConfig = $.extend(this.tableConfig, defaultSortingConfig, tableSortingConfig);
26685                    var tableHeaderModel, tableModel = tableConfig.model;
26686                    for (var index = 0 ; index < tableModel.children.length ; index++) {
26687                        if (isTableHeaderRow(tableModel.children[index])) {
26688                            tableHeaderModel = tableModel.children[index];
26689                            tableConfig.tableHeader = tableHeaderModel;
26690                            break;
26691                        }
26692                    }
26693                    var $tableHeaders = filterSortableHeaders(tableConfig, this);
26694                    $tableHeaders.click(function () {
26695                        if (this.sortingAllowed) {
26696                            sortCurrentColumn(this, table, tableConfig, $tableHeaders);
26697                        }
26698                    });
26699                    
26700                    $tableHeaders.each(function (index) {
26701                        if (this.sortingAllowed) {
26702                            sortOnFirstColumn(this, tableModel);
26703                            return false;
26704                        }
26705                    });
26706                });
26707            };
26708
26709            
26710            function sortOnFirstColumn(firstColumn, tableModel) {
26711                if (typeof tableModel._guide !== "undefined" && tableModel._guide()) {
26712                    var isSubmittedData = guidelib.util.GuideUtil._fetchJSONNodeValue(tableModel._guide().runtime.guideContext.guidePrefillJson, "afSubmissionInfo");
26713                    isSubmittedData = isSubmittedData || guidelib.util.GuideUtil.fetchXMLNodeValue(tableModel._guide().runtime.guideContext.guidePrefillXml, "afSubmissionInfo");
26714                    if (!isSubmittedData) {
26715                        $(firstColumn).trigger("click");
26716                    }
26717                }
26718            }
26719
26720            
26721            function filterSortableHeaders(tableConfig, tableDom) {
26722                var $tableHeaders = $(tableConfig.selectorsHeaders, tableDom).each(function (index) {
26723                    this.column = index;
26724                    this.order = 1;
26725                });
26726                for (var column = 0 ; column < tableConfig.tableHeader.children.length ; column++) {
26727                    var currColumnModel = tableConfig.tableHeader.children[column];
26728                    $tableHeaders[column].sortingAllowed = true;
26729                    var sortDataType = currColumnModel.jsonModel["sortingDataType"];
26730                    sortDataType = !sortDataType ? "STRING" : sortDataType;
26731                    currColumnModel.jsonModel.sortingDataType = sortDataType;
26732                    if (!tableConfig.tableHeader.visible || sortDataType === "noSort") {
26733                        $tableHeaders[column].sortingAllowed = false;
26734                        $($tableHeaders[column]).removeClass("sortEnabled");
26735                        var $sortingButton = $($tableHeaders[column]).find(".sortingButton").remove();
26736                    }
26737                }
26738                return $tableHeaders;
26739            }
26740
26741            
26742            function sortCurrentColumn(currentHeader, table, tableConfig, $tableHeaders) {
26743                var tableRows = (table[0].tBodies[0] && table[0].tBodies[0].rows.length) || 0;
26744                if (tableRows > 0) {
26745                    currentHeader.order = (++(currentHeader.order) % 2);
26746                    tableConfig.sortList = [];
26747                    tableConfig.sortList.push([currentHeader.column, currentHeader.order]);
26748                    setTimeout(function () {
26749                        updateTableHeaderStyles($tableHeaders, tableConfig.sortList, tableConfig);
26750                        sortGuideTableDataModel(tableConfig, tableConfig.sortList, tableConfig.model);
26751                    }, 1);
26752                }
26753            }
26754
26755            
26756            function updateTableHeaderStyles($headers, sortingList, tableConfig) {
26757                var order, headerCSS = [tableConfig.headerCss.asc, tableConfig.headerCss.desc, tableConfig.headerCss.random];
26758                $headers.each(function (index) {
26759                    var $sortingButton = $(this).find(".sortingButton");
26760                    $sortingButton.removeClass(headerCSS[0]).removeClass(headerCSS[1]).removeClass(headerCSS[2]);
26761                    if ($headers[index].sortingAllowed) {
26762                        if (index === sortingList[0][0]) {
26763                            order = sortingList[0][1];
26764                            $sortingButton.addClass(headerCSS[order]);
26765                        } else {
26766                            $sortingButton.addClass(tableConfig.headerCss.random);
26767                        }
26768                    }
26769                });
26770            }
26771
26772            
26773            function sortGuideTableDataModel(tableConfig, sortList, tableModel) {
26774                var i,j = 0,tableModelChildren = tableModel.children, tableDataRows = [], prevTableModel = tableModel,
26775                    modifiedGuideTableModel = [], tableContext = tableConfig.tableContext;
26776                
26777                for (i = 0; i < tableModelChildren.length; i++) {
26778                    if (tableModelChildren[i].className !== tableSortingComponents.GUIDE_INSTANCE_MANAGER) {
26779                        if (isTableRowsWithData(tableModelChildren[i])) {
26780                            tableDataRows.push(tableModelChildren[i]);
26781                        }
26782                    }
26783                }
26784                var dataType = tableConfig.tableHeader.children[[sortList[0][0]]].jsonModel.sortingDataType;
26785                tableDataRows = tableContext.tableSortComparator[dataType].call(tableConfig, tableDataRows, sortList, tableContext);
26786                for (i = 0; i < tableModel.children.length; i++) {
26787                    if (isTableRowsWithData(tableModel.children[i])) {
26788                        modifiedGuideTableModel.push(tableDataRows[j]);
26789                        j++;
26790                    } else {
26791                        modifiedGuideTableModel.push(tableModel.children[i]);
26792                    }
26793                }
26794                tableModel.children = modifiedGuideTableModel;
26795                tableModel._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "tableModelSorted", prevTableModel, tableModel);
26796                syncNewModelToHTML(tableConfig.tableContext, tableModel);
26797            }
26798
26799            
26800            function isTableRowsWithData(tableModelChildElement) {
26801                var resourceType = tableModelChildElement.options.jsonModel["sling:resourceType"],
26802                    childElementClassName = tableModelChildElement.className;
26803                return !((childElementClassName === tableSortingComponents.GUIDE_INSTANCE_MANAGER) || (resourceType === tableSortingComponents.AF_TABLE_HEADER_COMPONENT) || (resourceType === tableSortingComponents.WEB_CHANNEL_HEADER_COMPONENT));
26804            }
26805
26806            function isTableHeaderRow(tableModelChildElement) {
26807                var resourceType = tableModelChildElement.options.jsonModel["sling:resourceType"];
26808                return ((resourceType === tableSortingComponents.AF_TABLE_HEADER_COMPONENT) || (resourceType === tableSortingComponents.WEB_CHANNEL_HEADER_COMPONENT));
26809            }
26810
26811            this.formatRegexFloatData = function (data) {
26812                return (isNaN(parseFloat(data))) ? 0 : parseFloat(data);
26813            };
26814
26815            this.formatDateValue = function (data) {
26816                return (isNaN(new Date(data).getTime())) ? 0 : new Date(data).getTime();
26817            };
26818
26819            this.formatRichTextString = function (data) {
26820                data = "<div>" + data + "</div>";
26821                return $(data).text().trim();
26822            };
26823
26824            this.ComparedOrder = function (value_a, value_b, currOrder) {
26825                if (value_a > value_b) {
26826                    return (currOrder === 0) ? 1 : -1;
26827                } else if (value_a < value_b) {
26828                    return (currOrder === 0) ? -1 : 1;
26829                } else {
26830                    return -1;
26831                }
26832            };
26833
26834            this.getValueFromJsonModel = function (tableRow, currColumn, isString) {
26835                var jsonModel = tableRow.children[getValidCurrentColumn(tableRow.children, currColumn)].jsonModel, value = null;
26836                if (!isString && jsonModel.defaultValue && jsonModel.defaultValue.length === 1) {
26837                    value = jsonModel.defaultValue[0];
26838                }
26839                if (!value) {
26840                    value = jsonModel._value;
26841                }
26842                return value === null ? "" : this.formatRichTextString(value);
26843            };
26844
26845            
26846            function getValidCurrentColumn(tableRowModel, currColumn) {
26847                var validCurrColumn = currColumn, index = 0 ;
26848                while (currColumn > 0) {
26849                    if (tableRowModel[index].jsonModel.guideNodeClass === tableSortingComponents.GUIDE_INSTANCE_MANAGER) {
26850                        validCurrColumn++;
26851                    } else {
26852                        currColumn--;
26853                    }
26854                    index++;
26855                }
26856                return validCurrColumn;
26857            }
26858
26859            
26860            function syncNewModelToHTML(tableContext, tableModel) {
26861                var tableItemsViews = {}, childView, index;
26862                
26863                for (index = 0; index < tableContext.childViews.length; index++) {
26864                    childView = tableContext.childViews[index];
26865                    if (childView.isItem) {
26866                        tableItemsViews[childView.id] = childView;
26867                    }
26868                }
26869                for (index = 1; index < tableContext._model.items.length; index++) {
26870                    var childModel = tableContext._model.items[index], childId = childModel.id, view = tableItemsViews[childId],newChild = view._model,
26871                        $childItem = view.$item, $childItemNav = view.$itemNav, insertBeforeId, insertAfterId;
26872                    if (index === 1) {
26873                        if (tableModel.items.length > 2) {
26874                            insertBeforeId = tableModel.items[index + 1].id;
26875                        }
26876                    } else {
26877                        insertAfterId = tableModel.items[index - 1].id;
26878                    }
26879                    var insertAfterItemSelector = insertAfterId ? tableContext.guideUtil.itemSelector(insertAfterId, newChild) : "#" + newChild.instanceManager.id,
26880                        insertBeforeItemSelector = insertBeforeId ? tableContext.guideUtil.itemSelector(insertBeforeId, newChild) : "#" + newChild.instanceManager.id;
26881                    tableContext.$itemsContainer.each(function (index) {
26882                        var insertEl = $childItem.get(index) || $childItem.get(0),
26883                            $insertBeforeItem,
26884                            $insertAfterItem = $(this).find(insertAfterItemSelector);
26885                        if ($insertAfterItem.get(0) !== insertEl) {
26886                            $insertAfterItem.after($(insertEl));
26887                        } else {
26888                            $insertBeforeItem = $(this).find(insertBeforeItemSelector);
26889                            $insertBeforeItem.before($(insertEl));
26890                        }
26891                    });
26892                }
26893            }
26894        }
26895    });
26896}($, _, guidelib));
26897
26898(function ($, guidelib) {
26899    var GuideTableRowView = guidelib.view.GuideTableRowView = guidelib.view.GuidePanelView.extend({
26900
26901        handleChildChanged : function (event) {
26902            
26903        }
26904
26905    });
26906}($, guidelib));
26907(function ($, guidelib, _) {
26908    var GuideContainerView = guidelib.view.GuideContainerView =  guidelib.view.GuideItemsView.extend({
26909        initialize : function () {
26910            this._queueViewForLazyItems = [];
26911            
26912            window.guideBridge._guideView = this;
26913            var $htmlTemplateDom =  $(this.options.element).clone();
26914            this._domTemplateCacheStore =
26915                new guidelib.view.util.DomTemplateCacheStore({$htmlTemplateDom : $htmlTemplateDom});
26916            this._lastFocussedPanelForNonActionFields = null;
26917            GuideContainerView._super.initialize.call(this);
26918            this._currentFocusItemSom = null;
26919            
26920            
26921            this._previousFocusItemSom = "FIRST_TIME";
26922            $(window).on("keydown.guides", $.proxy(this.hotKeys, this));
26923            this.postInitialize();
26924            this._model.on(guidelib.event.GuideModelEvent.MODEL_REFRESH, function (evnt) {
26925                switch (evnt._property) {
26926                case "jsonModel":
26927                    this._syncGuideNodeToHtml(true);
26928                    break;
26929                default:
26930                    this._model.logger().error("unexpected event property " + evnt._property);
26931                }
26932            }, this);
26933        },
26934
26935        _reInitializeGuideContainerDom : function () {
26936            var $guideContainerDom = $('div.guideContainerWrapperNode');
26937            this.$element = $guideContainerDom;
26938        },
26939
26940        setFocus : function (somExp, focusOpt, runNavScr) {
26941            var options,
26942                focusOption,
26943                runNavScript,
26944                somExpression,
26945                muteScripts;
26946            if (_.isObject(somExp)) {
26947                options = somExp;
26948                somExpression = options.somExpression;
26949                focusOption = options.focusOption;
26950                runNavScript = options.runCompletionScript;
26951            } else {
26952                somExpression = somExp;
26953                focusOption = focusOpt;
26954                runNavScript = runNavScr;
26955            }
26956            muteScripts = !runNavScript;
26957            if (focusOption == "nextItemDeep" || focusOption == "prevItemDeep") {
26958                
26959                if (somExpression) {
26960                    this.logger().warn("AF", "somExpression is currently not supported for deepNavigation:" + somExpression + ":" + focusOption);
26961                    return false;
26962                }
26963                var existingFocusNavItem = this.getSomOnNavigableAncestor(this._lastFocussedPanelForNonActionFields);
26964                var existingNavView = this.getView(existingFocusNavItem);
26965                var siblingNavName = (focusOption == "nextItemDeep") ? "nextItem" : "prevItem";
26966                
26967                while (existingNavView && (existingNavView.parentView != this) && !existingNavView.getSiblingItemView(siblingNavName)) {
26968                    var navigableParentItem = this.getSomOnNavigableAncestor(existingNavView.parentView._model.somExpression);
26969                    existingNavView = this.getView(navigableParentItem);
26970                }
26971                if (existingNavView && existingNavView.parentView != this && existingNavView.getSiblingItemView(siblingNavName)) {
26972                    var madeActive = existingNavView.parentView.setActive(siblingNavName, false, muteScripts); 
26973                    if (!madeActive) {
26974                        this.logger().log("AF", "could not setActive for the deepNav:" + existingNavView._model.somExpression);
26975                        return false;
26976                    }
26977                    
26978                    var deepChildNav = (siblingNavName == "nextItem") ? "firstItem" : "lastItem";
26979                    var currentActiveChildView = existingNavView.parentView.currentActiveItemView;
26980                    while (currentActiveChildView) {
26981                        currentActiveChildView.setActive(deepChildNav, !currentActiveChildView.currentActiveItemView, true); 
26982                        currentActiveChildView = currentActiveChildView.currentActiveItemView;
26983                    }
26984                    return true;
26985                } else {
26986                    this.logger().warn("AF", "could not locate view for given somExpression:" + somExpression + ":" + focusOption);
26987                    return false;
26988                }
26989            }
26990
26991            if (!somExpression) {
26992                
26993                somExpression = this.guideModel.rootPanel.somExpression;
26994            }
26995            var currentView = this.rootPanelView;
26996            
26997            
26998            if (currentView) {
26999                var relativeSom = this.guideUtil.relativeSom(this.guideModel.rootPanel.somExpression, somExpression);
27000                if (relativeSom) {
27001                    var somTokens = relativeSom.split(".");
27002                    var error =
27003                        _.find(somTokens, function (qName) {
27004                            currentView.setActive(qName, false, muteScripts);
27005                            if (currentView instanceof guidelib.view.GuidePanelView && (currentView.currentActiveItemView == null || currentView.currentActiveItemView.qualifiedName != qName)) {
27006                                this.logger().log("AF", "could not find token:" + qName + ", som:" + somExpression);
27007                                return true; 
27008                            } else {
27009                                if (currentView.currentActiveItemView != null){
27010                                    currentView = currentView.currentActiveItemView;
27011                                }
27012                            }
27013                        }, this);
27014                    if (error) {
27015                        return false;
27016                    }
27017                }
27018            } else {
27019                
27020                var $element = this._getGuideDomElement(somExpression);
27021                
27022                
27023                if ($element && $element.length > 0) {
27024                    
27025                    
27026                    currentView = $element.data("guideView");
27027                }
27028            }
27029
27030            if (currentView) {
27031                return currentView.setActive(focusOption, true, muteScripts);
27032            } else {
27033                return false;
27034            }
27035        },
27036
27037        _getGuideDomElement : function (somExpression, option) {
27038            var nav = "", res, node, nodeElSelector;
27039            if (somExpression && typeof somExpression === 'string') {
27040                node = this.guideModel.resolveNode(somExpression);
27041                if (!node) {
27042                    return;
27043                }
27044                nodeElSelector = "#" + node.id;
27045                if (option === "nav") {
27046                    nodeElSelector = this.guideUtil.itemNavSelector(node.id);
27047                }
27048                res = this.$element.find(nodeElSelector);
27049                return res;
27050            }
27051        },
27052
27053        getView : function (somExpression) {
27054            if (!somExpression) {
27055                return null;
27056            }
27057            var $focusEl = this._getGuideDomElement(somExpression),
27058                view = null,
27059                ancestorView = null;
27060            if ($focusEl && $focusEl.length > 0) {
27061                if (!$focusEl.data("guideView")) {
27062                    var rootPanelSom = this.guideModel.rootPanel.somExpression;
27063                    var relativeSom = guidelib.util.GuideUtil.relativeSom(rootPanelSom, somExpression) || "";
27064                    
27065                    _.reduce(relativeSom.split("."), function (currentSom, somToken) {
27066                        currentSom = currentSom ? currentSom + "." + somToken : somToken;
27067                        ancestorView = this.getView(currentSom);
27068                        if (ancestorView instanceof guidelib.view.GuidePanelView && ancestorView._childInitializeWaiting) {
27069                            ancestorView._postInitializeChildren();
27070                        }
27071                        return currentSom;
27072                    }, rootPanelSom, this);
27073                }
27074                view = $focusEl.data("guideView");
27075                if (view instanceof guidelib.view.GuidePanelView && view._childInitializeWaiting) {
27076                    view._postInitializeChildren();
27077                }
27078
27079                return view;
27080            }
27081            return null;
27082        },
27083
27084        hotKeys : function (evnt) {
27085            var handled = false, currentFocusItemSom;
27086
27087            switch (evnt.keyCode) {
27088            case 37: 
27089                if (evnt.altKey) {
27090                    window.guideBridge.setFocus(null, 'prevItemDeep', true);
27091                    handled = true;
27092                }
27093                break;
27094            case 39: 
27095                if (evnt.altKey) {
27096                    window.guideBridge.setFocus(null, 'nextItemDeep', true);
27097                    handled = true;
27098                }
27099                break;
27100            case 82: 
27101                if (evnt.altKey) {
27102                    window.guideBridge.reset();
27103                    handled = true;
27104                }
27105                break;
27106            case 83: 
27107                if (evnt.altKey) {
27108                    window.guideBridge.submit();
27109                    handled = true;
27110                }
27111                break;
27112            }
27113            if (handled) {
27114                evnt.preventDefault();
27115            }
27116        },
27117
27118        getSomOnNavigableAncestor : function (somExpression) {
27119            if (!somExpression || somExpression === "") {
27120                return null;
27121            }
27122
27123            var index, parentView, parentSom, isNavigable;
27124            index = somExpression.lastIndexOf(".");
27125
27126            if (index !== -1) {
27127                parentSom = somExpression.substring(0, index);
27128                parentView = this.getView(parentSom);
27129                if (parentView) {
27130                    isNavigable = parentView.hasNavigableLayout;
27131                }
27132                if (isNavigable) {  
27133                    return somExpression;
27134                }
27135                return this.getSomOnNavigableAncestor(parentSom);
27136            }
27137            
27138            return this.guideModel.rootPanel.somExpression;
27139        },
27140
27141        __printSyncPending : function () {
27142            
27143            _.each(this.childViews, function (childView) {
27144                if (childView._syncPending) {
27145                    this.logger().error("AF", childView._model.somExpression);
27146                } else {
27147                    GuideContainerView.prototype.__printSyncPending.call(childView);
27148                }
27149            }, this);
27150        },
27151        
27152        _clearInactiveLazyViews : function (that) {
27153            _.each(this.childViews, function (item) {
27154                if (item._model.className === "rootPanelNode") {
27155                    item._clearInactiveLazyViews(that);
27156                }
27157            });
27158        }
27159
27160    });
27161
27162    GuideContainerView.defineProps({
27163        guideModel : {
27164            get : function () {
27165                return this._model;
27166            }
27167        },
27168
27169        rootPanelView : {
27170            get : function () {
27171                return this._findChildView(this.guideModel.rootPanel);
27172            }
27173        },
27174
27175        currentFocusItemSom : {
27176            get : function () {
27177                return this._currentFocusItemSom;
27178            },
27179            set : function (newSom) {
27180                if (this._currentFocusItemSom !== newSom) {
27181                    var oldValue = this._currentFocusItemSom;
27182                    if (oldValue) {
27183                        this._previousFocusItemSom = oldValue;
27184                    }
27185                    this._currentFocusItemSom = newSom;
27186                    
27187                    if (!this._model._guide().runtime.progressive && newSom != null && this._model.resolveNode(newSom).parent.className !== "guideToolbar") {
27188                        this._lastFocussedPanelForNonActionFields = this.get
27188SomOnNavigableAncestor(this._currentFocusItemSom);
27189                        
27190                        
27191                        this._model._currentNavigablePanelSom =  this._lastFocussedPanelForNonActionFields;
27192                    }
27193                    if (newSom) {
27194                        this._triggerOnBridge("elementFocusChanged", this._model.resolveNode(newSom), "focus", this._previousFocusItemSom, newSom);
27195                        if (this._previousFocusItemSom && !this._model._guide().runtime.progressive) {
27196                            var getPreviousItemNavigableSom = this.getSomOnNavigableAncestor(this._previousFocusItemSom),
27197                                getCurrentItemNavigableSom = this.getSomOnNavigableAncestor(newSom);
27198                            if (getCurrentItemNavigableSom !== getPreviousItemNavigableSom) {
27199                                this._triggerOnBridge("elementNavigationChanged", this._model.resolveNode(getCurrentItemNavigableSom),
27200                                    "navigate", getPreviousItemNavigableSom, getCurrentItemNavigableSom);
27201                            }
27202                        }
27203                    }
27204                }
27205            }
27206        },
27207
27208        skipFieldFocus : {
27209            
27210            get : function () {
27211                return this._skipFieldFocus;
27212            },
27213            
27214            set : function (newVal) {
27215                this._skipFieldFocus = newVal;
27216            }
27217        }
27218    });
27219}($, guidelib, _));
27220(function ($, guidelib) {
27221    var DomTemplateCacheStore = guidelib.view.util.DomTemplateCacheStore = xfalib.ut.Class.extend({
27222        cloneDomElement : function (htmlId) {
27223            return this.$htmlTemplateDom.find(htmlId).clone();
27224        },
27225
27226        putDomElement : function (parentIdSelector, $child) {
27227            
27228            this.$htmlTemplateDom.find(parentIdSelector).eq(0).append($child);
27229        },
27230
27231        removeDomElement : function (parentIdSelector) {
27232            
27233            this.$htmlTemplateDom.find(parentIdSelector).children().remove();
27234        }
27235    });
27236
27237    DomTemplateCacheStore.defineProps({
27238        $htmlTemplateDom : {
27239            get : function () {
27240                return this.options.$htmlTemplateDom;
27241            }
27242        }
27243    });
27244}($, guidelib));
27245(function (_, guidelib) {
27246    
27247    var AddMinMaxValidation = guidelib.model.mixin.AddMinMaxValidation = {
27248        normalProperties : {
27249
27250            _runMaximumValueTest : function () {
27251                if (this.exclusiveMaximum) {
27252                    return this.value < this.maximum;
27253                } else {
27254                    return this.value <= this.maximum;
27255                }
27256            },
27257
27258            _runMinimumValueTest : function () {
27259                if (this.exclusiveMinimum) {
27260                    return this.value > this.minimum;
27261                } else {
27262                    return this.value >= this.minimum;
27263                }
27264            },
27265
27266            
27267            _minMaxValidation : function (value, obj) {
27268                if (value != null && obj.validFlag) {
27269
27270                    if (this.maximum) {
27271                        obj.validFlag = this._runMaximumValueTest();
27272                        if (!obj.validFlag) {
27273                            var maxFormattedValue = this._getFormattedValue(this.maximum);
27274                            this._errorText = this.exclusiveMaximum ? this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.exclusiveMaxValErrorMessage, [maxFormattedValue]) :
27275                                this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.maxValErrorMessage, [maxFormattedValue]);
27276                            this._failedTest = this.guideUtil.MAXIMUM_VALUE_TEST;
27277                        }
27278                    }
27279
27280                    if (obj.validFlag && this.minimum !== null) {
27281                        obj.validFlag = this._runMinimumValueTest();
27282                        if (!obj.validFlag) {
27283                            var minFormattedValue = this._getFormattedValue(this.minimum);
27284                            this._errorText = this.exclusiveMinimum ? this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.exclusiveMinValErrorMessage, [minFormattedValue]) :
27285                                this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minValErrorMessage, [minFormattedValue]);
27286                            this._failedTest = this.guideUtil.MINIMUM_VALUE_TEST;
27287                        }
27288                    }
27289                }
27290            }
27291
27292        },
27293        propertyDescriptors : {
27294            
27295            maximum : {
27296                get : function () {
27297                    return this.getAttribute("maximum");
27298                }
27299            },
27300
27301            
27302            minimum : {
27303                get : function () {
27304                    return this.getAttribute("minimum");
27305                }
27306            },
27307
27308            
27309            exclusiveMaximum : {
27310                get : function () {
27311                    return this.getAttribute("exclusiveMaximum");
27312                }
27313            },
27314
27315            
27316            exclusiveMinimum : {
27317                get : function () {
27318                    return this.getAttribute("exclusiveMinimum");
27319                }
27320            }
27321
27322        }
27323    };
27324
27325}(_, guidelib));
27326(function (_, guidelib) {
27327    guidelib.model.mixin.ChoiceGroupOptionHandler = {
27328        normalProperties : {
27329            
27330            _getOptionsArray : function (saveValueKey, displayValueKey) {
27331                var items = [], items1 = this.items;
27332                saveValueKey = saveValueKey || "saveValue";
27333                displayValueKey = displayValueKey || "displayValue";
27334                if (_.isArray(items1)) {
27335                    _.each(items1, function (val) {
27336                        
27337                        
27338                        var temp = val.split('='),
27339                            obj = {};
27340                        obj[saveValueKey] = temp[0];
27341                        obj[displayValueKey] = temp[1] || temp[0];
27342                        items.push(obj);
27343                    });
27344                }
27345                return items;
27346            },
27347
27348            
27349            _getPossibleValueArray : function () {
27350                var values = [], items1 = this.items;
27351                if (_.isArray(items1)) {
27352                    _.each(items1, function (val) {
27353                        
27354                        var temp = val.split('=');
27355                        values.push(temp[0]);
27356                    });
27357                }
27358                return values;
27359            },
27360
27361            
27362            _triggerItemsChange : function (oldValue, newValue) {
27363                this.trigger(guidelib.event.GuideModelEvent.ITEMS_CHANGED,
27364                    guidelib.event.GuideModelEvent.createEvent(
27365                        guidelib.event.GuideModelEvent.ITEMS_CHANGED,
27366                        this,
27367                        "items",
27368                        oldValue,
27369                        newValue
27370                    )
27371                );
27372            },
27373
27374            _resetModelValueForOptionChange : function () {
27375                if (!_.isUndefined(this.jsonModel._value) && this.jsonModel._value != null) {
27376                    var valueArr = this.jsonModel._value.split(",");
27377                    var possibleValues = this._getPossibleValueArray();
27378                    var modelValue = "";
27379                    _.each(valueArr, function (val) {
27380                        if ($.inArray(val, possibleValues, 0) !== -1) {
27381                            modelValue += val + ",";
27382                        }
27383                    }, this);
27384                    if (modelValue.length > 0) {
27385                        modelValue = modelValue.substring(0, modelValue.length - 1);
27386                    }
27387                    this.jsonModel._value = modelValue;
27388                }
27389            }
27390        }
27391    };
27392
27393}(_, guidelib));
27394
27395(function ($) {
27396    var xfaUtil = xfalib.ut.XfaUtil.prototype;
27397    $.widget("xfaWidget.imageCheckButtonWidget", $.xfaWidget.XfaCheckBox, {
27398
27399        _widgetName : "imageCheckButtonWidget",
27400
27401        getOptionsMap : function () {
27402            var parentOptionsMap = $.xfaWidget.XfaCheckBox.prototype.getOptionsMap.apply(this, arguments);
27403            return $.extend({}, parentOptionsMap, {
27404                "displayValue" : function (val) {
27405                    parentOptionsMap.displayValue.apply(this, arguments);
27406                    var rbParent = this.$userControl.parents('.guideRadioButtonItem, .guideCheckBoxItem');
27407                    if (rbParent) {
27408                        rbParent.toggleClass('imageCheckButtonChecked', this.checkedState);
27409                    }
27410                    if (this.$userControl.attr('disabled') === 'disabled') {
27411                        rbParent.addClass('imageCheckButtonDisabled');
27412                    }
27413                }
27414            });
27415        }
27416    });
27417})($);
27418(function (_, guidelib) {
27419    var GuideModelRegistry = guidelib.model.GuideModelRegistry = xfalib.ut.Class.extend({
27420
27421        _nodeClassToFactoryMap : {
27422
27423        },
27424
27425        createModel : function (jsonModel, options) {
27426            var model = null;
27427            var guideNodeClassTag = "GuideNode";
27428            if (jsonModel.guideNodeClass && jsonModel.guideNodeClass.length > 0)     {
27429                guideNodeClassTag = jsonModel.guideNodeClass.charAt(0).toUpperCase() + jsonModel.guideNodeClass.substr(1);
27430            }
27431            var factoryFnName = "create" + guideNodeClassTag ;
27432            if (jsonModel.guideNodeClass && this._nodeClassToFactoryMap[jsonModel.guideNodeClass]) {
27433                factoryFnName = this._nodeClassToFactoryMap[jsonModel.guideNodeClass];
27434            }
27435            if (this[factoryFnName]) {
27436                model = this[factoryFnName].call(this, jsonModel, options);
27437            }
27438
27439            if (!model && guidelib.model[guideNodeClassTag]) {
27440                model = new guidelib.model[guideNodeClassTag](this._getOptions(jsonModel, options));
27441            }
27442
27443            if (!model) {
27444                if (jsonModel.items) {
27445                    model = new guidelib.model.GuideItemsContainer(this._getOptions(jsonModel, options));
27446                } else {
27447                    model = new guidelib.model.GuideNode(this._getOptions(jsonModel, options));
27448                }
27449            }
27450            return model;
27451        },
27452
27453        _getOptions : function (jsonModel, options) {
27454            return _.extend({}, options, {"jsonModel" : jsonModel});
27455        },
27456
27457        createInstanceManager : function (guidePanelModel) {
27458            var name =  guidePanelModel.getAttribute("name"),
27459                imJson = {
27460                    guideNodeClass : "guideInstanceManager",
27461                    minOccur : guidePanelModel.minOccur,
27462                    maxOccur : guidePanelModel.maxOccur,
27463                    initialOccur : guidePanelModel.initialOccur,
27464                    instanceTemplateId : guidePanelModel.templateId,
27465                    name : "_" + name,
27466                    instanceName : name,
27467                    templateId : "im_" + guidePanelModel.templateId,
27468                    id : "im_" + guidePanelModel.id
27469                };
27470            var options = {};
27471            if (guidePanelModel.options._guideContainer) {
27472                options = _.extend({}, options, {"_guideContainer" : guidePanelModel.options._guideContainer});
27473            }
27474            return guidelib.model.GuideModelRegistry.prototype.createModel(imJson, options);
27475        }
27476    });
27477})(_, guidelib);
27478(function (_, $) {
27479    "use strict";
27480
27481    
27482    var isBrowserIE = xfalib.ut.XfaUtil.prototype.detectIE();
27483
27484    var _defaults = {
27485        'showLink' : false,
27486        'scrollMode' : 'vertical',
27487        textAreaClass : ".guide-tnc-content",
27488        checkBoxClass : ".guide-tnc-checkbox",
27489        checkBoxDisableClass : ".guide-tnc-checkbox-disabled",
27490        checkBoxReviewedClass : ".guide-tnc-checkbox-reviewed",
27491        linkClass     : ".guide-tnc-link",
27492        documentVisitedClass : ".guide-tnc-document-visited",
27493        documentUnVisitedClass : ".guide-tnc-document-unvisited"
27494    };
27495
27496    var _reviewStatusMap = {
27497        REVIEWED : "reviewed",
27498        UNREVIEWD : "unreviewed",
27499        AGREE : "agree"
27500    };
27501
27502    var AfTnc = function (element, options) {
27503        this.options = options;
27504        this.$element = $(element);
27505
27506        
27507        this.enters = this.leaves = 0;
27508        this.inside = false;
27509
27510        
27511        this.reviewdoc = this.status = _reviewStatusMap.UNREVIEWD;
27512
27513        
27514        this.$elementCheckBox = this.$element.find(this.options.checkBoxClass || _defaults.checkBoxClass);
27515        
27516        this.$elementTextArea = $(this.textArea());
27517        
27518        this.$elementLink =  $(this.link());
27519
27520        this.isTextContentVisible = false;
27521
27522        if (this.options.showLink) {
27523            
27524            this.$elementLink.find('a').click($.proxy(this.handleReviewStatusChange, this));
27525        } else {
27526            var setCheckBoxState = function () {
27527                if (this.hasScrollBar(this.$elementTextArea.parent().get(0))) {
27528                    
27529                    
27530                    this.$elementTextArea.parent().scroll($.proxy(this.handleReviewStatusChange, this));
27531                } else {
27532                    
27533                    if (this.$elementTextArea.css('display') !== 'none') {
27534                        this.status = _reviewStatusMap.REVIEWED;
27535                        this.isTextContentVisible = true;
27536                        
27537                        if (!this.options.showAsPopUp) {
27538                            this.enableCheckBox();
27539                        }
27540                        this.reviewDoc = this.$elementTextArea.text();
27541                    }
27542                }
27543            };
27544            
27545            
27546            if (document.readyState === "complete") { 
27547                setCheckBoxState.call(this);          
27548            } else {
27549                
27550                
27551                $($.proxy(setCheckBoxState, this));
27552            }
27553        }
27554
27555        
27556        if (this.options.showAsPopUp) {
27557            var unvisitedClass = this.options.documentUnVisitedClass || _defaults.documentUnVisitedClass,
27558                visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
27559            var _self = this,
27560                dialogId = this.$elementCheckBox.find('a')
27561                .keydown(function (e) {
27562                    if (e.keyCode === 13 || e.which == 13 || e.charCode === 32) {
27563                        $(this).click();
27564                        return false;
27565                    }
27566                })
27567                .click(function (event) {
27568                    if ($(this).hasClass(unvisitedClass.substring(1))) {
27569                        $(this).toggleClass(visitedClass.substring(1) + " " + unvisitedClass.substring(1));
27570                    }
27571                    
27572                    
27573                    if (isBrowserIE || _self.isTextContentVisible) {
27574                        _self.enableCheckBox();
27575                    }
27576                }).attr("href");
27577            
27578            $(dialogId).on('hidden.bs.modal', function (e) {
27579                _self.$elementCheckBox.find('input').focus();
27580            });
27581        } else {
27582            
27583            this._updateScreenReaderText();
27584        }
27585
27586        
27587        this.$elementCheckBox.find('input').change($.proxy(this.handleCheckBoxChange, this));
27588    };
27589
27590    AfTnc.prototype = {
27591
27592        clear : function () {
27593            this.$element.val('');
27594        },
27595
27596        destroy : function () {
27597            this.$element.val('');
27598            this.$element.empty();
27599        },
27600
27601        _updateScreenReaderText : function () {
27602            if (!this.options.showAsPopUp) {
27603                var _self = this;
27604                
27605                this.$element.find(".guide-tnc-sr-only").each(function (i, obj) {
27606                    $(this).html(_self.options.screenReaderText);
27607                });
27608            }
27609        },
27610
27611        _restoreClickState : function (value) {
27612            if (this.options.showLink) {
27613                var arr = value.split("\n"),
27614                    linkState = [];
27615                
27616                _.each(arr, function (linkText, index) {
27617                    
27618                    linkState.push(_.last(linkText.split('=')));
27619                });
27620                var unvisitedClass = this.options.documentUnVisitedClass || _defaults.documentUnVisitedClass,
27621                    visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
27622                this.$elementLink.find('a').each(function (index) {
27623                    $(this).data("clicked", linkState[index]);
27624                    if (linkState[index] === "1") {
27625                        $(this).addClass(visitedClass.substring(1));
27626                    } else {
27627                        $(this).addClass(unvisitedClass.substring(1));
27628                    }
27629                });
27630            }
27631        },
27632
27633        value : function (value) {
27634            if (value) {
27635                
27636                if (this.options.showLink) {
27637                    this._restoreClickState(value);
27638                }
27639                this.reviewDoc = value;
27640            } else {
27641                return this.reviewDoc;
27642            }
27643
27644        },
27645
27646        reviewStatus : function (value) {
27647            var val = this.getClickState();
27648            if (!_.isUndefined(value)) {
27649                if (value == "true") {
27650                    this.enableCheckBox();
27651                    this.$elementCheckBox.find('input').attr("checked", "checked");
27652                    this.$elementCheckBox.find('input').prop("checked", true);
27653                } else if (value == null || value == "false") {
27654                    
27655                    this.$elementCheckBox.find('input').removeAttr("checked");
27656                    this.$elementCheckBox.find('input').removeProp("checked");
27657                }
27658                this.approvalStatus = value;
27659            } else {
27660                if (this.status == _reviewStatusMap.REVIEWED || this.status == _reviewStatusMap.UNREVIEWD) {
27661                    return null;
27662                } else if (this.status == _reviewStatusMap.AGREE) {
27663                    return true;
27664                }
27665            }
27666        },
27667
27668        clickStatus : function (value) {
27669            if (value) {
27670                if (value === _reviewStatusMap.REVIEWED) {
27671                    var arr = this.getClickState();
27672                    if (_.isArray(arr) && arr.length > 0) {
27673                        arr = arr.join("\n");
27674                        this._restoreClickState(arr);
27675                    }
27676                    this.enableCheckBox();
27677                }
27678                this.status = value;
27679            } else {
27680                return this.status;
27681            }
27682        },
27683
27684        showLink : function (value) {
27685            if (value !== undefined) {
27686                this.options.showLink = value;
27687            } else {
27688                return this.options.showLink;
27689            }
27690        },
27691
27692        access : function (value) {
27693            this.accessOption = value;
27694            if (value == "readOnly") {
27695                this.disableCheckBox();
27696                if (this.options.showLink) {
27697                    this.$elementLink.find('a').each(function (index, elem) {
27698                        $(elem).css('pointer-events', 'none');
27699                        
27700                        $(elem).attr('disabled', 'disabled');
27701                    });
27702                }
27703            } else if (value == "open") {
27704                
27705                
27706                if ((this.status == _reviewStatusMap.REVIEWED || this.status == _reviewStatusMap.AGREE) && !this.options.showAsPopUp) {
27707                    this.enableCheckBox();
27708                }
27709                if (this.options.showLink) {
27710                    this.$element.find('a').each(function (index, elem) {
27711                        $(elem).css('pointer-events', '');
27712                        $(elem).removeAttr('disabled');
27713                    });
27714                }
27715            }
27716        },
27717
27718        link : function () {
27719            return this.$element.find(this.options.linkClass || _defaults.linkClass);
27720        },
27721
27722        textArea : function () {
27723            return this.$element.find(this.options.textAreaClass || _defaults.textAreaClass);
27724        },
27725
27726        getClickState : function () {
27727            if (this.options.showLink) {
27728                var arr = [];
27729                this.$elementLink.find('a').each(function (index) {
27730                    arr.push({
27731                        'displayText' : $(this).text(),
27732                        'linkText' : $(this).attr('href'),
27733                        'clicked' : $(this).data("clicked")
27734                    });
27735                });
27736                return arr;
27737            }
27738        },
27739
27740        enableCheckBox : function () {
27741            if (this.accessOption !== "readOnly") {
27742                this.$elementCheckBox.find('input').removeAttr("disabled");
27743                this.$elementCheckBox.removeClass(this.options.checkBoxDisableClass.substring(1));
27744            }
27745        },
27746
27747        disableCheckBox : function () {
27748            this.$elementCheckBox.find('input').attr('disabled', 'disabled');
27749            this.$elementCheckBox.addClass(this.options.checkBoxDisableClass.substring(1));
27750        },
27751
27752        handleReviewStatusChange : function (event) {
27753            var arr = [],
27754                visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
27755            if (this.options.showLink) {
27756                this.status = _reviewStatusMap.REVIEWED;
27757                
27758                $(event.target).data("clicked", 1);
27759                $(event.target).addClass(visitedClass.substring(1));
27760                this.linkStateMap = this.getClickState();
27761                _.each(this.linkStateMap, function (element, index) {
27762                    if (!element.clicked) {
27763                        this.status = _reviewStatusMap.UNREVIEWD;
27764                    }
27765                    
27766                    arr.push(element.displayText + "=" + element.linkText + "=" + (_.isUndefined(element.clicked) ? "0" : "1"));
27767                }, this);
27768                if (arr.length > 0) {
27769                    this.reviewDoc = arr.join("\n");
27770                }
27771
27772                if (this.status == _reviewStatusMap.REVIEWED) {
27773                    this.enableCheckBox();
27774                }
27775
27776                
27777                this.$element.trigger('reviewComplete.tnc');
27778
27779            } else {
27780                
27781                var position = this.getScroll(this.$elementTextArea.parent().get(0)),
27782                    xy = position[this.options.scrollMode == 'vertical' ? 'y' : 'x'];
27783                var isScrolledToEnd = this.getScrollSize(this.$elementTextArea.parent().get(0)).y <=  (this.getSize(this.$elementTextArea.parent().get(0)).y + xy);
27784                
27785                this.reviewDoc = this.$elementTextArea.text();
27786
27787                
27788                if (isScrolledToEnd) {
27789                    
27790                    if (!this.inside) {
27791                        
27792                        this.inside = true;
27793                        this.enters++;
27794                        
27795                        this.status = _reviewStatusMap.REVIEWED;
27796                        this.enableCheckBox();
27797                        
27798                        this.$element.trigger('reviewComplete.tnc', [position,this.enters,event]);
27799
27800                    }
27801                }
27802                
27803                else if (this.inside) {
27804                    this.inside = false;
27805                    this.leaves++;
27806
27807                }
27808            }
27809
27810        },
27811
27812        handleCheckBoxChange : function (event) {
27813            if ($(event.target).is(':checked')) {
27814                this.status = _reviewStatusMap.AGREE;
27815                this.$elementCheckBox.addClass(this.options.checkBoxReviewedClass.substring(1));
27816            } else {
27817                this.status = _reviewStatusMap.UNREVIEWD;
27818                this.$elementCheckBox.removeClass(this.options.checkBoxReviewedClass.substring(1));
27819            }
27820            this.$element.trigger('checkboxStateChange.tnc');
27821        },
27822
27823        getScrollSize : function (elem) {
27824            return {x : elem.scrollWidth, y : elem.scrollHeight};
27825        },
27826
27827        getScroll : function (elem) {
27828            return {x : elem.scrollLeft, y : elem.scrollTop};
27829        },
27830
27831        getSize : function (elem) {
27832            return {x : elem.offsetWidth, y : elem.offsetHeight};
27833        },
27834
27835        hasScrollBar : function (container) {
27836            
27837            if (isBrowserIE) {
27838                
27839                return ((container.scrollHeight - 2) > container.clientHeight) || ((container.scrollWidth - 2) > container.clientWidth);
27840            } else {
27841                return container.scrollHeight > container.clientHeight || container.scrollWidth > container.clientWidth;
27842            }
27843        }
27844    };
27845
27846    $.fn.afTnc = function (option, value) {
27847        var get = '',
27848            element = this.each(function () {
27849
27850                var $this = $(this),
27851                    data = $this.data('AfTnc'),
27852                    options = $.extend({}, _defaults, typeof option === 'object' && option);
27853
27854                
27855                if (!data) {
27856                    $this.data('AfTnc', (data = new AfTnc(this, options)));
27857                }
27858
27859                
27860                if (typeof option === 'string') {
27861                    get = data[option](value);
27862                }
27863            });
27864
27865        if (typeof get !== undefined) {
27866            return get;
27867        } else {
27868            return element;
27869        }
27870    };
27871
27872})(_, $);
27873(function ($) {
27874    var xfaUtil = xfalib.ut.XfaUtil.prototype;
27875    $.widget("xfaWidget.tnc", $.xfaWidget.abstractWidget, {
27876
27877        _widgetName : "tnc",
27878        _superPrototype : $.xfaWidget.abstractWidget.prototype,
27879        getOptionsMap : function () {
27880            var parentOptionsMap = this._superPrototype.getOptionsMap.apply(this, arguments),
27881                newMap = $.extend({}, parentOptionsMap, $.extend({}, this.options, {
27882                    "value" : function (value) {
27883                        this.$userControl.afTnc("value", value);
27884                    },
27885                    "reviewStatus" : function (value) {
27886                        this.$userControl.afTnc("reviewStatus", value);
27887                    },
27888
27889                    "clickStatus" : function (value) {
27890                        this.$userControl.afTnc("clickStatus", value);
27891                    },
27892                    
27893                    "access" : function (value) {
27894                        this.$userControl.afTnc("access", value);
27895                    }
27896                }));
27897            return newMap;
27898        },
27899
27900        _getReviewStatus : function () {
27901            return $(this.element).afTnc("reviewStatus");
27902        },
27903
27904        _getClickStatus : function () {
27905            return $(this.element).afTnc("clickStatus");
27906        },
27907
27908        getEventMap : function () {
27909            var parentEventMap = this._superPrototype.getEventMap.apply(this, arguments),
27910                newMap = $.extend({}, parentEventMap,
27911                    {
27912                        "change" : null,
27913                        "reviewComplete.tnc" : xfaUtil.XFA_CHANGE_EVENT,
27914                        "checkboxStateChange.tnc" : xfaUtil.XFA_CHANGE_EVENT
27915                    });
27916            return newMap;
27917        },
27918        render : function () {
27919            this._superPrototype.render.apply(this, arguments);
27920            $(this.element).afTnc(this.getOptionsMap());
27921            return $(this.element);
27922        },
27923        showDisplayValue : function () {
27924            
27925        },
27926        showValue : function () {
27927            
27928        },
27929        getCommitValue : function () {
27930            this.options.reviewStatus = this._getReviewStatus();
27931            this.options.clickStatus = this._getClickStatus();
27932            return $(this.element).afTnc("value");
27933        }
27934    });
27935})($);
27936
27937(function (_, guidelib) {
27938    var orderGetAttribute = {
27939        "Guide" : "XFA",
27940        "XFA" : "Guide"
27941    },
27942    
27943    newlyAddedProperties = ["enabled", "visible"];
27944    
27945    var GuideNode = guidelib.model.GuideNode = xfalib.ut.EventClass.extend({
27946        msClassName : "guideNode",
27947        guideUtil : guidelib.util.GuideUtil,
27948
27949        initialize : function () {
27950            
27951            
27952            this.className = this.jsonModel.guideNodeClass || this.msClassName;
27953            this.parent = null;
27954            this._isItem = false;
27955            this._index = 0;
27956        },
27957
27958        _postInitialize : function () {
27959            
27960        },
27961
27962        _triggerOnBridge : function (eventName, target, property, oldVal, newVal) {
27963            if (window.guideBridge) {
27964                window.guideBridge.trigger(eventName,
27965                    guidelib.event.GuideModelEvent.createEvent(eventName, target, property,
27966                                                           oldVal, newVal));
27967            }
27968        },
27969
27970        _getEffectiveBindRef : function() {
27971            return this.bindRef || this.getAttribute("name");
27972        },
27973
27974        validate : function (errorList) {
27975
27976        },
27977
27978        
27979        
27980        _getXFAOptionStringFromGuideItems : function (guideItems) {
27981            var optionsStr = "", indexOfSeparator = 0;
27982            if (!_.isEmpty(guideItems) && !_.isArray(guideItems)) {
27983                guideItems = [guideItems];
27984            }
27985            _.each(guideItems, function (item, index, list) {
27986                if(item.indexOf(",") > -1){
27987                    item = item.replace(/,/g, "\\,");
27988                }
27989                indexOfSeparator = item.indexOf('=');
27990                
27991                
27992                if (indexOfSeparator > -1) {
27993                    optionsStr += item.substring(indexOfSeparator + 1) + "," + item.substring(0, indexOfSeparator);
27994                } else {
27995                    optionsStr += item + "," + item;
27996                }
27997                if (index < guideItems.length - 1) {
27998                    optionsStr += ",";
27999                }
28000            });
28001            return optionsStr;
28002        },
28003
28004        _compareXFAItemsWithGuideItems : function (xfaItems, guideItems) {
28005            var match = true;
28006            if (xfaItems.length !== guideItems.length) {
28007                match = false;
28008            }
28009            if (match) {
28010                var bndNode = this.bindNode;
28011                _.each(guideItems, function (item, index, list) {
28012                    if (item.indexOf('=') > -1) {
28013                        if ((bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index)) == item) {
28014                            match = false;
28015                        }
28016                    } else {
28017                        if ((bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index)) == (item + "=" + item)) {
28018                            match = false;
28019                        }
28020                    }
28021                });
28022            }
28023            return match;
28024        },
28025
28026        
28027        syncXFAProps : function () {
28028            if (this.bindNode) {
28029                _.each(this._guide()._guideSchema.getAttributes(this.className),
28030                    function (attr, attrName) {
28031                        var xfaProp = attr.xfaProp,
28032                            propChain = (xfaProp || "").split("."),
28033                            xfaAttr = propChain.length > 0 ? propChain[propChain.length - 1]
28034                                                           : undefined;
28035                        
28036                        
28037                        
28038                        
28039                        
28040                        
28041                        if (!xfaAttr || (newlyAddedProperties.indexOf(attrName) != -1 && _.isUndefined(this.jsonModel[attrName]))) {
28042                            return;
28043                        }
28044                        var objChain = propChain.splice(0, propChain.length - 1),
28045                            obj = _.reduce(objChain,
28046                                function (obj, prop) {
28047                                    if (_.isObject(obj)) {
28048                                        return obj[prop];
28049                                    }
28050                                    return undefined;
28051                                }, this.bindNode),
28052                            val = this.getGuideProp(attrName, attr),
28053                            convertor = this._guide()._guideSchema.getConvertor(attrName),
28054                            cVal = convertor ? convertor.guideToXfa.apply(this, [val]) : val,
28055                            xfaVal;
28056                        try {
28057                            if (obj) {
28058                                xfaVal = obj[xfaAttr];
28059                                if (cVal !== undefined) {
28060                                    if (xfaAttr === "items") {
28061                                        var match = this._compareXFAItemsWithGuideItems(obj, cVal);
28062                                        var SET_ITEMS_INSERT_MODE_PAIR = 2;
28063                                        if (!match) {
28064                                            var optionsStr = this._getXFAOptionStringFromGuideItems(cVal);
28065                                            if (optionsStr !== "") {
28066                                                obj.setItems(optionsStr, SET_ITEMS_INSERT_MODE_PAIR);
28067                                            } else {
28068                                                obj.clearItems();
28069                                            }
28070                                        }
28071                                    } else if (cVal !== xfaVal) {
28072                                        obj[xfaAttr] = cVal;
28073                                    }
28074                                }
28075                            }
28076                        } catch (e) {
28077                            this.logger().error("AF", "setting {0}(guide {1}) for {2} is not supported in xfa",
28078                                [xfaProp, attrName, this.bindNode.somExpression]);
28079                            if (e.stack) {
28080                                this.logger().error("AF", e.stack);
28081                            }
28082                        }
28083                    }, this);
28084            }
28085        },
28086
28087        
28088        prepare : function () {
28089
28090        },
28091
28092        
28093        nakedChildReferences : function (nIndex, obj) {
28094            return;
28095        },
28096
28097        
28098        getNaked : function (nIndex, container, scope) {
28099            var nodeName = this.getAttribute("name"),
28100                oldReference = container._private["_" + nodeName + "_"],
28101                canOverride = (container._isOverriden && !container._isOverriden["_" + nodeName + "_"]),
28102                isGlobalFieldRef = this.isGlobal && (container === guidelib.__runtime__ || container === this._guide().runtime) 
28103                    && (container[nodeName] instanceof guidelib.model.AbstractField);
28104
28105            if ((scope && scope._nameArray[nodeName] === 1) || (nIndex === this.index)) {
28106                if (oldReference === null || oldReference === undefined || canOverride || isGlobalFieldRef) {
28107                    guidelib.util.GuideUtil._createGetterSetter(container, nodeName, this);
28108                    if (canOverride === true) {
28109                        container._isOverriden["_" + nodeName + "_"] = true;
28110                    }
28111                }
28112            }
28113        },
28114
28115        _getReducedJSON : function () {
28116            var whitelistedProperties = ["name", "templateId", "_value", "guideNodeClass"],
28117                reducedJsonObject = {};
28118            guidelib.model.util.CommonUtils.returnMinimalJSON(whitelistedProperties, reducedJsonObject, this);
28119            return reducedJsonObject;
28120        },
28121
28122        _getNakedThis : function () {
28123            return this;
28124        },
28125
28126        _xfa : function () {
28127            if (window.xfalib) {
28128                return window.xfalib.runtime.xfa;
28129            }
28130            return null;
28131        },
28132
28133        _guide : function () {
28134            return this.options._guideContainer;
28135        },
28136
28137        
28138        playJson : function (pJsonModel) {
28139
28140        },
28141
28142        
28143        
28144        visit : function (callback, context) {
28145            callback.apply(context, [this]);
28146        },
28147
28148        _collectValues : function (keyValue) {
28149
28150        },
28151
28152        _setParentAccess : function (value) {
28153            
28154        },
28155
28156        _unloadModel : function () {
28157            this.trigger(guidelib.event.GuideModelEvent.OBJECT_DESTROYED,
28158                guidelib.event.GuideModelEvent.createEvent(
28159                    guidelib.event.GuideModelEvent.OBJECT_DESTROYED,
28160                    this,
28161                    "destroy",
28162                    null,
28163                    this
28164                )
28165            );
28166            this._guide()._modelTemplateCacheStore.removeModel(this.id);
28167            this.off();
28168
28169            if (_.isObject(guidelib.__runtime__[this.name]) && (guidelib.__runtime__[this.name] === this || guidelib.__runtime__[this.name].somExpression === this.somExpression)) {
28170                guidelib.__runtime__[this.name] = undefined;
28171                if (_.isObject(guidelib.__runtime__._private['_' + this.name + '_'])) {
28172                    guidelib.__runtime__._private['_' + this.name + '_'] = undefined;
28173                }
28174            }
28175
28176            if (_.isObject(this._guide().runtime[this.name]) && (this._guide().runtime[this.name] === this || this._guide().runtime[this.name].somExpression === this.somExpression)) {
28177                this._guide().runtime[this.name] = undefined;
28178                if (_.isObject(this._guide().runtime._private['_' + this.name + '_'])) {
28179                    this._guide().runtime._private['_' + this.name + '_'] = undefined;
28180                }
28181            }
28182        },
28183
28184        _triggerEvent : function (event, propName, prevText, newText) {
28185            this.trigger(event,
28186                guidelib.event.GuideModelEvent.createEvent(event, this, propName,
28187                                                           prevText, newText));
28188        },
28189
28190        
28191        dispatchEvent : function (eventName, payload) {
28192            this._triggerEvent(eventName, payload);
28193            if(this.parent !== null){
28194                this.parent.dispatchEvent(eventName, payload);
28195            }
28196        },
28197
28198        
28199        setAttribute : function (value, attrName) {
28200            if (this.jsonModel[attrName] !== value) { 
28201                var oldValue = this.jsonModel[attrName];
28202                this.jsonModel[attrName] = value;
28203                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, attrName, oldValue, value);
28204            }
28205        },
28206
28207        _getSomExpression : function () {
28208            if (this.parent == null) {
28209                return "guide[0]." + this._escapeQualifiedName();
28210            } else {
28211                return this.parent.somExpression + "." + this._escapeQualifiedName();
28212            }
28213        },
28214
28215        _escapeQualifiedName : function () {
28216            var name = this.getAttribute("name");
28217            var index = this._index;
28218            var qname = name + "[" + index + "]";
28219            return qname.replace(/\./, "\\.");
28220        },
28221
28222        
28223        getGuideProp : function (attrName, attr) {
28224            var val = this.getOrElse(this.jsonModel, attrName, attr["default"]);
28225            if (val === undefined) {
28226                return undefined;
28227            }
28228            return guidelib.model.GuideSchema.prototype.getTypedValue(attr.type, val);
28229            
28230        },
28231
28232        
28233        getXFAProp : function (attrName, attr) {
28234            var xfaName = attr.xfaProp,
28235                convertor = guidelib.model.GuideSchema.prototype.getConvertor(attrName),
28236                val;
28237            if (this.bindNode && xfaName !== undefined) {
28238                val = this.bindNode.getOrElse(this.bindNode, xfaName, undefined);
28239                if (convertor) {
28240                    val = convertor.xfaToGuide.apply(this, [val]);
28241                }
28242                if (val !== undefined) {
28243                    return val;
28244                }
28245            }
28246            return undefined;
28247        },
28248
28249        
28250        getAttribute : function (attrName) {
28251            var attr = guidelib.model.GuideSchema.prototype.getAttributeProps(this.className, attrName),
28252                priority = attr.priority || (attr.xfaProp !== undefined ? "XFA" : "Guide"), 
28253                                                  
28254                val = this["get" + priority + "Prop"].apply(this, [attrName, attr]); 
28255            
28256            if (val === undefined) {
28257                
28258                val = this["get" + orderGetAttribute[priority] + "Prop"].apply(this, [attrName, attr]);
28259            }
28260            return val;
28261        },
28262
28263        
28264        resetData : function () {
28265
28266        }
28267    });
28268
28269    GuideNode.defineProps({
28270
28271        
28272        "name" : {
28273            get : function () {
28274                return (this.getAttribute("name") || "").replace(/\s+/g, '');
28275            }
28276        },
28277
28278        "templateId" : {
28279            get : function () {
28280                return this.getAttribute("templateId");
28281            }
28282        },
28283
28284        
28285        "id" : {
28286            get : function () {
28287                return this.getAttribute("id") || this.templateId;
28288            }
28289        },
28290
28291        
28292        somExpression : {
28293            get : function () {
28294                return this._getSomExpression();
28295            }
28296        },
28297
28298        
28299        "title" : {
28300            get : function () {
28301                return this.getAttribute("jcr:title");
28302            }
28303        },
28304
28305        
28306        "nonLocalizedTitle" : {
28307            get : function () {
28308                return this.getAttribute("nonLocalizedTitle");
28309            }
28310        },
28311
28312        
28313        panel : {
28314            get : function () {
28315                return this.parent.panel;
28316            }
28317        },
28318
28319        viewVisited : {
28320            get : function () {
28321                return this.getAttribute("viewVisited");
28322            },
28323            set : function (visit) {
28324                this.setAttribute(visit, "viewVisited");
28325            }
28326        },
28327
28328        
28329        index : {
28330            get : function () {
28331                return this._index;
28332            }
28333        },
28334
28335        
28336        visible : {
28337            get : function () {
28338                return true;
28339            },
28340            set : function (value) {
28341                
28342            }
28343        },
28344
28345        
28346        enabled : {
28347            get : function () {
28348                return true;
28349            },
28350            set : function (value) {
28351                
28352            }
28353        },
28354
28355        
28356        cssClassName : {
28357            get : function () {
28358                return this.getAttribute("css");
28359            }
28360        },
28361
28362        enableLayoutOptimization : {
28363            get : function () {
28364                return false;
28365            }
28366        },
28367
28368        jcrPath : {
28369            get : function () {
28370                return this.jsonModel["jcr:path"];
28371            }
28372        },
28373
28374        
28375        targetVersion : {
28376            get : function () {
28377                return this.getAttribute("fd:targetVersion");
28378            }
28379        }
28380    });
28381}(_, guidelib));
28382(function (_, guidelib) {
28383    var Esign = guidelib.model.Esign = guidelib.model.GuideNode.extend({
28384        msClassName : "esign",
28385
28386        initialize : function () {
28387            Esign._super.initialize.call(this);
28388            this.validationStatus = true;
28389        },
28390
28391        validate : function (errorList) {
28392            
28393            
28394            var validationStatus =  true;
28395            if (FD.AFaddon.Signing !== undefined && FD.AFaddon.Signing !== null) {
28396                validationStatus = FD.AFaddon.Signing.isDocumentSigned(this.jsonModel.signingService);
28397                if (!validationStatus) {
28398                    errorList.push({som : this.somExpression, errorText : "Signing not complete."});
28399                }
28400            }
28401
28402            this.validationStatus = validationStatus;
28403            return validationStatus;
28404        }
28405    });
28406    Esign.defineProps({
28407        forceElementFocusChange : {
28408            get : function () {
28409                return true;
28410            }
28411        }
28412    });
28413})(_, guidelib);
28414(function (_, guidelib, $) {
28415    var Verify = guidelib.model.Verify = guidelib.model.GuideNode.extend({
28416        msClassName : "verify",
28417
28418        initialize : function () {
28419            Verify._super.initialize.call(this);
28420            this.validationStatus = true;
28421        },
28422
28423        validate : function (errorList) {
28424            
28425
28426            var iframeFormBridge = null, validationStatus = true;
28427
28428            if (this.jsonModel.interactive !== undefined && this.jsonModel.interactive === "true") {
28429                
28430                
28431                
28432                
28433                
28434                if (guideBridge.hostName === "client") {
28435                    iframeFormBridge = $('#verifiable_form').get(0).contentWindow.formBridge;
28436                }
28437                
28438                
28439                if (iframeFormBridge !== undefined && iframeFormBridge !== null) {
28440                    validationStatus = iframeFormBridge.validateForm();
28441                    if (!validationStatus) {
28442                        errorList.push({som : this.somExpression, errorText : "XFA validation errors."});
28443                    }
28444                    this.validationStatus = validationStatus;
28445                }
28446            }
28447
28448            return validationStatus;
28449        }
28450    });
28451    Verify.defineProps({
28452        forceElementFocusChange : {
28453            get : function () {
28454                return true;
28455            }
28456        }
28457    });
28458})(_, guidelib, $);
28459(function (_, xfalib, guidelib) {
28460    
28461    var expressionContent = "with(this) {" +
28462                        "\n\t with(guidelib.__runtime__) {" +
28463                        "\n\t with(this._guide().runtime) {" +
28464                        "\n\t\t var _guide_result = this[${affectedProp}] = eval(\"${expression}\");" +
28465                        "\n\t\t return _guide_result ;" +
28466                        "\n\t }" +
28467                        "\n}};",
28468        scriptContent = "with(this) {" +
28469                        "\n\t with(guidelib.__runtime__) {" +
28470                        "\n\t with(this._guide().runtime) {" +
28471                        "\n\t var result = eval(\"${expression}\");" +
28472                        "\n\t\t return result; " +
28473                        "\n\t }" +
28474                        "\n}}";
28475    
28476    var Scriptable = guidelib.model.Scriptable = guidelib.model.GuideNode.extend({
28477        msClassName : "scriptable",
28478
28479        initialize : function () {
28480            Scriptable._super.initialize.call(this);
28481            
28482            this.className = this.jsonModel.guideNodeClass || this.msClassName;
28483            this._compiledExpressions = {};
28484            this._compiledScripts = {};
28485            this.mActiveEvents = [];
28486            this.dependants = [];
28487            
28488            if (this.initScript) {
28489                this._isInitScriptExecuted = false;
28490            }
28491            this._collectExpressions();
28492        },
28493
28494        _postInitialize : function () {
28495            
28496            if (this._isXfaNode()) {
28497                this.bindNode = this.options.bindNode || this._getBindNode();
28498                if (this.bindNode) {
28499                    this.bindNode.on(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
28500                }
28501            }
28502            
28503            this._parentAccess = this.getOrElse(this, "parent.enabled", true);
28504        },
28505
28506        _unloadModel : function () {
28507            if (this._isXfaNode && this._isXfaNode()) {
28508                if (this.bindNode) {
28509                    this.bindNode.off(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
28510                }
28511            }
28512
28513            Scriptable._super._unloadModel.call(this);
28514        },
28515
28516        _collectExpressions : function () {
28517            if (this.visibleExp) {
28518                this._compiledExpressions["visibleExp"] = this._compileExpression(this.visibleExp, "visible");
28519            }
28520            if (this.enabledExp) {
28521                this._compiledExpressions["enabledExp"] = this._compileExpression(this.enabledExp, "enabled");
28522            }
28523            
28524            if (this.initScript) {
28525                this._compiledScripts.initScript = this._compileExpression(this.initScript, null);
28526            }
28527        },
28528
28529        _compileExpression : function (expression, affectedProp) {
28530            if (expression) {
28531                try {
28532                    
28533                    var content = affectedProp ? expressionContent.replace(/\${affectedProp}/g, '"' + affectedProp + '"')
28534                                                                  .replace(/\${expression}/g, expression.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/(?:\r\n|\r|\n)/g, " "))
28535                                               : scriptContent.replace(/\${expression}/g,
28536                                                                        expression.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/(?:\r\n|\r|\n)/g, " "));
28537
28538                    return new Function(content);
28539                } catch (exception) {
28540                    this.logger().error("AF", "Error in compiling expression:" + expression);
28541                }
28542            }
28543            return null;
28544        },
28545
28546        _isXfaNode : function () {
28547            return (this._xfa() && this.getOrElse(this, "jsonModel.bindRef", "").indexOf("xfa[0].form[0].") === 0);
28548        },
28549
28550        _xfa : function () {
28551            return this.getOrElse(window, "xfalib.runtime.xfa", null);
28552        },
28553
28554        prepare : function () {
28555            Scriptable._super.prepare.apply(this);
28556            
28557            
28558            
28559            
28560            
28561            if (this.initScript && !this._isInitScriptExecuted) {
28562                this.executeExpression("initScript");
28563                this._isInitScriptExecuted = true;
28564            }
28565            var expressionTypes = _.keys(this._compiledExpressions);
28566            this._guide().queueExpressions(this, expressionTypes);
28567        },
28568
28569        
28570        handleEvent : function (evnt) {
28571            if (evnt instanceof xfalib.script.XfaModelEvent) {  
28572                switch (evnt.name) {
28573                    case xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED:
28574                        this._handleXfaModelChanged(evnt);
28575                        break;
28576                    default:
28577                    
28578                }
28579            } else if (evnt instanceof guidelib.event.GuideModelEvent) {
28580                this.handleGuideEvent(evnt);
28581            }
28582        },
28583
28584        handleGuideEvent : function (evnt) {
28585        },
28586
28587        
28588        executeExpression : function (eventName, detail) {
28589            var guideContainerNode = this._guide();
28590            if (this._isXfaNode() && this.bindNode instanceof xfalib.script.EventContainerNode) {
28591                if (guidelib.util.GuideUtil.xfaExprMap[eventName] !== null) {
28592                    this.bindNode.execEvent(guidelib.util.GuideUtil.xfaExprMap[eventName] || eventName, detail);
28593                }
28594            }
28595            if (_.isUndefined(this._compiledExpressions[eventName]) && _.isUndefined(this._compiledScripts[eventName])) {
28596                if (!guideContainerNode._currentContext) {
28597                    guideContainerNode.runPendingExpressions();
28598                } else {
28599                    this.logger().log("AF", "executeExpression called withing from another executeExpression. Should NEVER happen ");
28600                }
28601                return true;
28602            }
28603
28604            if (this.mActiveEvents[eventName]) {
28605                return;
28606            }
28607            this.mActiveEvents[eventName] = true;
28608            var managedExp = this._compiledExpressions[eventName] ? true : false,
28609                oldContext = guideContainerNode._currentContext;
28610            
28611            guideContainerNode._currentContext = {contextNode : this, expression : eventName, managedExp : managedExp};
28612            this._setExpressionContext(this, this.index);
28613            var $event = {
28614                name : eventName,
28615                target : this,
28616                data : detail
28617            };
28618            guideContainerNode.runtime.$event = $event;
28619            var expResult = this._expressionHandler(eventName);
28620            this.mActiveEvents[eventName] = false;
28621            
28622            
28623            guideContainerNode._currentContext = oldContext;
28624            if (oldContext && oldContext.contextNode) {
28625                oldContext.contextNode._setExpressionContext(oldContext.contextNode, oldContext.contextNode.index);
28626            }
28627            guideContainerNode.runtime.$event = null;
28628            guideContainerNode.runPendingExpressions();
28629            return expResult;
28630        },
28631
28632        _setExpressionContext : function (startNode, currentIndex) {
28633            
28634            var currentSom = this.somExpression;
28635            function somCommonPrefixLen(field) {
28636                return guidelib.util.GuideUtil.commonPrefixLen(currentSom, field.somExpression);
28637            }
28638
28639            if (this._guide().internal.liveModel) {
28640                _.each(this._guide().internal.liveModel.getCrossFragmentFields(), function (fields, name) {
28641                    var loadedFields,
28642                        nearestField;
28643
28644                    
28645                    loadedFields = this._guide().internal.liveModel.getAllFieldModels(_.keys(fields));
28646
28647                    
28648                    if (!_.isEmpty(loadedFields)) {
28649                        nearestField = _.max(loadedFields, somCommonPrefixLen);
28650                    }
28651
28652                    
28653                    
28654
28655                    
28656                    guidelib.util.GuideUtil._createGetterSetter(guidelib.__runtime__, name, nearestField || fields[_.keys(fields)[0]]);
28657                    guidelib.util.GuideUtil._createGetterSetter(this._guide().runtime, name, nearestField || fields[_.keys(fields)[0]]);
28658                }, this);
28659            }
28660
28661            
28662            this._guide().runtime._isOverriden = {};
28663            guidelib.__runtime__._isOverriden = {};
28664            while (startNode) {
28665                
28666                startNode.nakedChildReferences(currentIndex, guidelib.__runtime__);
28667                startNode.nakedChildReferences(currentIndex, this._guide().runtime);
28668                currentIndex = startNode.index;
28669                startNode = startNode.parent;
28670            }
28671        },
28672
28673        _expressionHandler : function (expressionName) {
28674            var expFn, returnValue;
28675            if (this._compiledExpressions[expressionName]) {
28676                expFn = this._compiledExpressions[expressionName];
28677                try {
28678                    returnValue = expFn.apply(this);
28679                } catch (exception) {
28680                    
28681                    this.logger().error("AF", "Error in compiling expression:" + this.name + ":" + expressionName + ":" + exception.stack);
28682                }
28683            } else if (this._compiledScripts[expressionName]) {
28684                expFn = this._compiledScripts[expressionName];
28685                try {
28686                    return expFn.apply(this);
28687                } catch (scriptException) {
28688                    
28689                    this.logger().error("AF", "Error in compiling expression:" + this.name + ":" + expressionName + ":" + scriptException.stack);
28690                }
28691            }
28692            return returnValue;
28693        },
28694
28695        _handleXfaModelChanged : function (event) {
28696            if (event._property == "presence") {
28697                
28698                var newText = !(event.newText != "visible");
28699                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "visible", event.prevText, newText);
28700            } else if (event._property == "access") {
28701                this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
28702                    guidelib.event.GuideModelEvent.createEvent(
28703                        guidelib.event.GuideModelEvent.MODEL_CHANGED,
28704                        this,
28705                        "enabled",
28706                        event.prevText == "open",
28707                        event.newText == "open"
28708                    )
28709                );
28710            }
28711        },
28712
28713        _getScreenReaderText : function (index) {
28714            var screenReaderText, assistPriority = this._getAssistPriority();
28715            if (assistPriority == "custom") {
28716                screenReaderText = this._getCustomAssist(index) || this._getToolTip(index) || this._getCaption(index) || this._getName(index);
28717            } else if (assistPriority == "shortDescription") {
28718                screenReaderText = this._getToolTip(index) || this._getCaption(index) || this._getName(index);
28719            } else if (assistPriority == "label") {
28720                screenReaderText = this._getCaption(index) || this._getName(index);
28721            } else if (assistPriority == "name") {
28722                screenReaderText = this._getName(index);
28723            }
28724            return screenReaderText;
28725        },
28726
28727        _getAssistPriority : function () {
28728            
28729            return this.getAttribute("assistPriority") || "custom";
28730        },
28731
28732        _getCustomAssist : function () {
28733            var customAssist;
28734            if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
28735                customAssist = this.bindNode.assist.speak.value;
28736            } else if (this.jsonModel.custom) {
28737                customAssist = this.jsonModel.custom;
28738            }
28739            return customAssist;
28740        },
28741
28742        _getToolTip : function () {
28743            return this.shortDescription;
28744        },
28745
28746        _getCaption : function () {
28747            return this.getAttribute("jcr:title");
28748        },
28749
28750        _getName : function (index) {
28751            return this.getAttribute("name");
28752        },
28753
28754        _getBindNode : function () {
28755            var bindRef = this.getAttribute("bindRef");
28756            if (!bindRef) {
28757                return null;
28758            }
28759            var bindNode = null;
28760            var bindParent = this.parent ? this.parent._bindParent() : null;
28761            if (bindParent) {
28762                var bindParentRef = bindParent.getAttribute("bindRef");
28763                if (bindRef.substring(0, bindParentRef.length) == bindParentRef) {
28764                    
28765                    
28766                    var relativeBindRef = bindRef.substring(bindParentRef.length + 1); 
28767                    bindNode = bindParent.bindNode.resolveNode(relativeBindRef);
28768                }
28769            }
28770            if (!bindNode && this._isXfaNode()) {
28771                bindNode = this._xfa().resolveNode(bindRef);
28772            }
28773            return bindNode;
28774        },
28775
28776        _bindParent : function () {
28777            if (this.bindNode) {
28778                return this;
28779            } else if (this.parent) {
28780                return this.parent._bindParent();
28781            }
28782            return null;
28783        },
28784
28785        
28786        _getEnabled : function () {
28787            if (this.bindNode) {
28788                return this.bindNode.access == "open";
28789            } else {
28790                return this.getAttribute("enabled") && this._parentAccess;
28791            }
28792        },
28793
28794        
28795        _setEnabled : function (value) {
28796            if (!this.bindNode) {
28797                if (this.getAttribute("enabled") !== value) {
28798                    var oldEnabled = this.getAttribute("enabled");
28799                    this.setAttribute(value, "enabled");
28800                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
28801                        guidelib.event.GuideModelEvent.createEvent(
28802                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
28803                            this,
28804                            "enabled",
28805                            oldEnabled,
28806                            this.jsonModel.enabled
28807                        )
28808                    );
28809                    this._triggerOnBridge("elementEnableChanged", this, "enablement", oldEnabled, this.jsonModel.enabled);
28810                }
28811
28812            } else {
28813                var convertor = this._guide()._guideSchema.getConvertor("enabled");
28814                if (convertor) {
28815                    this.bindNode.access =  convertor.guideToXfa.apply(this, [value]);
28816                }
28817            }
28818        },
28819
28820        
28821        _setParentAccess : function (value) {
28822            var oldValue = this._parentAccess;
28823            this._parentAccess = value;
28824            this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
28825                guidelib.event.GuideModelEvent.createEvent(
28826                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
28827                    this,
28828                    "enabled",
28829                    oldValue,
28830                    this.enabled
28831                )
28832            );
28833        },
28834
28835        
28836        _addStateOverride : function (key, values) {
28837            if (key !== null && _.isString(key) && values !== null) {
28838                var somExpr = this.somExpression;
28839                somExpr = somExpr.substring(this._guide().somExpression.length + 1);
28840                this.jsonModel.stateOverrides = this.jsonModel.stateOverrides || {"somExpr" : somExpr};
28841                this.jsonModel.stateOverrides[key] = values;
28842                this._guide()._addToStateOverrideMap(this.id + this.name, this.jsonModel.stateOverrides);
28843            }
28844        }
28845    });
28846
28847    Scriptable.defineProps({
28848        
28849        shortDescription : {
28850            get : function () {
28851               return this.getAttribute("shortDescription");
28852           }
28853        },
28854
28855        
28856        longDescription : {
28857            get : function () {
28858                return this.getAttribute("longDescription");
28859            }
28860        },
28861
28862        visibleExp : {
28863            get : function () {
28864                return this.getAttribute("visibleExp");
28865            }
28866        },
28867
28868        initScript : {
28869            get : function () {
28870                return this.jsonModel.initScript;
28871            }
28872        },
28873
28874        enabledExp : {
28875            get : function () {
28876                return this.getAttribute("enabledExp");
28877            }
28878        },
28879
28880        
28881        visible : {
28882            get : function () {
28883                return this.getAttribute("visible");
28884            },
28885
28886            set : function (value) {
28887                if (!this.bindNode) {
28888                    if (this.getAttribute("visible") !== value) {
28889                        var oldVisible = this.getAttribute("visible"),
28890                            dorExclusionFlag;
28891                        this.setAttribute(value, "visible");
28892                        
28893                        
28894                        if (this.getAttribute("dorExclusion") !== null) {
28895                            if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true") 
28896                                || (this._guide().print
28897                                && this._guide().print["excludeFromDoRIfHidden"] === "true")) {
28898                                dorExclusionFlag = !value;
28899                                
28900                                
28901                                this.dorExclusion = dorExclusionFlag;
28902                            }
28903                        }
28904                        this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
28905                            guidelib.event.GuideModelEvent.createEvent(
28906                                guidelib.event.GuideModelEvent.MODEL_CHANGED,
28907                                this,
28908                                "visible",
28909                                oldVisible,
28910                                this.jsonModel.visible
28911                            )
28912                        );
28913                        this._triggerOnBridge("elementVisibleChanged", this, "visible", oldVisible, this.jsonModel.visible);
28914
28915                    }
28916                } else {
28917                    if (value == true) {
28918                        this.bindNode.presence = "visible";
28919                    } else {
28920                        this.bindNode.presence = "hidden";
28921                    }
28922                }
28923            }
28924        },
28925
28926        
28927        dorExclusion : {
28928            get : function () {
28929                
28930                if (this.jsonModel.dorExclusion != null) {
28931                    if (_.isString(this.jsonModel.dorExclusion)) {
28932                        
28933                        return this.jsonModel.dorExclusion === "true";
28934                    } else {
28935                        return this.jsonModel.dorExclusion;
28936                    }
28937                }
28938                
28939                else if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true") 
28940                    || (this._guide().print
28941                    && this._guide().print["excludeFromDoRIfHidden"] === "true")) {
28942                    return !this.visible;
28943                } else {
28944                    
28945                    return false;
28946                }
28947            },
28948
28949            set : function (value) {
28950                
28951                
28952                
28953                var somExpr = this.somExpression;
28954                somExpr = somExpr.substring(this._guide().somExpression.length + 1);
28955                this._guide()._addToExcludeFromDorMap(somExpr, value);
28956                this.jsonModel.dorExclusion = value;
28957            }
28958        },
28959
28960        
28961        stateOverrides : {
28962            get : function () {
28963                return this.jsonModel.stateOverrides;
28964            }
28965        },
28966
28967        
28968        enabled : {
28969            get : function () {
28970                return this._getEnabled();
28971            },
28972
28973            set : function (value) {
28974                
28975                this._setEnabled(!!value);
28976            }
28977        },
28978
28979        
28980        bindRef : {
28981            get : function () {
28982                return (this.getAttribute("bindRef") || "").replace(/\s+/g, '');
28983            }
28984        },
28985
28986        
28987        isXsd : {
28988            
28989            get : function () {
28990                return _.isString(guideBridge._guide.xsdRef) && !_.isEmpty(this.bindRef) && this.bindRef[0] === '/';
28991            }
28992        }
28993    });
28994})(_, window.xfalib, guidelib);
28995(function (_, guidelib) {
28996    var GuideImage = guidelib.model.GuideImage = guidelib.model.Scriptable.extend({
28997        msClassName : "guideImage"
28998    });
28999
29000    GuideImage.defineProps({
29001        value : {
29002            get : function () {
29003                if (this.bindNode) {
29004                    return this.bindNode.rawValue;
29005                } else {
29006                    return null;
29007                }
29008            }
29009        }
29010    });
29011})(_, guidelib);
29012(function (_, guidelib) {
29013    var GuideAdModule = guidelib.model.GuideAdModule = guidelib.model.Scriptable.extend({
29014        msClassName : "guideAdModule",
29015
29016        initialize : function () {
29017            GuideAdModule._super.initialize.call(this);
29018            this.jsonModel["{default}"] = this.getOrElse(this.jsonModel, "{default}", this.jsonModel._value);
29019            this.layoutConfigs = [];
29020            
29021            if (typeof this.jsonModel.layoutConfig === "string") {
29022                this.layoutConfigs.push(JSON.parse(this.jsonModel.layoutConfig));
29023            } else {
29024                _.each(this.jsonModel.layoutConfig, function (layoutConfig) {
29025                    this.layoutConfigs.push(JSON.parse(layoutConfig));
29026                }, this);
29027            }
29028        },
29029
29030        _getTypedValue : function (value) {
29031            if (_.isUndefined(value) || value === null || value === "") {
29032                return null;
29033            }
29034            return value + "";
29035        },
29036
29037        playJson : function (pJsonModel) {
29038            var olval = this.jsonModel._value;
29039            this.jsonModel._value = pJsonModel._value;
29040            this._triggerOnBridge("elementValueChanged", this, "value", olval, this.jsonModel._value);
29041        }
29042    });
29043
29044    GuideAdModule.defineProps({
29045        
29046        value : {
29047            get : function () {
29048                return this._getTypedValue(this.jsonModel._value);
29049            },
29050            set : function (newValue) {
29051                var oldValue = this._getTypedValue(this.jsonModel._value),
29052                    newTypedValue = this._getTypedValue(newValue);
29053                
29054                if (newTypedValue !== undefined && (newTypedValue !== oldValue)) {
29055                    if (this.jsonModel._value !== newValue) {
29056                        this.jsonModel._value = newTypedValue || "";
29057                    }
29058                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
29059                }
29060            }
29061        }
29062    });
29063}(_, guidelib));
29064(function (_, $) {
29065
29066    var Responsive = {
29067        breakpoints : [],
29068        controlRowDefaults : {}
29069    },
29070    isPad = navigator.userAgent.match(/iPad/i) !== null,
29071    isIphone = (navigator.userAgent.match(/iPhone/i) !== null) || (navigator.userAgent.match(/iPod/i) !== null),
29072    isIphoneOrIpad = isPad || isIphone;
29073    
29074    Responsive.breakpoints = [
29075        {
29076            name : 'desktop',
29077            width : Infinity
29078        },
29079        {
29080            name : 'tablet-landscape',
29081            width : 1024
29082        },
29083        {
29084            name : 'tablet-potrait',
29085            width : 768
29086        },
29087        {
29088            name : 'mobile-landscape',
29089            width : 480
29090        },
29091        {
29092            name : 'mobile-potrait',
29093            width : 320
29094        }
29095    ];
29096
29097    
29098    Responsive.controlRowDefaults = {
29099        
29100        breakpoints : Responsive.breakpoints,
29101
29102        
29103        controlRowDetails : {
29104            renderer : function (tablePlugin, row) {
29105                var cells = null;
29106                if (tablePlugin.options.bControlRowHiddenCells) {
29107                    cells = row.$tableRowElement.find("td:hidden");
29108                } else {
29109                    cells = row.$tableRowElement.find("td");
29110                    
29111                    if (tablePlugin.options.bDisableControlRowCells) {
29112                        
29113                        row.$tableRowElement.find("input, select, textarea, button").attr("disabled", "disabled");
29114                    }
29115                }
29116                var data = cells.map(function (index, cell) {
29117                    var $cell = $(cell),
29118                        header = tablePlugin.header($cell),
29119                        $clickedTableRow = row.$tableRowElement,
29120                        cellIdx = null,
29121                        cellData = null;
29122                    cellIdx = {
29123                        
29124                        row : $clickedTableRow.index(),
29125                        column : $cell.index()
29126                    };
29127
29128                    cellData = tablePlugin._getCellData(cellIdx);
29129                    return $("<li></li>").attr("data-rtp-index", cellIdx.column).addClass("clearfix").append(
29130                        $("<div></div>").addClass("rtp-title").text($.trim(header.text()))
29131                    ).append(
29132                        $("<div></div>").addClass("rtp-data").append(cellData)
29133                    );
29134                });
29135
29136                return $('<ul data-rtp-index="' + row.index + '"></ul>').append(data.get());
29137            },
29138
29139            target : 0,
29140
29141            type : 'inline'
29142        }
29143    };
29144    
29145    var ResponsiveTablePlugin = function (element, options) {
29146        this.options = options;
29147        this.$element = $(element);
29148        this.columns = [];
29149    };
29150
29151    
29152    var TableColumn = function ($tableElement, colIdx, bIsResize) {
29153        var $colHeaderElement = $tableElement.find("th").eq(colIdx);
29154        
29155        this.minWidth =  (bIsResize ? (parseInt($colHeaderElement.css("min-width"), 10)) : $colHeaderElement.outerWidth());
29156        this.header = $colHeaderElement;
29157        this.colIndex = colIdx;
29158        this.$tableElement = $tableElement;
29159    };
29160
29161    
29162    TableColumn.prototype = {
29163        
29164        cells : function () {
29165            
29166            var headerValue = this.header.attr("id");
29167            return this.$tableElement.find("tr td").filter(function () {
29168                var id = $(this).attr("headers");
29169                if (id) {
29170                    if (id.indexOf(headerValue) > -1) {
29171                        return $(this);
29172                    }
29173                }
29174            });
29175        },
29176        
29177        visible : function (bFlag) {
29178            var cells = this.cells();
29179            this.isVisible = bFlag;
29180            if (bFlag ===  true) {
29181                cells.show();
29182                this.header.show();
29183            } else {
29184                this.header.hide();
29185                
29186                var headers = this.header.prevAll().filter(":visible"),
29187                    headerLen = headers.length;
29188                
29189                $.each(cells, function () {
29190                    if (!$(this).data("shown")) {
29191                        $(this).hide();
29192                    }
29193                    var colSpan = $(this).data("colspan") || $(this).attr("colspan");
29194                    
29195                    if (colSpan > 1) {
29196                        var totalColSpan = 0;
29197                        $(this).prevAll().each(function () {
29198                            totalColSpan += (+($(this).data("colspan") || $(this).attr("colspan")));
29199                        });
29200                        
29201                        if (totalColSpan == 0) {
29202                            $(this).show();
29203                            $(this).data("shown", true);
29204                            
29205                            if ($(this).data("colspan") == null) {
29206                                $(this).data("colspan", $(this).attr("colspan"));
29207                            }
29208                            $(this).attr("colspan", headerLen);
29209                        }
29210                        
29211                        else if (totalColSpan < headerLen) {
29212                            $(this).show();
29213                            $(this).data("shown", true);
29214                            if ($(this).data("colspan") == null) {
29215                                $(this).data("colspan", $(this).attr("colspan"));
29216                            }
29217                            $(this).attr("colspan", (headerLen - totalColSpan));
29218                        }
29219                    }
29220                });
29221            }
29222        }
29223    };
29224
29225    
29226    var TableRow = function ($tableRowElement) {
29227        this.$tableRowElement = $tableRowElement;
29228        this.index = $tableRowElement.index();
29229        
29230        this.child = {
29231            $element : null,
29232            isShown : false
29233        };
29234        $tableRowElement.data("tableRow", this);
29235    };
29236
29237    TableRow.prototype = {
29238
29239        updateChild : function (info, colSpan) {
29240            
29241            if (this.child.$element && this.child.$element.length > 0) {
29242                this.child.$element.empty();
29243                this.child.$element.append($("<td></td>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).attr("colspan", colSpan).append($(info)));
29244            } else if (this.$tableRowElement.next(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).length > 0) {
29245                this.child.$element = this.$tableRowElement.next();
29246                this.child.$element.append($("<td></td>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).attr("colspan", colSpan).append($(info)));
29247            } else {
29248                
29249                this.child.$element = $("<tr></tr>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).append($("<td></td>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).attr("colspan", colSpan).append($(info)));
29250                
29251                this.$tableRowElement.after(this.child.$element);
29252            }
29253
29254        },
29255
29256        showChild : function () {
29257            
29258            this.child.$element.get(0).style.display = "";
29259            this.child.isShown = true;
29260        },
29261
29262        hideChild : function () {
29263            this.child.$element.hide();
29264            this.child.isShown = false;
29265        }
29266    };
29267
29268    ResponsiveTablePlugin.prototype = {
29269        
29270        _getCellData : function (index) {
29271            
29272            var tableRow = this.$element.find("tbody tr").eq(index.row),
29273                tableCell =   tableRow.find("td").eq(index.column);
29274            
29275            if (this.options.viewCallback) {
29276                
29277                var id = tableCell.find(ResponsiveTablePlugin.prototype.defaults.GUIDE_ID_SELECTOR).attr("id");
29278                
29279                return this.options.viewCallback(id);
29280            } else {
29281                return tableCell.html();
29282            }
29283        },
29284
29285        
29286        header : function (cell) {
29287            
29288            
29289            var id = cell.attr("headers").split(" ")[0];
29290            
29291            return this.$element.find("#" + id);
29292        },
29293
29294        initializeColumns : function (bIsResize) {
29295            var columns = [];
29296            
29297            
29298            
29299            this.colLength = this.$element.find("th").length;
29300            for (var colIdx = 0; colIdx < this.colLength; colIdx++) {
29301                
29302                
29303                columns.push(new TableColumn(this.$element, colIdx, bIsResize));
29304            }
29305            return columns;
29306        },
29307
29308        
29309        _initializeColumnWidth : function () {
29310            
29311            
29312            
29313            var display = this._getColumnsVisibility(),
29314                
29315                visibleColumns = _.filter(display, function (item) {
29316                    return item == true;
29317                }).length,
29318                $allTableHeaders = this.$element.find("th"),
29319                $tableHeader = null,
29320                width = null,
29321                sum = 0;
29322            if (!this.options.bAutoWidth) {
29323                
29324                
29325                for (var i = 0; i < visibleColumns; i++) {
29326                    sum += parseInt(this.options.aWidth[i], 10);
29327                }
29328            } else {
29329                sum = visibleColumns;
29330            }
29331
29332            if (display.length == this.colLength) {
29333                for (var i = 0; i < visibleColumns; i++) {
29334                    if (this.options.aWidth) {
29335                        
29336                        width = ((Math.floor((this.options.aWidth[i] * 100) / sum)) + "%");
29337                    } else {
29338                        width = ((Math.floor((1 * 100) / sum)) + "%");
29339                    }
29340                    $tableHeader = $allTableHeaders.eq(i);
29341                    
29342                    
29343                    $tableHeader[0].style.width = width;
29344                }
29345            }
29346        },
29347
29348        _constructor : function () {
29349            var that = this;
29350            
29351            this.controlRow = $.extend(true, {}, Responsive.controlRowDefaults);
29352            this.columns = this.initializeColumns();
29353            
29354            $(window).on("resize orientationchange", function (event) {
29355                that._initializeColumnVisibility(event);
29356            });
29357
29358            
29359            
29360            this.controlRow.breakpoints.sort(function (a, b) {
29361                return a.width < b.width ? 1 :
29362                    a.width > b.width ? -1 : 0;
29363            });
29364            this._initializeColumnVisibility();
29365            
29366            this._controlRowInitialization();
29367        },
29368
29369        _initializeColumnVisibility : function (event) {
29370            var that = this;
29371            
29372            if (event) {
29373                
29374                
29375                this.$element.find("td").each(function () {
29376                    $(this).removeData("shown");
29377                    
29378                    if ($(this).data("colspan") != null) {
29379                        
29380                        $(this).attr("colspan", $(this).data("colspan"));
29381                    }
29382                });
29383                
29384                
29385                
29386                this.columns = this.initializeColumns(event);
29387            }
29388            
29389            
29390            
29391            
29392            this._initializeColumnWidth();
29393            this.display = this._resize();
29394            
29395            
29396            this.$element.find("tbody tr:not(.child)").each(function () {
29397                if ($(this).next(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).length == 0) {
29398                    $(this).after($("<tr></tr>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).hide());
29399                }
29400            });
29401
29402            
29403            var details = this.controlRow.controlRowDetails;
29404            
29405            if (details.type) {
29406                
29407                this._controlRowVisibility(event);
29408                
29409                
29410                this.$element.on(ResponsiveTablePlugin.prototype.defaults.EVENT_COLUMN_VISIBILITY, function () {
29411                    that._controlRowVisibility();
29412                });
29413
29414                this.$element.addClass('rtp-' + details.type);
29415            }
29416            
29417            if (this.options.fixTableControls) {
29418                
29419                
29420                
29421                if (_.isUndefined(event) || event.type === "orientationchange" || (event.type === "resize" && !isIphoneOrIpad)) {
29422                    
29423                    this.options.fixTableControls(event);
29424                }
29425            }
29426        },
29427
29428        
29429        _fixControlRows : function () {
29430            this.$element.find(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).remove();
29431        },
29432
29433        
29434        isColumnHidden : function () {
29435            return this.bColumnHidden || false;
29436        },
29437
29438        
29439        _rearrangeTableRuntimeControls : function (lastVisibleColumn, event) {
29440            
29441            
29442            var $runtimeAddControls = this.$element.find(".guideTableRuntimeControls .guideTableRuntimeAddControl"),
29443                runtimeControlIndex = 0,
29444                that = this,
29445                index = null;
29446            $runtimeAddControls.each(function () {
29447                
29448                if ($(this).is(":visible")) {
29449                    runtimeControlIndex = $(this).closest("td").index();
29450                    return false;
29451                }
29452            });
29453            
29454            if ((runtimeControlIndex <= lastVisibleColumn)) {
29455                
29456                
29457                $runtimeAddControls.each(function () {
29458                    
29459                    
29460                    var $runtimeControl = $(this).closest(".guideTableRuntimeControls"),
29461                        $runtimeControlTableRow = $(this).closest("tr");
29462                    if ($runtimeControl.hasClass("guideTableRuntimeRightControls")) {
29463                        
29464                        $runtimeControl.appendTo($runtimeControlTableRow.find("td").eq(lastVisibleColumn));
29465                        if (runtimeControlIndex !== lastVisibleColumn) {
29466                            var $component = $runtimeControl.prev();
29467                            $component.css("display", "block");
29468                            $component.css("float", "none");
29469                        }
29470                    }
29471
29472                });
29473            }
29474        },
29475
29476        
29477        _controlRowVisibility : function (event) {
29478            var that = this,
29479                
29480                hiddenColumns = _.filter(this.columns, function (element) {
29481                    return (element.isVisible) !== true;
29482                }),
29483                lastVisibleColumn = this.columns.length - hiddenColumns.length;
29484            
29485            
29486            this._rearrangeTableRuntimeControls(lastVisibleColumn - 1, event);
29487            
29488            if (hiddenColumns && hiddenColumns.length > 0) {
29489                
29490                this.$element.addClass('collapsed');
29491                
29492            this.bColumnHidden = true;            } else {
29493                
29494                this.$element.removeClass('collapsed');
29495                
29496                this.bColumnHidden = false;
29497            }
29498        },
29499
29500        
29501        _controlRowInitialization : function () {
29502            var that    = this;
29503            var details = this.controlRow.controlRowDetails;
29504
29505            
29506            if (details.type === 'inline') {
29507                
29508                details.target = ("." +  (this.options.tableRuntimeEditControlClass || "tableRuntimeEditControl"));
29509            }
29510
29511            
29512            
29513            
29514            var target   = details.target;
29515            var selector = typeof target === 'string' ? target : 'td';
29516
29517            
29518            this.$element.on('click keypress', selector, function (e) {
29519                
29520                
29521                if ((e.type == "keypress" && e.keyCode == 13) || e.type == "click") {
29522                    
29523                    if (!that.$element.hasClass('collapsed')) {
29524                        return;
29525                    }
29526                    
29527                    var $row = $(this).closest('tr'),
29528                        rowData = $row.data("tableRow"),
29529                        row = rowData;
29530                    
29531                    
29532                    
29533                    if (row == null || row.child.$element.parent().length === 0) {
29534                        row = new TableRow($row);
29535                        $row.data("tableRow", row);
29536                    }
29537                    if (row.child.isShown) {
29538                        row.hideChild();
29539                        row.$tableRowElement.removeClass('parent');
29540                    } else {
29541                        var info = that.controlRow.controlRowDetails.renderer(that, row);
29542                        row.updateChild(info, that.colLength);
29543                        row.showChild();
29544                        row.$tableRowElement.addClass('parent');
29545                        
29546                        row.child.$element.find("input, select, textarea, button").eq(0).focus();
29547                    }
29548                }
29549            });
29550        },
29551
29552        
29553        _resize : function () {
29554            var width = $(window).width();
29555            var breakpoints = this.controlRow.breakpoints;
29556            var breakpoint = breakpoints[0].name;
29557
29558            
29559            for (var i = breakpoints.length - 1 ; i >= 0 ; i--) {
29560                if (width <= breakpoints[i].width) {
29561                    breakpoint = breakpoints[i].name;
29562                    break;
29563                }
29564            }
29565
29566            
29567            var display = this._getColumnsVisibility(breakpoint);
29568
29569            _.each(this.columns, function (item, index) {
29570                item.visible(display[index]);
29571            });
29572
29573            return display;
29574        },
29575
29576        
29577        _getColumnsVisibility : function (breakpoint) {
29578            var columns = this.columns,
29579                i,
29580                len = this.$element.find("th"),
29581                display = [];
29582
29583            
29584            var widthAvailable = this.$element.parent().outerWidth();
29585            var usedWidth = widthAvailable;
29586
29587            
29588            
29589            display = _.map(columns, function (item) {
29590                usedWidth -= item.minWidth;
29591                return ((usedWidth < 0) ? false : true);
29592            });
29593
29594            
29595            display[0] = true;
29596            return display;
29597        }
29598
29599    };
29600
29601    $.fn.responsiveTablePlugin = function (option, value) {
29602        var get = '',
29603            element = this.each(function () {
29604                
29605                if ($(this).is('table') === true) {
29606                    var $this = $(this),
29607                        data = $this.data('responsiveTablePlugin'),
29608                        options = $.extend({}, ResponsiveTablePlugin.prototype.defaults, typeof option === 'object' && option);
29609
29610                    
29611                    if (!data) {
29612                        $this.data('responsiveTablePlugin', (data = new ResponsiveTablePlugin(this, options)));
29613                        data._constructor();
29614                    }
29615
29616                    
29617                    if (typeof option === 'string') {
29618                        get = data[option](value);
29619                    }
29620                }
29621            });
29622
29623        if (get != "") {
29624            return get;
29625        } else {
29626            return element;
29627        }
29628    };
29629
29630    ResponsiveTablePlugin.prototype.defaults = {
29631        
29632        EVENT_COLUMN_VISIBILITY : "responsiveTablePlugin.columnVisibility",
29633        GUIDE_ID_SELECTOR : "div[data-guide-view-bind]",
29634        CONTROL_ROW_CLASS : "child",
29635        CONTROL_ROW_SELECTOR : "tr.child"
29636    };
29637
29638})(_, $);
29639(function ($, _, guidelib) {
29640
29641    
29642    var getPanelsWithNumericFields = function (panels, fieldName) {
29643            if (_.isUndefined(panels) || panels === null) {
29644                return [];
29645            }
29646            if (!_.isArray(panels)) {
29647                panels = [panels];
29648            }
29649            return _.filter(panels, function (panel) {
29650                return panel instanceof guidelib.model.GuidePanel
29651                    && panel[fieldName] instanceof guidelib.model.GuideNumericBox;
29652            });
29653        },
29654        
29655        sum = function (numPanels, fieldName) {
29656            return _.reduce(numPanels,
29657                function (memo, currentItem) {
29658                    var curValue = parseFloat(currentItem.getOrElse(currentItem, fieldName + ".value", 0));
29659                    if (isNaN(curValue)) {
29660                        curValue = 0;
29661                    }
29662                    return memo + curValue;
29663                }, 0);
29664        };
29665
29666    
29667    guidelib.__runtime__.af.sum = function (panels, fieldName) {
29668        return sum(getPanelsWithNumericFields(panels, fieldName), fieldName);
29669    };
29670
29671    
29672    guidelib.__runtime__.af.avg = function (panels, fieldName) {
29673        var n_panels = getPanelsWithNumericFields(panels, fieldName),
29674            total = sum(n_panels, fieldName);
29675        if (n_panels.length === 0) {
29676            return 0;
29677        }
29678        return total / n_panels.length;
29679    };
29680
29681    
29682    guidelib.__runtime__.af.max = function (panels, fieldName) {
29683        var panel = _.max(getPanelsWithNumericFields(panels, fieldName), function (panel) {
29684            return panel.getOrElse(panel, fieldName + ".value", Number.NEGATIVE_INFINITY);
29685        });
29686        if (panel instanceof guidelib.model.GuidePanel) {
29687            return panel[fieldName];
29688        }
29689        return null;
29690    };
29691
29692    
29693    guidelib.__runtime__.af.min = function (panels, fieldName) {
29694        var panel =  _.min(getPanelsWithNumericFields(panels, fieldName), function (panel) {
29695            return panel.getOrElse(panel, fieldName + ".value", Number.POSITIVE_INFINITY);
29696        });
29697        if (panel instanceof guidelib.model.GuidePanel) {
29698            return panel[fieldName];
29699        }
29700        return null;
29701    };
29702
29703}($, _, guidelib));
29704(function (_, guidelib) {
29705
29706    
29707    var GuideProgressiveSection = guidelib.model.GuideProgressiveSection = xfalib.ut.EventClass.extend({
29708        msClassName : "guideProgressiveSection",
29709
29710        initialize : function () {
29711            
29712            this.jsonModel = this.options.jsonModel;
29713            this.instanceIndex = this.options.instanceIndex;
29714            this.instance = this.options.instance;
29715            
29716            
29717            this.parent = this.options.parent;
29718
29719            
29720            this._currActivePart = 0;
29721
29722            this.className = this.jsonModel.guideNodeClass || this.msClassName;
29723            
29724            this._parts = [];
29725            
29726            this.initializeChildren();
29727
29728        },
29729
29730        _getChildModelFromId : function (id) {
29731            return this.childIdToModel[id];
29732        },
29733
29734        initializeChildren : function () {
29735            var that = this,
29736                
29737                fields = this.jsonModel.fields;
29738            this.children = this.children || [];
29739            this.childIdToModel = this.childIdToModel || {};
29740
29741            
29742            _.each(fields, function (item) {
29743                var model = guideBridge._resolveId(item.id);
29744                that.children.push(model);
29745                that.childIdToModel[item.id] = model;
29746            });
29747        },
29748
29749        setFocus : function () {
29750            
29751            this._triggerEvent(guidelib.event.GuideModelEvent.NAVIGATE_SECTION, "navigateWithinSection",
29752                null, null);
29753        },
29754
29755        _triggerEvent : function (event, propName, prevText, newText) {
29756            guidelib.model.GuideNode.prototype._triggerEvent.apply(this, arguments);
29757        },
29758
29759        playJson : function (pJsonModel) {
29760            
29761            
29762            this.jsonModel = _.extend({}, pJsonModel);
29763        }
29764
29765    });
29766
29767    GuideProgressiveSection.defineProps({
29768        sectionId : {
29769            get : function () {
29770                return this.jsonModel.id;
29771            }
29772        },
29773
29774        
29775        activePart : {
29776            get : function () {
29777                return this._parts[this._currActivePart];
29778            }
29779        },
29780
29781        isLastPart : {
29782            get : function () {
29783                return (this._currActivePart === (this._parts.length - 1));
29784            }
29785        },
29786
29787        isFirstPart : {
29788            get : function () {
29789                return this._currActivePart === 0;
29790            }
29791        },
29792
29793        
29794        currentActivePart : {
29795            
29796            
29797            set : function (activePartIndex) {
29798                this._currActivePart = activePartIndex;
29799            },
29800
29801            get : function () {
29802                return this._currActivePart;
29803            }
29804        },
29805
29806        sectionTitle : {
29807            get : function () {
29808                return this.jsonModel.title;
29809            }
29810        },
29811
29812        
29813        sectionName : {
29814            get : function () {
29815                return this.jsonModel.name;
29816            }
29817        },
29818
29819        sectionFields : {
29820            get : function () {
29821                return this.jsonModel.fields;
29822            }
29823        },
29824
29825        
29826        fetchedFromService : {
29827
29828            get : function () {
29829                return this.jsonModel.fetchedFromService === "true";
29830            }
29831        },
29832
29833        repeatablePanelPath : {
29834            get : function () {
29835                return this.jsonModel.repeatablePanelPath;
29836            }
29837        },
29838
29839        repeatablePanelId : {
29840            get : function () {
29841                return this.jsonModel.repeatablePanelId;
29842            }
29843        }
29844
29845    });
29846})(_, guidelib);
29847
29848(function (_, guidelib) {
29849
29850    
29851    var GuideProgressiveCompletionSection = guidelib.model.GuideProgressiveCompletionSection = guidelib.model.GuideProgressiveSection.extend({
29852        msClassName : "guideProgressiveCompletionSection"
29853
29854    });
29855
29856    GuideProgressiveCompletionSection.defineProps({
29857        sectionId : {
29858            get : function () {
29859                return this.jsonModel.id;
29860            }
29861        },
29862
29863        sectionTitle : {
29864            get : function () {
29865                return this.jsonModel.completionTitle;
29866            }
29867        },
29868
29869        completionScript : {
29870            get : function () {
29871                return this.jsonModel.completionScript;
29872            }
29873        },
29874
29875        completionBeforeMessage : {
29876            get : function () {
29877                return this.jsonModel.completionBeforeMessage;
29878            }
29879        },
29880
29881        completionAfterMessage : {
29882            get : function () {
29883                return this.jsonModel.completionAfterMessage;
29884            }
29885        },
29886
29887        completionSuccessScript : {
29888            get : function () {
29889                return this.jsonModel.completionSuccessScript;
29890            }
29891        },
29892
29893        completionFailureScript : {
29894            get : function () {
29895                return this.jsonModel.completionFailureScript;
29896            }
29897        }
29898
29899    });
29900})(_, guidelib);
29901
29902(function (_, guidelib) {
29903
29904    var currActivePart = 0;
29905
29906    
29907    var GuideProgressiveRepeatableSectionManager = guidelib.model.GuideProgressiveRepeatableSectionManager = guidelib.model.GuideProgressiveSection.extend({
29908        msClassName : "guideProgressiveRepeatableSectionManager",
29909
29910        initialize : function () {
29911            GuideProgressiveRepeatableSectionManager._super.initialize.apply(this, arguments);
29912            this.isRepeatable = true;
29913            this._instances =  this._instances || [];
29914            
29915            this._initializeRepeatability();
29916
29917        },
29918
29919        _getSectionFromPanelId : function (panel) {
29920            return _.find(this._instances, function (item) {
29921                return item.instance.id === panel.id;
29922            });
29923        },
29924
29925        insertInstance : function (index) {
29926            
29927            
29928            var insertedInstance = this.instanceManager.insertInstance(index),
29929                section;
29930            
29931            if (insertedInstance != null) {
29932                section = this._getSection(insertedInstance);
29933                if (section != null) {
29934                    
29935                    this._instances.splice(index, 0, section);
29936                    
29937                    guidelib.runtime.progressive.addRepeatable(section);
29938                }
29939            }
29940        },
29941
29942        removeInstance : function (panel) {
29943            var id = panel.id,
29944                index = panel.instanceIndex;
29945            
29946            if (index > -1
29947                && this.instanceManager.instanceCount > this.instanceManager.minOccur
29948                && index < this.instanceManager.instanceCount) {
29949                
29950                this.instanceManager.removeInstance(index);
29951                
29952                this._instances.splice(index, 1);
29953                
29954                guidelib.runtime.progressive.deleteRepeatable(id);
29955            }
29956        },
29957
29958        
29959        _getSection : function (panel) {
29960            var section = null,
29961                clonedJson = {},
29962                id = panel.id,
29963                templateId = panel.templateId,
29964                uniquePrefix = null;
29965            if (id !== templateId) {
29966                
29967                
29968                uniquePrefix = id.substring(0, id.indexOf(templateId) - 2);
29969                
29970                this.copyObject(this.jsonModel, clonedJson,
29971                        {
29972                            transformMaps : {
29973                                "id" : function (srcValue, options, parentObj) {
29974                                    
29975                                    
29976                                    if (parentObj.guideNodeClass && parentObj.guideNodeClass.indexOf("Progressive") !== -1) {
29977                                        return srcValue;
29978                                    } else {
29979                                        
29980                                        return uniquePrefix + "__" + srcValue;
29981                                    }
29982                                }
29983                            }
29984                        }
29985                    );
29986            } else {
29987                clonedJson = _.extend({}, this.jsonModel);
29988            }
29989            if (panel != null) {
29990                section = new guidelib.model.GuideProgressiveSection({
29991                    "jsonModel" : clonedJson,
29992                    "instanceIndex" : panel.instanceIndex,
29993                    "parent" : this,
29994                    "instance" : this.instanceManager.instances[panel.instanceIndex]
29995                });
29996            }
29997            return section;
29998        },
29999
30000        _initializeRepeatability : function () {
30001            var model = guideBridge._resolveId(this.repeatablePanelId), 
30002                oneActive = true,  
30003                that = this,
30004                childView;
30005            
30006            this.activeInstanceIndex = 0;
30007
30008            
30009            
30010            
30011            
30012            if (model == null) {
30013                
30014                this.instanceManager = guideBridge._resolveId("im_" + this.repeatablePanelId);
30015            } else {
30016                this.instanceManager = model.instanceManager;
30017            }
30018            
30019            if (this.instanceManager != null && this.instanceManager.instances && this.instanceManager.instances.length > 0) {
30020                
30021                _.each(this.instanceManager.instances, function (modelInstance) {
30022                    
30023                    that._instances.push(that._getSection(modelInstance));
30024                });
30025            }
30026        },
30027
30028        _getChildModelFromId : function (id) {
30029            return this.childIdToModel[id];
30030        },
30031
30032        initializeChildren : function () {
30033            var that = this;
30034            this.children = this.children || [];
30035            this.childIdToModel = this.childIdToModel || {};
30036            
30037            _.each(this.jsonModel.fields, function (item) {
30038                var model = guideBridge._resolveId(item.id);
30039                that.children.push(model);
30040                that.childIdToModel[item.id] = model;
30041            });
30042        },
30043
30044        setFocus : function () {
30045            
30046            this._triggerEvent(guidelib.event.GuideModelEvent.NAVIGATE_SECTION, "navigateWithinSection",
30047                null, null);
30048        },
30049
30050        playJson : function (pJsonModel) {
30051            
30052            
30053            this.jsonModel = _.extend({}, pJsonModel);
30054        }
30055    });
30056    GuideProgressiveRepeatableSectionManager.defineProps({
30057        activeInstance : {
30058            set : function (panelId) {
30059                this.activeInstanceIndex = guideBridge._resolveId(panelId).instanceIndex;
30060            },
30061
30062            get : function () {
30063                return this._instances[this.activeInstanceIndex];
30064            }
30065        }
30066
30067    });
30068
30069})(_, guidelib);
30070
30071(function ($, _, guidelib) {
30072
30073    
30074    
30075    guidelib.__runtime__.af.reduce = function (panels, fieldName, iterator, memo, context) {
30076        if (!_.isArray(panels)) {
30077            panels = [panels];
30078        }
30079        return _.reduce(panels, function (memo, panel) {
30080            if (panel instanceof guidelib.model.GuidePanel && !_.isUndefined(panel[fieldName])) {
30081                if (_.isFunction(iterator)) {
30082                    return iterator.apply(context, [memo, panel, panel[fieldName]]);
30083                }
30084            }
30085            return memo;
30086        }, memo);
30087    };
30088
30089    
30090    
30091    guidelib.__runtime__.af.filter = function (panels, fieldName, predicate, context) {
30092        if (!_.isArray(panels)) {
30093            panels = [panels];
30094        }
30095        return _.map(
30096            _.filter(panels, function (panel) {
30097                if (panel instanceof guidelib.model.GuidePanel && !_.isUndefined(panel[fieldName])) {
30098                    if (_.isFunction(predicate)) {
30099                        return predicate.apply(context, [panel, panel[fieldName]]);
30100                    }
30101                    return false;
30102                }
30103            }),
30104            function (panel) {
30105                return panel[fieldName];
30106            }
30107        );
30108    };
30109    
30110    guidelib.__runtime__.af.formatDateToISOString = function (dateObject) {
30111        var day, month, year;
30112        if (!_.isUndefined(dateObject) && _.isObject(dateObject)) {
30113            day = dateObject.getDate().toString();
30114            
30115            month = (dateObject.getMonth() + 1).toString();
30116            year = dateObject.getFullYear().toString();
30117            if (month.length === 1) {
30118                month = "0" + month.toString();
30119            }
30120            
30121            return year + "-" + month + "-" + day;
30122
30123        }
30124    };
30125}($, _, guidelib));
30126(function (_, guidelib) {
30127    
30128    var GuideNavigationContext = guidelib.model.util.GuideNavigationContext = xfalib.ut.Class.extend({
30129        msClassName : "guideNavigationContext",
30130        initialize : function () {
30131            GuideNavigationContext._super.initialize.call(this);
30132            this._currentItem = this.options.currentItem;
30133            this._parentPanel = this.options.parentPanel;
30134            this.guideUtil = guidelib.util.GuideUtil;
30135        },
30136
30137        getQualifiedNamedItem : function (qName) {
30138            var navItems = this._getNavigableItems();
30139            var qItem = _.find(navItems, function (item) {
30140                return (item._escapeQualifiedName() == qName);
30141            }, this);
30142            return qItem;
30143        },
30144
30145        getItemForNav : function (navToken) {
30146            if (navToken == "prevItem" || navToken == "nextItem" || navToken == "firstItem" || navToken == "lastItem") {
30147                return this[navToken];
30148            } else {
30149                return this.getQualifiedNamedItem(navToken);
30150            }
30151        },
30152
30153        
30154        _isNavigableItem : function (item) {
30155            return item.visible;
30156        },
30157
30158        
30159        _isNavigablePanel : function (item) {
30160            if (item && item instanceof guidelib.model.GuidePanel) {
30161                return item.visible && item.isNavigable;
30162            }
30163        },
30164
30165        _getNavigableItems : function () {
30166            var navItems = _.filter(this._parentPanel.items, function (item) {
30167                return this._isNavigableItem(item);
30168            }, this);
30169            return navItems;
30170        },
30171        
30172        _getNavigableDescendant : function (navigableAncestor) {
30173            
30174            
30175            if (navigableAncestor && navigableAncestor != this._parentPanel) {
30176                var currentItem = navigableAncestor.parent._navigationContext.currentItem,
30177                    deepItem = null;
30178                while (currentItem instanceof guidelib.model.GuidePanel) {
30179                    deepItem = currentItem;
30180                    currentItem = currentItem._navigationContext.currentItem;
30181                }
30182                return deepItem;
30183            }
30184            return null;
30185        },
30186
30187        
30188        _getSomOnNavigableAncestor : function (somExpression) {
30189            if (_.isEmpty(somExpression)) {
30190                return null;
30191            }
30192
30193            var index = somExpression.lastIndexOf("."),
30194                parentModel,
30195                parentSom,
30196                isNavigable,
30197                guideModel = this._parentPanel._guide();
30198
30199            if (index !== -1) {
30200                parentSom = somExpression.substring(0, index);
30201                parentModel = guideModel.resolveNode(parentSom);
30202                if (parentModel) {
30203                    isNavigable = this._isNavigablePanel(parentModel);
30204                }
30205                if (isNavigable) {  
30206                    return somExpression;
30207                }
30208                return this._getSomOnNavigableAncestor(parentSom);
30209            }
30210            
30211            return guideModel.rootPanel.somExpression;
30212        },
30213
30214        
30215        _getNavigableAncestor : function (navOrder) {
30216            
30217            
30218            
30219            var guideModel = this._parentPanel._guide(),
30220                navigableAncestorSom = this._getSomOnNavigableAncestor(guideModel._currentNavigablePanelSom),
30221                navigableAncestorItem = guideModel.resolveNode(navigableAncestorSom);
30222            
30223            while (navigableAncestorItem
30224                && navigableAncestorItem != this._parentPanel && !navigableAncestorItem.parent._navigationContext[navOrder]
30225                && this.guideUtil.isChildPartOfContainer(this._parentPanel, navigableAncestorItem)) {
30226                
30227                var navigableParentItemSom = this._getSomOnNavigableAncestor(navigableAncestorItem.parent.somExpression);
30228                navigableAncestorItem = guideModel.resolveNode(navigableParentItemSom);
30229            }
30230            return navigableAncestorItem;
30231        },
30232
30233        _getNakedThis : function () {
30234            return this;
30235        }
30236    });
30237
30238    GuideNavigationContext.defineProps({
30239        
30240        currentItem : {
30241            get : function () {
30242                if (this._currentItem) {
30243                    return this._currentItem;
30244                } else {
30245                    return this.firstItem;
30246                }
30247            },
30248            set : function (value) {
30249                this._currentItem = value;
30250            }
30251        },
30252        
30253        prevItem : {
30254            get : function () {
30255                var navItems = this._getNavigableItems();
30256                var item = this.currentItem;
30257                if (navItems.indexOf(item) > 0) {
30258                    return navItems[navItems.indexOf(item) - 1];
30259                } else {
30260                    return null;
30261                }
30262            }
30263        },
30264        
30265        nextItem : {
30266            get : function () {
30267                var navItems = this._getNavigableItems();
30268                var item = this.currentItem;
30269                if (navItems.indexOf(item) < (navItems.length - 1)) {
30270                    return navItems[navItems.indexOf(item) + 1];
30271                } else {
30272                    return null;
30273                }
30274            }
30275        },
30276        
30277        nextNavigablePanel : {
30278            get : function () {
30279                var navigableAncestor = this._getNavigableAncestor("nextItem"),
30280                
30281                    navigableDescendant = this._getNavigableDescendant(navigableAncestor);
30282                return navigableDescendant;
30283            }
30284        },
30285
30286        
30287        prevNavigablePanel : {
30288            get : function () {
30289                var navigableAncestor = this._getNavigableAncestor("prevItem"),
30290                
30291                    navigableDescendant = this._getNavigableDescendant(navigableAncestor);
30292                return navigableDescendant;
30293            }
30294        },
30295
30296        
30297        firstItem : {
30298            get : function () {
30299                var navItems = this._getNavigableItems();
30300                return navItems[0] || null;
30301            }
30302        },
30303        
30304        lastItem : {
30305            get : function () {
30306                var navItems = this._getNavigableItems();
30307                if (navItems.length) {
30308                    return navItems[navItems.length - 1];
30309                } else {
30310                    return null;
30311                }
30312            }
30313        },
30314        
30315        hasNextItem : {
30316            get : function () {
30317                return this.nextItem != null;
30318            }
30319        },
30320        
30321        hasPrevItem : {
30322            get : function () {
30323                return this.prevItem != null;
30324            }
30325        },
30326
30327        
30328        hasNextNavigablePanel : {
30329            get : function () {
30330                return this.nextNavigablePanel != null;
30331            }
30332        },
30333
30334        
30335        hasPrevNavigablePanel : {
30336            get : function () {
30337                return this.prevNavigablePanel != null;
30338            }
30339        },
30340
30341        
30342        isFirstItem : {
30343            get : function () {
30344                return this.currentItem == this.firstItem;
30345            }
30346        },
30347        
30348        isLastItem : {
30349            get : function () {
30350                return this.currentItem == this.lastItem;
30351            }
30352        }
30353    });
30354
30355})(_, guidelib);
30356
30357
30358(function (guidelib, $) {
30359
30360    var VERSION_AEM_61 = "AEM6.1",
30361        VERSION_AEM_62 = "AEM6.2",
30362        VERSION_AEM_63 = "AEM6.3",
30363        VERSION_AEM_65 = "AEM6.5",
30364        flagsStatus = {},
30365        getMinorMajor = function (version) {
30366            var match = version.match(/AEM(\d+)(?:\.(\d+))?/);
30367            if (match == null) {
30368                return null;
30369            }
30370            return {
30371                major : match[1],
30372                minor : match[2] === undefined ? "0" : match[2]
30373            };
30374        },
30375        compareNumbers = function (num1, num2) {
30376            return (num1 - num2);
30377        },
30378        compareVersions = function (version1, version2) {
30379            if (typeof version1 !== "string" || typeof version2 !== "string") {
30380                throw "Comparing Invalid Versions";
30381            }
30382            var v1 = getMinorMajor(version1),
30383                v2 = getMinorMajor(version2);
30384            if (v1 == null || v2 == null) {
30385                throw "Comparing Invalid Versions";
30386            }
30387            var c = compareNumbers(+v1.major, +v2.major);
30388            return c !== 0 ? c : compareNumbers(+v1.minor, +v2.minor);
30389        },
30390        Version = guidelib.util.Version = xfalib.ut.Class.extend({
30391            initialize : function (options) {
30392                flagsStatus = {};
30393                var compat = options.scriptingBehaviourVersion;
30394                if (compat === "None") {
30395                    compat = this.current();
30396                }
30397                this.scriptingBehaviourVersion = compat || VERSION_AEM_65;
30398                var majorMinor = getMinorMajor(this.scriptingBehaviourVersion);
30399                if (majorMinor == null) {
30400                    throw "Invalid Version number";
30401                }
30402                this.major = majorMinor.major;
30403                this.minor = majorMinor.minor;
30404            },
30405
30406            current : function () {
30407                return VERSION_AEM_65;
30408            },
30409
30410            compatibleVersion : function () {
30411                return this.scriptingBehaviourVersion;
30412            },
30413
30414            isPrevious : function (version) {
30415                return compareVersions(this.scriptingBehaviourVersion, version) < 0;
30416            },
30417
30418            isPreviousOrSame : function (version) {
30419                var c = compareVersions(this.scriptingBehaviourVersion, version);
30420                return c < 0 || c == 0;
30421            },
30422
30423            isAfter : function (version) {
30424                return compareVersions(this.scriptingBehaviourVersion, version) > 0;
30425            },
30426
30427            isAfterOrSame : function (version) {
30428                var c = compareVersions(this.scriptingBehaviourVersion, version);
30429                return c > 0 || c == 0;
30430            },
30431
30432            isSame : function (version) {
30433                return compareVersions(this.scriptingBehaviourVersion, version) == 0;
30434            },
30435
30436            isOn : function (flag) {
30437                switch (flag) {
30438                    case this.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE:
30439                        if (flagsStatus[flag] == undefined) {
30440                            flagsStatus[flag] = this.isAfter(this.AEM_61);
30441                        }
30442                        return flagsStatus[flag];
30443                    case this.Flags.RUN_VALUE_COMMMIT_ON_PREFILL:
30444                        if (flagsStatus[flag] == undefined) {
30445                            flagsStatus[flag] = this.isAfter(this.AEM_63);
30446                        }
30447                        return flagsStatus[flag];
30448                }
30449                throw "Invalid Flag";
30450            }
30451        });
30452
30453    Version.prototype.Flags = {};
30454    Object.defineProperties(Version.prototype.Flags, {
30455        RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE : {
30456            value : "manageValueCommit",
30457            writable : false
30458        },
30459        RUN_VALUE_COMMMIT_ON_PREFILL : {
30460            value : "manageValueCommitOnPrefill",
30461            writable : false
30462        }
30463    });
30464    Version.defineProps({
30465        AEM_61 : {
30466            value : VERSION_AEM_61,
30467            writable : false
30468        },
30469
30470        AEM_62 : {
30471            value : VERSION_AEM_62,
30472            writable : false
30473        },
30474
30475        AEM_63 : {
30476            value : VERSION_AEM_63,
30477            writable : false
30478        },
30479
30480        AEM_65 : {
30481            value : VERSION_AEM_65,
30482            writable : false
30483        }
30484    });
30485}(guidelib, $));
30486(function (_, guidelib) {
30487    guidelib.model.mixin.ValidationsDisabled = {
30488        normalProperties : {
30489            setParentValidationsDisabled : function (bParentValidationsDisabled) {
30490                var oldValidationsDisabled = this.validationsDisabled,
30491                    newValidationsDisabled;
30492                this._bParentValidationsDisabled = bParentValidationsDisabled;
30493                newValidationsDisabled = this.validationsDisabled;
30494                this.handleChildValidationsDisabled(newValidationsDisabled, oldValidationsDisabled);
30495            },
30496
30497            handleChildValidationsDisabled : function (newValidationsDisabled, oldValidationsDisabled) {
30498                if (newValidationsDisabled !== oldValidationsDisabled) {
30499                    if (this instanceof guidelib.model.Field) {
30500                        if (newValidationsDisabled === true) {
30501                            if (this.validationState === false) {
30502                                this._errorText = "";
30503                                this.validationState = true;
30504                                this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
30505                                    "validationStatus", this.validationState, this._errorText);
30506                            }
30507                        }
30508                    }
30509                    _.each(this._children, function (child) {
30510                        if (child instanceof guidelib.model.Field || child instanceof guidelib.model.GuideItemsContainer) {
30511                            child.setParentValidationsDisabled(newValidationsDisabled);
30512                        }
30513                    });
30514                }
30515            }
30516        },
30517        propertyDescriptors : {
30518            validationsDisabled : {
30519                get : function () {
30520                    return this._bParentValidationsDisabled || this._validationsDisabled;
30521                },
30522                set : function (bValidationsDisabled) {
30523                    var oldValidationsDisabled = this.validationsDisabled,
30524                        newValidationsDisabled;
30525                    this._validationsDisabled = bValidationsDisabled;
30526                    newValidationsDisabled = this.validationsDisabled;
30527                    this.handleChildValidationsDisabled(newValidationsDisabled, oldValidationsDisabled);
30528                }
30529            }
30530        }
30531    };
30532
30533}(_, guidelib));
30534(function (_, guidelib) {
30535
30536    
30537    var GuideItemsContainer = guidelib.model.GuideItemsContainer = guidelib.model.Scriptable.extend({
30538        msClassName : "guideItemsContainer",
30539
30540        initialize : function () {
30541            GuideItemsContainer._super.initialize.call(this);
30542            this._children = [];
30543            this._nameArray = {};
30544            this._private = {};
30545            this._initChildren();
30546            this._normalizeChildren();
30547            this._bParentValidationsDisabled = false;
30548            this._validationsDisabled = false;
30549        },
30550
30551        _postInitialize : function () {
30552            
30553            
30554            GuideItemsContainer._super._postInitialize.call(this);
30555            _.each(this._children, function (childNode) {
30556                childNode._postInitialize();
30557            }, this);
30558        },
30559
30560        
30561        validate : function (errorList) {
30562            var validationStatus = true,
30563                tempValidationStatus;
30564            
30565            if (!this.visible) {
30566                return true;
30567            }
30568            if (_.isUndefined(errorList)) {
30569                errorList = [];
30570            }
30571
30572            var subContainerErrorArray = [],
30573                arrLen;
30574            _.each(this.children, function (child) {
30575                tempValidationStatus = child.validate(subContainerErrorArray);
30576                if (tempValidationStatus === false) {
30577                    validationStatus = false;
30578                }
30579            }, this);
30580
30581            tempValidationStatus = GuideItemsContainer._super.validate.call(this, subContainerErrorArray);
30582            if (tempValidationStatus === false) {
30583                validationStatus = false;
30584            }
30585            arrLen = subContainerErrorArray.length;
30586            while (arrLen > 0) {
30587                errorList[errorList.length] = subContainerErrorArray[subContainerErrorArray.length - arrLen];
30588                arrLen--;
30589            }
30590            return validationStatus;
30591        },
30592
30593        prepare : function () {
30594            _.each(this._children, function (childNode) {
30595                childNode.prepare();
30596            }, this);
30597            GuideItemsContainer._super.prepare.call(this);
30598        },
30599
30600        syncXFAProps : function () {
30601            GuideItemsContainer._super.syncXFAProps.apply(this, arguments);
30602            _.each(this._children, function (childNode) {
30603                childNode.syncXFAProps();
30604            });
30605        },
30606
30607        _initChildren : function (bLazyInitialization) {
30608            var panelItems = [],
30609                jsonModelItemsWithoutRepeatJson = {},
30610                keyLengthForJsonWithoutRepeat = 0,
30611                keyLengthJsonItemsOriginal = 0;
30612            
30613            
30614            
30615            
30616            
30617            _.each(this.jsonModel.items, function (item) {
30618                
30619                
30620                
30621                if (item.templateId && item.templateId.indexOf("GUID") === -1) {
30622                    jsonModelItemsWithoutRepeatJson[item.templateId] = item;
30623                }
30624            });
30625            keyLengthForJsonWithoutRepeat = _.keys(jsonModelItemsWithoutRepeatJson).length;
30626            
30627            keyLengthJsonItemsOriginal = _.keys(this.jsonModel.items || {}).length;
30628            if (keyLengthForJsonWithoutRepeat > 0 && keyLengthForJsonWithoutRepeat !== keyLengthJsonItemsOriginal) {
30629                this.jsonModel.items = jsonModelItemsWithoutRepeatJson;
30630            }
30631            _.each(this.jsonModel.items,
30632                function (item) {
30633                    if (_.isObject(item)) {
30634                        
30635                        
30636                        
30637                        
30638                        var options = {};
30639                        if (this.options._guideContainer) {
30640                            options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
30641                        }
30642                        var panelItemModel = guidelib.model.GuideModelRegistry.prototype.createModel(item, options);
30643                        panelItemModel._isItem = true;
30644                        this._initializeChild(panelItemModel);
30645                        panelItems.push(panelItemModel);
30646                    }
30647                },
30648                this);
30649            this._children = panelItems;
30650        },
30651
30652        _initializeChild : function (childItem) {
30653            childItem.parent = this;
30654        },
30655
30656        _normalizeChildren : function () {
30657            this._nameArray = {};
30658            this._private = {};
30659            _.each(this.children, function (child) {
30660                child._index = this._addProperty(child);
30661                
30662                child.getNaked(child._index, guidelib.__runtime__, null);
30663                child.getNaked(child._index, this._guide().runtime, null);
30664            }, this);
30665        },
30666
30667        nakedChildReferences : function (nIndex, obj) {
30668            var i, oNode;
30669            for (i = 0; i < this._children.length; i++) {
30670                oNode = this._children[i];
30671                oNode.getNaked(nIndex, obj, this);
30672            }
30673        },
30674        _getReducedJSON : function (isRepeatable) {
30675            var reducedJSONChildren,
30676                that = this,
30677                index =  0;
30678            
30679            reducedJSONChildren = GuideItemsContainer._super._getReducedJSON.call(this);
30680            reducedJSONChildren.items = {};
30681            
30682            
30683            
30684            
30685            _.each(this.jsonModel.items, function (childNode, key) {
30686                reducedJSONChildren.items[key] = that.items[index]._getReducedJSON(isRepeatable);
30687                index += 1;
30688            });
30689            return reducedJSONChildren;
30690        },
30691
30692        _addProperty : function (oValueObject) {
30693            var sName = oValueObject.getAttribute("name"),
30694                nIndex = 0;
30695            
30696            
30697            
30698            this._nameArray[sName] = this._nameArray[sName] || nIndex;
30699            nIndex = this._nameArray[sName]++;
30700            if (nIndex === 0) {
30701                
30702                
30703                
30704                
30705                guidelib.util.GuideUtil._createGetterSetter(this, sName, oValueObject);
30706            }
30707            return nIndex;
30708        },
30709
30710        _getTitle : function () {
30711            return this.jsonModel["jcr:title"];
30712        },
30713
30714        visit : function (callback, context) {
30715            GuideItemsContainer._super.visit.apply(this, arguments);
30716            _.each(this._children, function (child, index) {
30717                child.visit(callback, context);
30718            });
30719        },
30720
30721        playJson : function (pJsonModel) {
30722            if (pJsonModel) {
30723                var pJsonItems = _.filter(pJsonModel.items, function (item) {
30724                    if (_.isObject(item)) {
30725                        return true;
30726                    }
30727                    return false;
30728                }, this);
30729                
30730                _.each(this.items, function (childNode, index) {
30731                    childNode.playJson(pJsonItems[index]);
30732                }, this);
30733                GuideItemsContainer._super.playJson.call(this, pJsonModel);
30734            }
30735
30736        },
30737
30738        _collectValues : function (keyValue) {
30739            _.each(this._children, function (childNode) {
30740                childNode._collectValues(keyValue);
30741            }, this);
30742        },
30743
30744        getElement : function (elClassName) {
30745            var element = _.find(this._children, function (childModel) {
30746                return childModel.className === elClassName;
30747            }, this);
30748            return element;
30749        },
30750
30751        
30752        _unloadModel : function () {
30753            _.each(this.children, function (child) {
30754                child._unloadModel();
30755            }, this);
30756            GuideItemsContainer._super._unloadModel.call(this);
30757        },
30758
30759        _findChildren : function (oSOM, bMultiple) {
30760            var arr = [],
30761                elemFound = false;
30762            _.find(this._children, function (child) {
30763                if (oSOM === child._escapeQualifiedName()) {
30764                    arr.push(child._getNakedThis());
30765                    elemFound = true;
30766                }
30767                if (elemFound && !bMultiple) {
30768                    return true; 
30769                }
30770                if (elemFound && oSOM.indexOf("[*]") < 0) {
30771                    return true; 
30772                }
30773            }, this);
30774            return arr;
30775        },
30776
30777        
30778        resetData : function () {
30779            _.each(this._children, function (childNode) {
30780                childNode.resetData();
30781            }, this);
30782        },
30783
30784        
30785        _changeDescendantsAccess : function (value) {
30786            _.each(this.items, function (child) {
30787                child._setParentAccess(value);
30788                if (child instanceof guidelib.model.GuideItemsContainer) {
30789                    child._changeDescendantsAccess(value);
30790                }
30791            }, this);
30792        },
30793
30794        
30795        _changeContainerAccess : function (value) {
30796            this._changeDescendantsAccess(value);
30797        },
30798
30799        
30800        _changeDescendantsProperty : function (value, property, leafNodesOnly) {
30801            _.each(this.items, function (child) {
30802                if (child instanceof guidelib.model.GuideItemsContainer) {
30803                    if (!leafNodesOnly) {
30804                        child[property] = value;
30805                    }
30806                    child._changeDescendantsProperty(value, property);
30807                } else {
30808                    child[property] = value;
30809                }
30810            }, this);
30811        },
30812
30813        
30814        disableAllFields : function () {
30815            this.enabled = false;
30816            var property = "enabled";
30817            this._changeDescendantsProperty(false, property, true);
30818        }
30819
30820    });
30821
30822    GuideItemsContainer.defineProps({
30823        children : {
30824            get : function () {
30825                return (this._children || []).slice(0); 
30826            },
30827            set : function (value) {
30828                this._children = value;
30829            }
30830        },
30831
30832        
30833        items : {
30834            get : function () {
30835                var itemChildren = _.filter(this._children, function (child) {
30836                    if (child._isItem) {
30837                        return true;
30838                    }
30839                    return false;
30840                }, this);
30841                return itemChildren;
30842            }
30843        },
30844        
30845        _selfOrAncestorIsLazyReference : {
30846            get : function () {
30847                if (this._lazyReference) {
30848                    return true;
30849                }
30850                return guidelib.util.GuideUtil._checkIfAncestorIsALazyReference(this);
30851            }
30852        },
30853        _lazyReference : {
30854            get : function () {
30855                return !_.isUndefined(this.jsonModel["fragRef"])
30856                    && !_.isUndefined(this.jsonModel["optimizeRenderPerformance"]);
30857            }
30858        }
30859    });
30860
30861    GuideItemsContainer.addMixins([
30862        guidelib.model.mixin.ValidationsDisabled
30863    ]);
30864
30865}(_, guidelib));
30866
30867(function (_, guidelib) {
30868
30869    
30870    var GuideCompositeField = guidelib.model.GuideCompositeField = guidelib.model.GuideItemsContainer.extend({
30871        msClassName : "guideCompositeField",
30872        initialize : function () {
30873            this._uuid = guideBridge._produceUUID();
30874            GuideCompositeField._super.initialize.call(this);
30875        },
30876
30877        _setGuideValue : function (value) {
30878            if (!_.isEmpty(value)) {
30879                _.each(this.items, function (item) {
30880                    if (value.hasOwnProperty(item.name) && _.isFunction(item._setGuideValue)) {
30881                        item._setGuideValue(value[item.name]);
30882                    }
30883                }, this);
30884            }
30885        },
30886
30887        _collectExpressions : function () {
30888            GuideCompositeField._super._collectExpressions.apply(this);
30889            if (this.valueCommitScript) {
30890                
30891                this._compiledScripts.valueCommitScript = this._compileExpression(this.valueCommitScript, null);
30892            }
30893        }
30894    });
30895
30896    GuideCompositeField.defineProps({
30897        valueCommitScript : {
30898            get : function () {
30899                return this.getAttribute("valueCommitScript");
30900            }
30901        },
30902        uuid : {
30903            get : function () {
30904                return this._uuid;
30905            },
30906            set : function (newUuid) {
30907                if (this._uuid != newUuid) {
30908                    this._uuid = newUuid;
30909                }
30910            }
30911        }
30912    });
30913
30914})(_, guidelib);
30915
30916(function (_, guidelib) {
30917
30918    
30919    var GuideFileUpload = guidelib.model.GuideFileUpload = guidelib.model.GuideCompositeField.extend({
30920        msClassName : "guideFileUpload",
30921
30922        _getReducedJSON : function () {
30923            this._syncModelToAttachments();
30924            var reducedJSONChildren = GuideFileUpload._super._getReducedJSON.call(this),
30925                addtionalWhitelistedProperties = ["id", "files"];
30926            guidelib.model.util.CommonUtils.returnMinimalJSON(addtionalWhitelistedProperties, reducedJSONChildren, this);
30927            var fileAttachmentValue = reducedJSONChildren.files;
30928            reducedJSONChildren.files = this._getFileAttachmentNames(fileAttachmentValue);
30929            return reducedJSONChildren;
30930        },
30931
30932        _getContentType : function(fileUrl) {
30933            var contentType = null,
30934                self = this;
30935            if (self._fileAttachmentWrapper) {
30936                var element = self._fileAttachmentWrapper.find(function(x) { return x.data === fileUrl});
30937                if (element) {
30938                    contentType = element.contentType;
30939                }
30940            }
30941            return contentType
30942        },
30943
30944        
30945        _getFileAttachmentNames : function (fileAttachmentValue) {
30946            var value = fileAttachmentValue || this.value;
30947            if (value) {
30948                var self = this,
30949                    fileNames = _.map(value.split("\n"), function (val) {
30950                        if (self._fileAttachmentWrapper) {
30951                            var element = self._fileAttachmentWrapper.find(function(x) { return x.data === val});
30952                            if (element) {
30953                                return element.name;
30954                            }
30955                        }
30956                        var fName = val;
30957                        
30958                        if (fName.lastIndexOf("/") === fName.length - 1) {
30959                            fName = fName.substring(0, fName.length - 1);
30960                        }
30961                        return fName.substring(fName.lastIndexOf("/") + 1);
30962                }).join("\n");
30963                return fileNames;
30964            }
30965        },
30966
30967        _triggerFileListChange : function () {
30968            var currValue = this._fileList;
30969            this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
30970                guidelib.event.GuideModelEvent.createEvent(
30971                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
30972                    this,
30973                    "fileList",
30974                    currValue,
30975                    currValue
30976                )
30977            );
30978        },
30979
30980        _getCurrentFileAttachmentWrapper : function(attachments) {
30981            var currentListOfAttachments = null,
30982                effectiveBindRef = this._getEffectiveBindRef(),
30983                self = this;
30984            if (_.isArray(attachments) && attachments.length > 0) {
30985                currentListOfAttachments = attachments.filter(function(x) {
30986                    return x.bindRef === effectiveBindRef;
30987                })
30988            }
30989            return currentListOfAttachments;
30990        },
30991
30992        _playAttachmentWrappers : function(currentAttachmentWrappers) {
30993            var currValue = this.fileAttachment.value,
30994                _guide = this._guide();
30995            if (_.isArray(currentAttachmentWrappers) && currentAttachmentWrappers.length > 0) {
30996                this._fileAttachmentWrapper = currentAttachmentWrappers;
30997                
30998                if (this.valueCommitScript && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_PREFILL) && currValue) {
30999                    
31000                    _guide.queueExpressions(this, ["valueCommitScript"]);
31001                }
31002                var data = currentAttachmentWrappers.map(function(x) {return x.data});
31003                
31004                var fieldValue = data.join("\n");
31005                this.fileAttachment._setGuideValue(fieldValue);
31006                if (!_.isEmpty(fieldValue)) {
31007                    this._fileList = fieldValue.split("\n");
31008                }
31009            }
31010        },
31011
31012        playJson : function (pJsonModel, attachments) {
31013            if (attachments) {
31014                var currentListOfAttachments = this._getCurrentFileAttachmentWrapper(attachments);
31015                this._playAttachmentWrappers(currentListOfAttachments);
31016            } else {
31017                
31018                GuideFileUpload._super.playJson.call(this, pJsonModel);
31019            }
31020        },
31021
31022        _syncModelToAttachments : function () {
31023            var files = this.fileAttachment.value || "",
31024                filesArray = files.split('\n'),
31025                uniqueNames = guideBridge._makeFileNameUnique();
31026            var isIOS = guidelib.util.GuideUtil._isIOS();
31027            var files = this.fileAttachment.value || "",
31028                filesArray = files.split('\n'),
31029                areNamesUnique = (new Set(filesArray)).size === filesArray.length;
31030            this.jsonModel.files =
31031                _.map(files.split('\n'), function (file, index) {
31032                    if (!_.isEmpty(file)) {
31033                        if ((uniqueNames || (!areNamesUnique && isIOS))  && file[0] !== '/') {
31034                            file = this.uuid + "-" + (index + 1) + "__afAttachment__" + file; 
31035                        }
31036                    }
31037                    return file;
31038                }, this).join('\n');
31039        },
31040
31041        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31042            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, "_updateLiveData");
31043        },
31044
31045        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31046            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, "_playLiveData");
31047        },
31048
31049        _handleFileAttachmentItem : function (fileAttachmentModel, bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
31050            
31051            var dataUtils = this._guide().internal.liveDataUtils,
31052                dataContext = dataUtils._getDataContext(fileAttachmentModel, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
31053            if (recurse == "_updateLiveData") {
31054                dataUtils._updateLazyAttachmentMapFromModel(this);
31055                dataUtils.setDataValue(dataContext.indexedXpath, dataContext.xmlSec,
31056                    !fileAttachmentModel.isEmpty(), fileAttachmentModel.isEmpty() ? "" : this._getFileAttachmentValue());
31057            } else {
31058                var data = dataUtils._getAttachmentDataForModel(this);
31059                if (!_.isArray(data) && !_.isEmpty(data)) {
31060                    this.fileList = data.fileList;
31061                    var fileAttachmentValue = [];
31062                    var value = data.value.split("\n");
31063                    _.each(value, function (value, index) {
31064                        if (value[0] != '/') {
31065                            
31066                            
31067                            var name = value.substr(value.lastIndexOf("_") + 1);
31068                            fileAttachmentValue.push(name);
31069                        } else {
31070                            
31071                            fileAttachmentValue.push(value);
31072                        }
31073                    });
31074                    fileAttachmentModel.value = fileAttachmentValue.join("\n");
31075                }
31076                if (_.isArray(data) && data.length > 0) {
31077                    this._playAttachmentWrappers(data);
31078                }
31079                this._syncModelToAttachments();
31080            }
31081        },
31082
31083        _syncModelAndData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
31084            if (_.isString(recurse)) {
31085                var liveDataUtils = this._guide().internal.liveDataUtils;
31086                var dataContext = liveDataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
31087                if (dataContext.xmlSec === liveDataUtils.constants.BOUND_TAG) {
31088                    bound_indexedXpathSoFar = dataContext.indexedXpath;
31089                } else {
31090                    unBound_indexedXpathSoFar = dataContext.indexedXpath;
31091                }
31092                _.each(this.items, function (item) {
31093                    if (_.isFunction(item[recurse])) {
31094                        if (item.name == "fileAttachment") {
31095                            
31096                            
31097                            this._handleFileAttachmentItem(item, bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse);
31098                        } else {
31099                            item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
31100                        }
31101                    }
31102                }, this);
31103            }
31104        },
31105
31106        
31107        _getIndexedXpath : function (model, bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31108            var name = model.getAttribute("name").replace(/\s+/g, '');
31109            return unBound_indexedXpathSoFar ? unBound_indexedXpathSoFar + '/' + name : bound_indexedXpathSoFar + '/' + name;
31110        },
31111
31112        
31113        _getFileAttachmentValue : function () {
31114            
31115            
31116            
31117            this._syncModelToAttachments();
31118            return this._getFileAttachmentNames(this.jsonModel.files);
31119        }
31120
31121    });
31122
31123    GuideFileUpload.defineProps({
31124        
31125        multiSelection : {
31126            get : function () {
31127                return this.getAttribute("multiSelection");
31128            }
31129        },
31130
31131        buttonText : {
31132            get : function () {
31133                return this.getAttribute("buttonText");
31134            }
31135        },
31136
31137        showComment : {
31138            get : function () {
31139                return this.getAttribute("showComment");
31140            }
31141        },
31142
31143        
31144        fileSizeLimit : {
31145            get : function () {
31146                return this.getAttribute("fileSizeLimit");
31147            }
31148        },
31149
31150        fileList : {
31151            get : function () {
31152                return this._fileList;
31153            },
31154
31155            set : function (newValue) {
31156                var oldValue = this._fileList;
31157                var newTypedValue = newValue;
31158                if (newTypedValue != oldValue) {
31159                    this._fileList = newTypedValue;
31160                }
31161                
31162                
31163                
31164                var isIOS = guidelib.util.GuideUtil._isIOS(),
31165                    fileList = this._fileList,
31166                    that = this;
31167                if (isIOS && fileList) {
31168                    
31169                    this._fileAttachmentWrapperIOS = [];
31170                    
31171                    for
31171 (var i = 0; i < fileList.length; i++) {
31172                        if (!_.isString(fileList[i])) {
31173                            
31174                            var files = fileList[i].get(0).files,
31175                                _readFile = function (file) {
31176                                    
31177                                    that._fileAttachmentWrapperIOS.push(
31178                                        new Promise(function(resolve, reject){
31179                                            var reader = new FileReader();
31180                                            reader.onload = function() {
31181                                                var faWrapper = new guidelib.model.FileAttachmentWrapper({
31182                                                    name: file.name,
31183                                                    data: this.result,
31184                                                    formElementName : that.name,
31185                                                    contentType: file.type,
31186                                                    bindRef: that._getEffectiveBindRef()
31187                                                });
31188                                                resolve(faWrapper);
31189                                            };
31190                                            reader.onerror = reject;
31191                                            reader.readAsDataURL(file);
31192                                        })
31193                                    )
31194                                };
31195                            if (files) {
31196                                
31197                                [].forEach.call(files, _readFile);
31198                            }
31199                        }
31200                    }
31201                }
31202                this._triggerFileListChange();
31203            }
31204        },
31205        value : {
31206            get : function () {
31207                this._syncModelToAttachments();
31208                return this.jsonModel.files;
31209            }
31210        }
31211    });
31212
31213})(_, guidelib);
31214
31215(function (_, guidelib) {
31216    
31217    var GuideTermsAndConditions = guidelib.model.GuideTermsAndConditions =  guidelib.model.GuideCompositeField.extend({
31218        msClassName : "guideTermsAndConditions",
31219
31220        playJson : function (pJsonModel) {
31221            this.jsonModel.clickStatus = pJsonModel.clickStatus;
31222            GuideTermsAndConditions._super.playJson.apply(this, arguments);
31223        },
31224
31225        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31226            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, '_updateLiveData');
31227        },
31228
31229        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31230            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, '_playLiveData');
31231            if (this.reviewStatus.value === "true") {
31232                this.clickStatus = "agree";
31233            } else {
31234                this.clickStatus = "unreviewed";
31235            }
31236        },
31237
31238        _syncModelAndData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
31239            if (_.isString(recurse)) {
31240                var dataContext = this._guide().internal.liveDataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
31241                if (dataContext.xmlSec === this._guide().internal.liveDataUtils.constants.BOUND_TAG) {
31242                    bound_indexedXpathSoFar = dataContext.indexedXpath;
31243                } else {
31244                    unBound_indexedXpathSoFar = dataContext.indexedXpath;
31245                }
31246                _.each(this.items, function (item) {
31247                    if (_.isFunction(item[recurse])) {
31248                        item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
31249                    }
31250                });
31251            }
31252        }
31253    });
31254
31255    GuideTermsAndConditions.defineProps({
31256        showLink : {
31257            get : function () {
31258                return this.getAttribute("showLink");
31259            }
31260        },
31261
31262        
31263        clickStatus : {
31264            get : function () {
31265                return this.getAttribute("clickStatus");
31266            },
31267            set : function (status) {
31268                this.setAttribute(status, "clickStatus");
31269            }
31270        },
31271
31272        showAsPopUp : {
31273            get : function () {
31274                return this.getAttribute("showAsPopUp");
31275            }
31276        }
31277    });
31278
31279})(_, guidelib);
31280(function (_, guidelib) {
31281    var GuideToolbar = guidelib.model.GuideToolbar = guidelib.model.GuideItemsContainer.extend({
31282        msClassName : "guideToolbar",
31283
31284        initialize : function () {
31285            GuideToolbar._super.initialize.call(this);
31286        },
31287
31288        execNavigationChangeExpression : function () {
31289            _.each(this.items, function (childModel) {
31290                if (childModel.navigationChangeExp) {
31291                    this._guide().queueExpressions(childModel, "navigationChangeExp");
31292                }
31293            }, this);
31294        }
31295
31296    });
31297
31298})(_, guidelib);
31299
31300(function (_, guidelib) {
31301    var GuideAdModuleGroup = guidelib.model.GuideAdModuleGroup = guidelib.model.GuideItemsContainer.extend({
31302        msClassName : "guideAdModuleGroup",
31303
31304        _getTypedValue : function (value) {
31305            
31306            if (_.isUndefined(value) || value === null) {
31307                return null;
31308            }
31309            return value + "";
31310        },
31311
31312        playJson : function (pJsonModel) {
31313            var typedValue = this._getTypedValue(pJsonModel._value);
31314            
31315            if (typedValue || typedValue === "") {
31316                
31317                var olval = this.jsonModel._value;
31318                this.jsonModel._value = pJsonModel._value;
31319                this._triggerOnBridge("elementValueChanged", this, "value", olval, this.jsonModel._value);
31320            } else {
31321                
31322                GuideAdModuleGroup._super.playJson.call(this, pJsonModel);
31323            }
31324        }
31325    });
31326
31327    GuideAdModuleGroup.defineProps({
31328        
31329        value : {
31330            get : function () {
31331                return this._getTypedValue(this.jsonModel._value);
31332            },
31333            set : function (newValue) {
31334                var oldValue = this._getTypedValue(this.jsonModel._value),
31335                    newTypedValue = this._getTypedValue(newValue);
31336                
31337                if (newTypedValue !== undefined && (newTypedValue !== oldValue)) {
31338                    if (this.jsonModel._value !== newValue) {
31339                        this.jsonModel._value = newTypedValue || "";
31340                    }
31341                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
31342                }
31343            }
31344        }
31345    });
31346
31347}(_, guidelib));
31348(function (_, guidelib) {
31349    guidelib.model.mixin.AddDependencyMgmt = {
31350        normalProperties : {
31351            _addDependant : function (oNode, expressionType) {
31352                var dependantConf = this._findDependant(oNode);
31353                if (!dependantConf) {
31354                    dependantConf = {dependant : oNode, events : []};
31355                    this.dependants.push(dependantConf);
31356                }
31357
31358                if (dependantConf.events.indexOf(expressionType) < 0) {
31359                    dependantConf.events.push(expressionType);
31360                    oNode.on(guidelib.event.GuideModelEvent.OBJECT_DESTROYED, this._handleDependentDestroyed, this);
31361                }
31362            },
31363
31364            _notifyDependants : function () {
31365                _.each(this.dependants, function (dependantConf) {
31366                    this._guide().queueExpressions(dependantConf.dependant, dependantConf.events);
31367                }, this);
31368            },
31369
31370            _removeDependant : function (oNode) {
31371                oNode.off(guidelib.event.GuideModelEvent.OBJECT_DESTROYED, this._handleDependentDestroyed, this);
31372                var dependantConf = this._findDependant(oNode);
31373                this.dependants = _.without(this.dependants, dependantConf);
31374            },
31375
31376            _findDependant : function (oNode) {
31377                return _.find(this.dependants, function (conf) { return (conf.dependant === oNode); });
31378            },
31379
31380            _handleDependentDestroyed : function (event) {
31381                this._removeDependant(event.target);
31382            }
31383        }
31384    };
31385})(_, guidelib);
31386
31387(function (_, guidelib) {
31388    var GuideChart = guidelib.model.GuideChart = guidelib.model.Scriptable.extend({
31389        msClassName : "guideChart",
31390
31391        _collectExpressions : function () {
31392            GuideChart._super._collectExpressions.apply(this);
31393            this._compiledExpressions["aggregateExp"] = this._compileExpression('guidelib.chartUtils.gatherAxisData(this);', "data");
31394        }
31395    });
31396
31397    GuideChart.defineProps({
31398        
31399        data : {
31400            get : function () {
31401                var context = this._guide()._currentContext;
31402                if (context && context.contextNode && context.expression
31403                    && !(context.contextNode === this && context.expression === "aggregateExp")) {
31404                    this._addDependant(context.contextNode, context.expression);
31405                }
31406                return this.jsonModel.data;
31407            },
31408
31409            set : function (newValue) {
31410                var oldValue = this.jsonModel.data;
31411                this.jsonModel.data = newValue;
31412                
31413                var valueHasChanged = !_.isEqual(oldValue, newValue);
31414                if (valueHasChanged) {
31415                    
31416                    this._notifyDependants();
31417                    this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "data", oldValue, newValue);
31418                }
31419            }
31420        },
31421
31422        
31423        dataSourceType : {
31424            get : function () {
31425                return this.getAttribute("dataSourceType");
31426            },
31427            set : function (newValue) {
31428                var oldValue = this.jsonModel.dataSourceType;
31429                this.jsonModel.dataSourceType = newValue;
31430                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "dataSourceType", oldValue, newValue);
31431            }
31432        },
31433
31434        
31435        width : {
31436            get : function () {
31437                return this.getAttribute("width");
31438            },
31439
31440            set : function (newValue) {
31441                this.jsonModel.width = newValue;
31442            }
31443        },
31444        
31445        height : {
31446            get : function () {
31447                return this.getAttribute("height");
31448            },
31449
31450            set : function (newValue) {
31451                this.jsonModel.height = newValue;
31452            }
31453        },
31454        
31455        xAxisTitle : {
31456            get : function () {
31457                return this.getAttribute("xAxisTitle");
31458            },
31459            set : function (newValue) {
31460                this.jsonModel.chartType = newValue;
31461            }
31462        },
31463        
31464        yAxisTitle : {
31465            get : function () {
31466                return this.getAttribute("yAxisTitle");
31467            },
31468            set : function (newValue) {
31469                this.jsonModel.chartType = newValue;
31470            }
31471        },
31472        
31473        chartType : {
31474            get : function () {
31475                return this.getAttribute("chartType");
31476            },
31477            set : function (newValue) {
31478                var oldValue = this.jsonModel.chartType;
31479                this.jsonModel.chartType = newValue;
31480                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "chartType", oldValue, newValue);
31481            }
31482        },
31483        
31484        repeatableItem : {
31485            get : function () {
31486                return this.getAttribute("repeatableItem");
31487            },
31488            set : function (newValue) {
31489                this.jsonModel.repeatableItem = newValue;
31490            }
31491        },
31492        
31493        xExp : {
31494            get : function () {
31495                return this.getAttribute("xExp");
31496            },
31497            set : function (newValue) {
31498                this.jsonModel.xExp = newValue;
31499            }
31500        },
31501        
31502        reducerXFunction : {
31503            get : function () {
31504                return this.getAttribute("reducerXFunction");
31505            },
31506            set : function (newValue) {
31507                this.jsonModel.reducerXFunction = newValue;
31508                if (newValue !== 'none') {
31509                    this.jsonModel.reducerYFunction = 'none';
31510                }
31511            }
31512        },
31513        
31514        yExp : {
31515            get : function () {
31516                return this.getAttribute("yExp");
31517            },
31518            set : function (newValue) {
31519                this.jsonModel.yExp = newValue;
31520            }
31521        },
31522        
31523        reducerYFunction : {
31524            get : function () {
31525                return this.getAttribute("reducerYFunction");
31526            },
31527            set : function (newValue) {
31528                this.jsonModel.reducerYFunction = newValue;
31529                if (newValue !== 'none') {
31530                    this.jsonModel.reducerXFunction = 'none';
31531                }
31532            }
31533        },
31534        
31535        innerRadius : {
31536            get : function () {
31537                return this.getAttribute("innerRadius");
31538            },
31539            set : function (newValue) {
31540                this.jsonModel.innerRadius = newValue;
31541            }
31542        },
31543        
31544        lineColor : {
31545            get : function () {
31546                return this.getAttribute("lineColor");
31547            },
31548            set : function (newValue) {
31549                this.jsonModel.lineColor = newValue;
31550            }
31551        },
31552        
31553        pointColor : {
31554            get : function () {
31555                return this.getAttribute("pointColor");
31556            },
31557            set : function (newValue) {
31558                this.jsonModel.pointColor = newValue;
31559            }
31560        },
31561        
31562        areaColor : {
31563            get : function () {
31564                return this.getAttribute("areaColor");
31565            },
31566            set : function (newValue) {
31567                this.jsonModel.areaColor = newValue;
31568            }
31569        },
31570        
31571        tooltipHtml : {
31572            get : function () {
31573                return this.getAttribute("tooltipHtml");
31574            },
31575            set : function (newValue) {
31576                this.jsonModel.tooltipHtml = newValue;
31577            }
31578        },
31579        
31580        showLegends : {
31581            get : function () {
31582                return this.getAttribute("showLegends");
31583            },
31584            set : function (newValue) {
31585                this.jsonModel.showLegends = newValue;
31586            }
31587        },
31588        
31589        legendPosition : {
31590            get : function () {
31591                return this.getAttribute("legendPosition");
31592            },
31593            set : function (newValue) {
31594                this.jsonModel.legendPosition = newValue;
31595            }
31596        }
31597    });
31598
31599    GuideChart.addMixins([
31600        guidelib.model.mixin.AddDependencyMgmt
31601    ]);
31602}(_, guidelib));
31603(function (_, guidelib) {
31604
31605    
31606    var Field = guidelib.model.Field = guidelib.model.Scriptable.extend({
31607        msClassName : "field",
31608        
31609        _runValidation : true,
31610        initialize : function () {
31611            Field._super.initialize.call(this);
31612            this.jsonModel["{default}"] = this.getOrElse(this.jsonModel, "{default}", this.jsonModel._value);
31613            this.isValid = true;
31614            this.forceErrorShow = false;
31615            
31616            this._bParentValidationsDisabled = false;
31617            
31618            this._validationsDisabled = false;
31619            
31620            this._failedTest = null;
31621
31622            
31623            this._errorText = "";
31624
31625            var effectiveBindRef = this._getEffectiveBindRef();
31626            
31627            if (this.isGlobal || (this._guide() && this._guide().internal.liveModel.isLive(effectiveBindRef))) {
31628                this._guide().internal.liveModel.add(effectiveBindRef, this);
31629            }
31630        },
31631        _postInitialize: function() {
31632            Field._super._postInitialize.call(this);
31633            if (this.getAttribute("dorExclusion") !== null && this.jsonModel.visible === false) {
31634                if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true")
31635                    ||
31636                    (this._guide().print &&
31637                        this._guide().print["excludeFromDoRIfHidden"] === "true")) {
31638                    this.dorExclusion = true;
31639                }
31640            }
31641        },
31642        _unloadModel : function () {
31643            var effectiveBindRef = this.bindRef || this.getAttribute("name");
31644            if (this.isGlobal || this._guide().internal.liveModel.isLive(effectiveBindRef)) {
31645                this._guide().internal.liveModel.remove(effectiveBindRef, this);
31646            }
31647            Field._super._unloadModel.call(this);
31648        },
31649
31650        _collectExpressions : function () {
31651            Field._super._collectExpressions.apply(this);
31652            if (this.calcExp) {
31653                this._compiledExpressions.calcExp = this._compileExpression(this.calcExp, "value");
31654            }
31655            if (this.validateExp) {
31656                
31657                this._compiledScripts.validateExp = this._compileExpression(this.validateExp, null);
31658            }
31659            if (this.valueCommitScript) {
31660                
31661                
31662                this._compiledScripts.valueCommitScript = this._compileExpression(this.valueCommitScript, null);
31663            }
31664            
31665            this._compiledScripts.validateAllExp = this._compileExpression("this._runTests()", null);
31666        },
31667
31668        _handleXfaModelChanged : function (event) {
31669            if (event._property === "rawValue") {
31670                this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value",
31671                    event.prevText, event.newText);
31672            } else if (event._property == "ClearError" || event._property == "ValidationState") {
31673                
31674                this._guide().queueExpressions(this, ["validateAllExp"]);
31675            } else {
31676                Field._super._handleXfaModelChanged.call(this, event);
31677            }
31678        },
31679
31680        
31681        
31682        validate : function (errorList) {
31683            
31684            if (!this.visible) {
31685                return true;
31686            }
31687            if (_.isUndefined(errorList)) {
31688                errorList = [];
31689            }
31690            var status = true;
31691            this._runTests(true);
31692            if (this._errorText) {
31693                errorList.push({
31694                    som : this.somExpression,
31695                    errorText : this._errorText
31696                });
31697                status = false;
31698            }
31699            return status;
31700        },
31701
31702        _getTypedValue : function (value) {
31703            if (this.checkIfNull(value)) {
31704                return null;
31705            }
31706            return value + "";
31707        },
31708
31709        _getFormattedValue : function (value) {
31710            if (_.isUndefined(value) || value === null || value === "") {
31711                return null;
31712            }
31713
31714            var picture = this.jsonModel.displayPictureClause;
31715            
31716            if (picture) {
31717                try {
31718                    
31719                    var formattedValue = xfalib.ut.PictureFmt.format(value + "", picture, null, true);
31720                    
31721                    return formattedValue != null && formattedValue !== "" ? formattedValue : value;
31722                } catch (exception) {
31723                    
31724                }
31725            }
31726            return value;
31727        },
31728
31729        _getValue : function () {
31730            if (this.bindNode) {
31731                return this.bindNode.rawValue;
31732            }
31733            return this._getTypedValue(this.jsonModel._value);
31734        },
31735
31736        _triggerDisplayFormatChange : function () {
31737            var currValue = this._getValue();
31738            this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value",
31739                currValue, this._getFormattedValue(currValue));
31740        },
31741
31742        
31743        checkIfNull : function (value) {
31744            return value == null || value === ""; 
31745        },
31746
31747        
31748        isEmpty : function () {
31749            return this.checkIfNull(this.value);
31750        },
31751
31752        _setXFAValue : function (value) {
31753            this.bindNode.rawValue = value;
31754        },
31755
31756        
31757        _setXFAMandatory : function (value) {
31758            
31759            
31760            var convertor = this._guide()._guideSchema.getConvertor("mandatory");
31761            if (convertor) {
31762                
31763                
31764                this.bindNode.validate.nullTest = convertor.guideToXfa.apply(this, [!!value]);
31765            }
31766        },
31767
31768        _setGuideValue : function (value) {
31769            this.jsonModel._value = (value === undefined || value === null) ? null : value;
31770        },
31771
31772        _runMandatoryTest : function () {
31773            var currValue = this._getValue(),
31774                isNull = this.checkIfNull(currValue);
31775            return !isNull;
31776        },
31777
31778        _runValidatePictureTest : function () {
31779            var value = this._getValue(),
31780                validateFlag = true,
31781                regex;
31782            if (!this.checkIfNull(value) && this.validatePictureClause) {
31783                
31784                try {
31785                    value = xfalib.ut.PictureFmt.format(value + "", this.validatePictureClause, null, false);
31786                } catch (exception) {
31787                    
31788                    this.logger().log("AF", exception);
31789                    
31790                    if (exception.indexOf("Invalid picture clause") !== -1) {
31791                        value = undefined;
31792                    } else {
31793                        value = null;
31794                    }
31795                }
31796            }
31797            if (_.isUndefined(value)) {
31798                try {
31799                    
31800                    regex = new RegExp(this.validatePictureClause);
31801                    if (regex) {
31802                        validateFlag = regex.test(this._getValue());
31803                    }
31804                } catch (exception) {
31805                    
31806                    this.logger().error("AF", "Invalid Regular Expression" + exception);
31807                    validateFlag = false;
31808                }
31809            } else if (value === null) {
31810                validateFlag = false;
31811            }
31812
31813            return validateFlag;
31814        },
31815
31816        
31817        _runTests : function (forceRun) {
31818            
31819            var validFlag = true,
31820                prevErrorText = this._errorText,
31821                prevValidationState = this.validationState,
31822                obj = {
31823                    'validFlag' : validFlag,
31824                    'forceRun' : forceRun
31825                };
31826
31827            if (this.validationsDisabled === true) {
31828                
31829                
31830                return true;
31831            }
31832
31833            this._runValidations(obj);
31834            validFlag = obj.validFlag;
31835
31836            if (validFlag) {
31837                this._errorText = "";
31838                this.validationState = true;
31839                
31840                this._failedTest = null;
31841            } else {
31842                this.validationState = false;
31843            }
31844            
31845            if ((prevErrorText !== this._errorText) || (prevValidationState !== this.validationState) || forceRun) {
31846                
31847                if (forceRun) {
31848                    this.forceErrorShow = true;
31849                }
31850                this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
31851                    "validationStatus", this.validationState, this._errorText);
31852            }
31853
31854            return this.validationState;
31855        },
31856
31857        playJson : function (pJsonModel) {
31858            var currValue = pJsonModel._value,
31859                _guide = this._guide();
31860            
31861            if (this.valueCommitScript && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_PREFILL) && currValue) {
31862                
31863                _guide.queueExpressions(this, ["valueCommitScript"]);
31864            }
31865            this._setGuideValue(pJsonModel._value);
31866        },
31867
31868        
31869        _runValidations : function (obj) {
31870            var isRegex = false,
31871                INVALID_PICTURE_CLAUSE_LIST = ["date.default{}", "date.short{}", "date.medium{}",
31872                    "date.long{}", "date.full{}", "num.percent{}", "num.decimal{}", "num.currency{}"];
31873            if (this.bindNode) {
31874                if (this.validatePictureClause && (this.value || this.value === 0)) {
31875                    
31876                    
31877                    try {
31878                        xfalib.ut.PictureFmt.format(this.value + "", this.validatePictureClause, null, false);
31879                    } catch (exception) {
31880                        if (INVALID_PICTURE_CLAUSE_LIST.indexOf(this.validatePictureClause) >= 0) {
31881                            isRegex = false;
31882                        } else if (exception.indexOf("Invalid picture clause") !== -1) {
31883                            isRegex = true;
31884                        }
31885                    }
31886                }
31887                if (isRegex) {
31888                    try {
31889                        
31890                        var regex = new RegExp(this.validatePictureClause);
31891                        if (regex) {
31892                            obj.validFlag = regex.test(this._getValue());
31893                        }
31894                    } catch (exception) {
31895                        this.logger().error("AF", "Error in running regular expression" + exception);
31896                        obj.validFlag = false;
31897                    }
31898                    if (!obj.validFlag) {
31899                        this.bindNode._setErrorData("formatTest", this.getOrElse(this.bindNode.validate.formatTest, this.bindNode._defaults.validate.formatTest), this.bindNode.formatMessage);
31900                        this._errorText = this.bindNode._errorText;
31901                        xfalib.ut.XfaUtil.prototype._triggerOnBridge("elementValidationStatusChanged", this.bindNode, "validationStatus", false, true);
31902                        this.bindNode.execEvent("validationState");
31903                    }
31904                } else {
31905                    if (obj.forceRun) {
31906                        this.bindNode.execValidate();
31907                    }
31908                    this._errorText = this.bindNode._errorText;
31909                    if (this._errorText) {
31910                        obj.validFlag = false;
31911                    }
31912                }
31913                
31914                this._failedTest = this.bindNode._mFailedValTest;
31915            } else {
31916                
31917                if (this.mandatory) {
31918                    obj.validFlag = this._runMandatoryTest();
31919                    if (!obj.validFlag) {
31920                        this._errorText = this.mandatoryMessage;
31921                        this._failedTest = this.guideUtil.MANDATORY_TEST;
31922                    }
31923                }
31924                if (obj.validFlag && this.validatePictureClause && !this.checkIfNull(this.value)) {
31925                    obj.validFlag = this._runValidatePictureTest();
31926                    if (!obj.validFlag) {
31927                        this._errorText = this.validatePictureClauseMessage;
31928                        this._failedTest = this.guideUtil.FORMAT_TEST;
31929                    }
31930                }
31931            }
31932
31933            if (obj.validFlag && this.validateExp) {
31934                obj.validFlag = this.executeExpression("validateExp");
31935                if (!obj.validFlag) {
31936                    this._errorText = this.validateExpMessage;
31937                    this._failedTest = this.guideUtil.SCRIPT_TEST;
31938                }
31939            }
31940        },
31941
31942        _collectValues : function (keyValue) {
31943            
31944            keyValue[this.name] = this.value;
31945        },
31946
31947        
31948        resetData : function () {
31949            this._runValidation = false;
31950            this.value = this.jsonModel["{default}"];
31951            this._runValidation = true;
31952            
31953            this._errorText = "";
31954            this.validationState = true;
31955            this._failedTest = null;
31956            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_RESET,
31957                "validationStatus", this.validationState, this._errorText);
31958        },
31959
31960        _preserveLazyValue : function () {
31961            return !(_.contains(['guideButton', 'guideTextDraw', 'guideAdobeSignBlock'], this.className) || this._isXfaNode());
31962        },
31963
31964        
31965        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31966            if (this._preserveLazyValue()) {
31967                var dataUtils = this._guide().internal.liveDataUtils,
31968                    dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar,
31969                        unBound_indexedXpathSoFar),
31970                    isRichText = this instanceof guidelib.model.GuideTextBox && this.allowRichText,
31971                    setValue = isRichText ? dataUtils.setRichTextValue : dataUtils.setDataValue;
31972                setValue.apply(dataUtils, [dataContext.indexedXpath, dataContext.xmlSec,
31973                    !this.isEmpty(), this.isEmpty() ? "" : this.value]);
31974            }
31975        },
31976
31977        
31978        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31979            if (this._preserveLazyValue()) {
31980                var dataUtils = this._guide().internal.liveDataUtils,
31981                    dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar,
31982                        unBound_indexedXpathSoFar),
31983                    isRichText = this instanceof guidelib.model.GuideTextBox && this.allowRichText,
31984                    getValue = isRichText ? dataUtils.getRichTextValue : dataUtils.getDataValue;
31985                var value = getValue.apply(dataUtils, [dataContext.indexedXpath, dataContext.xmlSec]);
31986                if (value != undefined) {
31987                    this.value = value;
31988                }
31989            }
31990        },
31991
31992        
31993        _allowEmptyValueString : function () {
31994            return false;
31995        },
31996
31997        markAsInvalid : function (errorText, shouldShowError) {
31998            shouldShowError = (typeof shouldShowError !== 'undefined') ? shouldShowError : false;
31999            this.validationState = false;
32000            if (!errorText) {
32001                errorText = this.validateExpMessage;
32002            }
32003            if(shouldShowError) {
32004                this._errorText = errorText;
32005                this.forceErrorShow = true;
32006            }
32007            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
32008                "validationStatus", this.validationState, errorText);
32009        },
32010
32011        
32012        _isStateOverridden : function (property) {
32013            return this.getOrElse(this.jsonModel.stateOverrides, property, null) != null;
32014        }
32015    });
32016
32017    Field.defineProps({
32018        calcExp : {
32019            get : function () {
32020                return this.getAttribute("calcExp");
32021            }
32022        },
32023
32024        
32025        isGlobal : {
32026            get : function () {
32027                return this.getAttribute('isGlobal') === "true";
32028            }
32029        },
32030
32031        
32032        title : {
32033            get : function () {
32034                return this.getAttribute("jcr:title");
32035            },
32036            set : function (title) {
32037                this.setAttribute(title, "jcr:title");
32038            }
32039        },
32040
32041        valueCommitScript : {
32042            get : function () {
32043                return this.getAttribute("valueCommitScript");
32044            }
32045        },
32046
32047        validateExp : {
32048            get : function () {
32049                return this.getAttribute("validateExp");
32050            }
32051        },
32052
32053        
32054        placeholderText : {
32055            get : function () {
32056                return this.getAttribute("placeholderText");
32057            }
32058        },
32059
32060        
32061        value : {
32062            get : function () {
32063                var context = this.getOrElse(this._guide(), "_currentContext", null);
32064                if (context && context.managedExp
32065                    
32066                    && !(context.contextNode === this
32067                    && context.expression === "calcExp")) {
32068                    
32069                    this._addDependant(context.contextNode, context.expression);
32070                }
32071                return this._getValue();
32072            },
32073            set : function (newValue) {
32074                var oldValue = this._getValue(),
32075                    newTypedValue = this._getTypedValue(newValue),
32076                    _guide = this._guide();
32077                
32078                if (this._allowEmptyValueString() && newValue === "") {
32079                    newTypedValue = "";
32080                }
32081
32082                
32083                if (newTypedValue !== undefined && !(this.checkIfNull(newTypedValue) && this.checkIfNull(oldValue))
32084                    && (newTypedValue !== oldValue)) {
32085                    if (this.bindNode) {
32086                        this._setXFAValue(newTypedValue);
32087                    } else if (this.jsonModel._value !== newValue) {
32088                        this._setGuideValue(newTypedValue);
32089                    }
32090                    if (_guide && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE)) {
32091                        var context = _guide._currentContext,
32092                            contextNode = this.getOrElse(context, "contextNode", null),
32093                            contextExpression = this.getOrElse(context, "expression", null);
32094                        if (!context || contextNode != this || contextExpression != "valueCommitScript") {
32095                            
32096                            _guide.queueExpressions(this, ["valueCommitScript"]);
32097                        }
32098                    }
32099                    
32100                    this._notifyDependants();
32101                    
32102                    if (this._runValidation && _guide) {
32103                        _guide.queueExpressions(this, ["validateAllExp"]);
32104                    }
32105                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
32106                    
32107                    
32108                    if (!this.bindNode || (this.bindNode && this.getAttribute("html5Type") !== undefined)) {
32109                        this._triggerDisplayFormatChange();
32110                    }
32111                }
32112            }
32113        },
32114
32115        
32116        formattedValue : {
32117            get : function () {
32118                var value;
32119                if (this.bindNode) {
32120                    value = this.bindNode.formattedValue;
32121                } else {
32122                    value = this._getFormattedValue(this._getValue());
32123                }
32124                return value;
32125            }
32126        },
32127
32128        
32129        displayPictureClause : {
32130            get : function () {
32131                return this.getAttribute("displayPictureClause");
32132            }
32133        },
32134
32135        
32136        validatePictureClause : {
32137            get : function () {
32138                if (this.jsonModel.displayIsSameAsValidate) {
32139                    return this.displayPictureClause;
32140                }
32141                return this.getAttribute("validatePictureClause");
32142            }
32143        },
32144
32145        
32146        editPictureClause : {
32147            get : function () {
32148                if (this.jsonModel.isEditSameAsDisplayPattern) {
32149                    return this.displayPictureClause;
32150                }
32151                return this.getAttribute("editPictureClause");
32152            }
32153        },
32154
32155        
32156        isEditPictureClausePresent : {
32157            get : function () {
32158                return typeof this.editPictureClause !== 'undefined';
32159            }
32160        },
32161
32162        
32163        mandatory : {
32164            get : function () {
32165                return this.getAttribute("mandatory");
32166            },
32167
32168            set : function (newValue) {
32169                var oldValue = this.getAttribute("mandatory");
32170                if (newValue !== undefined && oldValue !== newValue) {
32171                    if (this.bindNode) {
32172                        this._setXFAMandatory(newValue);
32173                    } else {
32174                        
32175                        this.jsonModel.mandatory = !!newValue;
32176                    }
32177                    
32178                    this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "mandatory", oldValue, newValue);
32179                }
32180            }
32181        },
32182
32183        
32184        mandatoryMessage : {
32185            get : function () {
32186                return this.getAttribute("mandatoryMessage");
32187            }
32188        },
32189
32190        
32191        validateExpMessage : {
32192            set : function (message) {
32193                
32194                if (this.isValid) {
32195                    this.jsonModel.validateExpMessage = message;
32196                } else {
32197                    this.setAttribute(message, "validateExpMessage");
32198                }
32199            },
32200            get : function () {
32201                return this.getAttribute("validateExpMessage");
32202            }
32203        },
32204
32205        
32206        validatePictureClauseMessage : {
32207            get : function () {
32208                return this.getAttribute("validatePictureClauseMessage");
32209            }
32210        },
32211
32212        
32213        validationState : {
32214            get : function () {
32215                return this.isValid;
32216            },
32217            set : function (newValue) {
32218                var oldVal = this.isValid;
32219                if (oldVal != newValue) {
32220                    this.isValid = newValue;
32221                    this._triggerOnBridge("elementValidationStatusChanged", this,
32222                        "validationStatus", oldVal, newValue);
32223                }
32224            }
32225        },
32226        
32227        width : {
32228            get : function () {
32229                return this.getAttribute("width");
32230            },
32231
32232            set : function (newValue) {
32233                this.jsonModel.width = newValue;
32234            }
32235        },
32236        
32237        height : {
32238            get : function () {
32239                return this.getAttribute("height");
32240            },
32241
32242            set : function (newValue) {
32243                this.jsonModel.height = newValue;
32244            }
32245        }
32246    });
32247
32248    Field.addMixins([
32249        guidelib.model.mixin.AddDependencyMgmt,
32250        guidelib.model.mixin.ValidationsDisabled
32251    ]);
32252}(_, guidelib));
32253
32254(function (_, guidelib) {
32255    
32256    var GuideButton = guidelib.model.GuideButton = guidelib.model.Field.extend({
32257        msClassName : "guideButton",
32258        defaultClickExpressions : {
32259            "moveNext" : "window.guideBridge.setFocus(this.panel.somExpression, 'nextItem', true)",
32260            "movePrev" : "window.guideBridge.setFocus(this.panel.somExpression, 'prevItem', true)"
32261        },
32262        defaultNavigationExpressions : {
32263            "moveNext" : "this.visible=this.panel.navigationContext.hasNextItem",
32264            "movePrev" : "this.visible=this.panel.navigationContext.hasPrevItem"
32265        },
32266
32267        _collectExpressions : function () {
32268            GuideButton._super._collectExpressions.apply(this);
32269            if (this.clickExp) {
32270                this._compiledScripts["clickExp"] = this._compileExpression(this.clickExp, null);
32271            } else if (this.targetVersion >= 1.1 && this.defaultClickExpressions[this.type]) {                  
32272                this.jsonModel.clickExp = this.defaultClickExpressions[this.type];                              
32273                this._compiledScripts["clickExp"] = this._compileExpression(this.clickExp, null);               
32274            }
32275            if (this.navigationChangeExp) {
32276                this._compiledScripts["navigationChangeExp"] = this._compileExpression(this.navigationChangeExp, null);
32277            } else if (this.targetVersion >= 1.1 &&  this.defaultNavigationExpressions[this.type]) {
32278                this.jsonModel.navigationChangeExp = this.defaultNavigationExpressions[this.type];
32279                this._compiledScripts["navigationChangeExp"] = this._compileExpression(this.navigationChangeExp, null);
32280            }
32281        },
32282
32283    });
32284
32285    GuideButton.defineProps({
32286        clickExp : {
32287            get : function () {
32288                return this.jsonModel.clickExp;
32289            }
32290        },
32291        navigationChangeExp : {
32292            get : function () {
32293                return this.jsonModel.navigationChangeExp;
32294            }
32295        },
32296        
32297        type : {
32298            get : function () {
32299                return this.getAttribute("type");
32300            }
32301        }
32302    });
32303})(_, guidelib);
32304
32305(function (_, guidelib) {
32306    var GuideListFileAttachmentButton = guidelib.model.GuideListFileAttachmentButton = guidelib.model.GuideButton.extend({
32307        msClassName : "guideListFileAttachmentButton",
32308        initialize : function () {
32309            
32310            if (_.isUndefined(this.jsonModel.clickExp)) {
32311                this.jsonModel.clickExp = "guideBridge._updateFileListing.call(this,this)";
32312
32313            }
32314            GuideListFileAttachmentButton._super.initialize.apply(this, arguments);
32315        }
32316    });
32317
32318})(_, guidelib);
32319(function (_, guidelib) {
32320    var GuideCheckBox = guidelib.model.GuideCheckBox = guidelib.model.Field.extend({
32321        msClassName : "guideCheckBox",
32322        
32323        _collectExpressions : function () {
32324            GuideCheckBox._super._collectExpressions.apply(this);
32325            if (this.optionsExp) {
32326                this._compiledExpressions.optionsExp = this._compileExpression(this.optionsExp, "items");
32327            }
32328        },
32329
32330        getOnOffValues : function (index) {
32331            var temp = this.jsonModel.options || [], items = [], on, off;
32332            if (this.bindNode) {
32333                on = this.bindNode.getSaveItem(0);
32334                off = this.bindNode.getSaveItem(1);
32335            } else {
32336
32337                if (temp.length == 0) {
32338                    on = "0";
32339                } else {
32340                    on = temp[index].split('=')[0].trim();
32341                }
32342                off = "-100";
32343            }
32344
32345            items = [on, off];
32346            return items;
32347        },
32348
32349        _setXFAValue : function (value) {
32350            
32351            if (value === "" || value === null) {
32352                this.bindNode.rawValue = this.bindNode.getSaveItem(1) || null;
32353            } else {
32354                this.bindNode.rawValue = value;
32355            }
32356        },
32357
32358        _getCustomAssist : function (index) {
32359            var customAssist, item;
32360
32361            if (index == null) {
32362
32363                if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
32364                    return this.bindNode.assist.speak.value;
32365                }
32366                return null;
32367            }
32368
32369            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
32370                item = this.bindNode.members.item(index);
32371                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
32372                    customAssist = item.assist.speak.value;
32373                }
32374            } else if (this.jsonModel.custom) {
32375
32376                var custom;
32377                custom = this.jsonModel.custom || [];
32378                if (_.isString(custom) && index <= 0) {
32379                    customAssist = custom;
32380                } else if (!custom.length === 0) {
32381                    customAssist = custom[index];
32382                }
32383            }
32384            return customAssist;
32385        },
32386        _getToolTip : function (index) {
32387            var toolTip, item;
32388            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
32389                item = this.bindNode.members.item(index);
32390
32391                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
32392                    toolTip = item.assist.toolTip.value;
32393                }
32394
32395            }
32395 else if (this.jsonModel.shortDescription) {
32396                toolTip = this.jsonModel.shortDescription;
32397            }
32398            return toolTip;
32399        },
32400        _getCaption : function (index) {
32401            var item, caption, option;
32402            if (index == null) {
32403
32404                if (this.bindNode && this.bindNode.caption && this.bindNode.caption.value && this.bindNode.caption.value.oneOfChild && this.bindNode.caption.value.oneOfChild.value) {
32405                    return this.bindNode.caption.value.oneOfChild.value;
32406                }
32407                return null;
32408            }
32409            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
32410                item = this.bindNode.members.item(index);
32411                if (item.caption && item.caption.value && item.caption.value.oneOfChild && item.caption.value.oneOfChild.value) {
32412                    caption = item.caption.value.oneOfChild.value;
32413                }
32414
32415            } else if (this.jsonModel.options) {
32416                var options;
32417                options = this.jsonModel.options || [];
32418                if (index < 0) {
32419                    index = 0;
32420                }
32421                if (!options.length == 0) {
32422                    option = options[index];
32423                    caption = guidelib.util.GuideUtil.getOptionsKeyValue(option).pop();
32424                }
32425
32426            }
32427            return caption;
32428        },
32429        _getName : function (index) {
32430            if (this.bindNode && this.bindNode.members && this.bindNode.members.item && this.bindNode.members.item(index)) {
32431                
32432                return this.bindNode.members.item(index).name;
32433            }
32434            return null;
32435        },
32436
32437        _getScreenReaderText : function (index) {
32438            var screenReaderText, assistPriority = this._getAssistPriority() || "caption";
32439
32440            if (this.bindNode) {
32441                screenReaderText = GuideCheckBox._super._getScreenReaderText.apply(this, [index]);
32442            } else {
32443                if (assistPriority == "custom") {
32444                    screenReaderText = this._getCustomAssist(index) || this._getCaption(index);
32445                } else if (assistPriority == "caption") {
32446                    screenReaderText = this._getCaption(index);
32447                }
32448            }
32449            return screenReaderText;
32450        }
32451    });
32452
32453    GuideCheckBox.defineProps({
32454        
32455        optionsExp : {
32456            get : function () {
32457                return this.getAttribute("optionsExp");
32458            }
32459        },
32460
32461        
32462        items : {
32463            get : function () {
32464                var items  =  this.jsonModel.options;
32465                if (items && !_.isArray(items)) {
32466                    items = items.split(",");
32467                } else if (items) {
32468                    items = items.slice(0);
32469                }
32470                return items;
32471            },
32472            set : function (newValue) {
32473                if (!this.bindNode) {
32474                    var oldValue = this.jsonModel.options;
32475                    if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
32476                        
32477                        this.jsonModel.options = newValue;
32478                        this._resetModelValueForOptionChange();
32479                        this._addStateOverride("options", {"option" : this._getOptionsArray()});
32480                        this._triggerItemsChange(oldValue, newValue);
32481                    }
32482                }
32483            }
32484        }
32485    });
32486
32487    GuideCheckBox.addMixins([
32488        guidelib.model.mixin.ChoiceGroupOptionHandler
32489    ]);
32490})(_, guidelib);
32491(function (_, guidelib) {
32492    var GuideSwitch = guidelib.model.GuideSwitch = guidelib.model.GuideCheckBox.extend({
32493        msClassName : "guideSwitch",
32494
32495        initialize : function () {
32496            
32497            var uncheckedValue = this.getOnOffValues()[1];
32498            this.jsonModel["_value"] = this.getOrElse(this.jsonModel, "_value", uncheckedValue);
32499            GuideSwitch._super.initialize.call(this);
32500        },
32501
32502        getOnOffValues : function (index) {
32503            var options, checkedLabel, uncheckedLabel, items;
32504            if (this.bindNode) {
32505                checkedLabel = this.bindNode.getSaveItem(0);
32506                uncheckedLabel = this.bindNode.getSaveItem(1);
32507            } else {
32508                items = this.jsonModel.options;
32509                
32510                if (Array.isArray(items) && items.length > 0) {
32511                    checkedLabel = items[0].split('=')[0].trim();
32512                } else if (!_.isUndefined(items) && items.length > 0) {
32513                    checkedLabel = items.split('=')[0].trim();
32514                } else {
32515                    checkedLabel = "1";
32516                }
32517                if (Array.isArray(items) && items.length > 1) {
32518                    uncheckedLabel = items[1].split('=')[0].trim();
32519                } else {
32520                    uncheckedLabel = "0";
32521                }
32522            }
32523            options = [checkedLabel, uncheckedLabel];
32524            return options;
32525        },
32526
32527        resetData : function () {
32528            this.value = this.jsonModel["{default}"];
32529        }
32530    });
32531})(_, guidelib);
32532(function (_, guidelib) {
32533    var GuideTextDraw = guidelib.model.GuideTextDraw = guidelib.model.Field.extend({
32534        msClassName : "guideTextDraw",
32535
32536        _valueEscapeRegex : new RegExp('\\$', 'g'),
32537
32538        
32539        _getValue : function () {
32540            if (this.bindNode) {
32541                return this.bindNode._getValue(null, true);
32542            }
32543            return this._getTypedValue(this.jsonModel._value);
32544        },
32545
32546        
32547        playJson : function (pJsonModel) {
32548            
32549            this._setGuideValue(this._floatingFieldResolutionFunction(pJsonModel));
32550        },
32551
32552        _allowEmptyValueString : function () {
32553            return true;
32554        },
32555
32556        _isFloatingField : function () {
32557            return this.documentFragmentVariables && this.documentFragmentVariables.length > 0;
32558        },
32559
32560        _floatingFieldResolutionFunction : function (jsonModel) {
32561            var resolvedValue = this.value,
32562                variableRegexMap = this._variableRegexMap,
32563                valueEscapeRegex = this._valueEscapeRegex,
32564                somExpression = this.somExpression,
32565                self = this,
32566
32567                
32568                variablesDefaultValue = [],
32569                documentFragmentVariables = this.documentFragmentVariables;
32570            if (jsonModel.documentFragmentVariables) {
32571                for (var index = 0 ; index < jsonModel.documentFragmentVariables.length ; index++) {
32572                    variablesDefaultValue[index] = jsonModel.documentFragmentVariables[index]._value;
32573                }
32574            }
32575            this.jsonModel.defaultValue = variablesDefaultValue;
32576            _.each(variableRegexMap, function (regexPattern, variableId) {
32577                var textVariable,
32578                    bindRef,
32579                    floatingFieldValue;
32580                textVariable = documentFragmentVariables.filter(function (variable) {
32581                    return variable.variableId === variableId;
32582                })[0];
32583                bindRef = textVariable.bindRef;
32584                if (!bindRef) {
32585                    bindRef = textVariable.name;
32586                }
32587                
32588                if (jsonModel && jsonModel.documentFragmentVariables && jsonModel.documentFragmentVariables.length > 0) {
32589                    var variableFromPlayJson = jsonModel.documentFragmentVariables.filter(function (variable) {
32590                        return variable.variableId === variableId;
32591                    })[0];
32592                    floatingFieldValue = variableFromPlayJson._value;
32593                } else {
32594                    floatingFieldValue = guidelib.util.GuideUtil.getValueForBindRefField(bindRef, somExpression, this._guide());
32595                }
32596                if (!floatingFieldValue) {
32597                    
32598                    floatingFieldValue = "";
32599                } else {
32600                    
32601                    
32602                    floatingFieldValue = floatingFieldValue.replace(valueEscapeRegex, '$$$$');
32603                }
32604                if (floatingFieldValue) {
32605                    var dataType = textVariable.dataType,
32606                        displayPattern = textVariable.displayPictureClause;
32607                    if (dataType === 'number' || dataType === 'integer') {
32608                        displayPattern = displayPattern ? displayPattern : 'num{zzz,zzz,zzz,zzz,zzz,zzz,zzz.zzzzzzzzzzzzzzz}';
32609                    } else if (dataType === 'date-time' || dataType === 'date') {
32610                        displayPattern = displayPattern ? displayPattern : 'date{' + guidelib.i18n.datePatterns.med + '}';
32611                    }
32612
32613                    if (displayPattern) {
32614                        if (floatingFieldValue.indexOf(',') !== -1) {
32615                            
32616                            var valArray = floatingFieldValue.split(','),
32617                            tmpValue = "";
32618                            valArray.forEach(function (val) {
32619                                tmpValue = tmpValue + guidelib.util.GuideUtil.formatValue(val, displayPattern, dataType) + ", " ;
32620                            });
32621                            floatingFieldValue = tmpValue.substr(0, tmpValue.length - 2);
32622                        } else {
32623                            floatingFieldValue = guidelib.util.GuideUtil.formatValue(floatingFieldValue, displayPattern, dataType);
32624                        }
32625                    }
32626                }
32627                resolvedValue = resolvedValue.replace(regexPattern, floatingFieldValue);
32628            });
32629            return resolvedValue;
32630        },
32631
32632        initialize : function () {
32633            if (this._isFloatingField()) {
32634                var variableRegexMap = this._variableRegexMap = {};
32635                _.each(this.documentFragmentVariables, function (documentFragmentVariable) {
32636                    var variableId = documentFragmentVariable.variableId,
32637                        regexPattern;
32638                    if (!variableRegexMap[variableId]) {
32639                        
32640                        regexPattern = '(?:<df-variable[^>]*variableid="' + variableId + '"[^>]*>)[^<]*(?:<\/df-variable>)';
32641                        variableRegexMap[variableId] = new RegExp(regexPattern, 'ig');
32642                    }
32643                });
32644            }
32645            GuideTextDraw._super.initialize.apply(this, [arguments]);
32646        }
32647    });
32648
32649    GuideTextDraw.defineProps({
32650        calcExp : {
32651            get : function () {
32652                return this._calcExp;
32653            }
32654        },
32655
32656        documentFragmentVariables : {
32657            get : function () {
32658                return this.jsonModel.documentFragmentVariables;
32659            }
32660        }
32661    });
32662}(_, guidelib));
32663
32664(function (_, guidelib) {
32665    var GuideAdobeSignBlock = guidelib.model.GuideAdobeSignBlock = guidelib.model.GuideTextDraw.extend({
32666        msClassName : "guideAdobeSignBlock"
32667    });
32668}(_, guidelib));
32669(function (_, guidelib) {
32670    
32671    var GuideTextBox = guidelib.model.GuideTextBox = guidelib.model.Field.extend({
32672        msClassName : "guideTextBox",
32673
32674        
32675        _runMinimumLengthTest : function () {
32676            return this.value && this.value.length >= this.minLength;
32677        },
32678
32679        
32680        _runTotalLengthTest : function () {
32681            return this.value && this.value.length === this.length;
32682        },
32683
32684        
32685        _runValidations : function (obj) {
32686            GuideTextBox._super._runValidations.call(this, obj);
32687            if (obj.validFlag) {
32688
32689                if (this.length != null) {
32690                    obj.validFlag = this._runTotalLengthTest();
32691                    if (!obj.validFlag) {
32692                        this._errorText = this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalLengthMessage, [this.length]);
32693                        this._failedTest = this.guideUtil.LENGTH_TEST;
32694                    }
32695                } else if (this.minLength != null) {
32696                    obj.validFlag =  this._runMinimumLengthTest();
32697                    if (!obj.validFlag) {
32698                        this._errorText = this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minimumLengthMessage, [this.minLength]);
32699                        this._failedTest = this.guideUtil.MINIMUM_LENGTH_TEST;
32700                    }
32701                }
32702
32703            }
32704        },
32705
32706        
32707        _runMandatoryTest : function () {
32708            if (this.allowRichText) {
32709                
32710                
32711                var getTextContent = function (htmlString) {
32712                        var result = htmlString,
32713                            regex = null;
32714                        if (htmlString != null) {
32715                            
32716                            
32717                            regex = /(<([^>]+)>)/ig;
32718                            result = htmlString.replace(regex, "");
32719                        }
32720                        return result;
32721                    },
32722                    currValue = getTextContent(this._getValue()),
32723                    isNull = this.checkIfNull(currValue);
32724                return !isNull;
32725            } else {
32726                return GuideTextBox._super._runMandatoryTest.apply(this, arguments);
32727            }
32728        },
32729
32730        _allowEmptyValueString : function () {
32731            return true;
32732        }
32733
32734    });
32735
32736    GuideTextBox.defineProps({
32737        
32738        "multiLine" : {
32739            get : function () {
32740                return this.getAttribute("multiLine");
32741            }
32742        },
32743
32744        
32745        "maxChars" : {
32746            get : function () {
32747                return this.getAttribute("maxChars");
32748            }
32749        },
32750
32751        
32752        "minLength" : {
32753            get : function () {
32754                return this.getAttribute("minLength");
32755            }
32756        },
32757
32758        
32759        "length" : {
32760            get : function () {
32761                return this.getAttribute("length");
32762            }
32763        },
32764        
32765        "allowRichText" : {
32766            get : function () {
32767                return this.getAttribute("allowRichText");
32768            }
32769        }
32770    });
32771
32772}(_, guidelib));
32773
32774(function (_, guidelib) {
32775    
32776    var countriesDialingCodesMap = {
32777        '441481' : 'Guernsey',
32778        '441624' : 'Isle of Man',
32779        '441534' : 'Jersey',
32780        '1868' : 'Trinidad and Tobago',
32781        '1473' : 'Grenada',
32782        '1670' : 'Northern Mariana Islands',
32783        '1869' : 'Saint Kitts and Nevis',
32784        '1758' : 'Saint Lucia',
32785        '1671' : 'Guam',
32786        "1684" : "American Samoa",
32787        "1268" : "Antigua and Barbuda",
32788        "1264" : "Anguilla",
32789        "1242" : "Bahamas",
32790        "1246" : "Barbados",
32791        '1441' : 'Bermuda',
32792        '1284' : 'British Virgin Islands',
32793        '1345' : 'Cayman Islands',
32794        '1787' : 'Puerto Rico',
32795        '1876' : 'Jamaica',
32796        '1939' : 'Puerto Rico',
32797        '1767' : 'Dominica',
32798        '1809' : 'Dominican Republic',
32799        '1829' : 'Dominican Republic',
32800        '1664' : 'Montserrat',
32801        '1849' : 'Dominican Republic',
32802        '1340' : 'U.S. Virgin Islands',
32803        '1784' : 'Saint Vincent and the Grenadines',
32804        '1649' : 'Turks and Caicos Islands',
32805        '1721' : 'Sint Maarten',
32806        "355" : "Albania",
32807        "213" : "Algeria",
32808        "376" : "Andorra",
32809        "244" : "Angola",
32810        "672" : "Antarctica",
32811        "374" : "Armenia",
32812        "297" : "Aruba",
32813        "994" : "Azerbaijan",
32814        "973" : "Bahrain",
32815        "880" : "Bangladesh",
32816        "375" : "Belarus",
32817        "501" : "Belize",
32818        "229" : "Benin",
32819        '975' : 'Bhutan',
32820        '591' : 'Bolivia',
32821        '387' : 'Bosnia and Herzegovina',
32822        '267' : 'Botswana',
32823        '246' : 'British Indian Ocean Territory',
32824        '673' : 'Brunei',
32825        '359' : 'Bulgaria',
32826        '226' : 'Burkina Faso',
32827        '257' : 'Burundi',
32828        '855' : 'Cambodia',
32829        '237' : 'Cameroon',
32830        '238' : 'Cape Verde',
32831        '236' : 'Central African Republic',
32832        '235' : 'Chad',
32833        '269' : 'Comoros',
32834        '682' : 'Cook Islands',
32835        '506' : 'Costa Rica',
32836        '385' : 'Croatia',
32837        
32838        '357' : 'Cyprus',
32839        '420' : 'Czech Republic',
32840        '243' : 'Democratic Republic of the Congo',
32841        '253' : 'Djibouti',
32842        '670' : 'East Timor',
32843        '593' : 'Ecuador',
32844        '503' : 'El Salvador',
32845        '240' : 'Equatorial Guinea',
32846        '291' : 'Eritrea',
32847        '372' : 'Estonia',
32848        '251' : 'Ethiopia',
32849        '500' : 'Falkland Islands',
32850        '298' : 'Faroe Islands',
32851        '679' : 'Fiji',
32852        '358' : 'Finland',
32853        '689' : 'French Polynesia',
32854        '241' : 'Gabon',
32855        '220' : 'Gambia',
32856        '995' : 'Georgia',
32857        '233' : 'Ghana',
32858        '350' : 'Gibraltar',
32859        '299' : 'Greenland',
32860        '502' : 'Guatemala',
32861        '224' : 'Guinea',
32862        '245' : 'Guinea-Bissau',
32863        '592' : 'Guyana',
32864        '509' : 'Haiti',
32865        '504' : 'Honduras',
32866        '852' : 'Hong Kong',
32867        '354' : 'Iceland',
32868        '964' : 'Iraq',
32869        '353' : 'Ireland',
32870        '972' : 'Israel',
32871        '225' : 'Ivory Coast',
32872        '962' : 'Jordan',
32873        '254' : 'Kenya',
32874        '686' : 'Kiribati',
32875        '383' : 'Kosovo',
32876        '965' : 'Kuwait',
32877        '996' : 'Kyrgyzstan',
32878        '856' : 'Laos',
32879        '371' : 'Latvia',
32880        '961' : 'Lebanon',
32881        '266' : 'Lesotho',
32882        '231' : 'Liberia',
32883        '218' : 'Libya',
32884        '423' : 'Liechtenstein',
32885        '370' : 'Lithuania',
32886        '352' : 'Luxembourg',
32887        '853' : 'Macau',
32888        '389' : 'Macedonia',
32889        '261' : 'Madagascar',
32890        '265' : 'Malawi',
32891        '960' : 'Maldives',
32892        '223' : 'Mali',
32893        '356' : 'Malta',
32894        '692' : 'Marshall Islands',
32895        '222' : 'Mauritania',
32896        '230' : 'Mauritius',
32897        
32898        '691' : 'Micronesia',
32899        '373' : 'Moldova',
32900        '377' : 'Monaco',
32901        '976' : 'Mongolia',
32902        '382' : 'Montenegro',
32903        
32904        '258' : 'Mozambique',
32905        '264' : 'Namibia',
32906        '674' : 'Nauru',
32907        '977' : 'Nepal',
32908        '599' : 'Netherlands Antilles',
32909        '687' : 'New Caledonia',
32910        '505' : 'Nicaragua',
32911        '227' : 'Niger',
32912        '234' : 'Nigeria',
32913        '683' : 'Niue',
32914        '850' : 'North Korea',
32915        '968' : 'Oman',
32916        '680' : 'Palau',
32917        '970' : 'Palestine',
32918        '507' : 'Panama',
32919        '675' : 'Papua New Guinea',
32920        '595' : 'Paraguay',
32921        '351' : 'Portugal',
32922        '974' : 'Qatar',
32923        '242' : 'Republic of the Congo',
32924        '262' : 'Reunion',
32925        '250' : 'Rwanda',
32926        
32927        '290' : 'Saint Helena',
32928        '590' : 'Saint Martin',
32929        '508' : 'Saint Pierre and Miquelon',
32930        '685' : 'Samoa',
32931        '378' : 'San Marino',
32932        '239' : 'Sao Tome and Principe',
32933        '966' : 'Saudi Arabia',
32934        '221' : 'Senegal',
32935        '381' : 'Serbia',
32936        '248' : 'Seychelles',
32937        '232' : 'Sierra Leone',
32938        '421' : 'Slovakia',
32939        '386' : 'Slovenia',
32940        '677' : 'Solomon Islands',
32941        '252' : 'Somalia',
32942        '211' : 'South Sudan',
32943        '249' : 'Sudan',
32944        '597' : 'Suriname',
32945        '268' : 'Swaziland',
32946        '963' : 'Syria',
32947        '886' : 'Taiwan',
32948        '992' : 'Tajikistan',
32949        '255' : 'Tanzania',
32950        '228' : 'Togo',
32951        '690' : 'Tokelau',
32952        '676' : 'Tonga',
32953        '216' : 'Tunisia',
32954        '993' : 'Turkmenistan',
32955        '688' : 'Tuvalu',
32956        '256' : 'Uganda',
32957        '380' : 'Ukraine',
32958        '971' : 'United Arab Emirates',
32959        '598' : 'Uruguay',
32960        '998' : 'Uzbekistan',
32961        '678' : 'Vanuatu',
32962        '379' : 'Vatican',
32963        '681' : 'Wallis and Futuna',
32964        '212' : 'Western Sahara',
32965        '967' : 'Yemen',
32966        '260' : 'Zambia',
32967        '263' : 'Zimbabwe',
32968        '60' : 'Malaysia',
32969        '58' : 'Venezuela',
32970        '30' : 'Greece',
32971        '84' : 'Vietnam',
32972        '44' : 'United Kingdom',
32973        '45' : 'Denmark',
32974        '53' : 'Cuba',
32975        '46' : 'Sweden',
32976        '52' : 'Mexico',
32977        '41' : 'Switzerland',
32978        '40' : 'Romania',
32979        
32980        '36' : 'Hungary',
32981        
32982        "43" : "Austria",
32983        '34' : 'Spain',
32984        '91' : 'India',
32985        '62' : 'Indonesia',
32986        '98' : 'Iran',
32987        '94' : 'Sri Lanka',
32988        '27' : 'South Africa',
32989        '95' : 'Myanmar',
32990        '65' : 'Singapore',
32991        '39' : 'Italy',
32992        '82' : 'South Korea',
32993        "32" : "Belgium",
32994        '81' : 'Japan',
32995        '31' : 'Netherlands',
32996        '20' : 'Egypt',
32997        "54" : "Argentina",
32998        "93" : "Afghanistan",
32999        
33000        '56' : 'Chile',
33001        '86' : 'China',
33002        '51' : 'Peru',
33003        '63' : 'Philippines',
33004        '64' : 'Pitcairn',
33005        '48' : 'Poland',
33006        '47' : 'Norway',
33007        '33' : 'France',
33008        
33009        '61' : 'Cocos Islands',
33010        '55' : 'Brazil',
33011        '92' : 'Pakistan',
33012        '49' : 'Germany',
33013        '57' : 'Colombia',
33014        '66' : 'Thailand',
33015        '90' : 'Turkey',
33016        
33017        '1' : 'Canada',
33018        
33019        '7' : 'Russia'
33020    };
33021
33022    var GuideTelephone = guidelib.model.GuideTelephone = guidelib.model.GuideTextBox.extend({
33023        msClassName : "guideTelephone",
33024
33025        _extractNumericDigits : function (telephoneNumber) {
33026            var digitArray,
33027                number = "";
33028            if (telephoneNumber) {
33029                digitArray = telephoneNumber.match(/\d+/g);
33030                if (digitArray) {
33031                    number = digitArray.join("");
33032                }
33033            }
33034            return number;
33035        },
33036
33037        _extractCountryCode : function (telephoneNumber) {
33038            var number = this._extractNumericDigits(telephoneNumber);
33039            if (!number || (telephoneNumber && number && telephoneNumber.lastIndexOf("+", 0) !== 0)) {
33040                return "";
33041            }
33042            for (var countryCode in countriesDialingCodesMap) {
33043                if (number && number.lastIndexOf(countryCode, 0) === 0) {
33044                    return countryCode;
33045                }
33046            }
33047            return "";
33048        },
33049
33050        _extractPhoneNumber : function (telephoneNumber) {
33051            var countryCode = this._extractCountryCode(telephoneNumber),
33052                number = this._extractNumericDigits(telephoneNumber),
33053                phoneNumber = "";
33054            if (number) {
33055                phoneNumber = number.substr(countryCode.length);
33056            }
33057            return phoneNumber;
33058        }
33059    });
33060
33061    GuideTelephone.defineProps({
33062        
33063        countryCode : {
33064            get : function () {
33065                var value = this._getValue();
33066                return this._extractCountryCode(value);
33067            }
33068        },
33069
33070        
33071        phoneNumber : {
33072            get : function () {
33073                var value = this._getValue();
33074                return this._extractPhoneNumber(value);
33075            }
33076        }
33077    });
33078
33079}(_, guidelib));
33080
33081(function (_, guidelib) {
33082    var GuideRadioButton = guidelib.model.GuideRadioButton = guidelib.model.Field.extend({
33083        msClassName : "guideRadioButton",
33084        prevOnItem : null,
33085        initialize : function () {
33086            
33087            GuideRadioButton._super.initialize.call(this);
33088        },
33089
33090        _postInitialize : function () {
33091            GuideRadioButton._super._postInitialize.call(this);
33092            this.prevOnItem = this.getSelectedIndex(this.value);
33093            if (this.bindNode && this.bindNode.members) {
33094                for (var i = 0; i < this.bindNode.members.length; i++) {
33095                    var field = this.bindNode.members.item(i);
33096                    field.on(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
33097                }
33098            }
33099        },
33100
33101        _unloadModel : function () {
33102            if (this.bindNode && this.bindNode.members) {
33103                for (var i = 0; i < this.bindNode.members.length; i++) {
33104                    var field = this.bindNode.members.item(i);
33105                    field.off(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
33106                }
33107            }
33108
33109            GuideRadioButton._super._unloadModel.call(this);
33110        },
33111
33112        
33113        _collectExpressions : function () {
33114            GuideRadioButton._super._collectExpressions.apply(this);
33115            if (this.optionsExp) {
33116                this._compiledExpressions.optionsExp = this._compileExpression(this.optionsExp, "items");
33117            }
33118        },
33119
33120        
33121        getItemIdentifier : function (index) {
33122            if (this.bindNode) {
33123                return this.bindNode.members.item(index).somExpression;
33124            } else {
33125                return index;
33126            }
33127
33128        },
33129
33130        playJson : function (pJsonModel) {
33131            GuideRadioButton._super.playJson.call(this, pJsonModel);
33132            this.prevOnItem = this.getSelectedIndex(this.jsonModel._value);
33133        },
33134
33135        getOnOffValues : function (index) {
33136            var temp = this.jsonModel.options || [],
33137                items = [],
33138                on,
33139                off;
33140            if (this.bindNode) {
33141                var item = this.bindNode.members.item(index);
33142                on = item.getSaveItem(0);
33143                off = item.getSaveItem(1) ? item.getSaveItem(1) : null;
33144            } else {
33145
33146                if (temp.length == 0) {
33147                    on = "0";
33148                } else {
33149                    on = temp[index].split('=')[0].trim();
33150                }
33151                off = null;
33152            }
33153
33154            items = [on, off];
33155            return items;
33156        },
33157
33158        _handleXfaModelChanged : function (event) {
33159            if (event._property == "rawValue") {
33160                this.trigger(guidelib.event.GuideModelEvent.VALUE_CHANGED,
33161                    guidelib.event.GuideModelEvent.createEvent(
33162                        guidelib.event.GuideModelEvent.VALUE_CHANGED,
33163                        this,
33164                        "value",
33165                        event.target.somExpression,
33166                        event.newText
33167                    )
33168                );
33169            } else {
33170                GuideRadioButton._super._handleXfaModelChanged.call(this, event);
33171            }
33172        },
33173
33174        getSelectedIndex : function (value) {
33175            var index = null;
33176            if (!_.isEmpty(this.jsonModel.options) && !_.isArray(this.jsonModel.options)) {
33177                this.jsonModel.options = [this.jsonModel.options];
33178            }
33179            var currOption = _.find(this.jsonModel.options, function (opt, i) {
33180                var items = this.getOnOffValues(i);
33181                index = i;
33182                return (items[0] == value);
33183            }, this);
33184
33185            if (currOption) {
33186                return index;
33187            } else {
33188                return null;
33189            }
33190
33191        },
33192
33193        
33194
33195        _triggerDisplayFormatChange : function () {
33196            if (!this.bindNode) {
33197                var currValue = this._getValue();
33198                var currSelected = this.getSelectedIndex(currValue);
33199
33200                if (this.prevOnItem !== null) {
33201                    this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value", this.prevOnItem, null);
33202                }
33203                if (currSelected !== null) {
33204                    this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value", currSelected, this._getFormattedValue(currValue));
33205                }
33206                this.prevOnItem = currSelected;
33207            }
33208        },
33209        _getCustomAssist : function (index) {
33210            var customAssist, item;
33211
33212            if (index == null) {
33213
33214                if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
33215                    return this.bindNode.assist.speak.value;
33216                }
33217                return null;
33218            }
33219
33220            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33221                item = this.bindNode.members.item(index);
33222                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33223                    customAssist = item.assist.speak.value;
33224                }
33225            } else if (this.jsonModel.custom) {
33226
33227                var custom;
33228                custom = this.jsonModel.custom || [];
33229                if (_.isString(custom) && index <= 0) {
33230
33231                    customAssist = custom;
33232                } else {
33233                    if (!custom.length == 0) {
33234                        customAssist = custom[index];
33235                    }
33236                }
33237            }
33238            return customAssist;
33239        },
33240        _getToolTip : function (index) {
33241            var toolTip, item;
33242            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33243                item = this.bindNode.members.item(index);
33244
33245                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33246                    toolTip = item.assist.toolTip.value;
33247                }
33248
33249            }
33249 else if (this.jsonModel.shortDescription) {
33250                toolTip = this.jsonModel.shortDescription;
33251            }
33252            return toolTip;
33253        },
33254        _getCaption : function (index) {
33255            var item, caption, option;
33256            if (index == null) {
33257
33258                if (this.bindNode && this.bindNode.caption && this.bindNode.caption.value && this.bindNode.caption.value.oneOfChild && this.bindNode.caption.value.oneOfChild.value) {
33259                    return this.bindNode.caption.value.oneOfChild.value;
33260                }
33261                return null;
33262            }
33263            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33264                item = this.bindNode.members.item(index);
33265                if (item.caption && item.caption.value && item.caption.value.oneOfChild && item.caption.value.oneOfChild.value) {
33266                    caption = item.caption.value.oneOfChild.value;
33267                }
33268
33269            } else if (this.jsonModel.options) {
33270                var options;
33271                options = this.jsonModel.options || [];
33272                if (index < 0) {
33273                    index = 0;
33274                }
33275                if (!options.length == 0) {
33276                    option = options[index];
33277                    caption = guidelib.util.GuideUtil.getOptionsKeyValue(option).pop();
33278                }
33279
33280            }
33281            return caption;
33282        },
33283        _getName : function (index) {
33284            if (this.bindNode && this.bindNode.members && this.bindNode.members.item && this.bindNode.members.item(index)) {
33285                
33286                return this.bindNode.members.item(index).name;
33287            }
33288            return null;
33289        },
33290
33291        _getScreenReaderText : function (index) {
33292            var screenReaderText, assistPriority = this._getAssistPriority() || "caption";
33293
33294            if (this.bindNode) {
33295                screenReaderText = GuideRadioButton._super._getScreenReaderText.apply(this, [index]);
33296            } else {
33297                if (assistPriority == "custom") {
33298                    screenReaderText = this._getCustomAssist(index) || this._getCaption(index);
33299                } else if (assistPriority == "caption") {
33300                    screenReaderText = this._getCaption(index);
33301                }
33302            }
33303            return screenReaderText;
33304        }
33305    });
33306
33307    GuideRadioButton.defineProps({
33308        
33309        optionsExp : {
33310            get : function () {
33311                return this.getAttribute("optionsExp");
33312            }
33313        },
33314
33315        
33316        items : {
33317            get : function () {
33318                var items  =  this.jsonModel.options;
33319                if (items && !_.isArray(items)) {
33320                    items = items.split(",");
33321                } else if (items) {
33322                    items = items.slice(0);
33323                }
33324                return items;
33325            },
33326            set : function (newValue) {
33327                if (!this.bindNode && newValue && newValue.length > 1) {
33328                    var oldValue = this.jsonModel.options;
33329                    if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
33330                        
33331                        this.jsonModel.options = newValue;
33332                        this._resetModelValueForOptionChange();
33333                        this._addStateOverride("options", {"option" : this._getOptionsArray()});
33334                        this._triggerItemsChange(oldValue, newValue);
33335                    }
33336                }
33337            }
33338        }
33339    });
33340
33341    GuideRadioButton.addMixins([
33342        guidelib.model.mixin.ChoiceGroupOptionHandler
33343    ]);
33344})(_, guidelib);
33345
33346(function (_, guidelib) {
33347    var GuidePasswordBox = guidelib.model.GuidePasswordBox = guidelib.model.Field.extend({
33348        msClassName : "guidePasswordBox",
33349        
33350        _getReducedJSON : function () {
33351            
33352            
33353            if (this.submitPassword) {
33354                return GuidePasswordBox._super._getReducedJSON.call(this);
33355            }
33356            
33357            var whitelistedProperties = ["name", "templateId", "guideNodeClass"],
33358                reducedJsonObject = {};
33359            guidelib.model.util.CommonUtils.returnMinimalJSON(whitelistedProperties, reducedJsonObject, this);
33360            return reducedJsonObject;
33361        },
33362
33363        _preserveLazyValue : function () {
33364            return !!this.submitPassword && GuidePasswordBox._super._preserveLazyValue.call(this);
33365        },
33366
33367        _allowEmptyValueString : function () {
33368            return true;
33369        }
33370    });
33371    GuidePasswordBox.defineProps({
33372        submitPassword : {
33373            get : function () {
33374                return this.getAttribute("submitPassword");
33375            }
33376        }
33377    });
33378
33379})(_, guidelib);
33380
33381(function (_, guidelib) {
33382    var GuideScribble = guidelib.model.GuideScribble = guidelib.model.Field.extend({
33383        msClassName : "guideScribble"
33384    });
33385})(_, guidelib);
33386(function (_, guidelib) {
33387    var GuideCompositeFieldItem = guidelib.model.GuideCompositeFieldItem = guidelib.model.Field.extend({
33388        msClassName : "GuideCompositeFieldItem"
33389    });
33390
33391    GuideCompositeFieldItem.defineProps({
33392        
33393        bindRef : {
33394            get : function () {
33395                if (this.parent && !this.parent._isXfaNode() && !_.isEmpty(this.parent.bindRef)) {
33396                    return this.parent.bindRef + '/' + this.getAttribute("name").replace(/\s+/g, '');
33397                } else {
33398                    return (this.getAttribute("bindRef") || "").replace(/\s+/g, '');
33399                }
33400            }
33401        }
33402    });
33403
33404})(_, guidelib);
33405(function (_, guidelib) {
33406
33407    
33408    var GuideNumericBox = guidelib.model.GuideNumericBox = guidelib.model.Field.extend({
33409        msClassName : "guideNumericBox",
33410
33411        _getTypedValue : function (value) {
33412            var dataType = this.dataType,
33413                tmpValue, str, leadD, fracD;
33414
33415            if (this.checkIfNull(value)) {
33416                return null;
33417            }
33418            switch (dataType) {
33419                case "integer":
33420                    tmpValue = parseInt(value);
33421                    break;
33422                case "float":
33423                    tmpValue = parseFloat(value);
33424                    break;
33425                case "decimal":
33426                    tmpValue = parseFloat(value);
33427                    if (!isNaN(tmpValue)) {
33428                        str =  tmpValue.toString();
33429                        leadD = str.indexOf(".");
33430                        leadD = leadD === -1 ? str.length : leadD;
33431                        leadD = str.indexOf("-") === 0 ? leadD - 1 : leadD;
33432                        fracD = str.length - leadD - 1;
33433                        if (fracD > this.fracDigits && this.fracDigits !== -1) {
33434                            tmpValue = parseFloat(tmpValue.toFixed(this.fracDigits));
33435                        }
33436                        if (leadD > this.leadDigits && this.leadDigits !== -1) {
33437                            return undefined;
33438                        }
33439                    }
33440                    break;
33441            }
33442            if (isNaN(tmpValue)) {
33443                return undefined;
33444            }
33445            return tmpValue;
33446        },
33447        _getFormattedValue : function (value) {
33448            if (_.isUndefined(value) || value === null || value === "") {
33449                return null;
33450            }
33451
33452            var picture = this.jsonModel.displayPictureClause,
33453                defaultPattern = "zzzzzzzzzzzzzzzzzzzzz.zzzzzzzzzzzzzzz";
33454
33455            
33456            try {
33457                if (picture && this.jsonModel.html5Type !== "number") {
33458                    return xfalib.ut.PictureFmt.format(value + "", picture, guideBridge._readRuntimeLocale(), true);
33459                } else {
33460                    var pattern = (this.jsonModel.html5Type === "number") ? defaultPattern : guidelib.i18n.numberPatterns.numeric;
33461                    return xfalib.ut.PictureFmt.format(value + "", "num{" + pattern + "}",
33462                        guideBridge._readRuntimeLocale(), true, true);
33463                }
33464            } catch (exception) {
33465                this.logger().error("Cannot format value " + value + " " + exception);
33466                
33467                return value;
33468            }
33469        },
33470
33471        
33472        _totalDigitValidation : function (value, obj) {
33473            if (value && obj.validFlag && this.leadDigits > -1) {
33474                obj.validFlag = true;
33475                if (this.dataType === "integer") {
33476                    obj.validFlag = this.value.toString().length <= this.leadDigits;
33477                }
33478                if (!obj.validFlag) {
33479                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalDigitMessage, [this.leadDigits]);
33480                    this._failedTest = this.guideUtil.TOTAL_DIGITS_TEST;
33481                }
33482            }
33483        },
33484
33485        
33486        _datatypeValidation : function (obj) {
33487            if (obj.validFlag) {
33488                var value = this.getAttribute("_value");
33489                obj.validFlag = !isNaN(value);
33490                if (!obj.validFlag) {
33491                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.datatypeMessage, ["numeric"]);
33492                    this._failedTest = this.guideUtil.FORMAT_TEST;
33493                }
33494            }
33495        },
33496
33497        
33498        _runValidations : function (obj) {
33499            var value = this.value;
33500            GuideNumericBox._super._runValidations.call(this, obj);
33501            this._datatypeValidation(obj);
33502            this._minMaxValidation(value, obj);
33503            this._totalDigitValidation(value, obj);
33504        }
33505    });
33506    GuideNumericBox.defineProps({
33507        
33508        dataType : {
33509            get : function () {
33510                return this.getAttribute("dataType");
33511            }
33512        },
33513
33514        
33515        leadDigits : {
33516            get : function () {
33517                return this.getAttribute("leadDigits");
33518            }
33519        },
33520
33521        
33522        fracDigits : {
33523            get : function () {
33524                return this.getAttribute("fracDigits");
33525            }
33526        }
33527    });
33528
33529    GuideNumericBox.addMixins([
33530        guidelib.model.mixin.AddMinMaxValidation
33531    ]);
33532
33533})(_, guidelib);
33534
33535 (function (_, guidelib) {
33536    var GuideFootnotePlaceHolder = guidelib.model.GuideFootnotePlaceHolder = guidelib.model.GuideTextDraw.extend({
33537        msClassName : "guideFootnotePlaceHolder",
33538
33539        initialize : function () {
33540            GuideFootnotePlaceHolder._super.initialize.apply(this);
33541        }
33542    });
33543    GuideFootnotePlaceHolder.defineProps({
33544        footnoteMap : {
33545            get : function () {
33546            if (this.options._guideContainer.jsonModel.textReplacementMap) {
33547                var footnoteMap = {};
33548                var footnoteArray = Object.entries(this.options._guideContainer.jsonModel.textReplacementMap)
33549                var parentDiv = document.createElement("p");
33550                parentDiv.setAttribute("class", "footnoteClass");
33551                for (var i = 0; i < footnoteArray.length; i++) {
33552                    var pTag = $("p[id=\"" + footnoteArray[i][0] + "\"]")[0];   
33553                    if (pTag != null && pTag.tagName == 'P') {
33554                        var childTag = document.createElement("p");
33555                        
33556                        childTag.setAttribute("role", "footnote");
33557                        childTag.setAttribute("aria-live", "polite");
33558                        childTag.setAttribute("aria-atomic", "true");
33559                        var supTag = document.createElement('sup');
33560                        var anchorTag = document.createElement('a');
33561                        var parentTag = pTag.cloneNode(true);
33562                         parentTag.removeAttribute("id");
33563                        anchorTag.setAttribute('id', footnoteArray[i][0]+ "_ftn");
33564                        anchorTag.innerHTML = footnoteArray[i][1];
33565                        supTag.appendChild(anchorTag);
33566                        parentTag.insertBefore(supTag, parentTag.children[0]);
33567                        parentTag.style.display = "block";
33568                        childTag.appendChild(parentTag);
33569                        footnoteMap[footnoteArray[i][0]] = childTag.outerHTML;
33570                    }
33571                }
33572                return footnoteMap;
33573            }
33574            return null;
33575        }
33576        }
33577    });
33578
33579}(_, guidelib));
33580
33581
33582(function (_, guidelib) {
33583    
33584    var GuideDatePicker = guidelib.model.GuideDatePicker = guidelib.model.Field.extend({
33585        msClassName : "guideDatePicker",
33586        errorList : [],
33587        that : this,
33588
33589        initialize : function () {
33590            GuideDatePicker._super.initialize.call(this);
33591            if (_.isEmpty(this.jsonModel._value) && this.jsonModel.defaultToCurrentDate === "true") {
33592                this._setGuideValue(new Date().toISOString().slice(0, 10));
33593            }
33594        },
33595
33596        _setGuideValue : function (value) {
33597            var retVal = guidelib.util.GuideUtil._reformatDate(value, this.isEditPictureClausePresent);
33598            GuideDatePicker._super._setGuideValue.call(this, retVal);
33599        },
33600
33601        _getTypedValue : function (value) {
33602            if (value) {
33603                return value;
33604            }
33605            return null;
33606        },
33607
33608        
33609        _datatypeValidation : function (obj) {
33610            if (obj.validFlag) {
33611                var value = this.getAttribute("_value");
33612                obj.validFlag = true;
33613                if (value != null && xfalib.ut.DateInfo.Parse(value, undefined, this.isEditPictureClausePresent) == null) {
33614                    obj.validFlag = false;
33615                }
33616                if (!obj.validFlag) {
33617                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.datatypeMessage, ["date"]);
33618                    this._failedTest = this.guideUtil.FORMAT_TEST;
33619                }
33620            }
33621        },
33622
33623        _validateDatePart : function (field, datePart, errorList) {
33624            if (field === "D") {
33625                if (datePart > 31) {
33626                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.month, guidelib.i18n.calendarSymbols.more, 31, guidelib.i18n.calendarSymbols.days]));
33627                }
33628                if (datePart < 1) {
33629                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.month, guidelib.i18n.calendarSymbols.less, 1, guidelib.i18n.calendarSymbols.days]));
33630                }
33631            }
33632            if (field === "M") {
33633                if (datePart > 12) {
33634                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.year, guidelib.i18n.calendarSymbols.more, 12, guidelib.i18n.calendarSymbols.months]));
33635                }
33636                if (datePart < 1) {
33637                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.year, guidelib.i18n.calendarSymbols.less, 1, guidelib.i18n.calendarSymbols.months]));
33638                }
33639            }
33640            if (field === "Y") {
33641                if (datePart.length < 4) {
33642                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidYearPart));
33643                }
33644
33645            }
33646        },
33647        _getOrderedDateParts : function (value) {
33648            var dateFormat = this.jsonModel.dateDisplayFormat || "date{M/D/YYYY}";
33649            var separator = dateFormat.match(/^date\{.*([^mdy]).*\}$/i)[1];
33650            var fieldOrder = ['M', 'D', 'Y']
33651                .map(function (val) {
33652                    return {
33653                        value : val,
33654                        index : dateFormat.indexOf(val)
33655                    };
33656                })
33657                .sort(function (a, b) {
33658                    return a.index - b.index;
33659                })
33660                .map(function (obj) {
33661                    return obj.value;
33662                });
33663            var dateParts = value.split(separator);
33664            return [dateParts, fieldOrder];
33665        },
33666        _checkIsolatedDateValidity : function (obj, value, errorList) {
33667            var orderedParts = this._getOrderedDateParts(value);
33668            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33669            for (var i = 0; i < fieldOrder.length; i++) {
33670                var field = fieldOrder[i];
33671                var datePart = dateParts[i];
33672                if (!_.isEmpty(datePart)) {
33673                    this._validateDatePart(field, datePart, errorList);
33674                }
33675            }
33676        },
33677        _validateDaysOfMonth : function (obj, value, errorList) {
33678            var orderedParts = this._getOrderedDateParts(value);
33679            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33680                month = dateParts[fieldOrder.indexOf('M')],
33681                day = dateParts[fieldOrder.indexOf('D')],
33682                year = dateParts[fieldOrder.indexOf('Y')];
33683            if (month !== "" && day !== "") {
33684                month = Number(month) || 0;
33685                day = Number(day) || 0;
33686                var currentMonthName = guidelib.i18n.calendarSymbols.monthNames[month - 1];
33687                if (31 === day && [4,6,9,11].includes(month)) {
33688                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.nonFebruaryMessage, [currentMonthName, day - 1]));
33689                }
33690            }
33691        },
33692        _validateFieldCompleteness : function (obj, value, errorList) {
33693            var orderedParts = this._getOrderedDateParts(value);
33694            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33695            var localizedFieldMapping = {
33696                M : guidelib.i18n.calendarSymbols.month,
33697                D : guidelib.i18n.calendarSymbols.day,
33698                Y : guidelib.i18n.calendarSymbols.year
33699            };
33700            var emptyFields = fieldOrder
33701                .map(function (fieldName) {
33702                    return localizedFieldMapping[fieldName];
33703                })
33704                .filter(function (_, index) {
33705                    return dateParts[index] === "";
33706                });
33707            if (emptyFields.length !== 3 && emptyFields.length > 0) {
33708                errorList.push("These fields still need to be filled: [" + emptyFields.join(", ") + "]");
33709            }
33710        },
33711        _validateFullDate : function (obj, value, errorList) {
33712            var orderedParts = this._getOrderedDateParts(value);
33713            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33714                month = dateParts[fieldOrder.indexOf('M')],
33715                day = dateParts[fieldOrder.indexOf('D')],
33716                year = dateParts[fieldOrder.indexOf('Y')];
33717            if (month !== "" && day !== "" && year !== "") {
33718                month = Number(month) || 0;
33719                day = Number(day) || 0;
33720                year = Number(year) || 0;
33721                var isLeapYear = (year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0));
33722                if (month === 2) {
33723                    var maxFebruary = isLeapYear ? 29 : 28;
33724                    if (day === 29 && !isLeapYear) {
33725                        errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.februaryMessage, [maxFebruary, year]));
33726                    }
33727                    if (day >= 30) {
33728                        errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.februaryMessage, [maxFebruary, year]));
33729                    }
33730                }
33731            }
33732        },
33733        _computeErrors : function (obj, errorList) {
33734            var that = this;
33735            obj.validFlag = errorList.length === 0;
33736            if (!obj.validFlag) {
33737                that._errorText = errorList.join(" ");
33738                that._failedTest = that.guideUtil.FORMAT_TEST;
33739            }
33740        },
33741
33742        
33743        _runValidations : function (obj) {
33744            var value = this.value;
33745            if (this.jsonModel.titleDay || this.jsonModel.titleMonth || this.jsonModel.titleYear) {
33746                if (null === value) {
33747                    value = "//";
33748                }
33749                var errorList = [];
33750                
33751                this._checkIsolatedDateValidity(obj, value, errorList);
33752                
33753                if (errorList.length === 0) {
33754                    this._validateDaysOfMonth(obj, value, errorList);
33755                }
33756                
33757                if (errorList && errorList.length === 0 && window.FD && window.FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_DATE_PICKER_ERRORMESSAGE) ) {
33758                    this._validateFieldCompleteness(obj, value, errorList);
33759                }
33760                
33761                if (errorList.length === 0) {
33762                    this._validateFullDate(obj, value, errorList);
33763                }
33764                this._computeErrors(obj, errorList);
33765
33766                
33767                if (errorList.length === 0) {
33768                    this.value = value = this.value === "//" ? "" : this.value;
33769                    GuideDatePicker._super._runValidations.call(this, obj);
33770                    try {
33771                        this.value = value = this.value !== null && this.value !== "" ? xfalib.ut.PictureFmt.parseDate(this.value, (this.jsonModel.dateDisplayFormat || "date{M/D/YYYY}")) : this.value;
33772                    } catch (error) {}
33773                    this._minMaxValidation(value, obj);
33774                }
33775            } else {
33776                GuideDatePicker._super._runValidations.call(this, obj);
33777                this._datatypeValidation(obj);
33778                this._minMaxValidation(value, obj);
33779            }
33780        }
33781    });
33782
33783    GuideDatePicker.addMixins([
33784        guidelib.model.mixin.AddMinMaxValidation
33785    ]);
33786
33787})(_, guidelib);
33788
33789(function (_, guidelib) {
33790    
33791    var GuideCaptcha = guidelib.model.GuideCaptcha = guidelib.model.Field.extend({
33792        msClassName : "guideCaptcha",
33793
33794        initialize : function () {
33795            GuideCaptcha._super.initialize.call(this);
33796            var invisibleMandatoryRecaptchaInitialization = "af.invisibleMandatoryRecaptchaInitialization";
33797            if ((FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)
33798                    && (this.isWidgetHcaptcha || this.isWidgetTurnstile) && this.captchaInvisible)
33799                || (this.isWidgetRecaptcha && ((this.captchaEnterprise && !this.checkBoxkey) || (this.captchaInvisible && this.mandatory)))) {
33800                
33801                this.captchaValidate = false;
33802                this._triggerOnBridge(invisibleMandatoryRecaptchaInitialization, this, null, null, null);
33803            }
33804        },
33805
33806        
33807        showCaptchaError : function (serverErrorMessage) {
33808
33809            if (this.captchaEnterprise) {
33810                if (this.checkBoxkey) {
33811                    serverErrorMessage = this.errorMessage;
33812                } else {
33813                    window.alert(this.errorMessage);
33814                    return;
33815                }
33816            }
33817            if (this.captchaInvisible) {
33818                if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)) {
33819                    window.alert(this.errorMessage);
33820                }
33821                return;
33822            }
33823
33824            if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && !this.isWidgetRecaptcha) {
33825                serverErrorMessage = this.errorMessage;
33826            } else {
33827                if (_.isEmpty(serverErrorMessage)) {
33828                    serverErrorMessage = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-006"]);
33829                }
33830            }
33831            
33832            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
33833                "validationStatus", false, serverErrorMessage);
33834        },
33835
33836        validate : function (errorList) {
33837            if (_.isUndefined(errorList)) {
33838                errorList = [];
33839            }
33840
33841            if(!this.captchaValidate) {
33842                return;
33843            }
33844
33845            if (window.guideBridge.hostName !== "server") {
33846                if ((this.visible && !this.value) || (this.mandatory && !this.visible)) {
33847                    errorList.push({
33848                    som : this.somExpression,
33849                    errorText : this.mandatoryMessage
33850                });
33851                    this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
33852                                "validationStatus", false, this.mandatoryMessage);
33853                    return false;
33854                } else {
33855                    this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
33856                                "validationStatus", true, null);
33857                }
33858            }
33859        }
33860    });
33861
33862    GuideCaptcha.defineProps({
33863        value : {
33864            get : function () {
33865                return this.jsonModel._value;
33866            },
33867            set : function (value) {
33868                var oldValue = this.jsonModel._value,
33869                    newTypedValue;
33870                
33871                this.jsonModel._value = (value === undefined) ? oldValue : value;
33872                newTypedValue = this.jsonModel._value;
33873                this.validate();
33874                this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
33875            }
33876        },
33877
33878        captchaWidget : {
33879            get : function () {
33880                return this.getAttribute("captchaService");
33881            }
33882        },
33883        captchaValidate : {
33884            get : function () {
33885                return this._captchaValidate == undefined ? true : this._captchaValidate;
33886            },
33887            set : function (value) {
33888                this._captchaValidate = value;
33889            }
33890        },
33891        captchaInvisible : {
33892            get : function () {
33893                if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && this.captchaWidget === "turnstile") {
33894                    return this.getAttribute("widgetType") == "invisible" ? true : false;
33895                } else if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && this.captchaWidget === "hcaptcha") {
33896                    return this.getAttribute("size") == "invisible" ? true : false;
33897                } else {
33898                    return this.getAttribute("rcSize") == "invisible" ? true : false;
33899                }
33900            }
33901        },
33902        captchaEnterprise : {
33903            get : function () {
33904                return this.getAttribute("rcVersion") === "enterprise" ? true : false;
33905            }
33906        },
33907        checkBoxkey : {
33908            get : function () {
33909                return this.getAttribute("rcKeyType") === "checkbox" ? true : false;
33910            }
33911        },
33912        errorMessage : {
33913            get : function () {
33914                return this.getAttribute("errorMessage");
33915            }
33916        },
33917        isWidgetRecaptcha : {
33918            get: function () {
33919                return (this.captchaWidget === "recaptcha");
33920            }
33921        },
33922        isWidgetHcaptcha : {
33923            get: function () {
33924                return (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && (this.captchaWidget === "hcaptcha"));
33925            }
33926        },
33927        isWidgetTurnstile : {
33928            get: function () {
33929                return (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && (this.captchaWidget === "turnstile"));
33930            }
33931        }
33932    });
33933
33934}(_, guidelib));
33935
33936(function (_, guidelib) {
33937
33938    
33939    var GuideDropDownList = guidelib.model.GuideDropDownList = guidelib.model.Field.extend({
33940        msClassName : "guideDropDownList" ,
33941
33942        _collectExpressions : function () {
33943            GuideDropDownList._super._collectExpressions.apply(this);
33944            if (this.optionsExp) {
33945                this._compiledExpressions["optionsExp"] = this._compileExpression(this.optionsExp, "items");
33946            }
33947        },
33948
33949        _handleXfaModelChanged : function (event) {
33950            if (event._property === "addItem" || event._property === "clearItems" || event._property === "deleteItem") {
33951                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, event._property, event.prevText, event.newText);
33952            } else {
33953                GuideDropDownList._super._handleXfaModelChanged.call(this, event);
33954            }
33955        },
33956
33957        _getDisplayValue : function (saveValue) {
33958            var items = this._getOptionsArray(),
33959                displayValue = null;
33960            _.each(items, function (val) {
33961                if (saveValue === val.saveValue) {
33962                    displayValue = val.displayValue;
33963                }
33964            }, this);
33965            return displayValue;
33966        },
33967
33968        _getItems : function () {
33969            return this.jsonModel.options;
33970        },
33971
33972        _setXFAItems : function (options) {
33973            var optionsStr = this._getXFAOptionStringFromGuideItems(options);
33974            var SET_ITEMS_INSERT_MODE_PAIR = 2;
33975            if (optionsStr) {
33976                this.bindNode.setItems(optionsStr, SET_ITEMS_INSERT_MODE_PAIR);
33977            } else {
33978                this.bindNode.clearItems();
33979            }
33980        },
33981
33982        
33983        _allowEmptyValueString : function () {
33984            return true;
33985        }
33986
33987    });
33988
33989    GuideDropDownList.defineProps({
33990
33991        
33992        
33993        multiSelect : {
33994            get : function () {
33995                return this.getAttribute("multiSelect");
33996            },
33997            set : function () {
33998                this.setAttribute("multiSelect");
33999            }
34000        },
34001
34002        optionsExp : {
34003            get : function () {
34004                return this.getAttribute("optionsExp");
34005            }
34006        },
34007
34008        
34009        displayValue : {
34010            get : function () {
34011                return this._getDisplayValue(this.value);
34012            }
34013        },
34014
34015        
34016        
34017        items : {
34018            get : function () {
34019                var items = [];
34020                if (this.bindNode) {
34021                    var that = this.bindNode;
34022                    for (var index = 0; index < that.length; index++) {
34023                        var item = that.getSaveItem(index) + "=" + that.getDisplayItem(index);
34024                        items.push(item);
34025                    }
34026                    return items;
34027                } else {
34028                    items  =  this._getItems();
34029                    if (items && !_.isArray(items)) {
34030                        items = items.split(",");
34031                    } else if (items) {
34032                        items = items.slice(0);
34033                    }
34034                    return items;
34035                }
34036            },
34037            set : function (newValue) {
34038                var oldValue = this._getItems();
34039                if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
34040                    if (this.bindNode) {
34041                        this._setXFAItems(newValue);
34042                    } else {
34043                        this.jsonModel.options = newValue;
34044                    }
34045                    if (this.multiSelect) {
34046                        this._resetModelValueForOptionChange();
34047                    }
34048                    this._addStateOverride("options", {"option" : this._getOptionsArray()});
34049                    this._triggerItemsChange(oldValue, this.items);
34050                }
34051            }
34052        }
34053    });
34054    GuideDropDownList.addMixins([
34055        guidelib.model.mixin.ChoiceGroupOptionHandler
34056    ]);
34057})(_, guidelib);
34058
34059(function (_, guidelib) {
34060    
34061    var GuideInstanceManager = guidelib.model.GuideInstanceManager = guidelib.model.GuideNode.extend({
34062        msClassName : "guideInstanceManager",
34063        initialize : function () {
34064            GuideInstanceManager._super.initialize.call(this);
34065            this._instances = [];
34066            this.dependants = [];
34067            this.deafen = false; 
34068            this._bindPending = true;
34069        },
34070
34071        _postInitializeBinding : function () {
34072            
34073            
34074            
34075            if (!this._bindPending) {
34076                return;
34077            } else {
34078                this._bindPending = false; 
34079            }
34080            
34081            
34082            
34083            
34084            
34085            
34086            var instance = this._instances[this.instanceCount - 1];
34087            if (!instance) {
34088                this.logger().log("There was no instance found for InstanceManager at postInitialize:" + this.somExpression);
34089            }
34090            if (instance.bindNode && instance.bindNode.instanceManager) {
34091                this.bindNode = instance.bindNode.instanceManager;
34092                this.bindNode.parent.on(xfalib.script.XfaModelEvent.CHILD_ADDED, this);
34093                this.bindNode.parent.on(xfalib.script.XfaModelEvent.CHILD_REMOVED, this);
34094            }
34095        },
34096
34097        _unloadModel : function () {
34098            var instance = this._instances[this.instanceCount - 1];
34099
34100            if (instance.bindNode && instance.bindNode.instanceManager) { 
34101                this.bindNode.parent.off(xfalib.script.XfaModelEvent.CHILD_ADDED, this);
34102                this.bindNode.parent.off(xfalib.script.XfaModelEvent.CHILD_REMOVED, this);
34103            }
34104
34105            GuideInstanceManager._super._unloadModel.call(this);
34106        },
34107
34108        
34109        handleEvent : function (event) {
34110            if (!this.deafen && event instanceof xfalib.script.XfaModelEvent) {
34111                switch (event.name) {
34112                    case xfalib.script.XfaModelEvent.CHILD_ADDED:
34113                        var addedInstance = event.newText;
34114                        if (addedInstance.instanceManager == this.bindNode) {
34115                            this._insertInstance(addedInstance.instanceIndex, addedInstance);
34116                        }
34117                        break;
34118                    case xfalib.script.XfaModelEvent.CHILD_REMOVED:
34119                        var removedInstance = event.prevText;
34120                        if (removedInstance.instanceManager == this.bindNode) {
34121                            this._removeInstance(removedInstance.instanceIndex, false);
34122                        }
34123                        break;
34124                    case xfalib.script.XfaModelEvent.CHILD_MOVED:
34125                        this.logger().log("CHILD_REMOVED should never be dispatched. It's achieved via ad and remove child.");
34126                        break;
34127                    default:
34128                        
34129                        break;
34130                }
34131            }
34132        },
34133
34134        _instanceTemplate : function () {
34135            return this._guide()._modelTemplateCacheStore.cloneJsonTemplate(this.jsonModel.instanceTemplateId);
34136        },
34137
34138        
34139        addInstance : function (addedXfaInstance) {
34140            return this._insertInstance(undefined, addedXfaInstance);
34141        },
34142
34143        
34144        addInstances : function (instancesConfig, addedXfaInstances) {
34145            var instanceCount = instancesConfig.instanceCount,
34146                instancesToAdd, availableInstances;
34147            if (this.maxOccur == -1) {
34148                instancesToAdd = instanceCount;
34149            }else {
34150                availableInstances = this.maxOccur - this.instanceCount;
34151                
34152                instancesToAdd = instanceCount > availableInstances ? availableInstances : instanceCount;
34153            }
34154            var oChildsAdded = [];
34155            for (var i = 0; i < instancesToAdd ; i++) {
34156                oChildsAdded.push(this._insertInstance(undefined, addedXfaInstances, true));
34157            }
34158            var oParentContainer = this.parent;
34159            oParentContainer._triggerEvent(guidelib.event.GuideModelEvent.MULTIPLE_CHILD_ADDED, "multipleChildAdded",
34160                null, oChildsAdded);
34161        },
34162
34163        _manageChild : function (oCreatedChild, nIndex) {
34164            oCreatedChild._instanceManager = this;
34165            if (nIndex === undefined) {
34166                this._instances.push(oCreatedChild);
34167            } else {
34168                this._instances.splice(nIndex, 0, oCreatedChild);
34169            }
34170        },
34171
34172        
34173        _insertInstance : function (nIndex, addedXfaInstance, muteEvent) {
34174            if ((+this.maxOccur >= 0) && (+this.maxOccur == this.instanceCount)) {
34175                return null;
34176            }
34177            
34178            if (nIndex !== undefined && nIndex > +this.maxOccur && +this.maxOccur > -1) {
34179                return null;
34180            }
34181
34182            var addedBindNode = addedXfaInstance;
34183            if (addedXfaInstance && this.bindNode == null) {
34184                this.logger().error("AF", "Invalid argument addedXfaInstance.");
34185            }
34186            if (!addedXfaInstance && this.bindNode) {
34187                this.deafen = true;
34188                try {
34189                    
34190                    addedBindNode = this.bindNode.insertInstance(nIndex);
34191                }
34192                finally {
34193                    this.deafen = false;
34194                }
34195            }
34196            var template = this._instanceTemplate();
34197            
34198            
34199            
34200            var clonedJson = {};
34201            var uniquePrefix = this.guideUtil.generateUID(),
34202                that = this;
34203            this.copyObject(template, clonedJson,
34204                {
34205                    transformMaps : {
34206                        "id" : function (srcValue, options, parentObj) {
34207                            return uniquePrefix + "__" + parentObj.templateId;
34208                        },
34209
34210                        
34211                        
34212                        "bindRef" : function (originalBindRef, options, src) {
34213                            if (addedBindNode != null && that.bindNode != null) {
34214                                if (template.bindRef === originalBindRef) {
34215                                    return addedBindNode.somExpression;
34216                                } else if (originalBindRef.substring(0, template.bindRef.length) === template.bindRef) {
34217                                    return originalBindRef.replace(template.bindRef, addedBindNode.somExpression);
34218                                }
34219                            }
34220
34221                            return originalBindRef;
34222                        }
34223                    }
34224                }
34225            );
34226            
34227            var options = ((addedBindNode && this.bindNode) ? {bindNode : addedBindNode} : null);
34228            if (this.options._guideContainer) {
34229                options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
34230            }
34231            var oChildAdded = guidelib.model.GuideModelRegistry.prototype.createModel(clonedJson, options);
34232            if (oChildAdded != null) {
34233                
34234                
34235                
34236                this._manageChild(oChildAdded, nIndex);
34237                var oParentContainer = this.parent;
34238                if (oParentContainer != null) {
34239                    if (this._instances.length > 0) {
34240                        
34241                        
34242                        
34243                        
34244                        nIndex = nIndex !== undefined ? nIndex : this._instances.length - 1 ;
34245                        if(nIndex === 0 ) {
34246                            
34247                            
34248                            
34249                            oParentContainer._addChildAt(oChildAdded, oParentContainer._children.indexOf(this) + 1, muteEvent);
34250                        } else {
34251                            var lastInstanceIndex = oParentContainer._children.indexOf(this._instances[nIndex - 1]);
34252                            oParentContainer._addChildAt(oChildAdded, lastInstanceIndex + 1, muteEvent);
34253                        }
34254                    } else {
34255                        
34256                        
34257                        
34258                        
34259                        oParentContainer._addChildAt(oChildAdded, oParentContainer._children.indexOf(this) + 1, muteEvent);
34260                    }
34261                    var guideStateConstants = guidelib.model.GuideSchema.prototype.GuideStateConstants;
34262                    var dataUtils = this._guide().internal.liveDataUtils;
34263                    if (this._isDataNodeUpdateRequired(oChildAdded)) {
34264                        var parentNode = dataUtils.getParentDataNode(this._getDataContext(oChildAdded), true, {});
34265                        var index = dataUtils._convertModelIndexToDataIndex(oChildAdded.instanceIndex);
34266                        var node = dataUtils._getElement(parentNode, oChildAdded._getDataNodeName(), {index : index});
34267                        
34268                        
34269                        if (!node || (node && !(oChildAdded.instanceIndex == this._instances.length - 1))) {
34270                            var dataNode = dataUtils.insertNode(parentNode, oChildAdded._getDataNodeName(), oChildAdded.instanceIndex);
34271                            if (!dataNode) {
34272                                this.logger().warn("AF", "Unable to store the data of the element");
34273                            }
34274                        }
34275                    }
34276                }
34277                this._execExpressions(nIndex);
34278                return oChildAdded;
34279            } else {
34280                this.logger().log("guide", "insertInstance could not create child" + this.jsonModel.instanceTemplateId);
34281            }
34282            return null;
34283        },
34284
34285        
34286        insertInstance : function (nIndex) {
34287            return this._insertInstance(nIndex);
34288        },
34289
34290        
34291        removeInstance : function (index) {
34292            this._removeInstance(index, true);
34293        },
34294
34295        
34296        _removeInstance : function (index, removeXfaInstance) {
34297            
34298            if (this.instanceCount == 0 || this.minOccur >= this.instanceCount) {
34299                return;
34300            }
34301
34302            if (index >= +this.instanceCount) {
34303                return;
34304            }
34305
34306            if (removeXfaInstance && this.bindNode) {
34307                this.deafen = true;
34308                try {
34309                    this.bindNode.removeInstance(index);
34310                }
34311                finally {
34312                    this.deafen = false;
34313                }
34314            }
34315            
34316            
34317            
34318            var oChild =  this._instances[index];
34319            var dataUtils = this._guide().internal.liveDataUtils;
34320            if (this._isDataNodeUpdateRequired(oChild)) {
34321                var parentNode = dataUtils.getParentDataNode(this._getDataContext(oChild));
34322                dataUtils.removeChild(parentNode, oChild._getDataNodeName(), oChild.instanceIndex);
34323            }
34324            this._instances.splice(index, 1);
34325            var parent = oChild.parent;
34326            parent._removeChild(oChild);
34327            this._execExpressions(index);
34328        },
34329
34330        _isDataNodeUpdateRequired : function (child) {
34331            var guideStateConstants = guidelib.model.GuideSchema.prototype.GuideStateConstants,
34332                guide = guideBridge._guide;
34333            return guide && guide.getGuideState() === guideStateConstants.GUIDE_STATE_MODEL_COMPLETE
34334                && child._hasLazyDescendant;
34335        },
34336
34337        _getDataContext : function (model) {
34338            var dataUtils = this._guide().internal.liveDataUtils,
34339                elementContext = dataUtils._getXpathContext(model),
34340                xmlContext = dataUtils._getDataContext(model, elementContext.bound,
34341                    elementContext.unBound),
34342                xpath = xmlContext.indexedXpath;
34343            xpath = dataUtils.addIndexToPath(xpath, model.instanceIndex);
34344            return {
34345                indexedXpath : xpath,
34346                xmlSec : xmlContext.xmlSec
34347            };
34348        },
34349
34350        _getInstanceName : function () {
34351            return this.jsonModel.instanceName;
34352        },
34353
34354        _instanceIsTableRow : function () {
34355            
34356            return this._instanceTemplate()["guideNodeClass"] === "guideTableRow";
34357        },
34358
34359        
34360        _execExpressions : function (modifiedIndex) {
34361            try {
34362                
34363                this._notifyDependants();
34364                
34365                
34366                for (var i = modifiedIndex; i < this.instances.length; i++) {
34367                    this.instances[i]._notifyDependants();
34368                }
34369                
34370                this._guide().runPendingExpressions();
34371            } catch (ex) {
34372                this.logger().error("guide", ex.message);
34373            }
34374        }
34375
34376    });
34377    GuideInstanceManager.defineProps({
34378        
34379        minOccur : {
34380            get : function () {
34381                var isTableRow = this._instanceIsTableRow();
34382                
34383                if (isTableRow) {
34384                    return ((+this.jsonModel.minOccur) || 1);
34385                } else {
34386                    return this.getOrElse(this.jsonModel.minOccur, 1);
34387                }
34388            }
34389        },
34390
34391        
34392        maxOccur : {
34393            get : function () {
34394                return this.getOrElse(this.jsonModel.maxOccur, 1);
34395            }
34396        },
34397
34398        initialOccur : {
34399            get : function () {
34400                return this.getOrElse(this.jsonModel.initialOccur, 1);
34401            }
34402        },
34403
34404        
34405        instanceTemplateId : {
34406            get : function () {
34407                return this.jsonModel.instanceTemplateId;
34408            }
34409        },
34410
34411        
34412        instanceCount : {
34413            get : function () {
34414                var context = this._guide()._currentContext;
34415                if (context && context.managedExp) {
34416                    
34417                    this._addDependant(context.contextNode, context.expression);
34418                }
34419                return this._instances.length ;
34420            }
34421        },
34422
34423        
34424        repeatable : {
34425            get : function () {
34426                return (this.minOccur != 1 || this.maxOccur != 1);
34427            }
34428        },
34429        
34430        instances : {
34431            
34432            get : function () {
34433                var context = this._guide()._currentContext;
34434                if (context && context.managedExp) {
34435                    
34436                    this._addDependant(context.contextNode, context.expression);
34437                }
34438                return (this._instances || []).slice(0);
34439            }
34440        }
34441    });
34442
34443    GuideInstanceManager.addMixins([
34444        guidelib.model.mixin.AddDependencyMgmt
34445    ]);
34446})(_, guidelib);
34447
34448
34449(function (_, guidelib) {
34450    var AbstractField = guidelib.model.AbstractField = guidelib.model.GuideNode.extend({
34451        msClassName : "abstractField",
34452
34453        initialize : function () {
34454            this._name = this.options.name || "";
34455            this._className = this.options.className || "";
34456            this._bindRef = this.options.bindRef || "";
34457            this._afDataSom = this.options.afDataSom || "";
34458            this._dataSom = this._isXfaNode() ? this.options.dataSom : "";
34459            this.dependants = [];
34460            
34461            this._depdendantIds = [];
34462        },
34463
34464        _getValue : function () {
34465            return this.jsonModel._value;
34466        },
34467
34468        _setValue : function (value) {
34469            this.jsonModel._value = value;
34470        },
34471
34472        resetData : function () {
34473            return guidelib.model.Field.prototype.resetData.call(this);
34474        },
34475
34476        _isXfaNode : function () {
34477            return this.bindRef.indexOf("xfa[0].form[0].") === 0;
34478        },
34479
34480        getAttribute : function (attrName) {
34481            var attrValue;
34482            switch (attrName) {
34483                case "name":
34484                    attrValue = this.name;
34485                    break;
34486                case "bindRef":
34487                    attrValue = this.bindRef;
34488                    break;
34489                default:
34490                    attrValue = null;
34491                    break;
34492            }
34493            return attrValue;
34494        }
34495    });
34496
34497    AbstractField.defineProps({
34498        somExpression : {
34499            get : function () {
34500                return "";
34501            }
34502        },
34503        name : {
34504            get : function () {
34505                return (this._name || "").replace(/\s+/g, '');
34506            }
34507        },
34508        className : {
34509            get : function () {
34510                return (this._className || "");
34511            }
34512        },
34513        bindRef : {
34514            get : function () {
34515                return (this._bindRef || "").replace(/\s+/g, '');
34516            }
34517        },
34518        dataSom : {
34519            get : function () {
34520                return this._dataSom;
34521            }
34522        },
34523        afDataSom : {
34524            get : function () {
34525                return this._afDataSom.replace(/\s+/g, '');
34526            }
34527        },
34528
34529        value : {
34530            get : function () {
34531                var context = this._guide()._currentContext;
34532                if (context && context.managedExp && context.contextNode && context.expression) {
34533                    this._addDependant(context.contextNode, context.expression);
34534                    
34535                    this._depdendantIds.push(context.contextNode.id);
34536                }
34537                return this.jsonModel._value;
34538            },
34539            set : function (newValue) {
34540                if (this.jsonModel._value !== newValue) {
34541                    this.jsonModel._value = newValue;
34542                    
34543                    var guideDirtyMarkerAndVisitor = this._guide().internal.GuideDirtyMarkerAndVisitor,
34544                        visitMap = guideDirtyMarkerAndVisitor.visitMap,
34545                        listOfDependents = this._depdendantIds;
34546                    guideDirtyMarkerAndVisitor._findAndMarkDirty(visitMap, listOfDependents);
34547                    this._notifyDependants();
34548                }
34549            }
34550        }
34551    });
34552
34553    AbstractField.addMixins([
34554        guidelib.model.mixin.AddDependencyMgmt
34555    ]);
34556}(_, guidelib));
34557
34558(function ($, guidelib, _) {
34559    var ModelTemplateCacheStore = guidelib.model.util.ModelTemplateCacheStore = xfalib.ut.Class.extend({
34560        initialize : function () {
34561            ModelTemplateCacheStore._super.initialize.apply(this);
34562            this._modelIdCache = {};
34563            this._templateIdCache = {};
34564            
34565            
34566            
34567            
34568            this._lazyTemplateIdCache = {};
34569            var guideJson = JSON.parse(JSON.stringify(this.options.modelTemplateJson));
34570            this._putTemplate(guideJson);
34571        },
34572
34573        
34574        putModel : function (model) {
34575            if (model.id) {
34576                var modelId = model.id;
34577                this._modelIdCache[modelId] = model;
34578                if (model.children) {
34579                    _.each(model.children, function (child) {
34580                        this.putModel(child);
34581                    }, this);
34582                }
34583            } else {
34584                this.logger().log("no Id found for model" + model.getAttribute("name"));
34585            }
34586        },
34587
34588        
34589        removeModel : function (id) {
34590            if (this._modelIdCache.hasOwnProperty(id)) {
34591                delete this._modelIdCache[id];
34592            }
34593        },
34594
34595        getModel : function (id) {
34596            if (this._modelIdCache.hasOwnProperty(id)) {
34597                return this._modelIdCache[id];
34598            }
34599        },
34600
34601        
34602        _putTemplate : function (jsonTemplate) {
34603            if (jsonTemplate.templateId && jsonTemplate.guideNodeClass) {
34604                this._templateIdCache[jsonTemplate.templateId] = jsonTemplate;
34605            }
34606            _.each(jsonTemplate, function (childTemplate, key) {
34607                if (_.isObject(childTemplate)) {
34608                    this._putTemplate(childTemplate);
34609                }
34610            }, this);
34611        },
34612
34613        
34614        _putLazyTemplate : function (lazyTemplateJson) {
34615            if (lazyTemplateJson.templateId && lazyTemplateJson.guideNodeClass) {
34616                this._lazyTemplateIdCache[lazyTemplateJson.templateId] = lazyTemplateJson;
34617            }
34618        },
34619
34620        cloneJsonTemplate : function (templateId) {
34621            if (this._templateIdCache[templateId]) {
34622                var template = this._templateIdCache[templateId];
34623                return JSON.parse(JSON.stringify(template)); 
34624            }
34625        },
34626        
34627        _getTemplate : function (templateId, lookupLazyStore) {
34628            var template = this._templateIdCache[templateId];
34629            
34630            
34631            
34632            if (lookupLazyStore && guidelib.util.GuideUtil.isLazyJson(template)) {
34633                template = this._lazyTemplateIdCache[templateId];
34634            }
34635
34636            if (!_.isUndefined(template)) {
34637                return JSON.parse(JSON.stringify(template));
34638
34639            }
34640        }
34641    });
34642
34643    ModelTemplateCacheStore.defineProps({
34644    });
34645}($, guidelib, window._));
34646(function (guidelib, $, _) {
34647    var ErrorConstants = guidelib.util.ErrorConstants = {
34648        DATA_ATTRIBUTE_ERROR_ITEM : "data-af-global-error-item",
34649        DATA_ATTRIBUTE_DISPLAY_ON : "data-af-global-errors-display-on",
34650        DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER : "data-af-global-error-text",
34651        DATA_ATTRIBUTE_ERROR_CONTAINER : "data-af-global-errors",
34652        DATA_ATTRIBUTE_SOM : "data-af-som",
34653        CONTEXT_SUBMISSION : "form",
34654        CONTEXT_NAVIGATION : "panel",
34655        CONTEXT_FIELD : "field" 
34656
34657    };
34658    ErrorConstants[ErrorConstants.CONTEXT_SUBMISSION] = 4;
34659    ErrorConstants[ErrorConstants.CONTEXT_NAVIGATION] = 2;
34660    ErrorConstants[ErrorConstants.CONTEXT_FIELD] = 1;
34661
34662    var GlobalErrorContainer = function ($el, options) {
34663        this.$container = $el;
34664        var $items = $el.find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_ITEM + "]").first(),
34665            displayOnAttribute = $el.attr(ErrorConstants.DATA_ATTRIBUTE_DISPLAY_ON) || "";
34666        this.displayOn = 0;
34667        this.errorCount = 0;
34668        this.$container.addClass("no-validation-errors");
34669        _.each(displayOnAttribute.split(","), function (displayOn) {
34670            var val = ErrorConstants[displayOn] || 0;
34671            this.displayOn += val;
34672        }, this);
34673        this.$item = $items.eq(0).clone();
34674        $items.remove();
34675    };
34676    _.extend(GlobalErrorContainer.prototype, {
34677        
34678        showError : function (msg, context, fieldSom) {
34679            var nContext,
34680            $el  = this.$container.find('[' + ErrorConstants.DATA_ATTRIBUTE_SOM + '="' + fieldSom + '"]');;
34681            if ($el.length > 0) {
34682                $el.find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
34683                    .addBack("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
34684                    .text(msg);
34685            } else {
34686                if (typeof ErrorConstants[context] !== "number") {
34687                    return;
34688                }
34689                nContext = ErrorConstants[context];
34690                if ((nContext & this.displayOn) === nContext) {
34691                    if (this.errorCount === 0) {
34692                        this.$container.removeClass("no-validation-errors");
34693                    }
34694                    this.errorCount++;
34695                    this.$item.clone()
34696                        .find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
34697                        .addBack("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
34698                        .text(msg)
34699                        .click(function (evnt) {
34700                            guideBridge.setFocus(fieldSom);
34701                        })
34702                        .end()
34703                        .end()
34704                        .attr(ErrorConstants.DATA_ATTRIBUTE_SOM, fieldSom)
34705                        .appendTo(this.$container);
34706                }
34707            }
34708        },
34709        hideError : function (fieldSom) {
34710            var $err = this.$container.find('[' + ErrorConstants.DATA_ATTRIBUTE_SOM + '="' + fieldSom + '"]');
34711            if ($err.length > 0) {
34712                $err.remove();
34713                this.errorCount--;
34714            }
34715            if (this.errorCount === 0) {
34716                this.$container.addClass("no-validation-errors");
34717            }
34718        }
34719    });
34720
34721    $.fn.globalErrorContainer = function (options) {
34722        var args = arguments;
34723        return this.each(function () {
34724            var $this = $(this),
34725                obj = $this.data("global-error-container");
34726            if (obj === undefined) {
34727                obj = new GlobalErrorContainer($this, $.extend({}, typeof options === "object" && options));
34728                $this.data("global-error-container", obj);
34729            }
34730            if (typeof options === "string" && typeof obj[options] === "function") {
34731                obj[options].apply(obj, [].splice.apply(args, [1]));
34732            }
34733        });
34734    };
34735}(guidelib, $, _));
34736
34737(function (guidelib, $, _) {
34738
34739    var ErrorConstants = guidelib.util.ErrorConstants,
34740        $GlobalErrorContainer;
34741    var GuideErrorManager = guidelib.util.GuideErrorManager = xfalib.ut.Class.extend({
34742
34743        _defaultErrorMessage : "There is an error in this field !",
34744
34745        initialize : function () {
34746            GuideErrorManager._super.initialize.apply(arguments);
34747            $GlobalErrorContainer = $("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_CONTAINER + "]").globalErrorContainer();
34748        },
34749
34750        
34751        
34752        markError : function (msg, wrapper, fieldSom, context, type) {
34753            var errorDiv;
34754            
34755            if (_.isUndefined(msg)) {
34756                msg = this._defaultErrorMessage;
34757            }
34758
34759            msg = msg.trim();
34760
34761            $GlobalErrorContainer.globalErrorContainer("showError", msg, context, fieldSom);
34762
34763            
34764            if (wrapper) {
34765                if (wrapper.length >= 1) {
34766                    errorDiv = wrapper.find(".guideFieldError");
34767                    if (errorDiv.length < 1) {
34768                        $("<div class='guideFieldError'></div>").appendTo(wrapper).text(msg);
34769                    } else {
34770                        errorDiv.text(msg);
34771                        var roleAttr = errorDiv.attr('role');
34772                        if (roleAttr != undefined || roleAttr !== false) {
34773                            errorDiv.attr('role', 'alert');
34774                        }
34775                        errorDiv.show();
34776                    }
34777
34778                }
34779            }
34780        },
34781
34782        unMarkError : function (wrapper, fieldSom) {
34783            
34784            wrapper.find(".guideFieldError").hide();
34785            wrapper.find(".guideFieldError").text("");
34786            $GlobalErrorContainer.globalErrorContainer("hideError", fieldSom);
34787        }
34788    });
34789})(guidelib, $, _);
34790
34791(function (guidelib, $, _) {
34792
34793    var GuideLazyUtil = guidelib.util.GuideLazyUtil = xfalib.ut.Class.extend({
34794
34795        
34796        putDirtyToTemplateCacheIfMissing : function (guide) {
34797            var guideDirtyMarker = guide.internal.GuideDirtyMarkerAndVisitor || this._guide().internal.GuideDirtyMarkerAndVisitor,
34798                listOfDirtyChildren = guideDirtyMarker._flattenDirtyPanelToList();
34799            this._getAllDirtyJsonTemplateInCache(listOfDirtyChildren);
34800        },
34801        
34802
34803        _getAllDirtyJsonTemplateInCache : function (listOfTemplateIds) {
34804            var modelTemplateCache = window.guideBridge._guide._modelTemplateCacheStore,
34805                toGetFromServer = this._generateListOfCacheMissFromTemplateJson(listOfTemplateIds);
34806            if (toGetFromServer.length > 0 && window.guideBridge.panelProvider) {
34807                var options = {
34808                    path : window.guideBridge._getGuidePathUrl(".jsonhtmlemitter"),
34809                    listOfTemplateIds : toGetFromServer,
34810                    success : addToTemplateCache
34811                };
34812                window.guideBridge.panelProvider.getMultipleTemplateJson(options);
34813            }
34814
34815            function addToTemplateCache(toInsertToTemplateCache) {
34816                _.each(toInsertToTemplateCache, function (jsonModelString) {
34817                    var template = JSON.parse(jsonModelString);
34818                    modelTemplateCache._putLazyTemplate(template);
34819                });
34820            }
34821        },
34822
34823        
34824        _generateListOfCacheMissFromTemplateJson : function (listOfTemplateIds) {
34825            var templateCache = window.guideBridge._guide._modelTemplateCacheStore,
34826                cacheMiss = [];
34827            _.each(listOfTemplateIds, function (templateID) {
34828                var templateJson = templateCache._getTemplate(templateID, true);
34829                if (guidelib.util.GuideUtil.isLazyJson(templateJson)) {
34830                    cacheMiss.push(templateID);
34831                }
34832            });
34833            return cacheMiss;
34834        },
34835
34836        _guide : function () {
34837            return this.options._guideContainer;
34838        }
34839
34840    });
34841})(guidelib, $, _);
34842(function (_, guidelib) {
34843    var guideSchema = {},
34844        convertor = {
34845            "visible" : {
34846                "xfaToGuide" : function (xfaValue) {
34847                    return xfaValue === "visible";
34848                },
34849                "guideToXfa" : function (guideValue) {
34850                    return guideValue === true ? "visible" : "hidden";
34851                }
34852            },
34853            "enabled" : {
34854                "xfaToGuide" : function (xfaValue) {
34855                    return xfaValue === "open";
34856                },
34857                "guideToXfa" : function (guideValue) {
34858                    return guideValue === true ? "open" : "readOnly";
34859                }
34860            },
34861            "assistPriority" : {
34862                "xfaToGuide" : function (xfaValue) {
34863                    return {
34864                        "custom" : "custom",
34865                        "toolTip" : "shortDescription",
34866                        "caption" : "label",
34867                        "name" : "name"
34868                    }[xfaValue];
34869                },
34870                "guideToXfa" : function (guideValue) {
34871                    return {
34872                        "custom" : "custom",
34873                        "shortDescription" : "toolTip",
34874                        "title" : "caption",
34875                        "name" : "name"
34876                    }[guideValue];
34877                }
34878            },
34879            "mandatory" : {
34880                "xfaToGuide" : function (xfaValue) {
34881                    return xfaValue === "error";
34882                },
34883                "guideToXfa" : function (guideValue) {
34884                    return guideValue === true ? "error" : "disabled";
34885                }
34886            },
34887            "multiLine" : {
34888                "xfaToGuide" : function (xfaValue) {
34889                    return xfaValue == 1;
34890                },
34891                "guideToXfa" : function (guideValue) {
34892                    return guideValue === true ? 1 : 0;
34893                }
34894            },
34895            
34896            
34897            "options" : {
34898                "xfaToGuide" : function (xfaValue) {
34899                    var items = [];
34900                    if (xfaValue) {
34901                        var bndNode = this.bindNode;
34902                        _.each(xfaValue, function (item, index, list) {
34903                            items.push(bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index));
34904                        });
34905                    }
34906                    return items;
34907                },
34908                "guideToXfa" : function (guideValue) {
34909                    return guideValue;
34910                }
34911            },
34912            "multiSelect" : {
34913                "xfaToGuide" : function (xfaValue) {
34914                    return xfaValue === "multiSelect";
34915                },
34916                "guideToXfa" : function (guideValue) {
34917                    return guideValue === true ? "multiSelect" : "userControl";
34918                }
34919            },
34920            "calcExp" : {
34921                "xfaToGuide" : function (xfaValue) {
34922                    return xfaValue !== null && xfaValue !== "" ? null : undefined;
34923                },
34924                "guideToXfa" : function (guideValue) {
34925                    return guideValue !== null && guideValue !== "" ? null : undefined;
34926                }
34927            },
34928            "dataType" : {
34929                "xfaToGuide" : function (xfaValue) {
34930                    return xfaValue;
34931                },
34932                "guideToXfa" : function (guideValue) {
34933                    return undefined;
34934                }
34935            }
34936        };
34937    convertor.validateExp = convertor.visibleExp =
34938                          convertor.enabledExp =
34939                          convertor.clickExp =
34940                          convertor.calcExp;
34941
34942    guidelib.model.GuideSchema = xfalib.ut.Class.extend({
34943
34944        GuideStateConstants : {
34945            
34946            GUIDE_STATE_MODEL_CREATION : 0,
34947            
34948            GUIDE_STATE_MODEL_CREATED : 1,
34949            
34950            GUIDE_STATE_MERGE_PROGRESS : 2,
34951            
34952            GUIDE_STATE_MERGE_COMPLETE : 3,
34953            
34954            GUIDE_STATE_MODEL_COMPLETE : 4
34955        },
34956
34957        initialize : function () {
34958            
34959            this.addSchema('guideNode',
34960                [
34961                    ["name", "string", null],
34962                    ["id", "string", null],
34963                    ["jcr:title", "string", null],
34964                    ["jcr:description", "string", null],
34965                    ["css", "string", ""],
34966                    ["fd:targetVersion", "float", 1.0]
34967                ]);
34968
34969            this.addSchema("scriptable",
34970                [
34971                    ["visibleExp", "string", null],
34972                    ["enabledExp", "string", null],
34973                    ["visible", "boolean", true, "presence"],
34974                    ["enabled", "boolean", true, "access"],
34975                    ["assistPriority", "string", null, "assist.speak.priority"],
34976                    ["custom", "string", null, "assist.speak.value"],
34977                    ["shortDescription", "string", null, "assist.toolTip.value"],
34978                    ["longDescription", "string", null]
34979                ],
34980                'guideNode');
34981
34982            this.addSchema("guideInstanceManager", [], "guideNode");
34983
34984            this.addSchema("esign", [], "guideNode");
34985
34986            this.addSchema("verify", [], "guideNode");
34987
34988            this.addSchema("guideItemsContainer", [], "scriptable");
34989
34990            this.addSchema("guideImage", [], "scriptable");
34991
34992            this.addSchema("guideContainerNode",
34993            [
34994                ["disableSwipeGesture", "boolean", false]
34995            ],
34996            "guideItemsContainer");
34997
34998            this.addSchema("guidePanel",
34999                [
35000                  ["validateOnStepCompletion","boolean",false]
35001                ],
35002                "guideItemsContainer");
35003
35004            this.addSchema("rootPanelNode", [], "guidePanel");
35005
35006            this.addSchema("guideTable", [], "guidePanel");
35007
35008            this.addSchema("guideTableRow", [], "guidePanel");
35009
35010            this.addSchema("guideToolbar", [], "guideItemsContainer");
35011
35012            this.addSchema("guideCompositeField", [], "guideItemsContainer");
35013
35014            this.addSchema("guideFileUpload",
35015                [
35016                    ["multiSelection", "boolean", false],
35017                    ["buttonText", "string", null],
35018                    ["fileSizeLimit", "integer", 2],
35019                    ["showComment", "boolean", false]
35020                ],
35021                "guideCompositeField");
35022
35023            
35024            
35025            this.addSchema("guideField",
35026                [
35027                    ["jcr:title", "string", null, "caption.value.oneOfChild.value","Guide"],
35028                    ["calcExp", "string", null, "calculate.script.value", "Guide"],
35029                    ["validateExp", "string", null, "validate.script.value", "Guide"],
35030                    ["_value", "string", null, "rawValue"],
35031                    ["displayPictureClause", "string", null, "format.picture.value"],
35032                    ["validatePictureClause", "string", null, "validate.picture.value"],
35033                    ["mandatory", "boolean", false, "validate.nullTest"],
35034                    ["mandatoryMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-005"]),
35035                        "mandatoryMessage"],
35036                    ["validateExpMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-006"]),
35037                        "validationMessage","Guide"],
35038                    ["validatePictureClauseMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-007"]),
35039                        "formatMessage"],
35040                    ["validationState", "boolean", false], 
35041                    ["width", "string", null],
35042                    ["height", "string", null]
35043                ],
35044                "scriptable");
35045
35046            this.addSchema("guideTextBox",
35047                [
35048                    ["multiLine", "boolean", false, "ui.textEdit.multiLine"],
35049                    ["maxChars", "integer", 0, "value.text.maxChars"],
35050                    ["minLength", "integer", null],
35051                    ["length", "integer", null]
35052                ],
35053                "guideField");
35054
35055            this.addSchema("guideCaptcha", [], "guideField");
35056
35057            this.addSchema("guideTelephone", [], "guideField");
35058
35059            this.addSchema("guideNumericBox",
35060                [
35061                    ["dataType", "string", "decimal", "value.oneOfChild.className"],
35062                    ["leadDigits", "integer", -1, "value.decimal.leadDigits"],
35063                    ["fracDigits", "integer", 2, "value.decimal.fracDigits"],
35064                    ["maximum", "integer", null],
35065                    ["minimum", "integer", null],
35066                    ["exclusiveMaximum", "boolean", null],
35067                    ["exclusiveMinimum", "boolean", null]
35068                ],
35069                "guideField");
35070
35071            this.addSchema("guidePasswordBox", [], "guideField");
35072
35073            this.addSchema("guideRadioButton", [
35074                ["optionsExp", "string", null],
35075                ["options", "object", null, "items"]
35076            ], "guideField");
35077
35078            this.addSchema("guideCheckBox", [
35079                ["optionsExp", "string", null],
35080                ["options", "object", null, "items"]
35081            ], "guideField");
35082
35083            this.addSchema("guideSwitch", [], "guideCheckBox");
35084
35085            this.addSchema("guideScribble", [], "guideField");
35086
35087            this.addSchema("guideDatePicker",
35088                [
35089                    ["maximum", "string", null],
35090                    ["minimum", "string", null],
35091                    ["exclusiveMaximum", "boolean", null],
35092                    ["exclusiveMinimum", "boolean", null]
35093                ], "guideField");
35094
35095            this.addSchema("guideButton", [], "guideField");
35096
35097            this.addSchema("guideListFileAttachmentButton", [], "guideButton");
35098
35099            this.addSchema("guideTextDraw",
35100                [
35101                    ["documentFragmentVariables", "string", null]
35102                ],
35103                "guideField");
35104
35105            this.addSchema("guideFootnotePlaceHolder",[], "guideTextDraw");
35106
35107            this.addSchema("guideAdobeSignBlock",
35108                [
35109                    ["documentFragmentVariables", "string", null]
35110                ],
35111                "guideField");
35112
35113            this.addSchema("guideCompositeFieldItem", [], "guideField");
35114
35115            this.addSchema("guideDropDownList",
35116                [
35117                    ["title", "string", "DropDown"],
35118                    ["multiSelect", "boolean", false, "ui.oneOfChild.open"],
35119                    ["optionsExp", "string", null],
35120                    ["options", "object", null, "items"]
35121                ],
35122                "guideField");
35123
35124            this.addSchema("guideTermsAndConditions",
35125                [
35126                    ["showLink", "boolean", false],
35127                    ["showAsPopUp", "boolean", false],
35128                    ["clickStatus", "string", null]
35129                ],
35130                "guideCompositeField");
35131
35132            this.addSchema("guideChart", [
35133                ["height", "integer", 300],
35134                ["width", "integer", 100],
35135                ["data", "object", null],
35136                ["xAxisTitle", "string", null],
35137                ["yAxisTitle", "string", null],
35138                ["chartType", "string", "linepoint"],
35139                ["repeatableItem", "string", null],
35140                ["xExp", "string", null],
35141                ["reducerXFunction", "string", "none"],
35142                ["yExp", "string", null],
35143                ["reducerYFunction", "string", "none"],
35144                ["innerRadius", "integer", 0],
35145                ["lineColor", "string", "#000000"],
35146                ["pointColor", "string", "#000000"],
35147                ["areaColor", "string", "#000000"],
35148                ["tooltipHtml", "string", "<p>${x}(${y})</p>"],
35149                ["showLegends", "boolean", false],
35150                ["legendPosition", "string", "right"]
35151            ], "scriptable");
35152
35153            this.addSchema("guideAdModule", [["_value", "string", null]], "scriptable");
35154            this.addSchema("guideAdModuleGroup", [["_value", "string", null]], "scriptable");
35155        },
35156
35157        addSchema : function (elementName, attrArray, superElement) {
35158            var el = {};
35159            if (typeof superElement === "object") {
35160                _.extend(el, superElement);
35161            } else if (typeof superElement === "string" && guideSchema[superElement]) {
35162                _.extend(el, guideSchema[superElement]);
35163            }
35164            this.addAttributes(el, attrArray);
35165            guideSchema[elementName] = el;
35166        },
35167
35168        addAttributes : function (element, attrArray) {
35169            _.each(attrArray, function (elem) {
35170                element[elem[0]] = {
35171                    "type" : elem[1],
35172                    "default" : elem[2],
35173                    "xfaProp" : elem[3],
35174                    "priority" : elem[4]
35175                };
35176            });
35177        },
35178
35179        getAttributeProps : function (element, attribute) {
35180            try {
35181                return guideSchema[element][attribute] || {};
35182            } catch (e) {
35183                this.logger().error("AF", "schema has no element " + element);
35184            }
35185        },
35186        getAttributes : function (element) {
35187            return guideSchema[element];
35188        },
35189
35190        getTypedValue : function (type, value) {
35191            if (value === null || value === undefined) {
35192                return value;
35193            }
35194            if (type instanceof Array) {
35195                return value;
35196            }
35197            switch (type) {
35198                case "string":
35199                    return value + "";
35200                case "integer":
35201                    return parseInt(value);
35202                case "boolean":
35203                    return value === true || value === "true" ? true : false;
35204                case "float":
35205                    return parseFloat(value);
35206                default :
35207                    return value;
35208            }
35209        },
35210
35211        getConvertor : function (attr) {
35212            return convertor[attr];
35213        }
35214    });
35215
35216}(_, guidelib));
35217
35218(function (_, guidelib) {
35219
35220    
35221    
35222    var GuideContainerNode = guidelib.model.GuideContainerNode = guidelib.model.GuideItemsContainer.extend({
35223        msClassName : "guideContainerNode",
35224
35225        setGuideState : function (guideState) {
35226            var isStateValid = _.some(guidelib.model.GuideSchema.prototype.GuideStateConstants, function (val) {
35227                return val === guideState;
35228            });
35229            if (isStateValid === true) {
35230                this._guideState = guideState;
35231            }
35232        },
35233
35234        getGuideState : function () {
35235            return this._guideState;
35236        },
35237
35238        initialize : function () {
35239            var configString = "";
35240            
35241            guidelib.__runtime__.guide = this;
35242
35243            
35244            
35245            this._guideState = guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MODEL_CREATION;
35246
35247            
35248            this.internal = this.internal || {};
35249            
35250            
35251            this.internal.liveDataUtils = this.options.liveDataUtils || new guidelib.model.LiveXmlUtils();
35252            this.internal.liveModel = this.options.liveModel || new guidelib.model.LiveModel();
35253            this.internal.GuideDirtyMarkerAndVisitor = new guidelib.model.GuideDirtyMarkerAndVisitor();
35254
35255            
35256            this.runtime =  {
35257                guideContext : {},
35258                _private : {},
35259                errorManager : {}
35260            };
35261
35262            
35263            this.runtime.errorManager = new guidelib.util.GuideErrorManager();
35264
35265            this._modelTemplateCacheStore =
35266                new guidelib.model.util.ModelTemplateCacheStore({modelTemplateJson : this.jsonModel});
35267            this._guideSchema = new guidelib.model.GuideSchema();
35268            this.guideLazyUtil = new guidelib.util.GuideLazyUtil({"_guideContainer" : this});
35269            this._pendingQueues = {
35270                calcExp : [],
35271                valueCommitScript : [],
35272                enabledExp : [],
35273                visibleExp : [],
35274                validateAllExp : [],
35275                optionsExp : [],
35276                navigationChangeExp : [],
35277                summaryExp : [],
35278                autoSaveStartExp : [],
35279                aggregateExp : [],
35280                submitSuccess : [],
35281                submitError : []
35282            };
35283            this._resetExpressionCounters();
35284            this._currentContext = null;
35285            GuideContainerNode._super.initialize.call(this);
35286            this.autoSaveStart = false;
35287            
35288            
35289            this._modelTemplateCacheStore.putModel(this);
35290            this._postInitialize();
35291            var xfaHost = this.getOrElse(xfalib, "runtime.xfa.host", null);
35292            if (xfaHost !== null) {
35293                xfaHost.on(xfalib.script.XfaModelEvent.FORM_MODEL_REFRESH,
35294                    function (evnt) {
35295                        switch (evnt.name) {
35296                        case xfalib.script.XfaModelEvent.FORM_MODEL_REFRESH:
35297                            this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_REFRESH, "jsonModel", null, null);
35298                            break;
35299                        default:
35300                        
35301                        }
35302                    },
35303                    this);
35304            }
35305        },
35306
35307        _resetExpressionCounters : function () {
35308            this._runningExpressionCount = {
35309                calcExp : {},
35310                valueCommitScript : {},
35311                enabledExp : {},
35312                visibleExp : {},
35313                validateAllExp : {},
35314                optionsExp : {},
35315                navigationChangeExp : {},
35316                summaryExp : {},
35317                autoSaveStartExp : {},
35318                aggregateExp : {},
35319                submitSuccess : {},
35320                submitError : {}
35321            };
35322        },
35323
35324        _getReducedJSON : function () {
35325            
35326            
35327            var reducedJSONChildren = guidelib.model.GuideNode.prototype._getReducedJSON.call(this),
35328                addtionalWhitelistedProperties = ["xdpRef", "xsdRef", "id", "dorTemplateRef", "dorType", "excludeFromDoRIfHidden", "schemaRef", "schemaType"];
35329            guidelib.model.util.CommonUtils.returnMinimalJSON(addtionalWhitelistedProperties, reducedJSONChildren, this);
35330            reducedJSONChildren["rootPanel"] = this["rootPanel"]._getReducedJSON();
35331            if (this.jsonModel.toolbar) {
35332                reducedJSONChildren["toolbar"]  = this["toolbar"]._getReducedJSON();
35333            }
35334            return reducedJSONChildren;
35335        },
35336
35337        _initChildren : function () {
35338            
35339            var options =  {"_guideContainer" : this};
35340            this.rootPanel = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.rootPanel, options);
35341            this._initializeChild(this.rootPanel);
35342            this._children.push(this.rootPanel);
35343            
35344            var instanceManager = guidelib.model.GuideModelRegistry.prototype.createInstanceManager(this.rootPanel);
35345            this._initializeChild(instanceManager);
35346            this._children.splice(this._children.indexOf(this.rootPanel), 0, instanceManager);
35347            instanceManager._manageChild(this.rootPanel);
35348
35349            if (this.jsonModel.toolbar) {
35350                var options = {};
35351                if (this._guide()) {
35352                    options = _.extend({}, options, {"_guideContainer" : this._guide()});
35353                }
35354                this.toolbar = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.toolbar, options);
35355                this._initializeChild(this.toolbar);
35356                this._children.push(this.toolbar);
35357            }
35358        },
35359
35360        
35361        _addToExcludeFromDorMap : function (fieldTemplateId, bExcludeFromDor) {
35362            this._excludeFromDorMap = this._excludeFromDorMap || {};
35363            this._excludeFromDorMap[fieldTemplateId] = bExcludeFromDor;
35364        },
35365
35366        
35367        _getExcludeFromDorMap : function () {
35368            var that = this;
35369            if (!_.isUndefined(that._excludeFromDorMap)) {
35370                return _.keys(that._excludeFromDorMap).map(function (key) {
35371                    
35372                    return key  + "="  + that._excludeFromDorMap[key];
35373                });
35374            }
35375        },
35376
35377        
35378        _addToStateOverrideMap : function (fieldName, fieldsOverrid
35378denMap) {
35379            this._stateOverrideMap = this._stateOverrideMap || {};
35380            this._stateOverrideMap[fieldName] = fieldsOverriddenMap;
35381        },
35382
35383        
35384        _getStateOverrideMap : function () {
35385            var that = this;
35386            var retval = {};
35387            if (!_.isUndefined(that._stateOverrideMap)) {
35388                var elementsArray = _.keys(that._stateOverrideMap).map(function (key) {
35389                    return that._stateOverrideMap[key];
35390                });
35391                retval = {"element" : elementsArray};
35392            }
35393            return retval;
35394
35395        },
35396
35397        
35398        _resolveAfDataSom : function (afDataSom) {
35399            var resolvedField = null;
35400            
35401            
35402            _.each(this.internal.liveModel.getCrossFragmentFields(), function (fields) {
35403                
35404                var globalFieldModels = this.internal.liveModel.getAllAbstractFieldModels(_.keys(fields));
35405                _.each(globalFieldModels, function (globalField) {
35406                    if (globalField.afDataSom === afDataSom) {
35407                        resolvedField = globalField;
35408                        return false;
35409                    }
35410                });
35411                if (resolvedField) {
35412                    return false;
35413                }
35414            });
35415            return resolvedField;
35416        },
35417
35418        
35419        _getSigners : function () {
35420           var signers = {};
35421           
35422           if (this.enableAdobeSign && (_.isString(this.xdpRef) ||  _.isString(this.xsdRef) || (!_.isString(this.jsonModel.schemaRef)))) {
35423               var signer,
35424                  that = this,
35425                  email,
35426                  number,
35427                  countryCode,
35428                   evalExp = function (fldSom, fldAfDataSom, type) {
35429                       var val = null,
35430                           resolvedField;
35431                       try {
35432                           resolvedField = guideBridge._guide.resolveNode(fldSom);
35433                           if (!resolvedField) {
35434                               resolvedField = guideBridge._guide._resolveAfDataSom(fldAfDataSom);
35435                           }
35436                           val = resolvedField.value;
35437                           if (resolvedField.className === 'guideTelephone') {
35438                               if (type === 'countryCode') {
35439                                   val = guidelib.model.GuideTelephone.prototype._extractCountryCode(val);
35440                               } else if (type === 'phone') {
35441                                   val = guidelib.model.GuideTelephone.prototype._extractPhoneNumber(val);
35442                               }
35443                           }
35444                       } catch (e) {
35445                           
35446                       }
35447                       
35448                       
35449                       return val ? val.toString() : val;
35450                   };
35451               if (this.signerInfo) {
35452                   _.each(_.keys(this.signerInfo), function (name) {
35453                       signer = that.signerInfo[name];
35454                       if (signer && typeof signer === "object") {
35455                           email = null;
35456                           number = null;
35457                           countryCode = null;
35458                           if (signer.emailSource === 'form' && signer.email) {
35459                               email = evalExp(signer.email, signer.emailAfDataSom, 'email');
35460                           }
35461                           signers[name] = {};
35462                           signers[name].email = email ? email : "";
35463                           if (signer.securityOption === 'PHONE') {
35464                               if (signer.phoneSource === 'form' && signer.phone) {
35465                                   number = evalExp(signer.phone, signer.phoneAfDataSom, 'phone');
35466                               }
35467                               if (signer.countryCodeSource === 'form' && signer.countryCode) {
35468                                   countryCode = evalExp(signer.countryCode, signer.countryCodeAfDataSom, 'countryCode');
35469                               }
35470                               signers[name].phone = {};
35471                               signers[name].phone.countryCode = countryCode ? countryCode : "";
35472                               signers[name].phone.number = number ? number : "";
35473                           }
35474                       }
35475                   });
35476               }
35477           }
35478
35479           return signers;
35480       },
35481
35482        
35483        defaultSubmitSuccess : "window.guideBridge._defaultSubmitSuccessHandler($event.data)",
35484
35485        
35486        defaultSubmitError : "window.guideBridge._handleServerValidationError($event.data)",
35487
35488        
35489        _collectExpressions : function () {
35490            if (this.autoSaveStartExpression) {
35491                this._compiledExpressions["autoSaveStartExp"] = this._compileExpression(this.autoSaveStartExpression, "autoSaveStart");
35492            }
35493
35494            
35495            if (!this.submitSuccess) {
35496                this.jsonModel.submitSuccess = this.defaultSubmitSuccess;
35497            }
35498            this._compiledScripts.submitSuccess = this._compileExpression(this.submitSuccess, null);
35499
35500            if (!this.submitError) {
35501                this.jsonModel.submitError = this.defaultSubmitError;
35502            }
35503            this._compiledScripts.submitError = this._compileExpression(this.submitError, null);
35504        },
35505
35506        prepare : function () {
35507            
35508            
35509            if ((this.getGuideState() !== guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_PROGRESS) && (this.getGuideState() !== guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MODEL_CREATION)) {
35510                _.each(this._children, function (childNode) {
35511                    childNode.prepare();
35512                }, this);
35513                this.queueExpressions(this, ["autoSaveStartExp"]);
35514                this.runPendingExpressions();
35515            }
35516        },
35517
35518        runPendingExpressions : function () {
35519            
35520            this._runExpressionQueue("calcExp");
35521            this._runExpressionQueue("enabledExp");
35522            this._runExpressionQueue("visibleExp");
35523            this._runExpressionQueue("valueCommitScript");
35524            this._runExpressionQueue("validateAllExp");
35525            this._runExpressionQueue("optionsExp");
35526            this._runExpressionQueue("navigationChangeExp");
35527            this._runExpressionQueue("summaryExp");
35528            this._runExpressionQueue("aggregateExp");
35529            this._runExpressionQueue("submitSuccess");
35530            this._runExpressionQueue("submitError");
35531            if (window.guideBridge.hostName !== "server") {
35532                this._runExpressionQueue("autoSaveStartExp");
35533            }
35534            this._resetExpressionCounters();
35535        },
35536
35537        _runExpressionQueue : function (expName) {
35538            var expQueue = this._pendingQueues[expName], node;
35539            if (expQueue) {
35540                while (expQueue.length > 0) {
35541                    node = this._pendingQueues[expName].shift();
35542                    if (node) {
35543                        node.executeExpression(expName);
35544                    }
35545                }
35546            }
35547        },
35548
35549        queueExpressions : function (node, expressionArray) {
35550            if (!node || !expressionArray) {
35551                return;
35552            }
35553            if (_.isString(expressionArray)) {
35554                expressionArray = [expressionArray];
35555            }
35556            _.each(expressionArray, function (expression) {
35557                var expQueue = this._pendingQueues[expression],
35558                    som = node.somExpression,
35559                    counters = this._runningExpressionCount[expression];
35560                counters[som] = counters[som] || 0;
35561                if (expQueue && expQueue.indexOf(node) < 0 && counters[som] < 10) {
35562                    expQueue.push(node);
35563                    counters[som] += 1;
35564                }
35565            }, this);
35566        },
35567
35568        playJson : function (pJsonModel, attachments) {
35569            this.rootPanel.playJson(pJsonModel.rootPanel, attachments);
35570            if (this.toolbar) {
35571                this.toolbar.playJson(pJsonModel.toolbar, attachments);
35572            }
35573        },
35574
35575        _guide : function () {
35576            return this;
35577        },
35578
35579        _collectValues : function (keyValue) {
35580            _.each(this._children, function (childNode) {
35581                childNode._collectValues(keyValue);
35582            }, this);
35583        },
35584
35585        
35586        resolveNode : function (somExpression) {
35587            if (!somExpression || somExpression === "") {
35588                return;
35589            }
35590            var hierarchy = somExpression.split("."),
35591                componentInModel = null;
35592            if (hierarchy[0] === "guide[0]") {
35593                hierarchy.shift();
35594                componentInModel = this;
35595            }
35596            if (hierarchy[0] === this._escapeQualifiedName()) {
35597                componentInModel = this;
35598                hierarchy.shift();
35599            } else if (this.hasOwnProperty(hierarchy[0])) {
35600                componentInModel = this[hierarchy[0]];
35601                hierarchy.shift();
35602            } else if (!componentInModel) {
35603                componentInModel = this.rootPanel;
35604            }
35605            _.each(hierarchy, function (element) {
35606                if (componentInModel && componentInModel._findChildren) {
35607                    componentInModel = componentInModel._findChildren(element, false)[0];
35608                } else {
35609                    componentInModel = null;
35610                }
35611            }, this);
35612            if (componentInModel == null) {
35613                
35614                var relativeName = somExpression;
35615                componentInModel = this.getOrElse(this._guide().runtime, relativeName, null);
35616            }
35617            return componentInModel;
35618        }
35619    });
35620
35621    GuideContainerNode.defineProps({
35622
35623        submitSuccess : {
35624            get : function () {
35625                return this.jsonModel.submitSuccess;
35626            }
35627        },
35628
35629        submitError : {
35630            get : function () {
35631                return this.jsonModel.submitError;
35632            }
35633        },
35634
35635        
35636        "autoSaveStart" : {
35637            get : function () {
35638                return this.jsonModel.autoSaveStart;
35639            },
35640
35641            set : function (newValue) {
35642                this.jsonModel.autoSaveStart = newValue;
35643                if (newValue === true) {
35644                    delete this._compiledExpressions.autoSaveStartExp;
35645                    this._triggerOnBridge(window.guideBridge.GUIDE_AUTO_SAVE_START, this);
35646                }
35647            }
35648        },
35649
35650        
35651        "enableAutoSave" : {
35652            set : function (newValue) {
35653                this.jsonModel.enableAutoSave = newValue;
35654            },
35655
35656            get : function () {
35657                return this.jsonModel.enableAutoSave || false;
35658            }
35659        },
35660
35661        
35662        "autoSaveStartExpression" : {
35663            get : function () {
35664                return this.jsonModel.autoSaveStartExpression;
35665            }
35666        },
35667
35668        
35669        "autoSaveInfo" : {
35670            get : function () {
35671                return this.jsonModel.autoSaveInfo;
35672            }
35673        },
35674
35675        
35676        "globalMetaInfo" : {
35677            get : function () {
35678                return this.jsonModel.globalMetaInfo;
35679            }
35680        },
35681
35682        
35683        "submissionMetaInfo" : {
35684            get : function () {
35685                return this.jsonModel.submissionMetaInfo;
35686            }
35687        },
35688
35689        
35690        "signerInfo" : {
35691           get : function () {
35692               return this.jsonModel.signerInfo;
35693           }
35694       },
35695
35696        "xdpRef" : {
35697            get : function () {
35698                return this.jsonModel.xdpRef;
35699            }
35700        },
35701
35702        "dorTemplateRef" : {
35703            get : function () {
35704                return this.jsonModel.dorTemplateRef;
35705            }
35706        },
35707
35708        "dorType" : {
35709            get : function () {
35710                return this.jsonModel.dorType;
35711            }
35712        },
35713
35714        "actionType" : {
35715            get : function () {
35716                return this.jsonModel.actionType;
35717            }
35718        },
35719
35720        "xsdRef" : {
35721            get : function () {
35722                return this.jsonModel.xsdRef;
35723            }
35724        },
35725
35726        
35727        panel : {
35728            get : function () {
35729                return this.rootPanel;
35730            }
35731        },
35732
35733        
35734        print : {
35735            get : function () {
35736                if (this.dorType === "generate" && this.jsonModel.view) {
35737                    return this.jsonModel.view.print;
35738                }
35739
35740                return null;
35741            }
35742        },
35743
35744        
35745        "allLazyChildren" : {
35746            get : function () {
35747                return this.jsonModel.allLazyChildren;
35748            }
35749        },
35750
35751        
35752        "enableAsyncSubmission" : {
35753            set : function (newValue) {
35754                this.jsonModel.enableAsyncSubmission = newValue;
35755            },
35756
35757            get : function () {
35758                if (this.jsonModel.enableAsyncSubmission && (this.jsonModel.enableAsyncSubmission === "true" || this.jsonModel.enableAsyncSubmission === true)) {
35759                    return true;
35760                } else {
35761                    return false;
35762                }
35763            }
35764        },
35765
35766        
35767        "enableAdobeSign" : {
35768            get : function () {
35769                return this.jsonModel._useSignedPdf;
35770            }
35771        },
35772
35773        
35774        "enableFocusOnFirstField" : {
35775            set : function (newValue) {
35776                this.jsonModel.enableFocusOnFirstField = newValue;
35777            },
35778
35779            get : function () {
35780                if (this.jsonModel.enableFocusOnFirstField === undefined) {
35781                    return true;
35782                }
35783                return this.jsonModel.enableFocusOnFirstField;
35784            }
35785        }
35786    });
35787}(_, guidelib));
35788
35789(function (_, guidelib) {
35790    guidelib.model.mixin.AddNavigationContext = {
35791        propertyDescriptors : {
35792            "navigationContext" : {
35793                get : function () {
35794                    if (!this._navigationContext) {
35795                        this._navigationContext = new guidelib.model.util.GuideNavigationContext({
35796                            currentItem : null,
35797                            parentPanel : this.panel
35798                        });
35799                    }
35800                    return this._navigationContext;
35801                }
35802            }
35803        }
35804    };
35805})(_, guidelib);
35806
35807(function (_, guidelib) {
35808
35809    
35810    var GuidePanel = guidelib.model.GuidePanel = guidelib.model.GuideItemsContainer.extend({
35811        msClassName : "guidePanel",
35812        defaultExpressions : {
35813            "summary" : "this.title + (this.instanceIndex > 0 ? ' ' + this.instanceIndex : '')"
35814        },
35815
35816        initialize : function () {
35817            GuidePanel._super.initialize.call(this);
35818            this._currentItem = null;
35819            
35820            this._navigationContext = null;
35821        },
35822
35823        _collectExpressions : function () {
35824            GuidePanel._super._collectExpressions.call(this);
35825            if (this.completionExp) {
35826                this._compiledScripts.completionExp = this._compileExpression(this.completionExp, null);
35827            }
35828            if (this.jsonModel.summaryExp) {
35829                this._compiledExpressions.summaryExp = this._compileExpression(this.jsonModel.summaryExp, "summary");
35830            } else {
35831                this._compiledExpressions.summaryExp = this._compileExpression(this.defaultExpressions["summary"], "summary");
35832            }
35833        },
35834
35835        _initializeInstanceManager : function (child, index, insertOffset) {
35836            var instanceManager = guidelib.model.GuideModelRegistry.prototype.createInstanceManager(child);
35837            this._initializeChild(instanceManager);
35838            
35839            this._children.splice(index + insertOffset++, 0, instanceManager);
35840            instanceManager._manageChild(child);
35841            
35842            var bindNode = child._getBindNode(),
35843                bindNodeInstCount = this.getOrElse(bindNode, "instanceManager.count", 0),
35844            
35845                panelInstancesToAdd = Math.max(child.minOccur, bindNodeInstCount) - 1,
35846                bindNodeOffset = 1,
35847                addedXfaInstance;
35848            while (panelInstancesToAdd > 0) {
35849                
35850                addedXfaInstance = null;
35851                if (bindNodeInstCount > 1) {
35852                    
35853                    addedXfaInstance = bindNode.instanceManager.instances[bindNodeOffset++];
35854                }
35855                instanceManager.addInstance(addedXfaInstance);
35856                panelInstancesToAdd -= 1;
35857                insertOffset += 1;
35858            }
35859            return insertOffset;
35860        },
35861
35862        
35863        _initChildren : function (bLazyInitialization) {
35864            GuidePanel._super._initChildren.call(this);
35865            if (!bLazyInitialization) {
35866                this._instanceManager = null;
35867            }
35868            this._childInitializeGoingOn = true;
35869            var currentChildren = this.children,
35870                insertOffset = 0;
35871            _.each(currentChildren, function (child, index) {
35872                if (child instanceof guidelib.model.GuidePanel) {
35873                    insertOffset = this._initializeInstanceManager(child, index, insertOffset);
35874                }
35875            }, this);
35876            if (this.jsonModel.toolbar) {
35877                var options = {};
35878                if (this.options._guideContainer) {
35879                    options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
35880                }
35881                var toolbar = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.toolbar, options);
35882                this._initializeChild(toolbar);
35883                this._children.push(toolbar);
35884            }
35885            this._summary = null;
35886            this._childInitializeGoingOn = false;
35887        },
35888
35889        _postInitialize : function () {
35890            GuidePanel._super._postInitialize.call(this);
35891            
35892            this.instanceManager._postInitializeBinding();
35893        },
35894
35895        _addChildAt : function (child, childIndex, muteEvent) {
35896            if (child) {
35897                this._initializeChild(child);
35898                this._guide()._modelTemplateCacheStore.putModel(child);
35899                var newItemIndex = this._getItemsInsertIndex(childIndex - 1);
35900                var newItems = {};
35901                var newItemKey = child.id;
35902                var lastItemIndex = -1;
35903                _.each(this.jsonModel.items, function (value, key) {
35904                    if (lastItemIndex == newItemIndex - 1) {
35905                        newItems[newItemKey] = child.jsonModel;
35906                    }
35907                    newItems[key] = value;
35908                    lastItemIndex++;
35909                }, this);
35910                if (lastItemIndex == newItemIndex - 1) {
35911                    newItems[newItemKey] = child.jsonModel;
35912                }
35913                this.jsonModel.items = newItems;
35914                child._isItem = true;
35915                this._children.splice(childIndex, 0, child);
35916                this._normalizeChildren();
35917                child._postInitialize();
35918                if (this._guide().getGuideState() >= guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_COMPLETE) {
35919                    child.prepare();
35920                }
35921                
35922                
35923                
35924                if (!(this._lazyReference && this._childInitializeGoingOn)) {
35925                    if (!muteEvent) {
35926                        this._triggerEvent(guidelib.event.GuideModelEvent.CHILD_CHANGED, "childAdded", null, child);
35927                    }
35928                }
35929            }
35930        },
35931
35932        
35933        validate : function (errorList) {
35934            var markInvalid = false;
35935
35936            
35937            if (!this.visible) {
35938                return true;
35939            }
35940            var lazyModelUnloadPending = false;
35941            
35942            if (this._lazyReference && this.guideUtil.isLazyJson(this.jsonModel)) {
35943                var guideDirtyMarker = this._guide().internal.GuideDirtyMarkerAndVisitor,
35944                    visitMap = guideDirtyMarker.visitMap,
35945                    modelTemplateCacheStore = this._guide()._modelTemplateCacheStore,
35946                    guideUtil = guidelib.util.GuideUtil,
35947                    templateJson,
35948                    templateId = this.templateId,
35949                    uniquePrefix;
35950                
35951                if (visitMap[templateId] === 0) {
35952                    if (this._ancestorRepeatable) {
35953                        uniquePrefix = guideUtil.generateUID();
35954                    }
35955                    
35956                    templateJson = modelTemplateCacheStore._getTemplate(templateId, true);
35957                    
35958                    
35959                    if (!_.isEmpty(templateJson)) {
35960                        this._embedJson(templateJson.items, uniquePrefix);
35961                        this._guide().internal.liveDataUtils.playLiveData(this);
35962                        
35963                        this.prepare();
35964                        this._guide().runPendingExpressions();
35965                        this._guide().internal.liveDataUtils.updateLiveData(); 
35966                        lazyModelUnloadPending = true;
35967                    } else {
35968                        
35969                        markInvalid = true;
35970                    }
35971
35972                }
35973
35974            }
35975            var validationResult = GuidePanel._super.validate.call(this, errorList);
35976            if (lazyModelUnloadPending) {
35977                
35978                
35979                this._unloadLazyReferenceModel(true);
35980            }
35981            if (markInvalid === true) {
35982                validationResult = false;
35983            }
35984            return validationResult;
35985        },
35986
35987        _loadLazyFragment : function (options) {
35988            options = options || {};
35989            if (_.isUndefined(this._itemsLoaded)) {
35990                
35991                var path = this.jsonModel["jcr:path"],
35992                    externalizedPath;
35993                
35994                externalizedPath = guideBridge._getGuidePathUrl(".jsonhtmlemitter");
35995                this._fetchFromAjaxCall(externalizedPath, options);
35996            } else {
35997                if (_.isFunction(options.success)) {
35998                    options.success.call(this);
35999                }
36000            }
36001            
36002            
36003        },
36004
36005        _fetchFromAjaxCall : function (externalizedPath, options) {
36006            if (options && _.isFunction(options.preFetch)) {
36007                options.preFetch.call(this);
36008            }
36009            var that = this,
36010                lazyOptions = {
36011                    path : externalizedPath,
36012                    templateId : that.templateId,
36013                    fetchJSON : true,
36014                    fetchHTML : true,
36015                    success : fetchCallback,
36016                    error : (options && _.isFunction(options.error)) ? options.error : errorCallback,
36017                    complete : completeCallback
36018                };
36019
36020            window.guideBridge.panelProvider.getHtmlJson(lazyOptions);
36021
36022            function fetchCallback(jsonHtml) {
36023                var uniquePrefix;
36024                
36025                
36026                
36027                if (that.repeatable || that._ancestorRepeatable) {
36028                    uniquePrefix = that.guideUtil.generateUID();
36029                }
36030                if (guidelib.util.GuideUtil._embedHtml(that, jsonHtml["html"], uniquePrefix)) {
36031                    that._ajaxCallDone = true;
36032
36033                    
36034                    
36035                    
36036                    var referredJson = JSON.parse(jsonHtml["json"])["items"];
36037                    that._embedJson(referredJson, uniquePrefix);
36038                    
36039                    var guideDirtyMarkerAndVisitor = that._guide().internal.GuideDirtyMarkerAndVisitor;
36040                    
36041                    if (!that.repeatable) {
36042                        guideDirtyMarkerAndVisitor._updateCountOrInsert(guideDirtyMarkerAndVisitor.visitMap, that.templateId);
36043                    }
36044                    
36045                    that._guide().internal.liveDataUtils.playLiveData(that);
36046                    
36047                    that.prepare();
36048                    that._itemsLoaded = true;
36049                    that._guide().trigger(guidelib.event.GuideModelEvent.LAZY_LOADED);
36050                    
36051                    that._triggerOnBridge("elementLazyLoaded", that);
36052                    
36053                    
36054                    if (options && _.isFunction(options.success)) {
36055                        options.success.call(this);
36056                    }
36057                    
36058                    
36059                    
36060                }
36061            }
36062
36063            function errorCallback() {
36064                that.logger().error("AF", "Failed to fetch HTML and JSON for :" + externalizedPath);
36065            }
36066
36067            function completeCallback() {
36068                if (options && _.isFunction(options.postFetch)) {
36069                    options.postFetch.call(this);
36070                }
36071            }
36072
36073        },
36074
36075        
36076        _unloadLazyReferenceModel : function (muteValidation) {
36077            try {
36078                if (this._lazyReference) {
36079                    window.guideBridge._populateBindRefToSomMap(this);
36080                    if (!muteValidation) {
36081                        var validationStatus = this.validate(),
36082                            visitMap = this._guide().internal.GuideDirtyMarkerAndVisitor.visitMap;
36083                        if (validationStatus === false && visitMap[this.id] > 0) {
36084                            visitMap[this.id] = 0;
36085                        }
36086                    }
36087                    
36088                    
36089                    _.each(this.children, function (child) {
36090                        child._unloadModel(muteValidation);
36091                        var nIndex = this._children.indexOf(child);
36092                        
36093                        this._children.splice(nIndex, 1);
36094                        var childKey = null;
36095                        
36096                        _.each(this.jsonModel.items, function (value, key) {
36097                            if (value === child.jsonModel) {
36098                                childKey = key;
36099                            }
36100                        }, this);
36101                        if (childKey) {
36102                            delete this.jsonModel.items[childKey];
36103                        }
36104                        
36105                        this._normalizeChildren();
36106                    }, this);
36107                    
36108                    this._navigationContext = null;
36109                    this._currentItem = null;
36110                }
36111            } catch (exception) {
36112                this.logger().error(exception);
36113            }
36114
36115        },
36116        
36117        _unloadModel : function (muteValidation) {
36118            var visitMap = this._guide().internal.GuideDirtyMarkerAndVisitor.visitMap;
36119            _.each(this.children, function (child) {
36120                if (this._lazyReference && !muteValidation) {
36121                    var validationStatus = child.validate();
36122                    if (validationStatus === false) {
36123                        if (!_.isUndefined(visitMap[this.templateId])) {
36124                            visitMap[this.templateId] = 0;
36125                        }
36126                    }
36127                }
36128                child._unloadModel(muteValidation);
36129            }, this);
36130            guidelib.model.Scriptable.prototype._unloadModel.call(this);
36131        },
36132
36133        _removeChild : function (oChild) {
36134            oChild._unloadModel();
36135            var nIndex = this._children.indexOf(oChild);
36136            this._children.splice(nIndex, 1);
36137            var childKey = null;
36138            _.each(this.jsonModel.items, function (value, key) {
36139                if (value === oChild.jsonModel) {
36140                    childKey = key;
36141                }
36142            }, this);
36143            if (childKey) {
36144                delete this.jsonModel.items[childKey];
36145            }
36146            this._normalizeChildren();
36147            this._triggerEvent(guidelib.event.GuideModelEvent.CHILD_CHANGED, "childRemoved", oChild, null);
36148        },
36149
36150        
36151        _embedJson : function (referredJson, uniquePrefix) {
36152            
36153            var bIsSuccess = false;
36154            var clonedJson = JSON.parse(JSON.stringify(referredJson)),
36155                currentPanelId = this.id,
36156                referredPanelRoot = null,
36157                referredPanelRootName = null,
36158                bindRefPrefix = this.jsonModel.bindRef;
36159            
36160            currentPanelId = currentPanelId.slice(0, -2);
36161            if (referredJson) {
36162                
36163                if (this.repeatable || this._ancestorRepeatable) {
36164                    this.copyObject(referredJson, clonedJson,
36165                        {
36166                            transformMaps : {
36167                                "id" : function (srcValue, options, parentObj) {
36168                                    return uniquePrefix + "__" + parentObj.templateId;
36169                                }
36170                            }
36171                        }
36172                    );
36173                }
36174                
36175                
36176                _.each(clonedJson, function (panelJson, panelName) {
36177                    if (_.isObject(panelJson)) {
36178                        bIsSuccess = true;
36179                        
36180                        this.jsonModel.items = this.jsonModel.items || {};
36181                        this.jsonModel.items[panelName] = panelJson;
36182                        
36183                        this._guide()._modelTemplateCacheStore._putTemplate(JSON.parse(JSON.stringify(panelJson)));
36184                    }
36185                }, this);
36186                
36187                this._embedModel();
36188
36189            }
36190            if (bIsSuccess === true) {
36191                
36192            }
36193            return bIsSuccess;
36194        },
36195
36196        
36197        _embedModel : function () {
36198            
36199            this._initChildren(true);
36200            
36201            
36202            this._guide()._modelTemplateCacheStore.putModel(this);
36203            
36204            this._postInitialize();
36205            
36206            this._normalizeChildren();
36207        },
36208
36209        _getItemsInsertIndex : function (childIndex) {
36210            var itemIndex = 0;
36211            _.find(this._children, function (child, index) {
36212                if (child._isItem) {
36213                    itemIndex++;
36214                }
36215                if (index >= childIndex) {
36216                    return true; 
36217                }
36218            }, this);
36219            return itemIndex;
36220        },
36221
36222        playJson : function (pJsonModel, attachments) {
36223            var playNonPanelItems = {};
36224            var playPanelItems = {};
36225            _.each(pJsonModel.items, function (item) {
36226                if (_.isObject(item)) {
36227                    
36228                    if (item.guideNodeClass === "guidePanel" || item.guideNodeClass === "guideTable" || item.guideNodeClass === "guideTableRow") {
36229                        if (playPanelItems[item.name]) {
36230                            playPanelItems[item.name].push(item);
36231                        } else {
36232                            playPanelItems[item.name] = [item];
36233                        }
36234                    } else {
36235                        if (playNonPanelItems[item.name]) {
36236                            playNonPanelItems[item.name].push(item);
36237                        } else {
36238                            playNonPanelItems[item.name] = [item];
36239                        }
36240                    }
36241                }
36242            }, this);
36243
36244            
36245            var panelIMs = _.filter(this._children, function (child) {
36246                return child instanceof guidelib.model.GuideInstanceManager;
36247            }, this);
36248
36249            _.each(panelIMs, function (instanceManager) {
36250                var panelName = instanceManager._getInstanceName();
36251                var newPanelItems = playPanelItems[panelName] || []; 
36252                var panelInstances = instanceManager._instances.slice(0);
36253                _.each(panelInstances, function (panelInstance, index) {
36254                    if (newPanelItems.length > 0) {
36255                        var panelJson = newPanelItems.shift();
36256                        panelInstance.playJson(panelJson, attachments);
36257                    } else {
36258                        instanceManager.removeInstance(index);
36259                    }
36260                }, this);
36261                if (newPanelItems.length > 0) {
36262                    _.each(newPanelItems, function (paneljson) {
36263                        var addedInstance = instanceManager.addInstance();
36264                        if (addedInstance) {
36265                            addedInstance.playJson(paneljson, attachments);
36266                        }
36267                    }, this);
36268                }
36269            }, this);
36270
36271            
36272            _.each(this.items, function (child) {
36273                if (!(child instanceof guidelib.model.GuidePanel)) {
36274                    var nonPanelItemName = child.name;
36275                    var nonPanelItem = playNonPanelItems[nonPanelItemName];
36276                    if (nonPanelItem && nonPanelItem.length > 0) {
36277                        child.playJson(nonPanelItem.shift(), attachments);
36278                    }
36279                }
36280            }, this);
36281
36282            
36283            if (this.toolbar) {
36284                this.toolbar.playJson(pJsonModel.toolbar, attachments);
36285            }
36286        },
36287        
36288        _getReducedJSON : function (isParentRepeatable) {
36289            var reducedJSONChildren,
36290                isRepeatable;
36291            isRepeatable = isParentRepeatable || this.canBeRepeatable;
36292            reducedJSONChildren = GuidePanel._super._getReducedJSON.call(this, isRepeatable);
36293            
36294            
36295            if (this.jsonModel.toolbar) {
36296                reducedJSONChildren["toolbar"] = this.toolbar._getReducedJSON();
36297            }
36298            return reducedJSONChildren;
36299        },
36300
36301        _getRole : function () {
36302            var guideRole, xfaRole, roleMap;
36303            
36304            roleMap = {
36305                "Table" : "grid",
36306                "Header Row" : "rowHeader",
36307                "Body Row" : "rowGroup",
36308                "Footer Row" : "rowGroup",
36309                "List" : "list"
36310            };
36311            if (this.bindNode) {
36312                xfaRole = this.getOrElse(this.bindNode.assist && this.bindNode.assist.role, null);
36313                if (xfaRole) {
36314                    guideRole = roleMap[xfaRole];
36315                }
36316            }
36317            return guideRole;
36318        },
36319        _getAssistPriority : function () {
36320            return (this.getAttribute("assistPriority") || "description");
36321        },
36322
36323        _getScreenReaderText : function () {
36324            var screenReaderText, assistPriority = this._getAssistPriority();
36325            if (assistPriority !== "description") {
36326                screenReaderText = GuidePanel._super._getScreenReaderText.apply(this);
36327            }
36328            return screenReaderText;
36329        },
36330
36331        execCompletion : function () {
36332            var complete = true;
36333            _.find(this.children, function (childModel) {
36334                
36335                if (childModel instanceof guidelib.model.GuidePanel && !childModel.execCompletion()) {
36336                    complete = false;
36337                    return true;    
36338                }
36339            }, this);
36340            if (complete && this.completionExp) {
36341                complete = this.executeExpression("completionExp");
36342            }
36343            return complete;
36344        },
36345
36346        _preserveLazyValue : function () {
36347            return !this._isXfaNode() && !(this instanceof guidelib.model.RootPanelNode)
36348                && (this.canBeRepeatable || this._guide().internal.liveDataUtils.isIndexedPath(this.bindRef));
36349        },
36350
36351        
36352        _syncModelAndData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateInstances, recurse) {
36353            var dataUtils = this._guide().internal.liveDataUtils;
36354            if (this._preserveLazyValue()) {
36355
36356                var dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar),
36357                    indexedXpath = dataContext.indexedXpath;
36358
36359                if (this.canBeRepeatable) {
36360                    
36361                    if (_.isFunction(updateInstances) && this.instanceIndex === 0) {
36362                        updateInstances(dataUtils.getDataInstances(dataContext, this._getDataNodeName()),
36363                            dataUtils.getParentDataNode(dataContext));
36364                    }
36365                    indexedXpath = dataUtils.addIndexToPath(indexedXpath, this.instanceIndex);
36366                }
36367
36368                
36369                if (dataContext.xmlSec === dataUtils.constants.UNBOUND_TAG) {
36370                    unBound_indexedXpathSoFar = indexedXpath;
36371                } else if (dataContext.xmlSec === dataUtils.constants.BOUND_TAG) {
36372                    bound_indexedXpathSoFar = indexedXpath;
36373                }
36374            }
36375
36376            if (_.isString(recurse)) {
36377                
36378                _.each(this.items, function (item) {
36379                    if (_.isFunction(item[recurse])) {
36380                        item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
36381                    }
36382                });
36383            }
36384
36385            return {
36386                'bound' : bound_indexedXpathSoFar,
36387                'unBound' : unBound_indexedXpathSoFar
36388            };
36389        },
36390
36391        _getDataNodeName : function () {
36392            var bindRef = this.bindRef,
36393                dataNodeName;
36394            if (bindRef) {
36395                dataNodeName = bindRef.substring(bindRef.lastIndexOf("/") + 1);
36396            } else {
36397                
36398                dataNodeName = this.getAttribute("name");
36399            }
36400            return dataNodeName;
36401        },
36402
36403        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
36404            var dataUtils = this._guide().internal.liveDataUtils,
36405                that = this;
36406
36407            function updateDataInstances(dataNodes, parentNode) {
36408                var count = that.instanceManager.instanceCount;
36409                if (dataNodes && (dataNodes.length > count)) {
36410                    
36411                    
36412                    for (var i = dataNodes.length -1; i >= count; --i) {
36413                        dataUtils.removeChild(parentNode, that._getDataNodeName(), i);
36414                    }
36415                }
36416            }
36417
36418            var contextSoFar = this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateDataInstances, '_updateLiveData');
36419        },
36420
36421        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
36422            var parentArgs = arguments,
36423                that = this;
36424
36425            function updateModelInstances(dataNodes, parentNode) {
36426                var _dataNodes = dataNodes;
36427                if (_dataNodes == null) {
36428                    _dataNodes = []; 
36429                }
36430                
36431                var i;
36432                if (_dataNodes && (_dataNodes.length < that.instanceManager.instanceCount)) {
36433                    
36434                    for (i = Math.max(_dataNodes.length, Math.abs(that.minOccur)); i < that.instanceManager.instanceCount; ++i) {
36435                        that.instanceManager.removeInstance(i);
36436                    }
36437                } else if (_dataNodes && (_dataNodes.length > that.instanceManager.instanceCount)) {
36438                    
36439                    var totalInstances = that.maxOccur < 0 ? _dataNodes.length : Math.min(_dataNodes.length, that.maxOccur);
36440                    for (i = that.instanceManager.instanceCount; i < totalInstances; ++i) {
36441                        var addedInstance = that.instanceManager.addInstance();
36442                        if (addedInstance) {
36443                            that._playLiveData.apply(addedInstance, parentArgs);
36444                        }
36445                    }
36446                }
36447            }
36448
36449            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateModelInstances, '_playLiveData');
36450        }
36451    });
36452
36453    GuidePanel.defineProps({
36454        
36455        completionExp : {
36456            get : function () {
36457                return this.getAttribute("completionExp");
36458            }
36459        },
36460
36461        completionExpReq : {
36462            get : function () {
36463                return this.getAttribute("completionExpReq");
36464            }
36465        },
36466
36467        
36468        minOccur : {
36469            get : function () {
36470                return this.getOrElse(this.jsonModel.minOccur, 1);
36471            }
36472        },
36473
36474        
36475        maxOccur : {
36476            get : function () {
36477                return this.getOrElse(this.jsonModel.maxOccur, 1);
36478            }
36479        },
36480        initialOccur : {
36481            get : function () {
36482                return this.getOrElse(this.jsonModel.initialOccur, 1);
36483            }
36484        },
36485        
36486        repeatable : {
36487            get : function () {
36488                return (this.minOccur != 1 || this.maxOccur != 1);
36489            }
36490        },
36491
36492        
36493        canBeRepeatable : {
36494            get : function () {
36495                return (this.maxOccur < 0 || this.maxOccur > 1);
36496            }
36497        },
36498        
36499        panel : {
36500            get : function () {
36501                return this;
36502            }
36503        },
36504        toolbar : {
36505            get : function () {
36506                this.getElement("guideToolbar");
36507            }
36508        },
36509        
36510        instanceManager : {
36511            get : function () {
36512                return this._instanceManager;
36513            }
36514        },
36515
36516        
36517        instanceIndex : {
36518            get : function () {
36519                var context = this._guide()._currentContext;
36520                if (context && context.managedExp) {
36521                    this._addDependant(context.contextNode, context.expression);
36522                }
36523                return this.instanceManager._instances.indexOf(this);
36524            }
36525        },
36526        
36527        title : {
36528            get : function () {
36529                return this.jsonModel["jcr:title"];
36530            },
36531            set : function (value) {
36532                var oldTitle = this.title;
36533                if (oldTitle !== value) {
36534                    this.jsonModel["jcr:title"] = value;
36535                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
36536                        guidelib.event.GuideModelEvent.createEvent(
36537                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
36538                            this,
36539                            "title",
36540                            oldTitle,
36541                            value
36542                        )
36543                    );
36544                }
36545            }
36546        },
36547        
36548        summary : {
36549            get : function () {
36550                return this._summary;
36551            },
36552            set : function (value) {
36553                var oldSummary = this._summary;
36554                if (oldSummary !== value) {
36555                    this._summary = value;
36556                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
36557                        guidelib.event.GuideModelEvent.createEvent(
36558                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
36559                            this,
36560                            "summary",
36561                            oldSummary,
36562                            this._summary
36563                        )
36564                    );
36565                }
36566            }
36567        },
36568        enableLayoutOptimization : {
36569            get : function () {
36570                return this.getOrElse(this.jsonModel, "layout.enableLayoutOptimization", false);
36571            }
36572        },
36573
36574        
36575        isNavigable : {
36576            get : function () {
36577                var isNonNavigable = this.getOrElse(this.jsonModel, "layout.nonNavigable", false);
36578                
36579                
36580                if (typeof isNonNavigable === 'string') {
36581                    return !(isNonNavigable === "true");
36582                } else {
36583                    return !isNonNavigable;
36584                }
36585            }
36586        },
36587        
36588        _hopsToRootPanel : {
36589            get : function () {
36590                return guidelib.util.GuideUtil._countHopsToRootPanel(this);
36591            }
36592
36593        },
36594        
36595        _ancestorRepeatable : {
36596            get : function () {
36597                var parentOrAncestor = this.parent;
36598                while (parentOrAncestor) {
36599                    if (parentOrAncestor && parentOrAncestor.repeatable) {
36600                        return true;
36601                    }
36602                    parentOrAncestor = parentOrAncestor.parent;
36603                }
36604
36605                return false;
36606            }
36607        },
36608
36609        
36610        enabled : {
36611            get : function () {
36612                return guidelib.model.Scriptable.prototype._getEnabled.call(this);
36613            },
36614
36615            set : function (value) {
36616                var oldValue = this.enabled;
36617                guidelib.model.Scriptable.prototype._setEnabled.call(this, value);
36618                if (this._parentAccess && value != oldValue) {
36619                    this._changeContainerAccess(value);
36620                }
36621            }
36622        },
36623
36624        
36625        _hasLazyDescendant : {
36626            get : function () {
36627                if (!_.isEmpty(guideBridge._guide.allLazyChildren)) {
36628                    return true;  
36629                }
36630                return false;
36631            }
36632        }
36633    });
36634
36635    
36636    GuidePanel.addMixins([
36637        guidelib.model.mixin.AddNavigationContext,
36638        guidelib.model.mixin.AddDependencyMgmt
36639    ]);
36640
36641})(_, guidelib);
36642
36643(function (_, guidelib) {
36644    var GuideTableRow = guidelib.model.GuideTableRow = guidelib.model.GuidePanel.extend({
36645        msClassName : "guideTableRow"
36646    });
36647}(_, guidelib));
36648(function (_, guidelib) {
36649
36650    
36651    var GuideTable = guidelib.model.GuideTable = guidelib.model.GuidePanel.extend({
36652        msClassName : "guideTable"
36653    });
36654
36655    GuideTable.defineProps({
36656        
36657        mobileLayout : {
36658            get : function () {
36659                return this.jsonModel.layout.mobileLayout;
36660            }
36661        },
36662
36663        columnWidth : {
36664            get : function () {
36665                return this.jsonModel.columnWidth;
36666            }
36667        }
36668    });
36669})(_, guidelib);
36670
36671(function (_, guidelib) {
36672    var RootPanelNode = guidelib.model.RootPanelNode = guidelib.model.GuidePanel.extend({
36673        msClassName : "rootPanelNode",
36674        
36675        _clearInactiveLazyViews : function (panelView) {
36676            _.each(this.childViews, function (item) {
36677                item._clearInactiveLazyViews(panelView);
36678            });
36679        }
36680
36681    });
36682    RootPanelNode.defineProps({
36683        toolbar : {
36684            get : function () {
36685                
36686                return this.getElement("guideToolbar") || this.parent.toolbar;
36687            }
36688        }
36689    });
36690})(_, guidelib);
36691(function ($, guidelib, _) {
36692    function negate(predicateFunc) {
36693        return function () {
36694            return !predicateFunc.apply(this, arguments);
36695        };
36696    }
36697
36698    function getPredicate(condition) {
36699        return condition instanceof Array
36700            ? Array.prototype.includes.bind(condition)
36701            : condition;
36702    }
36703
36704    var CommonUtils = {
36705        
36706        
36707        returnMinimalJSON : function (whitelistedProperties, reducedJsonObject, that) {
36708            if (!_.isObject(reducedJsonObject)) {
36709                reducedJsonObject = {};
36710            }
36711            _.each(whitelistedProperties, function (whitelistedProperty) {
36712                if (!_.isUndefined(that.jsonModel[whitelistedProperty])) {
36713                    reducedJsonObject[whitelistedProperty] = that.jsonModel[whitelistedProperty] ;
36714
36715                } else if (!_.isUndefined(that[whitelistedProperty])) {
36716                    reducedJsonObject[whitelistedProperty] = that[whitelistedProperty];
36717                }
36718            });
36719        },
36720
36721        createMap : function (list, value) {
36722            return _.mapObject(_.object(list, []), function () {
36723                return value;
36724            });
36725        },
36726
36727        updatedMapIfNot : function (map, condition, value) {
36728            return this._updateMap(map, negate(getPredicate(condition)), value);
36729        },
36730
36731        updateMap : function (map, condition, value) {
36732            return this._updateMap(map, getPredicate(condition), value);
36733        },
36734
36735        _updateMap : function (map, condition, value) {
36736            var newMap = {},
36737                prop;
36738            for (prop in map) {
36739                if (map.hasOwnProperty(prop)) {
36740                    newMap[prop] = condition(prop) ? value : map[prop];
36741                }
36742            }
36743            return newMap;
36744        },
36745
36746        _getScope : function (context) {
36747            var mergedScope = Object.assign(guidelib.runtime, context._guide().runtime);
36748            return mergedScope;
36749        }
36750    };
36751
36752    guidelib.model.util.CommonUtils = CommonUtils;
36753}($, guidelib, _));
36754(function (_, $, guidelib) {
36755    var getOrElse = xfalib.ut.XfaUtil.prototype.getOrElse,
36756        commonUtils = guidelib.model.util.CommonUtils,
36757        logger,
36758        constants = guidelib.model.GuideSchema.prototype.GuideStateConstants;
36759
36760    var initializeLogger = function () {
36761        var configString = window.AF_log_config === undefined ? "0-a9"
36762            : "1-" + window.AF_log_config;
36763
36764        xfalib.ut.XfaUtil.prototype.registerLocaleProperties(guidelib.i18n);
36765        if (window.formBridge) {
36766            window.formBridge.registerConfig("contextPath", window.guideBridge.userConfig["contextPath"]);
36767            window.formBridge.registerConfig("LoggerConfig", {
36768                "logConfigString" : configString,
36769                "categoryAcronyms" : {"d" : "AF"}
36770            });
36771        } else {
36772            xfalib.ut.XfaUtil.prototype.logger = new xfalib.ut.Logger({
36773                "jsonModel" : {
36774                    "logConfigString" : configString,
36775                    "categoryAcronyms" : {"d" : "AF"}
36776                }
36777            });
36778            logger = xfalib.ut.XfaUtil.prototype.logger;
36779        }
36780    };
36781
36782    var utils = {
36783        triggerEventOnWindow : function (eventPayload) {
36784            $(window).trigger(eventPayload);
36785        },
36786
36787        postExternalMessage : function (name) {
36788            window.guideBridge._postExternalMessage({name : name});
36789        }
36790    };
36791
36792    var viewOnlyUtils = {
36793        createView : function (guide, $element) {
36794            utils.postExternalMessage("_layoutstart");
36795
36796            var guideContainerView = new guidelib.view.GuideContainerView({
36797                element : $element,
36798                model : guide
36799            });
36800            
36801            
36802            window.guideBridge._setGuideView(guideContainerView);
36803            guidelib.util.GuideUtil.initializeHelp();
36804
36805            
36806            guidelib.util.AdUtil.applyDescriptionPlugin();
36807
36808            utils.postExternalMessage("_layoutend");
36809
36810            $(window).on("mousedown.guidebridge", function () {
36811                window.guideBridge.clickedOnWindow = true;
36812            });
36813        },
36814
36815        getLastFocusItem : function (guide) {
36816            var lastFocusItem;
36817            if (guide.runtime.guideContext) {
36818                lastFocusItem = guidelib.util.GuideUtil.fetchXMLNodeValue(guide.runtime.guideContext.guidePrefillXml, "lastFocusItem");
36819            }
36820            
36821            if (_.isUndefined(lastFocusItem)) {
36822                lastFocusItem = guidelib.util.GuideUtil._fetchJSONNodeValue(guide.runtime.guideContext.guidePrefillJson, "afSubmissionInfo.lastFocusItem");
36823            }
36824            
36825            if (_.isUndefined(lastFocusItem)) {
36826                lastFocusItem = window.guideBridge.customContextProperty("lastFocusItem");
36827            }
36828            return lastFocusItem;
36829        },
36830
36831        setFocus : function (item) {
36832            if (item) {
36833                window.guideBridge.setFocus(item);
36834            } else {
36835                window.guideBridge.setFocus();
36836            }
36837        },
36838
36839        preventCheckBoxMovementOnClick : function () {
36840            
36841            
36842            
36843
36844            if (xfalib.ut.XfaUtil.prototype.isSafari() && !xfalib.ut.TouchUtil.TOUCH_ENABLED) {
36845                $('#guideContainerForm').addClass('macSafariForm');
36846            }
36847        },
36848
36849        disableDefaultSubmit : function () {
36850            
36851            
36852            $("#guideContainerForm").submit(function (evnt) {
36853                evnt.preventDefault();
36854            });
36855        },
36856
36857        preventFormSubmitOnEnter : function () {
36858            
36859            
36860            $("#guideContainerForm input").keypress(function (evnt) {
36861                if (evnt.keyCode == 13 || evnt.charCode == 13 || evnt.which == 13) {
36862                    evnt.preventDefault();
36863                }
36864            });
36865        },
36866
36867        renderView : function (guide, $guideElement) {
36868            viewOnlyUtils.createView(guide, $guideElement);
36869
36870            var lastFocusItem = viewOnlyUtils.getLastFocusItem(guide);
36871            viewOnlyUtils.setFocus(lastFocusItem);
36872            utils.triggerEventOnWindow({type : "guideInitialized", guide : guide});
36873
36874            viewOnlyUtils.preventCheckBoxMovementOnClick();
36875            viewOnlyUtils.disableDefaultSubmit();
36876            viewOnlyUtils.preventFormSubmitOnEnter();
36877        }
36878
36879    };
36880
36881    
36882    guidelib.model._createXfaAndGuideModel = function (guideJson, xfaJson, options) {
36883        if (xfaJson) {
36884            xfalib.script.XfaModelRegistry.prototype.createModel(xfaJson);
36885            
36886            new xfalib.acrobat.Acrobat();
36887        }
36888        var guide = {};
36889        guide = guidelib.model.GuideModelRegistry.prototype.createModel(guideJson, options);
36890        
36891        guide._bindRefMap = {};
36892        return guide;
36893
36894    };
36895
36896    
36897    guidelib.model._getGuideJsonWithSyncXfaProps = function (guideJson, xfaJson) {
36898        
36899        var guide = guidelib.model._createXfaAndGuideModel(guideJson, xfaJson);
36900        
36901        guide.syncXFAProps();
36902
36903        
36904        return {
36905            "guidejson" : JSON.stringify(guideJson),
36906            "xfajson" : JSON.stringify(xfaJson)
36907        };
36908    };
36909
36910    guidelib.model._prepareGuide = function (prefillData, guide) {
36911        var liveDataUtils = guide.internal.liveDataUtils,
36912            liveModel = guide.internal.liveModel,
36913            _getFileAttachmentWrappers = function(prefillDataAttachments) {
36914                var fileAttachmentWrappers = [];
36915                try {
36916                    var atts = JSON.parse(prefillDataAttachments);
36917                    fileAttachmentWrappers = atts.map(function (x) {
36918                        return new guidelib.model.FileAttachmentWrapper(JSON.parse(x))
36919                    });
36920                } catch (e) {
36921                    if (e.stack) {
36922                        guide.logger().error(e.stack);
36923                    }
36924                }
36925                return fileAttachmentWrappers;
36926            };
36927        
36928        if (prefillData.isMergedJson && prefillData.data) {
36929            
36930            if (prefillData.data.guideState && prefillData.data.guideState.attachments) {
36931                prefillData.data["attachments"] = _getFileAttachmentWrappers(prefillData.data.guideState.attachments);
36932            }
36933            window.guideBridge.restoreGuideState(prefillData.data);
36934        } else if (prefillData.data) {
36935            guide.setGuideState(constants.GUIDE_STATE_MERGE_PROGRESS);
36936            liveDataUtils.initLiveData(prefillData.data,
36937                null,
36938                _.isString(guide.xdpRef),
36939                _.isString(guide.xsdRef),
36940                guide.getAttribute("xsdRootElement"),
36941                _getFileAttachmentWrappers(prefillData.attachments));
36942            liveDataUtils.playLiveData(guide.rootPanel);
36943            liveModel.prefillCrossFragFields(guide);
36944            guide.setGuideState(constants.GUIDE_STATE_MERGE_COMPLETE);
36945            guide.prepare();
36946        } else {
36947            guide.prepare();
36948            liveDataUtils.initLiveData(null, null,
36949                _.isString(guide.xdpRef), _.isString(guide.xsdRef),
36950                guide.getAttribute("xsdRootElement"));
36951        }
36952
36953        var fileAttachmentMap,
36954            obj = guideBridge.customContextProperty("fileAttachmentMap");
36955        if (!_.isUndefined(obj) && typeof(obj) === "string") {
36956            try {
36957                obj = JSON.parse(obj);
36958            } catch (e) {
36959                if (e.stack) {
36960                    guide.logger().error(e.stack);
36961                }
36962                obj = undefined;
36963            }
36964        }
36965        fileAttachmentMap = obj;
36966        
36967        var  i, node, fieldValue,
36968            fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
36969        
36970        
36971        if (!_.isUndefined(fileAttachmentMap)) {
36972            for (i = 0; i < fileAttachmentsList.length; i++) {
36973                node = fileAttachmentsList[i];
36974                fieldValue = fileAttachmentMap[node.somExpression];
36975                node.fileAttachment.value = fieldValue;
36976                if (!_.isEmpty(fieldValue)) {
36977                    node._fileList = fieldValue.split("\n");
36978                }
36979            }
36980        }
36981        guide.setGuideState(constants.GUIDE_STATE_MODEL_COMPLETE);
36982    };
36983
36984    guidelib.model.markDirtyPanels = function (lazyChildren, dataString, dirtyPanels, guide) {
36985        var lazyChildrenMap = commonUtils.createMap(lazyChildren, 0);
36986        
36987        if (!_.isEmpty(dataString)) { 
36988            if (dirtyPanels === null || dirtyPanels.length === 0) {
36989                dirtyPanels = guide.internal.liveDataUtils.getListOfDirtyPanels(dataString);
36990            }
36991            if (dirtyPanels && dirtyPanels.length > 0) {
36992                lazyChildrenMap = commonUtils.updatedMapIfNot(lazyChildrenMap, dirtyPanels, 1);
36993                guide.internal.GuideDirtyMarkerAndVisitor.visitMap = lazyChildrenMap;
36994            }
36995        } else {
36996            guide.internal.GuideDirtyMarkerAndVisitor.visitMap = lazyChildrenMap;
36997        }
36998    };
36999
37000    guidelib.model.initializeLiveDataUtils = function (schemaType) {
37001        var liveDataUtils = null;
37002        if (schemaType === "formdatamodel" || schemaType === "jsonschema") {
37003            liveDataUtils = new guidelib.model.LiveJsonUtils();
37004        } else {
37005            liveDataUtils = new guidelib.model.LiveXmlUtils();
37006        }
37007        return liveDataUtils;
37008    };
37009
37010    guidelib.model.prepareInput = function (guideJsonData) {
37011        return {
37012            guideJson : JSON.parse(guideJsonData.guidejson || "null"),
37013            guideContext : JSON.parse(guideJsonData.guidecontext || "null"),
37014            guidemergedjson : JSON.parse(guideJsonData.guidemergedjson || "null"),
37015            xfaJson : JSON.parse(guideJsonData.xfajson || "null"),
37016            xfaRenderContext : JSON.parse(guideJsonData.xfarendercontext || "null")
37017        };
37018    };
37019
37020    guidelib.model.mergeData = function (prefillData, guide, guideContext) {
37021        var rawData = prefillData.data,
37022            liveDataUtils = guide.internal.liveDataUtils,
37023            dirtyPanels = [],
37024            customPropertyMap = {},
37025            mergedXfaRenderContext = null;
37026
37027        guide.runtime.guideContext = guide.runtime.guideContext || {};
37028
37029        if (prefillData.isMergedJson) {
37030            if (typeof prefillData.data === "string") {
37031                try {
37032                    prefillData.data = JSON.parse(prefillData.data);
37033                } catch (e) {
37034                    prefillData.data = "";
37035                }
37036            }
37037            rawData = getOrElse(prefillData.data,
37038                "guideState.guideLiveData",
37039                getOrElse(rawData,
37040                    "guideState.guidePrefillXml",
37041                    getOrElse(prefillData.data,
37042                        "guideState.guidePrefillJson", undefined)));
37043
37044            var dirtyPanelsStr = getOrElse(prefillData.data,
37045                "guideState.guideContext.afSubmissionInfo.afDraft", "")
37046                .replace(/\"/g, "");
37047            
37048            if (dirtyPanelsStr) {
37049                dirtyPanels = dirtyPanelsStr.split(",");
37050            }
37051            customPropertyMap = getOrElse(prefillData.data,
37052                "guideState.guideContext.customPropertyMap",
37053                {});
37054
37055            var ccpMapViaNewPrefillService = getOrElse(prefillData.data, "guideState.customContext", null);
37056            var ccpMapViaOldImplementation = getOrElse(guidelib, "__runtime__.guideContext.customPropertyMap", {});
37057            var ccpMapViaOldAndNewImplementation = _.extend({}, ccpMapViaOldImplementation, getOrElse(guide, "runtime.guideContext.customPropertyMap", {}));
37058            if (!_.isEmpty(ccpMapViaNewPrefillService) && _.isEmpty(ccpMapViaOldAndNewImplementation)) {
37059                guideBridge.customContextProperty(ccpMapViaOldAndNewImplementation);
37060            }
37061
37062            var fileMapViaNewPrefillService = getOrElse(prefillData.data, "guideState.fileAttachmentMap", null);
37063            var fileMapViaOldImplementation = guideBridge.customContextProperty("fileAttachmentMap");
37064            if (!_.isEmpty(fileMapViaNewPrefillService) && _.isEmpty(fileMapViaOldImplementation)) {
37065                guideBridge.customContextProperty("fileAttachmentMap", fileMapViaNewPrefillService);
37066            }
37067        } else {
37068            guideBridge.customContextProperty("fileAttachmentMap", prefillData.fileAttachmentMap);
37069            guideBridge.customContextProperty("fileAttachmentWrappers", prefillData.fileAttachmentWrappers);
37070        }
37071
37072        if (guide.xdpRef) {
37073            mergedXfaRenderContext = getOrElse(prefillData.data, "guideState.xfaState.xfaRenderContext", null);
37074
37075            if (mergedXfaRenderContext != null) {
37076                
37077                xfalib.runtime.renderContext = JSON.parse(mergedXfaRenderContext);
37078            }
37079
37080            xfalib.runtime.xfa.form._initialize(true);
37081            $(window).trigger("XfaInitialized");
37082        }
37083
37084        if (rawData !== "") {
37085            if (guideContext.schemaType === "formdatamodel" || guideContext.schemaType === "jsonschema") {
37086                guideContext.guidePrefillJson = rawData;
37087            } else {
37088                guideContext.guidePrefillXml = rawData;
37089            }
37090        }
37091
37092        guideContext.customPropertyMap = $.extend({}, guideContext.customPropertyMap, customPropertyMap);
37093
37094        
37095        $.extend(true, guide.runtime.guideContext, guideContext);
37096
37097        guidelib.model.markDirtyPanels(guide.allLazyChildren, rawData, dirtyPanels, guide);
37098
37099        guidelib.model._prepareGuide(prefillData, guide);
37100
37101        
37102        
37103        if (guide.allLazyChildren.length > 0 && guideBridge.customContextProperty("fileAttachmentMap")) {
37104            var fileAttachmentMap = guideBridge.customContextProperty("fileAttachmentMap");
37105            if (typeof fileAttachmentMap === "string") {
37106                fileAttachmentMap = JSON.parse(fileAttachmentMap);
37107            }
37108            guide.internal.liveDataUtils._updateLazyAttachmentMap(fileAttachmentMap);
37109        }
37110    };
37111
37112    guidelib.model.fireOnContainerDomElementReady = function (guideJsonData, fetchData, $htmlElement, localContextCustomPropertyMap) {
37113        initializeLogger();
37114        var inputData = this.prepareInput(guideJsonData),
37115            guideJson = inputData.guideJson,
37116            guideContext = inputData.guideContext,
37117            guidemergedjson = inputData.guidemergedjson,
37118            xfaJson = inputData.xfaJson,
37119            xfaRenderContext = inputData.xfaRenderContext,
37120            localStorage,
37121            guide,
37122            dataPromise;
37123
37124        if (guideJson === null || guideContext == null) {
37125            console.error("Unable to load Form. Adaptive Form Json is invalid.");
37126            return;
37127        }
37128
37129        if (window.guideBridge !== undefined) {
37130            localStorage = window.guideBridge._getStorage();
37131        }
37132        try {
37133            
37134            localContextCustomPropertyMap = _.isObject(localContextCustomPropertyMap) ?
37135                JSON.stringify(localContextCustomPropertyMap) : localContextCustomPropertyMap;
37136            localContextCustomPropertyMap = JSON.parse(localContextCustomPropertyMap);
37137        } catch(e) {
37138            localContextCustomPropertyMap = {};
37139        }
37140
37141        if (fetchData && (guidemergedjson === null || guidemergedjson === "" || getOrElse(localStorage, "guideState", null) !== null)) {
37142            if (fetchData instanceof Function) {
37143                var result = fetchData();
37144                if (result.then instanceof Function) {
37145                    dataPromise = result;
37146                } else {
37147                    dataPromise = _.extend({}, {isMergedJson : false}, fetchData());
37148                }
37149            } else if ((!(window.FD && window.FD.isToggleEnabled("FT_FORMS-14840"))) ||
37150                ((guideJson.prefillService !== undefined && guideJson.prefillService !== "none") || (new URLSearchParams(window.location.search)).get("dataRef") !== null)) {
37151                var formContainerPath = getOrElse(window.guideBridge, "userConfig.submitConfig.aemFormComponentPath", guideContext.guidePath);
37152                var guideUrl = window.guideBridge._getGuidePathUrl(".af.prefilldata.json", formContainerPath);
37153                dataPromise = this.fetchData(guideUrl + window.location.search);
37154            } else {
37155                dataPromise = {data: "", isMergedJson: false};
37156            }
37157        } else {
37158            var _mergeData = guidemergedjson;
37159            if (getOrElse(localStorage, "guideState", null) !== null) {
37160                _mergeData = localStorage;
37161            }
37162            
37163            
37164            dataPromise = {
37165                data : _mergeData,
37166                isMergedJson : true
37167            };
37168        }
37169
37170        
37171        var liveDataUtils = this.initializeLiveDataUtils(guideContext.schemaType),
37172            liveModel = new guidelib.model.LiveModel();
37173
37174        if (window.guideBridge.hostName == "server") {
37175            
37176            if (!FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_BROWSERLESS_SUBMISSION)) {
37177                liveModel._disableFunctions();
37178                liveDataUtils._disableFunctions();
37179            }
37180
37181            _.each(_.functions(viewOnlyUtils), function (funcName) {
37182                viewOnlyUtils[funcName] = function () {};
37183            });
37184
37185            if (window.formBridge) {
37186                
37187                
37188                
37189                window.formBridge.ajaxCallMode = "server";
37190            }
37191        }
37192
37193        liveModel.createDataNodes(guideJson.repeatBindRef);
37194        var allLazyChildren = getOrElse(guideJson, "allLazyChildren", []);
37195        
37196        var options = {};
37197        options = _.extend({}, options, {"liveModel" : liveModel, "liveDataUtils" : liveDataUtils});
37198
37199        utils.postExternalMessage("_formdomstart");
37200        try {
37201            guide = guidelib.model._createXfaAndGuideModel(guideJson, xfaJson, options);
37202            
37203            guide.runtime.guideContext.customPropertyMap = _.extend({}, guide.runtime.guideContext.customPropertyMap, localContextCustomPropertyMap);
37204            if (allLazyChildren.length > 0) {
37205                liveModel.createCrossFragFields(guideJson.guideGlobalLazyField, guide);
37206            }
37207            guide.version = new guidelib.util.Version({
37208                scriptingBehaviourVersion: guideContext.scriptingBehaviourVersion
37209            });
37210            guide.setGuideState(constants.GUIDE_STATE_MODEL_CREATED);
37211            if (xfaJson && xfaRenderContext) {
37212                xfalib.runtime.renderContext = xfaRenderContext;
37213            }
37214            utils.triggerEventOnWindow({type: "guideModelInitialized", guide: guide});
37215        } catch (e) {
37216            
37217            if (e.stack) {
37218                console.error(e.stack);
37219            }
37220        }
37221
37222        var $guideElement = $htmlElement || $("div.guideContainerWrapperNode");
37223
37224        if (dataPromise.then instanceof Function) {
37225            return dataPromise.then(function (result) {
37226                guidelib.model.mergeData(result, guide, guideContext);
37227                viewOnlyUtils.renderView(guide, $guideElement);
37228            });
37229        } else {
37230            
37231            guidelib.model.mergeData(dataPromise, guide, guideContext);
37232            viewOnlyUtils.renderView(guide, $guideElement);
37233            return guide;
37234        }
37235    };
37236
37237    guidelib.model.fetchData = function (path) {
37238        var deferred = $.Deferred();
37239        if (window.guideBridge.hostName === "server") { 
37240            deferred.resolve({
37241                data : "",
37242                isMergedJson : false
37243            });
37244        } else {
37245            $.ajax({
37246                url : path,
37247                type : 'POST',
37248                dataType : 'json'
37249            }).done(function (data) {
37250                var obj = _.extend({}, data, {isMergedJson : false});
37251                deferred.resolve(obj);
37252            }).fail(function (obj, textStatus, errorThrown) {
37253                console.error(textStatus + " " + errorThrown);
37254                deferred.resolve({
37255                    data : "",
37256                    isMergedJson : false
37257                });
37258            });
37259        }
37260        return deferred.promise();
37261    };
37262})(_, $, window.guidelib);
37263
37264/*************************************************************************
37265 *
37266 * ADOBE CONFIDENTIAL
37267 * __________________
37268 *
37269 *  Copyright 2014 Adobe Systems Incorporated
37270 *  All Rights Reserved.
37271 *
37272 * NOTICE:  All information contained herein is, and remains
37273 * the property of Adobe Systems Incorporated and its suppliers,
37274 * if any.  The intellectual and technical concepts contained
37275 * herein are proprietary to Adobe Systems Incorporated and its
37276 * suppliers and may be covered by U.S. and Foreign Patents,
37277 * patents in process, and are protected by trade secret or copyright law.
37278 * Dissemination of this information or reproduction of this material
37279 * is strictly forbidden unless prior written permission is obtained
37280 * from Adobe Systems Incorporated.
37281 **************************************************************************/
37282
37283/**
37284 * Created with IntelliJ IDEA.
37285 * User: rismehta
37286 * Date: 1/15/14
37287 * Time: 5:49 PM
37288 * To change this template use File | Settings | File Templates.
37289 */
37290
37291/*anonymous function to handle show of file list view */
37292(function ($, guidelib) {
37293
37294    // Was causing problem in IE9
37295    // hence have added timeout to ensure that once button is rendered, event handler is registered
37296    // todo: may have to think of better namespace ?
37297    guidelib.intervals = guidelib.intervals || {};
37298    guidelib.intervals.intId = setInterval(function () {
37299        var fileAttachmentListingBtn = $("div.fileattachmentlisting button[data-guide-fileListing]");
37300        if (fileAttachmentListingBtn.length > 0) {
37301            clearInterval(guidelib.intervals.intId);
37302            var self;
37303            fileAttachmentListingBtn.click(function () {
37304                self = $(this);
37305                // added because in mobile devices it was causing problem of backdrop
37306                $("#fileAttachment").addClass("fileAttachmentDialog");
37307                $("#fileAttachment").appendTo('body');
37308                $("#fileAttachment").modal("show");
37309            });
37310
37311            // bring focus back to file attachment listing button on dialog hide
37312            $(".fileAttachmentDialog").on('hidden.bs.modal', function (e) {
37313                $(this).removeClass("fileAttachmentDialog");
37314                self.focus();
37315            });
37316        }
37317    }, 1000);
37318}($, guidelib));
37319
37320/*************************************************************************
37321 *
37322 * ADOBE CONFIDENTIAL
37323 * __________________
37324 *
37325 *  Copyright 2014 Adobe Systems Incorporated
37326 *  All Rights Reserved.
37327 *
37328 * NOTICE:  All information contained herein is, and remains
37329 * the property of Adobe Systems Incorporated and its suppliers,
37330 * if any.  The intellectual and technical concepts contained
37331 * herein are proprietary to Adobe Systems Incorporated and its
37332 * suppliers and may be covered by U.S. and Foreign Patents,
37333 * patents in process, and are protected by trade secret or copyright law.
37334 * Dissemination of this information or reproduction of this material
37335 * is strictly forbidden unless prior written permission is obtained
37336 * from Adobe Systems Incorporated.
37337 **************************************************************************/
37338
37339(function ($) {
37340
37341    // GUIDE ADD REMOVE CLASS DEFINITION
37342    // ====================
37343
37344    var GuideAddRemove = function (element) {
37345        this.element = $(element);
37346    };
37347
37348    GuideAddRemove.prototype.add = function () {
37349        $this = this.element;
37350        var id = $this.attr("data-guide-id"),
37351            nextPanel;
37352
37353        if (id) {
37354            if (window.guideBridge) {
37355                var guidePanel = window.guideBridge._resolveId(id);
37356                if (guidePanel) {
37357                    nextPanel = guidePanel.instanceManager.insertInstance(guidePanel.instanceIndex + 1);
37358                    if (nextPanel) {
37359                        window.guideBridge.setFocus(nextPanel.somExpression, "firstItem");
37360                    }
37361                }
37362            } else {
37363                console.log("could not add new instance" + id);
37364            }
37365        }
37366    };
37367
37368    GuideAddRemove.prototype.remove = function () {
37369        $this = this.element;
37370        var id       = $this.attr("data-guide-id");
37371
37372        if (id) {
37373            if (window.guideBridge) {
37374                var guidePanel = window.guideBridge._resolveId(id);
37375                if (guidePanel) {
37376                    guidePanel.instanceManager.removeInstance(guidePanel.instanceIndex);
37377                }
37378            } else {
37379                console.log("could not remove instance");
37380            }
37381        }
37382    };
37383
37384    // GUIDE ADD REMOVE PLUGIN DEFINITION
37385    // =====================
37386
37387    var old = $.fn.guideAddRemove;
37388
37389    $.fn.guideAddRemove = function (option) {
37390        return this.each(function () {
37391            var $this = $(this);
37392            var data  = $this.data('guideAddRemove');
37393
37394            if (!data) {
37395                $this.data('guideAddRemove', (data = new GuideAddRemove(this)));
37396            }
37397            if (typeof option == 'string') {
37398                data[option]();
37399            }
37400        });
37401    };
37402
37403    $.fn.guideAddRemove.Constructor = GuideAddRemove();
37404
37405    // ADD REMOVE NO CONFLICT
37406    // ===============
37407
37408    $.fn.guideAddRemove.noConflict = function () {
37409        $.fn.guideAddRemove = old;
37410        return this;
37411    };
37412
37413    // ADD REMOVE DATA-API
37414    // ============
37415
37416    $(document).on('click.guideAddRemove.data-api keypress.guideAddRemove.data-api', '[data-guide-addremove="add"]', function (e) {
37417        if (e.type == "keypress" && !guidelib.util.GuideUtil.isEnterKeyPressed(e)) {
37418            return;
37419        }
37420        e.preventDefault();
37421        //This is required for setting the focus on the new panel. Otherwise the focus remains on the previous panel.
37422        e.stopImmediatePropagation();
37423        $(this).guideAddRemove('add');
37424    }).on('click.guideAddRemove.data-api keypress.guideAddRemove.data-api', '[data-guide-addremove="remove"]', function (e) {
37425            if (e.type == "keypress" && !guidelib.util.GuideUtil.isEnterKeyPressed(e)) {
37426                return;
37427            }
37428            e.preventDefault();
37429            $(this).guideAddRemove('remove');
37430        });
37431
37432}($));
37433
37434/*************************************************************************
37435 *
37436 * ADOBE CONFIDENTIAL
37437 * __________________
37438 *
37439 *  Copyright <year> Adobe Systems Incorporated
37440 *  All Rights Reserved.
37441 *
37442 * NOTICE:  All information contained herein is, and remains
37443 * the property of Adobe Systems Incorporated and its suppliers,
37444 * if any.  The intellectual and technical concepts contained
37445 * herein are proprietary to Adobe Systems Incorporated and its
37446 * suppliers and may be covered by U.S. and Foreign Patents,
37447 * patents in process, and are protected by trade secret or copyright law.
37448 * Dissemination of this information or reproduction of this material
37449 * is strictly forbidden unless prior written permission is obtained
37450 * from Adobe Systems Incorporated.
37451 **************************************************************************/
37452
37453(function ($) {
37454
37455    // TABLE LAYOUT PLUGIN
37456    // ============
37457
37458    $(document).on('panelRemoved.af', '.guideTableNode', function (e, $childRemoved, index) {
37459        // this plugin is specific to a layout
37460        // one can also check the layout based on CSS class set and perform things accordingly
37461        // prevent the bubbling up of the event
37462        e.stopPropagation();
37463        // this would work only in runtime
37464        var $bodyRows = $(e.target).find("tr.guideTableRowNode:not(.guideTableHeader)");
37465        // Set focus to first child
37466        if (index > 1) {
37467            // set focus on prev row since index is greater than 1
37468            var $prevRow = $bodyRows.eq(index - 1);
37469            guidelib.util.GuideUtil.setFocusOnFirstItemOfTableRow($prevRow);
37470        } else if (index == 1) {
37471            var $nextRow = $bodyRows.eq(1);
37472            // may there is only one row which has got deleted, hence check if next row actually exists
37473            if ($nextRow.length > 0) {
37474                guidelib.util.GuideUtil.setFocusOnFirstItemOfTableRow($nextRow);
37475            }
37476        }
37477    });
37478
37479}($));
37480
37481/*************************************************************************
37482 *
37483 * ADOBE CONFIDENTIAL
37484 * __________________
37485 *
37486 *  Copyright 2014 Adobe Systems Incorporated
37487 *  All Rights Reserved.
37488 *
37489 * NOTICE:  All information contained herein is, and remains
37490 * the property of Adobe Systems Incorporated and its suppliers,
37491 * if any.  The intellectual and technical concepts contained
37492 * herein are proprietary to Adobe Systems Incorporated and its
37493 * suppliers and may be covered by U.S. and Foreign Patents,
37494 * patents in process, and are protected by trade secret or copyright law.
37495 * Dissemination of this information or reproduction of this material
37496 * is strictly forbidden unless prior written permission is obtained
37497 * from Adobe Systems Incorporated.
37498 **************************************************************************/
37499
37500/*handle click of default next and previous navigator*/
37501$(function ($) {
37502    var getPanelSom = function (panelId) {
37503            var panel = window.guideBridge._resolveId(panelId);
37504            if (panel === undefined || panel === null) {
37505                return "";
37506            }
37507            return panel.somExpression;
37508        },
37509        pointerup_evnt = xfalib.ut.TouchUtil.POINTER_UP;
37510
37511    if (pointerup_evnt === "touchend") {
37512        // touchend happens before blur, hence the value of the current
37513        // focused field is not committed and setFocus API receives the old
37514        // value. So as a hack we are using mouseup instead of touchend to
37515        // make sure that the value gets committed
37516        pointerup_evnt = "mouseup";
37517    }
37518    $('body').on(pointerup_evnt + " keydown", '[data-guide-wizard-nav]', function (e) {
37519        var triggerKeyEvent = false;
37520        //  check for event type and key press space/enter
37521        if (e.type === "keydown" && (e.keyCode === 32 || e.keyCode === 13)) {
37522            e.preventDefault();
37523            triggerKeyEvent =  true; // set to trigger key event
37524        }
37525
37526        //  when event is pointerup(click) or space/enter key is pressed, trigger navigation
37527        if (e.type === "pointerup" || triggerKeyEvent) {
37528            var $this = $(this),
37529                options = $this.data("guide-wizard-nav");
37530            if (_.isObject(options)) { //case of all the options, get som expression out of id
37531                options.somExpression = getPanelSom(options.panelId);
37532            } else { //case where its value of somId
37533                var somExpr = getPanelSom(options),
37534                    navType = $(this).data("guide-wizard-nav-type");
37535                options = {
37536                    somExpression: somExpr,
37537                    focusOption: navType,
37538                    runCompletionScript: true
37539                };
37540            }
37541            window.guideBridge.setFocus(options);
37542        }
37543    });
37544
37545    window.guideBridge.on("elementNavigationChanged",
37546        function (evntName, evnt) {
37547            var activePanelSom = evnt.newText,
37548                activePanel = window.guideBridge._guideView.getView(activePanelSom),
37549                scrollDirection,
37550                scrollStep,
37551                scrollPos,
37552                list,
37553                $listElements;
37554            if (activePanel instanceof guidelib.view.GuidePanelView) {
37555                $listElements = activePanel.parentView.$element.find('[id*="' + guidelib.util.GuideUtil.GUIDE_ITEM_NAV_CONTAINER_SUFFIX + '"]');
37556                if (!_.isUndefined($listElements) && !_.isNull($listElements) && $listElements.length > 0) {
37557                    list = $listElements.eq(0);
37558                    if (_.isUndefined(list.attr("data-guide-nav-scroll-pos"))) {
37559                        list.attr("data-guide-nav-scroll-pos", 0);
37560                    }
37561                    scrollPos = parseInt(list.attr("data-guide-nav-scroll-pos"), 10);
37562                    //Find index among the visible panels
37563                    var parentChildViews = activePanel.parentView.childViews,
37564                        iterator,
37565                        navPos = 0;
37566                    for (iterator = 0; iterator < parentChildViews.length; iterator++) {
37567                        if (activePanel === parentChildViews[iterator]) {
37568                            break;
37569                        }
37570                        if (parentChildViews[iterator]._model.visible) {
37571                            navPos = navPos + 1;
37572                        }
37573                    }
37574                    if (navPos > scrollPos) {
37575                        scrollDirection = "right";
37576                    } else {
37577                        scrollDirection = "left";
37578                    }
37579                    scrollStep = Math.abs(navPos - scrollPos);
37580                    guidelib.util.GuideUtil.navScroll(list, scrollDirection, scrollStep, '[id*="' + guidelib.util.GuideUtil.GUIDE_ITEM_
37580NAV_SUFFIX + '"]:not(.hidden)');
37581                }
37582            }
37583        });
37584});
37585
37586/*************************************************************************
37587 *
37588 * ADOBE CONFIDENTIAL
37589 * __________________
37590 *
37591 *  Copyright 2014 Adobe Systems Incorporated
37592 *  All Rights Reserved.
37593 *
37594 * NOTICE:  All information contained herein is, and remains
37595 * the property of Adobe Systems Incorporated and its suppliers,
37596 * if any.  The intellectual and technical concepts contained
37597 * herein are proprietary to Adobe Systems Incorporated and its
37598 * suppliers and may be covered by U.S. and Foreign Patents,
37599 * patents in process, and are protected by trade secret or copyright law.
37600 * Dissemination of this information or reproduction of this material
37601 * is strictly forbidden unless prior written permission is obtained
37602 * from Adobe Systems Incorporated.
37603 **************************************************************************/
37604
37605$(function ($) {
37606
37607    /* handle swipe*/
37608    var setSwipeGestureState = function () {
37609        var swipeEnabled = !window.guideBridge._guide.getAttribute("disableSwipeGesture");
37610        window.guideBridge.enableSwipeGesture(swipeEnabled, swipeEnabled);
37611    };
37612    window.guideBridge.connect(setSwipeGestureState, this);
37613
37614    /*show scroll indication on mobile devices*/
37615    var scrollIndicator = function () {
37616        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
37617            $('[data-guide-scroll-indicator]').removeClass('mobileScrollIndicator');
37618        } else if ($(window).scrollTop() < $(document).height() - $(window).height()) {
37619            $('[data-guide-scroll-indicator]').addClass('mobileScrollIndicator');
37620        }
37621    };
37622
37623    //this should be changed back to $(document).ready(scrollIndicator) instead of windows onload,
37624    //once jquery version is bumped
37625    $(window).on('load scroll resize', scrollIndicator);
37626    window.guideBridge.on('elementNavigationChanged', scrollIndicator);
37627});
37628
37629/*************************************************************************
37630 *
37631 * ADOBE CONFIDENTIAL
37632 * __________________
37633 *
37634 *  Copyright 2014 Adobe Systems Incorporated
37635 *  All Rights Reserved.
37636 *
37637 * NOTICE:  All information contained herein is, and remains
37638 * the property of Adobe Systems Incorporated and its suppliers,
37639 * if any.  The intellectual and technical concepts contained
37640 * herein are proprietary to Adobe Systems Incorporated and its
37641 * suppliers and may be covered by U.S. and Foreign Patents,
37642 * patents in process, and are protected by trade secret or copyright law.
37643 * Dissemination of this information or reproduction of this material
37644 * is strictly forbidden unless prior written permission is obtained
37645 * from Adobe Systems Incorporated.
37646 **************************************************************************/
37647/*anonymous function to handle click of default next and previous navigator*/
37648(function ($) {
37649    window.guideBridge.on("elementNavigationChanged",
37650        function (evntName, evnt) {
37651            var activePanelSom = evnt.newText,
37652                activePanel = window.guideBridge.resolveNode(activePanelSom);
37653            if (activePanel) {
37654                var dynamicContentSelector = "[data-target-guide-content]",
37655                    text = $(dynamicContentSelector).text();
37656                // if there is an active panel already set and active panel is not an instance of root panel node
37657                // only then set the active panel title to the content
37658                if (text != null && text.length > 0 && (!(activePanel instanceof guidelib.model.RootPanelNode))) {
37659                    $(dynamicContentSelector).text(activePanel.title ? activePanel.title : "");
37660                }
37661            }
37662        });
37663}($));
37664
37665/*************************************************************************
37666 *
37667 * ADOBE CONFIDENTIAL
37668 * __________________
37669 *
37670 *  Copyright 2015 Adobe Systems Incorporated
37671 *  All Rights Reserved.
37672 *
37673 * NOTICE:  All information contained herein is, and remains
37674 * the property of Adobe Systems Incorporated and its suppliers,
37675 * if any.  The intellectual and technical concepts contained
37676 * herein are proprietary to Adobe Systems Incorporated and its
37677 * suppliers and may be covered by U.S. and Foreign Patents,
37678 * patents in process, and are protected by trade secret or copyright law.
37679 * Dissemination of this information or reproduction of this material
37680 * is strictly forbidden unless prior written permission is obtained
37681 * from Adobe Systems Incorporated.
37682 **************************************************************************/
37683
37684/*handle click of default next and previous navigator for PDC*/
37685$(function ($) {
37686    window.guideBridge.connect(function () {
37687        //this function will be called after adaptive form is initialized
37688        var progressive = window.guideBridge.progressive;
37689        if (progressive) {
37690            /**
37691             * Add listener to navigate across section for custom layout
37692             */
37693            $(document).on('click', 'button[data-guide-progressive-nav]', $.proxy(progressive.navigateSection, progressive));
37694        }
37695    });
37696
37697});
37698
37699// jscs:disable requireDotNotation
37700/*
37701 * ***********************************************************************
37702 * ADOBE CONFIDENTIAL
37703 * __________________
37704 *
37705 * Copyright 2015 Adobe Systems Incorporated
37706 * All Rights Reserved.
37707 *
37708 * NOTICE:  All information contained herein is, and remains
37709 * the property of Adobe Systems Incorporated and its suppliers,
37710 * if any.  The intellectual and technical concepts contained
37711 * herein are proprietary to Adobe Systems Incorporated and its
37712 * suppliers and may be covered by U.S. and Foreign Patents,
37713 * patents in process, and are protected by trade secret or copyright law.
37714 * Dissemination of this information or reproduction of this material
37715 * is strictly forbidden unless prior written permission is obtained
37716 * from Adobe Systems Incorporated.
37717 * ***********************************************************************
37718 */
37719
37720(function ($, guidelib, _) {
37721    var GuideUtil = guidelib.util.GuideUtil,
37722        CHART_TYPE = GuideUtil.chartType,
37723
37724        ChartUtils = guidelib.chartUtils = {
37725
37726            reducerOptions : window.chartReducer.reducerOptions,
37727
37728            /**
37729             * Returns the display format of axis data
37730             * @param dataType {string} representing data type of axis
37731             * @returns {string}
37732             */
37733            getDisplayFormat : function (dataType) {
37734                var displayFormat = "";
37735                if (dataType === 'date' || dataType === 'date-time') {
37736                    displayFormat = 'date{' + guidelib.i18n.datePatterns.med + '}';
37737                }
37738                return displayFormat;
37739            },
37740
37741            /**
37742             * Reads chart model for chart configuration and computes the data for chart
37743             * @param chartModel
37744             * @returns {{}}
37745             */
37746            gatherAxisData : function (chartModel) {
37747                var categoryExp,
37748                    valueExp,
37749                    reducerFunction,
37750                    repeatableInstances,
37751                    repeatableItem,
37752                    seriesRepeatableItem,
37753                    series,
37754                    relativeSeriesNameExp,
37755                    currentSeries,
37756                    repeatablePath,
37757                    seriesLength = 0,
37758                    seriesRepeatableInstances,
37759                    relativeSeriesRefExp,
37760                    data = new Map(),
37761                    chartBuildOptions = {},
37762                    isWebChannelChart = chartModel.jsonModel["sling:resourceType"] === 'fd/ccm/web-channel/components/chart/v1/chart',
37763                    dataToFill = {};
37764                chartBuildOptions.isFDMDataSource = chartModel.dataSourceType === "fdm" ? true : false;
37765                chartBuildOptions.chartModel = chartModel;
37766                dataToFill.valueDisplayFormat = "";
37767                dataToFill.labelDisplayFormat = "";
37768                dataToFill.categoryDataType = "";
37769                dataToFill.valueDataType = "";
37770
37771                repeatableItem = chartModel.getOrElse(chartModel._guide().runtime, chartModel.repeatableItem, undefined);
37772
37773                //Do not support reducer functions on x-axis for Web channel charts
37774                if (chartModel.reducerXFunction && chartModel.reducerXFunction !== 'none' && !isWebChannelChart) {
37775                    chartBuildOptions.categoryExp = chartModel.yExp;
37776                    chartBuildOptions.valueExp = chartModel.xExp;
37777                    chartBuildOptions.reducerFunction = chartModel.reducerXFunction;
37778                    dataToFill = ChartUtils._setProp(dataToFill, "categoryDataType", chartModel.jsonModel.yDataType);
37779                    dataToFill = ChartUtils._setProp(dataToFill, "valueDataType", chartModel.jsonModel.xDataType);
37780                } else {
37781                    chartBuildOptions.categoryExp = chartModel.xExp;
37782                    chartBuildOptions.valueExp = chartModel.yExp;
37783                    dataToFill = ChartUtils._setProp(dataToFill, "categoryDataType", chartModel.jsonModel.yDataType);
37784                    dataToFill = ChartUtils._setProp(dataToFill, "valueDataType", chartModel.jsonModel.xDataType);
37785                    if (chartModel.reducerYFunction && chartModel.reducerYFunction !== 'none') {
37786                        chartBuildOptions.reducerFunction = chartModel.reducerYFunction;
37787                    }
37788                }
37789
37790                if (chartBuildOptions.isFDMDataSource) {
37791                    dataToFill.valueDisplayFormat = ChartUtils.getDisplayFormat(dataToFill.valueDataType);
37792                    dataToFill.labelDisplayFormat = ChartUtils.getDisplayFormat(dataToFill.categoryDataType);
37793                    repeatableItem = chartModel.repeatableItem;
37794                    chartBuildOptions.categoryExp = chartBuildOptions.categoryExp.substring(repeatableItem.length + 1, chartBuildOptions.categoryExp.length).split("/");
37795                    chartBuildOptions.valueExp = chartBuildOptions.valueExp.substring(repeatableItem.length + 1, chartBuildOptions.valueExp.length).split("/");
37796                    if (isWebChannelChart) {
37797                        dataToFill.series = series = [];
37798                        if (chartModel.jsonModel.chartType === 'quadrant') {
37799                            chartBuildOptions.isXYReferencePointSet = false;
37800                            if (chartModel.jsonModel.referencePointType === 'staticReferencePoint') {
37801                                if (chartModel.jsonModel.xDataType === 'date' || chartModel.jsonModel.xDataType === 'date-time') {
37802                                    //Whenx-axis is of Date type we need to compute reference value in milliseconds.
37803                                    chartModel.jsonModel.xAxisReferencePoint = new Date(chartModel.jsonModel.xAxisReferencePoint).getTime();
37804                                }
37805                                chartBuildOptions.isXYReferencePointSet = true;
37806                            }
37807                        }
37808                    }
37809                    if ("true" == chartModel.jsonModel.multiSeries) {
37810                        seriesRepeatableItem = chartModel.jsonModel.seriesRepeatableItem;
37811                        relativeSeriesNameExp = chartModel.jsonModel.seriesName.substring(seriesRepeatableItem.length + 1, chartModel.jsonModel.seriesName.length);
37812                        seriesRepeatableInstances = this._getRepeatableInstances(seriesRepeatableItem, null, chartModel);
37813                        seriesLength = seriesRepeatableInstances ? seriesRepeatableInstances.length : seriesLength;
37814                        repeatablePath = repeatableItem.substring(seriesRepeatableItem.length, repeatableItem.length);
37815                        if (chartModel.jsonModel.chartType === 'quadrant' && chartModel.jsonModel.referencePointType === 'fdmReferencePoint') {
37816                            relativeSeriesRefExp = chartModel.jsonModel.seriesReferenceExp.substring(seriesRepeatableItem.length + 1, chartModel.jsonModel.seriesReferenceExp.length);
37817                        }
37818                        for (var i = 0; i < seriesLength; i++) {
37819                            chartBuildOptions.repeatableInstances = this._getRepeatableInstances(repeatablePath, seriesRepeatableInstances[i], chartModel);
37820                            chartBuildOptions.repeatableItemForReferencePoint;
37821                            if (relativeSeriesRefExp && !chartBuildOptions.isXYReferencePointSet) {
37822                                chartBuildOptions.repeatableItemForReferencePoint = undefined;
37823                                if (this.matchUserInputWithFDM(chartModel.jsonModel.seriesReferenceDataType, seriesRepeatableInstances[i][relativeSeriesRefExp], chartModel.jsonModel.seriesReferenceValue)) {
37824                                    chartBuildOptions.repeatableItemForReferencePoint = repeatableItem;
37825                                }
37826                            }
37827                            currentSeries = this.buildChartData(chartBuildOptions);
37828                            currentSeries.name = seriesRepeatableInstances[i][relativeSeriesNameExp];
37829                            series.push(currentSeries);
37830                        }
37831                    } else {
37832                        chartBuildOptions.repeatableInstances = this._getRepeatableInstances(repeatableItem, null, chartModel);
37833                        chartBuildOptions.repeatableItemForReferencePoint = repeatableItem;
37834                        currentSeries = this.buildChartData(chartBuildOptions);
37835                        series.push(currentSeries);
37836                    }
37837                    if (isWebChannelChart && chartModel.jsonModel.chartType === 'quadrant' && chartModel.jsonModel.referencePointType === 'fdmReferencePoint' && !chartBuildOptions.isXYReferencePointSet) {
37838                        chartModel.jsonModel.xAxisReferencePoint = undefined;
37839                        chartModel.jsonModel.yAxisReferencePoint = undefined;
37840                    }
37841                    chartBuildOptions.repeatableInstances = null;
37842                } else if (repeatableItem) {
37843                    chartBuildOptions.repeatableInstances = repeatableItem.instanceManager.instances;
37844                }
37845                if (chartBuildOptions.repeatableInstances) {
37846                    var chartData = this.buildChartData(chartBuildOptions);
37847                    dataToFill.label = chartData.label;
37848                    dataToFill.value = chartData.value;
37849                }
37850                return dataToFill;
37851            },
37852
37853            buildChartData : function (chartBuildOptions) {
37854                var dataToFill = {},
37855                    data = new Map(),
37856                    referencePointExp,
37857                    isFDMReferencePointSet = false;
37858                dataToFill.value = [];
37859                dataToFill.label = [];
37860
37861                if (chartBuildOptions.chartModel.jsonModel.chartType === 'quadrant' && chartBuildOptions.chartModel.jsonModel.referencePointType === 'fdmReferencePoint' && chartBuildOptions.repeatableItemForReferencePoint) {
37862                    referencePointExp = chartBuildOptions.chartModel.jsonModel.xyReferencePointExp.substring(chartBuildOptions.repeatableItemForReferencePoint.length + 1, chartBuildOptions.chartModel.jsonModel.xyReferencePointExp.length).split("/");
37863                }
37864                var that = this;
37865                _.each(chartBuildOptions.repeatableInstances, function (repeatableInstance, index) {
37866                    var categoryPropVal,
37867                        valuePropVal,
37868                        xyReferenceVal;
37869                    if (chartBuildOptions.isFDMDataSource) {
37870                        if (_.isArray(chartBuildOptions.categoryExp) && _.isArray(chartBuildOptions.valueExp)) {
37871                            //Handling composite key case.
37872                            var temp = repeatableInstance;
37873                            _.each(chartBuildOptions.categoryExp, function (obj) {
37874                                temp = temp[obj];
37875                            });
37876                            categoryPropVal = temp;
37877
37878                            temp = repeatableInstance;
37879                            _.each(chartBuildOptions.valueExp, function (obj) {
37880                                temp = temp[obj];
37881                            });
37882                            valuePropVal = temp;
37883
37884                            if (chartBuildOptions.chartModel.jsonModel.chartType === 'quadrant' && !chartBuildOptions.isXYReferencePointSet) {
37885                                if (chartBuildOptions.repeatableItemForReferencePoint && chartBuildOptions.chartModel.jsonModel.referencePointType === 'fdmReferencePoint') {
37886                                    temp = repeatableInstance;
37887                                    _.each(referencePointExp, function (obj) {
37888                                        temp = temp[obj];
37889                                    });
37890                                    xyReferenceVal = temp;
37891                                    if (that.matchUserInputWithFDM(chartBuildOptions.chartModel.jsonModel.xyReferencePointDataType, xyReferenceVal, chartBuildOptions.chartModel.jsonModel.xyReferencePointValue)) {
37892                                        //For date type x-axis FDM value we need to get time in milliseconds to send to Highcharts
37893                                        chartBuildOptions.chartModel.jsonModel.xAxisReferencePoint = (chartBuildOptions.chartModel.jsonModel.xDataType === 'date' || chartBuildOptions.chartModel.jsonModel.xDataType === 'date-time') ? new Date(categoryPropVal).getTime() : categoryPropVal;
37894                                        chartBuildOptions.chartModel.jsonModel.yAxisReferencePoint = valuePropVal;
37895                                        chartBuildOptions.isXYReferencePointSet = true;
37896                                    }
37897                                }
37898                            }
37899                        }
37900                    } else {
37901                        categoryPropVal = repeatableInstance[chartBuildOptions.categoryExp].value;
37902                        valuePropVal = repeatableInstance[chartBuildOptions.valueExp].value;
37903                    }
37904
37905                    categoryPropVal = _.isUndefined(categoryPropVal) ? '' : categoryPropVal;
37906                    valuePropVal = _.isUndefined(valuePropVal) ? '' : valuePropVal;
37907                    if (chartBuildOptions.reducerFunction) {
37908                        if (!data.has(categoryPropVal)) {
37909                            data.set(categoryPropVal, []);
37910                        }
37911                        data.get(categoryPropVal).push(valuePropVal);
37912                    } else {
37913                        dataToFill.label.push(categoryPropVal);
37914                        dataToFill.value.push(valuePropVal);
37915                    }
37916                });
37917
37918                if (chartBuildOptions.reducerFunction) {
37919                    var reducer = ChartUtils.reducerOptions[chartBuildOptions.reducerFunction] || window[chartBuildOptions.reducerFunction];
37920                    data.forEach(function (value, key) {
37921                        dataToFill.label.push(key);
37922                        dataToFill.value.push(reducer(data.get(key)));
37923                    });
37924                }
37925                return dataToFill;
37926            },
37927
37928            matchUserInputWithFDM : function (fdmObjectDataType, fdmObjectValue, userInputValue) {
37929                return (((fdmObjectDataType == 'date-time' || fdmObjectDataType == 'date')  && new Date(userInputValue).getTime() == new Date(fdmObjectValue).getTime())
37930                    || (fdmObjectDataType == 'boolean' && JSON.parse(userInputValue) == fdmObjectValue)
37931                    || (userInputValue == fdmObjectValue));
37932            },
37933
37934            /**
37935             * Returns dv.chart object created from chart model.
37936             * @param chartModel
37937             * @param $chartElement
37938             * @returns {dv.chart}
37939             */
37940            constructChart : function (chartModel, $chartElement) {
37941                var chartType = chartModel.chartType,
37942                    showLegends = chartModel.showLegends,
37943                    legendPosition = chartModel.legendPosition,
37944                    tooltipHtml = chartModel.tooltipHtml,
37945                    innerRadius = chartModel.innerRadius,
37946                    lineColor = chartModel.lineColor,
37947                    pointColor = chartModel.pointColor,
37948                    areaColor = chartModel.areaColor,
37949                    dataToFill = chartModel.data,
37950                    chartBehavior = [],
37951                    axisMap = {},
37952                    axisScale = {},
37953                    chartLayers,
37954                    chart,
37955                    categoryAxis,
37956                    valueAxis;
37957                if (chartModel.reducerXFunction && chartModel.reducerXFunction !== 'none') {
37958                    categoryAxis = 'y';
37959                    valueAxis = 'x';
37960                } else {
37961                    categoryAxis = 'x';
37962                    valueAxis = 'y';
37963                }
37964
37965                if (dataToFill.labelDisplayFormat) {
37966                    dataToFill.label = dataToFill.label.map(function (value) {
37967                        return guidelib.util.GuideUtil.formatValue(value,
37968                            dataToFill.labelDisplayFormat,
37969                            dataToFill.categoryDataType);
37970                    });
37971                }
37972
37973                if (dataToFill.valueDisplayFormat) {
37974                    dataToFill.value = dataToFill.value.map(function (value) {
37975                        return guidelib.util.GuideUtil.formatValue(value,
37976                            dataToFill.valueDisplayFormat,
37977                            dataToFill.valueDataType);
37978                    });
37979                }
37980
37981                axisMap[categoryAxis] = 'label';
37982                axisMap[valueAxis] = 'value';
37983                axisScale[valueAxis] = dv.scale.linear().lowerLimit(0);
37984
37985                try {
37986                    if (GuideUtil.isChartTooltipApplicable(chartType)) {
37987                        if (tooltipHtml && tooltipHtml !== '') {
37988                            var xValMap = axisMap['x'],
37989                                yValMap = axisMap['y'];
37990                            chartBehavior = [dv.behavior.rollover().content(function (d) {
37991                                var tooltip = tooltipHtml.replace(/\${x}/g, d.data[xValMap]);
37992                                tooltip = tooltip.replace(/\${y}/g, d.data[yValMap]);
37993                                return tooltip;
37994                            })];
37995                        }
37996                    }
37997                    axisScale[categoryAxis] = dv.scale.ordinal();
37998                    chart = dv.chart();
37999                    chart.map('fill', 'label')
38000                        .map('x', axisMap['x'], axisScale['x'])
38001                        .map('y', axisMap['y'], axisScale['y']);
38002
38003                    var chartPoint = dv.geom.point().set('fill', pointColor).behaviors(chartBehavior),
38004                        chartLine = dv.geom.line().set('fill', lineColor),
38005                        chartArea = dv.geom.area().set('alpha', 0.1).set('fill', areaColor),
38006                        flippedCaretesianCoord = dv.coord.cartesian().flip(true),
38007                        lineCommon = function () {
38008                            chart.set('stroke', lineColor);
38009                            chartLayers = [dv.geom.line()];
38010                        },
38011                        barTypeCommon = function () {
38012                            chartLayers = [dv.geom.bar().behaviors(chartBehavior)];
38013                            chart.map('x', 'label', axisScale[categoryAxis])
38014                                .map('y', 'value');
38015                        },
38016                        barCommon = function () {
38017                            barTypeCommon();
38018                            if (categoryAxis === 'x') {
38019                                chart.coord(flippedCaretesianCoord);
38020                            }
38021                        },
38022                        columnCommon = function () {
38023                            barTypeCommon();
38024                            if (categoryAxis === 'y') {
38025                                chart.coord(flippedCaretesianCoord);
38026                            }
38027                        },
38028                        pieCommon = function (radius) {
38029                            columnCommon();
38030                            dataToFill[categoryAxis] = Array.apply(null, Array(dataToFill["label"].length)).map(function () {
38031                                return 1;
38032                            });
38033                            axisMap[categoryAxis] = categoryAxis;
38034                            if (radius > 0) {
38035                                axisScale[categoryAxis] = axisScale[categoryAxis].padding(.3);
38036                            }
38037
38038                            chart.map('x', axisMap[categoryAxis], axisScale[categoryAxis]);
38039
38040                            chart.coord(dv.coord.polar().flip(true).innerRadius(radius))
38041                                .guide(['x', 'y'], 'none')
38042                                .position('fill');
38043                        };
38044
38045                    switch (chartType) {
38046                        case CHART_TYPE.LINE:
38047                            lineCommon();
38048                            chartLayers.push(chartLine);
38049                            break;
38050                        case CHART_TYPE.POINT:
38051                            lineCommon();
38052                            chartLayers.push(chartPoint);
38053                            break;
38054                        case CHART_TYPE.AREA:
38055                            lineCommon();
38056                            chartLayers.push(chartLine);
38057                            chartLayers.push(chartArea);
38058                            break;
38059                        case CHART_TYPE.LINE_POINT:
38060                            lineCommon();
38061                            chartLayers.push(chartPoint);
38062                            chartLayers.push(chartLine);
38063                            break;
38064                        case CHART_TYPE.BAR:
38065                            barCommon();
38066                            break;
38067                        case CHART_TYPE.COLUMN:
38068                            columnCommon();
38069                            break;
38070                        case CHART_TYPE.PIE:
38071                            pieCommon(0);
38072                            break;
38073                        case CHART_TYPE.DONUT:
38074                            pieCommon(innerRadius);
38075                            break;
38076                    }
38077
38078                    chart.layers(chartLayers);
38079                    chart.data(dataToFill)
38080                        .width(chartModel.width + '%')
38081                        .height(chartModel.height)
38082                        .parent("#" + $chartElement.attr('id'))
38083                        .padding({"left" : 10, "top" : 10, "right" : 10, "bottom" : 10});
38084
38085                    if (GuideUtil.isChartAxisTitleApplicable(chartType)) {
38086                        chart.guide('x', dv.guide.axis().title(chartModel.xAxisTitle))
38087                            .guide('y', dv.guide.axis().title(chartModel.yAxisTitle));
38088                    }
38089
38090                    if (GuideUtil.isChartLegendApplicable(chartType) && showLegends) {
38091                        chart.guide('fill', dv.guide.legend().orientation(legendPosition));
38092                    }
38093                } catch (exception) {
38094                    window.guideBridge._guide.logger().log("Error while constructing chart " + exception);
38095                }
38096                return chart;
38097            },
38098
38099            _setProp : function (object, prop, value) {
38100                if (object.constructor == {}.constructor && !_.isEmpty(value)) {
38101                    object[prop] = value;
38102                }
38103                return object;
38104            },
38105
38106            /**
38107            *   Retrieves Repeatable Instances using liveDataUtils API for the given
38108            *   repeatablePath. This API internally handles naked/non-naked case.
38109            *
38110            *   @param  repeatablePath
38111            *   @param  data
38112            *   @return Repeatable Instances for the given repeatablePath using liveDataUtils.
38113            *
38114            *   TODO Move this API to data utils.
38115            */
38116            _getRepeatableInstances : function (repeatablePath, data, chartModel) {
38117                var liveDataUtils = chartModel._guide().internal.liveDataUtils,
38118                    liveData = data ? data : liveDataUtils._liveDataDoc,
38119                    xpath = "";
38120
38121                if (_.isEmpty(liveData) || _.isEmpty(repeatablePath)) {
38122                    return;
38123                }
38124
38125                if (!_.isEmpty(liveData.afData)) {//Non-Naked data case
38126                    liveData = liveData.afData;
38127                    xpath = liveDataUtils.constants.BOUND_DATA_XPATH;
38128                } else {//Naked data case or multiple series case
38129                    repeatablePath = repeatablePath.substring(1, repeatablePath.length);
38130                }
38131
38132                //Find the repeatable instances.
38133                repeatableInstances = liveDataUtils._getElement(liveData, xpath + repeatablePath);
38134
38135                return repeatableInstances;
38136            }
38137        };
38138}($, guidelib, _));
38139
38140//Poly-filling request animation frame function for IE 9
38141(function () {
38142    var lastFramePaintTime = 0;
38143    if (!window.requestAnimationFrame) {
38144        window.requestAnimationFrame = function (callback, element) {
38145            var currTime = new Date().getTime(),
38146                timeToCall = Math.max(0, 16 - (currTime - lastFramePaintTime)), //16-16 frames per second
38147                id = window.setTimeout(function () {
38148                        callback(currTime + timeToCall);
38149                    }, timeToCall);
38150            lastFramePaintTime = currTime + timeToCall;
38151            return id;
38152        };
38153    }
38154
38155    if (!window.cancelAnimationFrame) {
38156        window.cancelAnimationFrame = function (id) {
38157            clearTimeout(id);
38158        };
38159    }
38160}());
38161
38162/*
38163 * ***********************************************************************
38164 * ADOBE CONFIDENTIAL
38165 * __________________
38166 *
38167 * Copyright 2015 Adobe Systems Incorporated
38168 * All Rights Reserved.
38169 *
38170 * NOTICE:  All information contained herein is, and remains
38171 * the property of Adobe Systems Incorporated and its suppliers,
38172 * if any.  The intellectual and technical concepts contained
38173 * herein are proprietary to Adobe Systems Incorporated and its
38174 * suppliers and may be covered by U.S. and Foreign Patents,
38175 * patents in process, and are protected by trade secret or copyright law.
38176 * Dissemination of this information or reproduction of this material
38177 * is strictly forbidden unless prior written permission is obtained
38178 * from Adobe Systems Incorporated.
38179 * ***********************************************************************
38180 */
38181
38182(function ($, guidelib, xfalib, _) {
38183    var errorHandler = function (jqXHR) {
38184         var errorPayload;
38185
38186         // Actually we need clean-up old data but its not even happening in case of success with empty data
38187        // Running output mapping with empty result set to ensure old data is cleared
38188
38189         if (jqXHR.responseText) {
38190             var inputMapping = this.inputMapping;
38191             try {
38192                 errorPayload = JSON.parse(jqXHR.responseText);
38193             } catch (error) {
38194                 // result should be json if its not wel formed json or empty then ignoring it
38195             }
38196             if(errorPayload && errorPayload.errors) {
38197
38198                 // Iterating over violations received and set it at field level using input mapping provided.
38199                 var violations = errorPayload.errors;
38200                 $.each(violations, function (key, violation) {
38201                     if(violation && violation.bindRef && violation.errorMessages) {
38202                         var key = violation.bindRef.slice(1).split("/").join(".");
38203                         var field = inputMapping[key];
38204                         if (field) {
38205                             field.markAsInvalid(violation.errorMessages.join("\n"));
38206                         }
38207                     }
38208                 })
38209             }
38210         }
38211         // Invoke author register error handler (if any)
38212         if(this.customErrorHandler) {
38213             this.customErrorHandler.call(this, jqXHR, errorPayload);
38214         }
38215    };
38216
38217    var defaultErrorHandler = function (responseJson, headerMap) {
38218        if (responseJson) {
38219            if (responseJson && responseJson.validationErrors) {
38220                var violations = responseJson.validationErrors;
38221                $.each(violations, function (key, violation) {
38222                    if (violation && violation.details && (violation.fieldName || violation.dataRef)) {
38223                        if (!window.guideBridge._guide._bindRefMap || Object.keys(window.guideBridge._guide._bindRefMap).length === 0) {
38224                            window.guideBridge._populateBindRefToSomMap();
38225                        }
38226                        var som = (violation.fieldName) ? violation.fieldName : window.guideBridge._guide._bindRefMap[violation.dataRef];
38227                        var field = window.guideBridge.resolveNode(som);
38228                        if (field) {
38229                            field.markAsInvalid(violation.details.join("\n"));
38230                        }
38231                    }
38232                });
38233            }
38234        }
38235    };
38236
38237    var defaultErrorHandlerWrapper = function(jqXHR) {
38238        if (jqXHR.responseText) {
38239            try {
38240                responseJson = JSON.parse(jqXHR.responseText);
38241            } catch (error) {
38242                // result should be json if its not well formed json or empty then ignoring it
38243            }
38244        }
38245
38246        var headers = jqXHR.getAllResponseHeaders();
38247
38248        // Convert the header string into an array
38249        // of individual headers
38250        var arr = headers.trim().split(/[\r\n]+/);
38251
38252        // Create a map of header names to values
38253        var headerMap = {};
38254        arr.forEach(function (line) {
38255            var parts = line.split(': ');
38256            var header = parts.shift();
38257            var value = parts.join(': ');
38258            headerMap[header] = value;
38259        });
38260
38261        if(this.customErrorHandler) {
38262            this.customErrorHandler.call(this, responseJson, headerMap);
38263        }
38264    }
38265
38266    // Counts the number of Array(repeatable) in the output JSON of the WSDL.
38267    var outputJsonRepeatCount = function (wsdlOutputId, outputJSONObj) {
38268        var count = 0,
38269            wsdlOutputHierarchy = wsdlOutputId.split(".");
38270        if (Array.isArray(outputJSONObj)) {
38271            count++;
38272            outputJSONObj = outputJSONObj[0];
38273        }
38274        $.each(wsdlOutputHierarchy, function (depth) {
38275            if (outputJSONObj) {
38276                outputJSONObj = outputJSONObj[wsdlOutputHierarchy[depth]];
38277                if (Array.isArray(outputJSONObj)) {
38278                    count++;
38279                    outputJSONObj = outputJSONObj[0];
38280                }
38281            }
38282        });
38283        return count;
38284    };
38285
38286    //Traversing to the highest repeatable field in hierarchy as a starting point.
38287    var outputRepeatAncestor = function (targetNode, repeatCount, targetNameHierarchy) {
38288        while (repeatCount > 0) {
38289            if (_.isNull(targetNode.parent)) {
38290                return targetNode;
38291            }
38292            targetNameHierarchy.push(targetNode.name);
38293            targetNode = targetNode.parent;
38294            if (targetNode.repeatable) {
38295                repeatCount--;
38296            }
38297        }
38298        return targetNode;
38299    };
38300
38301    /**
38302     * Extract value of a hierarchy of properties
38303     * from a nested javascript object.
38304     * @param {Object} obj Nested javascript object
38305     * @param {Array|String} props list of properties
38306     * or dot separated string from root to leaf object
38307     * @return {Array} return list of values found
38308     */
38309    function extractValues(obj, props) {
38310        // handle easy cases
38311        if (obj === null || typeof(obj) === "undefined") {
38312            return [];
38313        }
38314        if (typeof(props) == "string") {
38315            props = props.split(".");
38316        }
38317        if (props.length == 0) {
38318            return [obj];
38319        }
38320        var ret = [];
38321        if (obj instanceof Array) {
38322            for (var i = 0; i < obj.length; i++) {
38323                ret = ret.concat(extractValues(obj[i], props));
38324            }
38325            return ret;
38326        }
38327        if (!obj.hasOwnProperty(props[0])) {
38328            return [];
38329        }
38330        // handle actual case now
38331
38332        var key = props[0];
38333        var remainingKeys = props.slice(1);
38334        var values = obj[key];
38335        if (!(values instanceof Array)) {
38336            values = [values];
38337        }
38338        for (var x = 0; x < values.length; x++) {
38339            ret = ret.concat(extractValues(values[x], remainingKeys));
38340        }
38341        return ret;
38342    }
38343    //Maps the output JSON(outputJSONObj) to the Model(targetNode)
38344    var outputJsonMapping = function (wsdlOutputId, targetNode, targetNameHierarchy, outputJSONObj) {
38345        if (targetNameHierarchy.length === 0) {
38346            targetNode.value = xfalib.ut.XfaUtil.prototype.getOrElse(outputJSONObj, wsdlOutputId, "");
38347            return;
38348        }
38349        var targetName = targetNameHierarchy.pop();
38350        if (targetNode.repeatable) {
38351            //Gets respective array for this repeatable field.
38352            while (typeof outputJSONObj === "object" && !Array.isArray(outputJSONObj)) {
38353                var argsIndex = wsdlOutputId.indexOf('.');
38354                outputJSONObj = outputJSONObj[wsdlOutputId.substring(0, argsIndex)] || "";
38355                wsdlOutputId = wsdlOutputId.substring(argsIndex + 1);
38356            }
38357            //Adjust the number of instances to the number of array elements.
38358            var jsonLength = outputJSONObj.length,
38359                instanceCount = targetNode.instanceManager.instanceCount;
38360            if (instanceCount < jsonLength) {
38361                targetNode.instanceManager.addInstances({
38362                    instanceCount : jsonLength
38363                });
38364            }
38365            //Check as "" might occur too for incorrect mappings.
38366            if (Array.isArray(outputJSONObj)) {
38367                //Recursive call for every instance with corresponding value.
38368                $.each(outputJSONObj, function (index) {
38369                    // if the output from external API call contains more records, than the number
38370                    // of instances present, return
38371                    if (index >= targetNode.instanceManager.instanceCount) {
38372                        return false;
38373                    }
38374                    targetNode = targetNode.instanceManager.instances[index];
38375                    outputJsonMapping(wsdlOutputId, targetNode[targetName], targetNameHierarchy, outputJSONObj[index]);
38376                });
38377            }
38378        } else {
38379            //Recursive call down the hierarchy.
38380            outputJsonMapping(wsdlOutputId, targetNode[targetName], targetNameHierarchy, outputJSONObj);
38381        }
38382        //Pushing back the hierarchy for next instance if any.
38383        targetNameHierarchy.push(targetName);
38384    };
38385
38386    var populateWsdlOutput = function (wsdlOutput, textStatus, jqXHR) {
38387        if (wsdlOutput == null || wsdlOutput.length == 0) {
38388            return;
38389        }
38390
38391        var origOutputJSONObj,
38392            outputMappingObj = this.callbackData;
38393        try {
38394            origOutputJSONObj = JSON.parse(wsdlOutput);
38395        } catch (e) {
38396            //Handling primitive output
38397            origOutputJSONObj = {"response" : wsdlOutput};
38398        }
38399
38400        /*  For each entry in outputMappingObj, we need to find the corresponding value in responseObj.
38401         *  wsdlOutputId - wsdlOutput hierarchy, targetNode - field in the form whose value is to be set.
38402         *  e.g. {ipinfo.ip, txtfield} */
38403        $.each(outputMappingObj, function (wsdlOutputId, targetNode) {
38404            /* Gets value in outputJSONObj corresponding to targetNode.
38405             * First, It counts the number of Array in hierarchy as repeatCount.
38406             * Next, targetNode is taken to the starting point for traversal.
38407             * It's the topmost repeatable node in hierarchy.
38408             * Lastly, The outputJson is mapped to the TargetNode.*/
38409            var repeatCount = outputJsonRepeatCount(wsdlOutputId, origOutputJSONObj),
38410                targetNameHierarchy = [],
38411                targetNode = outputRepeatAncestor(targetNode, repeatCount, targetNameHierarchy);
38412            outputJsonMapping(wsdlOutputId, targetNode, targetNameHierarchy, origOutputJSONObj);
38413        });
38414        window.guideBridge._guide.runPendingExpressions();
38415    };
38416
38417    /**
38418     * Create and set items to dropdown field from wsdl response.
38419     * @this {Object} is of form {callbackData:data}
38420     */
38421    function setOptionsCallback(wsdlOutput) {
38422       var cbData = this.callbackData;
38423       var options = [];
38424       if (!_.isEmpty(wsdlOutput)) {
38425           var wsdlOutputObj = JSON.parse(wsdlOutput);
38426           var savedValues = extractValues(wsdlOutputObj, cbData.savedValue);
38427           var displayedValues = extractValues(wsdlOutputObj, cbData.displayedValue);
38428           for (var i = 0; i < savedValues.length; i++) {
38429               options.push(savedValues[i] + "=" + displayedValues[i]);
38430           }
38431       }
38432       cbData.field.items = options;
38433   }
38434
38435    function setValueCallback(wsdlOutput) {
38436        var cbData = this.callbackData;
38437        var wsdlOutputObj = JSON.parse(wsdlOutput);
38438        cbData.field.value = extractValues(wsdlOutputObj, cbData.value);
38439    }
38440
38441    function appendLoadingIcon() {
38442        $("#loadingPage").addClass("guideServiceLoading");
38443    }
38444
38445    function removeLoadingIcon() {
38446        $("#loadingPage").removeClass("guideServiceLoading");
38447    }
38448
38449    function executeOperationInternal (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler, apiVersion) {
38450        // populate operationDetails object
38451        var successHandler = processOutputCallback || populateWsdlOutput;
38452        var wsdlInputObj = {};
38453
38454        /* Iterate through the jsonInputMapping and create the input object.
38455         * wsdlInputId - wsdlInput hierarchy, targetNode - field in the form whose value is to be retrieved.*/
38456        $.each(jsonInputMappingObj, function (wsdlInputId, targetNode) {
38457            var argsHierarchy = wsdlInputId.split("."),
38458                wsdlArgObj = wsdlInputObj,
38459                argDepth,
38460                valueToBeAssigned;
38461
38462            for (argDepth = 0; argDepth < argsHierarchy.length - 1; argDepth++) {
38463                wsdlArgObj[argsHierarchy[argDepth]] = wsdlArgObj[argsHierarchy[argDepth]] || {};
38464                wsdlArgObj = wsdlArgObj[argsHierarchy[argDepth]];
38465            }
38466            // assign the value of targetNode
38467            if (typeof targetNode === "object") {
38468                valueToBeAssigned = targetNode.value;
38469            } else {
38470                valueToBeAssigned = targetNode;
38471            }
38472            wsdlArgObj[argsHierarchy[argDepth]] = valueToBeAssigned;
38473        });
38474
38475        var wsdlEndPoint = wsdlInfoObj.wsdlEndPoint,
38476            operationDetails = {};
38477        operationDetails.operationName = wsdlInfoObj.operationName;
38478        operationDetails.input = JSON.stringify(wsdlInputObj);
38479        operationDetails.port = wsdlInfoObj.port;
38480        operationDetails.soapActionURI = wsdlInfoObj.soapActionURI;
38481        operationDetails.namespace = wsdlInfoObj.namespace;
38482        operationDetails.inputRoot = wsdlInfoObj.inputRoot;
38483        operationDetails.inputAttr = JSON.stringify(wsdlInfoObj.inputAttr);
38484        operationDetails.serviceEndPoint = wsdlInfoObj.serviceEndPoint;
38485        if (!model) {
38486            console.log("No model parameter passed to this API, this may fail during server side re-validation. Please correct your scripts.")
38487        }
38488        // TODO: this needs to be fixed, this API does not have access to guideContext but would execute in context of AF always
38489        var guide = model && model._guide && model._guide();
38490        var wsdlServletURL  = ((guide ? guide.jcrPath : guidelib.__runtime__.guide.jcrPath) + ".af.dermis");
38491        var externalizedWSDLServletURL;
38492        if (guideBridge != null) {
38493            externalizedWSDLServletURL = guideBridge._getUrl(wsdlServletURL);
38494        } else {
38495            externalizedWSDLServletURL = Granite.HTTP.externalize(wsdlServletURL);
38496        }
38497
38498        var invokeData = {};
38499        if (wsdlInfoObj.wsdlEndPoint) {
38500            invokeData.functionToExecute = 'invokeWsdlOperation';
38501            invokeData.wsdlEndPoint = wsdlEndPoint;
38502            invokeData.operationName = operationDetails.operationName;
38503            invokeData.input = operationDetails.input;
38504
38505            if (operationDetails.port) {
38506                invokeData.port = operationDetails.port;
38507            }
38508            if (operationDetails.soapActionURI) {
38509                invokeData.soapActionURI = operationDetails.soapActionURI;
38510            }
38511            if (operationDetails.namespace) {
38512                invokeData.namespace = operationDetails.namespace;
38513            }
38514            if (operationDetails.inputRoot) {
38515                invokeData.inputRoot = operationDetails.inputRoot;
38516            }
38517            if (operationDetails.inputAttr) {
38518                invokeData.inputAttr = operationDetails.inputAttr;
38519            }
38520            if (operationDetails.serviceEndPoint) {
38521                invokeData.serviceEndPoint = operationDetails.serviceEndPoint;
38522            }
38523        } else if (wsdlInfoObj.formDataModelId) {
38524            invokeData.functionToExecute = 'invokeFDMOperation';
38525            invokeData.formDataModelId = wsdlInfoObj.formDataModelId;
38526            invokeData.input = JSON.stringify(wsdlInputObj);
38527            invokeData.operationName = wsdlInfoObj.operationName;
38528            invokeData.runValidation = wsdlInfoObj.runValidation;
38529            invokeData.apiVersion = apiVersion;
38530        }
38531        invokeData.guideNodePath = guide ? guide._currentContext.contextNode.jcrPath : guidelib.__runtime__.guide._currentContext.contextNode.jcrPath;
38532
38533        $.ajax({
38534            type : 'POST',
38535            url : externalizedWSDLServletURL,
38536            data : invokeData,
38537            beforeSend : appendLoadingIcon,
38538            complete : removeLoadingIcon,
38539            dataType : 'text',
38540            success : successHandler,
38541            error : defaultErrorHandler,
38542            context : {callbackData : jsonOutputMappingObj, inputMapping: jsonInputMappingObj, customErrorHandler: customErrorHandler}
38543        });
38544    }
38545
38546    var DataIntegrationUtils = guidelib.dataIntegrationUtils = {
38547
38548        setOptionsFromService : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
38549            this.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setOptionsCallback);
38550            return jsonOutputMapping.field.items;
38551        },
38552
38553        setValueFromService : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
38554            this.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setValueCallback);
38555            return jsonOutputMapping.field.items;
38556        },
38557
38558        /**
38559         * @deprecated
38560         */
38561        executeOperation : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model) {
38562            var defaultErrorHandler = errorHandler;
38563            executeOperationInternal(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler);
38564        },
38565
38566        executeOperationV2 : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model) {
38567            var defaultErrorHandler = defaultErrorHandlerWrapper;
38568            var apiVersion = "2";
38569            executeOperationInternal(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler, apiVersion);
38570        },
38571
38572        defaultErrorHandler : defaultErrorHandler
38573    };
38574
38575    var WsdlUtils = guidelib.wsdlUtils = {
38576        /**
38577         *  Internal API, called for invoking webservice and setting items in a drop down
38578         */
38579        setOptionsFromWSDL : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
38580            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setOptionsCallback);
38581            return jsonOutputMapping.field.items;
38582        },
38583
38584        setValueFromWSDL : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
38585            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setValueCallback);
38586            return jsonOutputMapping.field.items;
38587        },
38588
38589        executeWSDLFunction : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj) {
38590            // populate operationDetails object
38591            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj);
38592        }
38593    };
38594}($, guidelib, xfalib, _));
38595
38596/*
38597 * ***********************************************************************
38598 * ADOBE CONFIDENTIAL
38599 * __________________
38600 *
38601 * Copyright 2015 Adobe Systems Incorporated
38602 * All Rights Reserved.
38603 *
38604 * NOTICE:  All information contained herein is, and remains
38605 * the property of Adobe Systems Incorporated and its suppliers,
38606 * if any.  The intellectual and technical concepts contained
38607 * herein are proprietary to Adobe Systems Incorporated and its
38608 * suppliers and may be covered by U.S. and Foreign Patents,
38609 * patents in process, and are protected by trade secret or copyright law.
38610 * Dissemination of this information or reproduction of this material
38611 * is strictly forbidden unless prior written permission is obtained
38612 * from Adobe Systems Incorporated.
38613 * ***********************************************************************
38614 */
38615
38616/**
38617 * @package guidelib.model.GuideDirtyMarkerAndVisitor
38618 * @version 0.0.1
38619 */
38620
38621(function ($, _, guidelib) {
38622    var GuideDirtyMarkerAndVisitor = guidelib.model.GuideDirtyMarkerAndVisitor = xfalib.ut.EventClass.extend({
38623
38624        initialize : function() {
38625            // need to save the map while save and restore - will do it in getGuideState
38626            this.visitMap = {};
38627        },
38628        /**
38629         * Return a list of dirty children
38630         * @returns {Array}
38631         * @private
38632         */
38633        _flattenDirtyPanelToList : function () {
38634            var csv = this.flattenDirtyPanelMapToCSV();
38635            if (csv.length > 0) {
38636                return csv.split(",");
38637            }
38638        },
38639        /**
38640         * If any dirty element then save it to CSV
38641         */
38642        flattenDirtyPanelMapToCSV : function () {
38643            var listOfDirtyPanels = "";
38644            _.each(_.keys(this.visitMap), function (key, index) {
38645                if (this.visitMap[key] === 0) {
38646                    listOfDirtyPanels += key + ",";
38647                }
38648            }, this);
38649            if (listOfDirtyPanels.length > 0) {
38650                // strip last ,
38651                listOfDirtyPanels = listOfDirtyPanels.substring(0, listOfDirtyPanels.length - 1);
38652            }
38653            return listOfDirtyPanels;
38654        },
38655        /**
38656         * This method finds and marks dirty all the lazy children that were dependant of global field's value
38657         * @param mapOfLazyChildren
38658         * @param listOfIdsOfDependents
38659         * @private
38660         */
38661        _findAndMarkDirty : function (mapOfLazyChildren, listOfIdsOfDependents) {
38662            var listOfLazyChildren = _.keys(mapOfLazyChildren);
38663
38664            _.each(listOfIdsOfDependents, function (depenId, index) {
38665                var longestPrefixLenSoFar = 0,
38666                    currentPrefixLen = 0,
38667                    nearestLazyId = null,
38668                    i;
38669                // find hierarchically closest field by matching longest som prefix
38670                for (i = 0; i < listOfLazyChildren.length; ++i) {
38671                    currentPrefixLen = guidelib.util.GuideUtil.commonPrefixLen(depenId, listOfLazyChildren[i]);
38672                    if (longestPrefixLenSoFar < currentPrefixLen) {
38673                        longestPrefixLenSoFar = currentPrefixLen;
38674                        nearestLazyId = listOfLazyChildren[i];
38675                    }
38676                }
38677                //  Mark dirty
38678                if (longestPrefixLenSoFar > 0) {
38679                    mapOfLazyChildren[nearestLazyId] = 0;
38680                }
38681            });
38682        },
38683        /**
38684         * Iterates a map and finds the first occurrence of value found in any key
38685         * @param map
38686         * @param value
38687         */
38688        _iterateMapAndReturnKeyOnValueFound : function (map, value) {
38689            var keyToReturn;
38690            _.each(_.keys(map), function (key, index) {
38691                if (map[key] === value) {
38692                    keyToReturn =  key;
38693                }
38694            });
38695            return keyToReturn;
38696        },
38697        /**
38698         * Updates the value of the key in map by one if present otherwise puts the key with value zero
38699         * @param map
38700         * @param key
38701         * @returns {*}
38702         */
38703        _updateCountOrInsert : function (map, key) {
38704            if (_.isUndefined(map[key])) {
38705                map[key] = 0;
38706            } else {
38707                map[key]++;
38708            }
38709
38710            return map;
38711        }
38712    });
38713
38714}($, _, window.guidelib));
38715
38716/*
38717 * ***********************************************************************
38718 * ADOBE CONFIDENTIAL
38719 * __________________
38720 *
38721 * Copyright 2016 Adobe Systems Incorporated
38722 * All Rights Reserved.
38723 *
38724 * NOTICE:  All information contained herein is, and remains
38725 * the property of Adobe Systems Incorporated and its suppliers,
38726 * if any.  The intellectual and technical concepts contained
38727 * herein are proprietary to Adobe Systems Incorporated and its
38728 * suppliers and may be covered by U.S. and Foreign Patents,
38729 * patents in process, and are protected by trade secret or copyright law.
38730 * Dissemination of this information or reproduction of this material
38731 * is strictly forbidden unless prior written permission is obtained
38732 * from Adobe Systems Incorporated.
38733 * ***********************************************************************
38734 */
38735
38736(function ($) {
38737    //Firing resize as, CSS is loaded after table mobile layout, cell width is adjusted for repeatable row, to accommodate +, - controls
38738    $(function () {
38739        $(window).trigger('resize');
38740    });
38741}($));
38742
38743/*
38744 * ADOBE CONFIDENTIAL
38745 * ___________________
38746 *
38747 * Copyright 2014 Adobe Systems Incorporated
38748 * All Rights Reserved.
38749 *
38750 * NOTICE:  All information contained herein 
38750is, and remains
38751 * the property of Adobe Systems Incorporated and its suppliers,
38752 * if any.  The intellectual and technical concepts contained
38753 * herein are proprietary to Adobe Systems Incorporated and its
38754 * suppliers and may be covered by U.S. and Foreign Patents,
38755 * patents in process, and are protected by trade secret or copyright law.
38756 * Dissemination of this information or reproduction of this material
38757 * is strictly forbidden unless prior written permission is obtained
38758 * from Adobe Systems Incorporated.
38759 *
38760 */
38761(function ($, _) {
38762    window.FD = window.FD || {};
38763    FD.FP = FD.FP || {};
38764
38765    FD.FP.AF = {
38766        /***
38767         * Saves the draft of adaptive forms
38768         @param options: {object} options can consist of following
38769         * <ul>
38770         *     <li> isAutoSaveTriggered: {boolean} Indicates if the auto save is triggered or not   </li>
38771         *     <li> metadataToSave: {object} The meta data to save with draft </li>
38772         *     <li> enableAnonymous: {boolean} indicating whether you want to have anonymous save or not.</li>
38773         *     <li> success: {function}  Handler executed in case when the draft is successfully saved</li>
38774         *     <li> error: {function}  Handler  executed in case of draft failure</li>
38775         *     <li> context {object}  The context with which the success or error handler needs to be executed</li>
38776         * </ul>
38777         * @private
38778         */
38779        _handleDraftSave: function (options) {
38780            var isAutoSaveTriggered = options.isAutoSaveTriggered,
38781                metadataToSave = options.metadataToSave,
38782                enableAnonymous = options.enableAnonymous,
38783                guidePath = window.guideBridge.getGuideContext().data[window.guideBridge.GUIDE_PATH],
38784                draftID = window.guideBridge.customContextProperty("draftID"),
38785                customContextProperty = xfalib.ut.Class.prototype.getOrElse(window.guidelib.runtime.guideContext.customPropertyMap,{}),
38786                errorObj,
38787                dataXML,
38788                node,
38789                fileAttachmentsList = [],
38790                fileAttachmentMap = {};
38791
38792            $("#draftID").attr("value", draftID);
38793            var currentNodePath = $("#saveButtonPath").data("savebuttonpath") || guidePath,
38794                contextPath = window.guideBridge._getUrl(currentNodePath);
38795            var fileUploadPath = contextPath + ".fp.attach.jsp/" + draftID;
38796            // If custom uploader plugin is configured, then portal should not send fileUploadPath
38797            if (window.guideBridge && window.guideBridge.userConfig && window.guideBridge.userConfig.uploaderPluginName && window.guideBridge.userConfig.uploaderPluginName !== 'adobeFileUploader') {
38798                fileUploadPath = '';
38799            }
38800            if(customContextProperty == null) {
38801                customContextProperty = {};
38802            };
38803
38804            var paramObj = {
38805                "success": function (result) {
38806                    window.guideBridge.trigger(
38807                        "saveStarted",
38808                        window.guidelib.event.GuideModelEvent.createEvent("saveStarted")
38809                    );
38810                    dataXML = result.data;
38811                    //it can be json, fdm, xsd, xdp or nothing.
38812                    var guide = guideBridge.resolveNode("guide[0].guide1[0]");
38813                    var schemaType = guide.getAttribute("schemaType");
38814					//keep it default as xml
38815                    var dataType = "XML";
38816                    if(!_.isUndefined(schemaType)) {
38817                        if(schemaType == "jsonschema" || schemaType == "formdatamodel") {
38818                            dataType = "JSON";
38819                        } else {
38820                            dataType = "XML";
38821                        }
38822                    }
38823                    /*
38824                     * file attachment map will be used for restoring the attachment for xml based adaptive forms
38825                     * as this information is not available in dataXML,sending it seperately
38826                     */
38827                    fileAttachmentMap = window.guideBridge.getFileAttachmentMap();
38828                    var urlForDraft = contextPath + ".fp.draft.json?func=saveDraft";
38829                    var data = {
38830                        'formPath': guidePath,
38831                        'formData': dataXML,
38832                        'draftID': draftID,
38833                        'formType': "af",
38834                        '_charset_': "UTF-8",
38835                        'enableAnonymousSave': enableAnonymous,
38836                        'dataType': dataType,  //dataType for defining the type of formdata for backward compatibility
38837                        'fileAttachmentMap': JSON.stringify(fileAttachmentMap),
38838                        'customContextProperty' : JSON.stringify(customContextProperty)
38839                    };
38840                    if (metadataToSave) {
38841                        for (var key in metadataToSave) {
38842                            if (metadataToSave.hasOwnProperty(key)) {
38843                                data[key] = metadataToSave[key];
38844                            }
38845                        }
38846                    }
38847                    var allowedMetadata = [];
38848                    for (key in data) {
38849                        if (key !== 'formData') {
38850                            allowedMetadata.push(key);
38851                        }
38852                    }
38853                    data["fpAllowedMetadata"] = allowedMetadata.toString();
38854
38855                    $.ajax({
38856                        type: "POST",
38857                        url: urlForDraft,
38858                        async: true,
38859                        cache: false,
38860                        mimeType: "multipart/form-data",
38861                        data: data,
38862                        success: function (result) {
38863                            if (!isAutoSaveTriggered) {
38864                                alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings["draftSavedSuccessMessage"]));
38865                            }
38866                            window.guideBridge.trigger(
38867                                "saveCompleted",
38868                                window.guidelib.event.GuideModelEvent.createEvent("saveCompleted")
38869                            );
38870                            if (!_.isUndefined(options.success)) {
38871                                options.success.call(options.context || this);
38872                            }
38873                        },
38874                        error: function (result) {
38875                            if (!isAutoSaveTriggered) {
38876                                if (result.status == "503") {
38877                                    alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-008"]));
38878                                } else {
38879                                    alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-009"]));
38880                                }
38881                            }
38882                            if (!_.isUndefined(options.error)) {
38883                                options.error.call(options.context || this);
38884                            }
38885                        }
38886                    });
38887                },
38888                "error": function (result) {
38889                    errorObj = result;
38890                    if (errorObj != null) {
38891                        console.log(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-009"]));
38892                        return 0;
38893                    }
38894                },
38895                "fileUploadPath": fileUploadPath
38896            };
38897            window.guideBridge.getData(paramObj);
38898        },
38899
38900        _handleDraftSaveWrapper: function (options) {
38901            var draftAndSubmissionRenderPath = $("#saveButtonPath").data("draftandsubmissionp
38901ortalnode") || '/content/forms/portal/draftandsubmission';
38902            if (typeof window.guideBridge.customContextProperty("draftID") === "undefined" || window.guideBridge.customContextProperty("draftID") == null) {
38903                $.ajax({
38904                    method: "GET",
38905                    url: Granite.HTTP.externalize(draftAndSubmissionRenderPath + ".fp.draft.json?func=getUid"),
38906                    cache: false,
38907                    dataType: "json"
38908                }).done(function (response) {
38909                    var draftID = response.id;
38910                    window.guideBridge.customContextProperty("draftID", draftID + "_af");
38911                    FD.FP.AF._handleDraftSave(options);
38912                }).fail(function (errorObj) {
38913                    alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-009"]));
38914                    return 0;
38915                });
38916            } else {
38917                FD.FP.AF._handleDraftSave(options);
38918            }
38919        }
38920    };
38921
38922    /**
38923     * Save draft of the current adaptive form loaded
38924     * @param saveBtnConfig {object} Optional parameter for providing
38925     * @param options {object} Optional parameter options can consist of following -
38926     *  <ul>
38927     *     <li> success: {function}  Handler executed in case when the draft is successfully saved</li>
38928     *     <li> error: {function}  Handler  executed in case of draft failure</li>
38929     *     <li> context {object}  The context with which the success or error handler needs to be executed</li>
38930     * </ul>
38931     *
38932     */
38933        // To maintain backward compatibility, keeping this function on window
38934        // This method will be used for click expression of save button
38935        // saveBtnConfig  kept as it is for backward compatiablity metadata to the save button
38936    handleDraftSave = function (saveBtnConfig, options) {
38937        var metadataToSave = {}, enableAnonymous = false, fpMetadata = null, metadata = null;
38938        if (saveBtnConfig) {
38939            var metadataselector = saveBtnConfig.getAttribute('metadataselector');
38940            if (metadataselector && metadataselector === 'local') {
38941                fpMetadata = saveBtnConfig.getAttribute("fpmetadata");
38942            } else {
38943                var metaInfo = window.guideBridge.getGlobalMetaInfo();
38944                fpMetadata = metaInfo && metaInfo.hasOwnProperty("metadata") ? metaInfo['metadata'] : null;
38945            }
38946            if (fpMetadata) {
38947                if (typeof fpMetadata === 'object') {
38948                    for (var index in fpMetadata) {
38949                        var currentMetadata = JSON.parse(fpMetadata[index]);
38950                        metadataToSave[currentMetadata["key"]] = window.guideBridge._guide._compileExpression(currentMetadata["value"]).call(window.guideBridge._guide);
38951                    }
38952                } else if (typeof fpMetadata === 'string') {
38953                    var currentMetadata = JSON.parse(fpMetadata);
38954                    metadataToSave[currentMetadata["key"]] = window.guideBridge._guide._compileExpression(currentMetadata["value"]).call(window.guideBridge._guide);
38955                }
38956            }
38957            if (saveBtnConfig.getAttribute("enableAnonymous")) {
38958                enableAnonymous = saveBtnConfig.getAttribute("enableAnonymous");
38959            }
38960        }
38961        if (_.isUndefined(options)) {
38962            options = {}
38963        }
38964        options.metadataToSave = metadataToSave;
38965        options.enableAnonymous = enableAnonymous;
38966        options.isAutoSaveTriggered = false;
38967        window.FD.FP.AF._handleDraftSaveWrapper(options);
38968    }
38969})(jQuery, _);
38970
38971/*************************************************************************
38972 *
38973 * ADOBE CONFIDENTIAL
38974 * __________________
38975 *
38976 *  Copyright 2015 Adobe Systems Incorporated
38977 *  All Rights Reserved.
38978 *
38979 * NOTICE:  All information contained herein is, and remains
38980 * the property of Adobe Systems Incorporated and its suppliers,
38981 * if any.  The intellectual and technical concepts contained
38982 * herein are proprietary to Adobe Systems Incorporated and its
38983 * suppliers and may be covered by U.S. and Foreign Patents,
38984 * patents in process, and are protected by trade secret or copyright law.
38985 * Dissemination of this information or reproduction of this material
38986 * is strictly forbidden unless prior written permission is obtained
38987 * from Adobe Systems Incorporated.
38988 **************************************************************************/
38989
38990(function(){
38991    window.FD = window.FD || {};
38992    FD.FP = FD.FP || {};
38993    FD.FP.SaveConfigChangeListener = function(field){
38994        var dialog, hasClickExpChanged, clickExp;
38995        dialog = field instanceof CQ.Dialog ? field : field.findParentByType('dialog');
38996        clickExp = dialog.getField('./clickExp');
38997        hasClickExpChanged = dialog.getField('./hasClickExpChanged');
38998        if(hasClickExpChanged){
38999            var value = hasClickExpChanged.getValue();
39000            var clickExpVal = clickExp.getValue();
39001            if((!value || value != 'true') && (clickExpVal === "handleDraftSave()")){
39002                clickExp.setValue('handleDraftSave(this)');
39003                hasClickExpChanged.setValue('true');
39004            }
39005        }
39006    }
39007})();
39008

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.