PageSourceSearch

https://www.coca-cola.com/etc.clientlibs/fd/af/runtime/clientlibs/…-0e68c77e7c186891ab6c48488deeaa47-lc.min.js

js coca-cola.com collected 2026-09-24 08:24:21 UTC 1,537,052 bytes, 38,105 lines download raw bytes

1/*
2 * ADOBE CONFIDENTIAL
3 *
4 * Copyright 2024 Adobe Systems Incorporated
5 * All Rights Reserved.
6 *
7 * NOTICE:  All information contained herein is, and remains
8 * the property of Adobe Systems Incorporated and its suppliers,
9 * if any.  The intellectual and technical concepts contained
10 * herein are proprietary to Adobe Systems Incorporated and its
11 * suppliers and may be covered by U.S. and Foreign Patents,
12 * patents in process, and are protected by trade secret or copyright law.
13 * Dissemination of this information or reproduction of this material
14 * is strictly forbidden unless prior written permission is obtained
15 * from Adobe Systems Incorporated.
16 *
17 */
18(function() {
19    "use strict";
20    window.af = window.af || {};
21
22    function waitForRumInitialization() {
23        return new Promise(function(resolve, reject){
24            var timeout = 10000; // 10 seconds
25            var startTime = Date.now();
26            function checkSampleRUM() {
27                // only execute forms runtime FT check if sampleRUM is defined via SITES FT
28                // adding check for forms specific feature toggle for RUM
29                if (window.hlx && window.hlx.sampleRUM) {
30                    resolve(window.hlx.sampleRUM);
31                } else if (Date.now() - startTime >= timeout) {
32                    // Reject the promise if the sampleRUM is not available within the timeout
33                    reject();
34                } else {
35                    // If the rum is not set, wait and check again
36                    setTimeout(checkSampleRUM, 50);
37                }
38            }
39            checkSampleRUM();
40        });
41    }
42    function initializeBridgeEvents(callback) {
43        var bridge;
44        var startTime = (new Date()).getTime();
45        // this is for AF v1
46        if (window.guideBridge !== undefined) {
47            bridge = window.guideBridge;
48            if ('_guide' in bridge && bridge._guide != null) {
49                callback(bridge, null, bridge._guide.jcrPath, startTime);
50            }
51        } else {
52            window.addEventListener("bridgeInitializeStart", function(event) {
53                bridge = event.detail.guideBridge;
54                // this is only for AF v1, since in v2 we wont know all AF's, instead we rely on "AF_FormContainerInitialized" event
55                if ('_guide' in bridge) {
56                    callback(bridge, null, null, startTime);
57                }
58            });
59        }
60        // this is for AF v2
61        document.addEventListener("AF_FormContainerInitialised", function(event) {
62            callback(bridge, event, null, startTime);
63        });
64    }
65
66    initializeBridgeEvents(function(bridge, e, _formContainerPath, startTime){
67        var containerState = {};
68        var CheckPoints = {
69            RENDER: "viewblock"
70        };
71
72        var formContainerPath = e ? e.detail.getPath() : _formContainerPath;
73        if (formContainerPath != null) {
74            containerState[formContainerPath] = {
75                submitted: false,
76                formPath: formContainerPath
77            };
78        }
79        bridge.connect(function() {
80            // special case for af v1
81            if (formContainerPath == null) {
82                formContainerPath = bridge._guide.jcrPath;
83                containerState[formContainerPath] = {
84                    submitted: false,
85                    formPath: formContainerPath
86                };
87            }
88
89             waitForRumInitialization().then(function(sampleRUM) {
90                 // form specific FT
91                if (window.FD && window.FD.isToggleEnabled("FT_FORMS-8965")) {
92                    var timeToFormInteractivity = ((new Date()).getTime() - startTime) / 1000;
93                    sampleRUM(CheckPoints.RENDER,
94                        {
95                            source: ".form",
96                            target: bridge._guide != null ? "foundation" : "core",
97                        }
98                    );
99                }
100            })
101            .catch(function() {
102                // Handle the rejection without logging any error
103            });
104        }, null, formContainerPath);
105    });
106
107
108    // Attach functions to the window namespace
109    window.af.waitForRumInitialization = waitForRumInitialization;
110
111})();
112
113/*
114 * ***********************************************************************
115 * ADOBE CONFIDENTIAL
116 * __________________
117 *
118 * Copyright 2015 Adobe Systems Incorporated
119 * All Rights Reserved.
120 *
121 * NOTICE:  All information contained herein is, and remains
122 * the property of Adobe Systems Incorporated and its suppliers,
123 * if any.  The intellectual and technical concepts contained
124 * herein are proprietary to Adobe Systems Incorporated and its
125 * suppliers and may be covered by U.S. and Foreign Patents,
126 * patents in process, and are protected by trade secret or copyright law.
127 * Dissemination of this information or reproduction of this material
128 * is strictly forbidden unless prior written permission is obtained
129 * from Adobe Systems Incorporated.
130 * ***********************************************************************
131 */
132
133(function ($) {
134    $.uaMatch = function( ua ) {
135        ua = ua.toLowerCase();
136        var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
137            /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
138            /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
139            /(msie) ([\w.]+)/.exec( ua ) ||
140            ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || [];
141        return {
142            browser: match[ 1 ] || "",
143            version: match[ 2 ] || "0"
144        };
145    };
146    // Not clobbering any existing $.browser
147    if ( !$.browser ) {
148        var
149            matched = $.uaMatch( navigator.userAgent ),
150            browser = {};
151        if ( matched.browser ) {
152            browser[ matched.browser ] = true;
153            browser.version = matched.version;
154        }
155        // Chrome is Webkit, but Webkit is also Safari.
156        if ( browser.chrome ) {
157            browser.webkit = true;
158        } else if ( browser.webkit ) {
159            browser.safari = true;
160        }
161        $.browser = browser;
162    }
163})($);
164/*************************************************************************
165 * ADOBE CONFIDENTIAL
166 * ___________________
167 *
168 *  Copyright 2013 Adobe Systems Incorporated
169 *  All Rights Reserved.
170 *
171 * NOTICE:  All information contained herein is, and remains
172 * the property of Adobe Systems Incorporated and its suppliers,
173 * if any.  The intellectual and technical concepts contained
174 * herein are proprietary to Adobe Systems Incorporated and its
175 * suppliers and are protected by all applicable intellectual property
176 * laws, including trade secret and copyright laws.
177 * Dissemination of this information or reproduction of this material
178 * is strictly forbidden unless prior written permission is obtained
179 * from Adobe Systems Incorporated.
180 **************************************************************************/
181
182
183/**
184 * @package xfalib.ut.Class
185 */
186(function(_, xfalib){
187
188    xfalib.ns = xfalib.ns || function (namespaceString) {
189        var parts = namespaceString.split('.'),
190            parent = window,
191            currentPart = '';
192
193        for(var i = 0, length = parts.length; i < length; i++) {
194            currentPart = parts[i];
195            parent[currentPart] = parent[currentPart] || {};
196            parent = parent[currentPart];
197        }
198
199        return parent;
200    };
201
202    var Class = xfalib.ut.Class = function(options) {
203        this.options = _.extend({}, this.options, options);
204        if(!this.options.jsonModel)
205            this.options.jsonModel = {};
206        //For perf reason, we are setting jsonModel as direct property instead of using property descriptor
207        this.jsonModel = this.options.jsonModel;
208        this.initialize.apply(this, arguments);
209    };
210
211    _.extend(Class.prototype, {
212        initialize : function(){
213        },
214
215        xfaUtil :function(){
216          return xfalib.ut.XfaUtil.prototype;
217        },
218
219        copyArray : function(src,dst,options) {
220            var keepReference = this.getOrElse(options, "keepReference", true);
221            if(src instanceof Array)
222            {
223                for (var i = 0;i<src.length;i++)
224                {
225                    var obj;
226                    if(src[i] instanceof Array)
227                    {
228                        obj = this._createDestination(dst, i, keepReference, []);
229                        this.copyArray(src[i],obj,options);
230                    }
231                    else if(typeof src[i] == "object")
232                    {
233                        obj = this._createDestination(dst, i, keepReference, {});
234                        this.copyObject(src[i],obj,options);
235                    } else {
236                        obj = src[i];
237                    }
238                    dst[i] = obj;
239                }
240                if(dst.length > src.length){
241                    dst.splice(src.length, (dst.length - src.length));  //Remove ths rest of the extra destination items
242                }
243            }
244        },
245
246        /**
247         *
248         * @param src
249         * @param dst
250         * @param options e.g. {keepReference: true, exceptions:["htmlId"], transformMaps: {"dataId", function(src, options){ return src "33"+src; }}}
251         */
252        copyObject : function(src,dst,options) {
253            var keepReference = this.getOrElse(options, "keepReference", true);
254            var exceptions = this.getOrElse(options, "exceptions", []);
255            var transformMaps = this.getOrElse(options, "transformMaps", {});
256            if(typeof src == "object") {
257                for (var child in src) {
258                    if(exceptions.indexOf(child) == -1) {
259                        if(src[child] instanceof Array) {
260                            dst[child] = this._createDestination(dst, child, keepReference, []);
261                            this.copyArray(src[child],dst[child],options);
262                        }
263                        else if(typeof src[child] == "object" && src[child] != null) {
264                            dst[child] = this._createDestination(dst, child, keepReference, {});
265                            this.copyObject(src[child],dst[child],options);
266                        }
267                        else{
268                            if(!_.isUndefined(transformMaps[child])){
269                                dst[child] = transformMaps[child](src[child], options, src);
270                            }
271                            else
272                                dst[child] = src[child];
273                        }
274                    }
275                }
276            }
277        },
278
279        _createDestination : function(obj, property, keepReference, defaultValue) {
280            if(!keepReference)
281                return defaultValue;
282            else if(_.isObject(obj) && !obj.hasOwnProperty(property))
283                return defaultValue;
284            else
285                return obj[property] || defaultValue ;  //Would handle both, Array and objects
286        },
287
288        /**
289         * will replace functions in the object with noop function based on a predicate function's result.
290         * If no predicate is passed all functions will be disabled.
291         * Warning once disabled object cant be re-enabled.
292         *
293         * sample predicate to disable all 'public' functions : function (funcName) { return funcName[0] != '_'}
294         *
295         * @param predicate
296         * @private
297         */
298        _disableFunctions: function (predicate) {
299            var noop = function () {},
300                disableAll = !_.isFunction(predicate);
301
302            _.each(_.functions(this), function (funcName) {
303                if (disableAll || predicate(funcName)) {
304                    this[funcName] = noop;
305                }
306            }, this);
307        },
308
309        /**
310         * getOrElse can take multiple arguments.
311         * arg1(obj): base Object
312         * arg2: string representing property chain where properties are concatenated via dot
313         * arg3: default value
314         **/
315
316        getOrElse : function(obj){
317            var currObject = obj;
318            if(arguments.length < 2)
319                return currObject;
320            else if(arguments.length == 2) {
321                if(!_.isUndefined(currObject)){
322                    return currObject;
323                } else {
324                    return _.clone(arguments[1]);
325                }
326            }
327            else {
328                var propChain = (arguments[1] || "").split(".");
329                var defaultValue = arguments[2];
330                _.each(propChain, function(prop){
331                    if(_.isObject(currObject))
332                        currObject = currObject[prop];
333                    else
334                        currObject = undefined;
335                }, this);
336
337                if(!_.isUndefined(currObject))
338                    return currObject;
339                else {
340                    return _.clone(defaultValue) ; //May have to do deep clone in future. TODO: support for conditional clone
341                }
342            }
343        },
344
345        jqId: function (id) {
346            return xfalib.ut.XfaUtil.prototype.jqId(id);
347        },
348
349        logger : function(){
350            return this.xfaUtil().getLogger();
351        },
352
353        validateInput : function(param, dataType,fallback){
354        	if(typeof param !== "undefined" && param !== null) {
355        		switch(dataType) {
356        		case "string":
357        			param = param+"";
358        			break;
359        		case "object":
360        			if(typeof param !== "object")
361        				param = fallback;
362        			break;
363        	    case "integer":
364                    param = parseInt(param);
365                    if(isNaN(param))
366                        param = fallback;
367                    break;
368               case "measurement":
369                     break;
370        		default:
371        			if(dataType instanceof Array) {
372                        if(!~dataType.indexOf(param))
373                            param = fallback
374                    }
375        		}
376        	}
377        	return param;
378        }
379
380    });
381
382    _.extend(Class, {
383        defineProps : function(propsMap){
384            _.each(propsMap, function(propDesc, propName){
385                //Check property can be resolved using resolveNode
386                if(propDesc.resolve) {
387                    //Check whether prototype owns the object resolveProperties
388                    if(!this.prototype.hasOwnProperty("resolveProperties")) {
389                        //check whether prototype inherits the object resolveProperties
390                        if(this.prototype.resolveProperties) {
391                            //clone the object since we do not want to modify parent's prototype
392                            this.prototype.resolveProperties = _.clone(this.prototype.resolveProperties);
393                        }
394                        else
395                            this.prototype.resolveProperties = [];
396                    }
397                    this.prototype.resolveProperties.push(propName)
398                }
399                Object.defineProperty(this.prototype, propName, propDesc);
400
401            }, this);
402        },
403        extend : function(props){
404            var child = inherits(this, props);
405            child.extend = this.extend;
406            return child;
407        },
408        addMixins : function(mixinBakers){
409            if(!_.isArray(mixinBakers)){
410                mixinBakers = [mixinBakers];
411            }
412            _.each(mixinBakers, function(mixinBaker){
413                if(mixinBaker.normalProperties){
414                    _.extend(this.prototype, mixinBaker.normalProperties);
415                }
416                if(mixinBaker.propertyDescriptors){
417                    this.defineProps(mixinBaker.propertyDescriptors);
418                }
419            }, this);
420        }
421    });
422
423    // Shared empty constructor function to aid in prototype-chain creation.
424    var ctor = function(){};
425
426    // Helper function to correctly set up the prototype chain, for subclasses.
427    // Similar to `goog.inherits`, but uses a hash of prototype properties and
428    // class properties to be extended.
429    function inherits(parent, protoProps, staticProps) {
430        var child;
431        var _super = parent.prototype;
432        // The constructor function for the new subclass is either defined by you
433        // (the "constructor" property in your `extend` definition), or defaulted
434        // by us to simply call the parent's constructor.
435        if (protoProps && protoProps.hasOwnProperty('constructor')) {
436            child = protoProps.constructor;
437        } else {
438            child = function(){ parent.apply(this, arguments); };
439        }
440
441        // Inherit class (static) properties from parent.
442        _.extend(child, parent);
443
444        // Set the prototype chain to inherit from `parent`, without calling
445        // `parent`'s constructor function.
446        ctor.prototype = parent.prototype;
447        child.prototype = new ctor();
448        child._super = parent.prototype;
449        child._superClass = parent;
450
451        // Add prototype properties (instance properties) to the subclass,
452        // if supplied.
453        if (protoProps) { //_.extend(child.prototype, protoProps);
454            // Copy the properties over onto the new prototype
455            for (var name in protoProps) {
456                if(name == "_defaults"){
457                    protoProps[name] = _.extend({}, _super[name], protoProps[name]);
458                }
459                child.prototype[name] = protoProps[name];
460            }
461        }
462
463
464        // Add static properties to the constructor function, if supplied.
465        if (staticProps) _.extend(child, staticProps);
466
467        // Correctly set child's `prototype.constructor`.
468        child.prototype.constructor = child;
469
470        // Set a convenience property in case the parent's prototype is needed later.
471        child.__super__ = parent.prototype;
472
473        return child;
474    };
475})(_, window.xfalib);
476/**
477 * Created by vdua on 2/18/2015.
478 */
479(function (_, xfalib) {
480    var XMLUtils = {
481        dataSom2xpath: function (dataSom) {
482            var xpath = "";
483
484            if (!_.isEmpty(dataSom)) {
485                // any dot preceded by ], takes care of dot-s in name,
486                // and remove constant prefix "xfa[0].datasets[0].data[0]" and form root name, then join using '/'
487                _.each(dataSom.split(/\]\./).slice(4),
488                    function (part) {
489                        var openBracketPos = part.lastIndexOf('[');
490                        xpath += part.substring(0, openBracketPos + 1) +
491                            (parseInt(part.substring(openBracketPos + 1)) + 1) + // increment index by 1 for xpath query
492                            "]/";
493                    });
494
495                if (_.isEmpty(xpath)) {
496                    xpath = dataSom;
497                } else if (xpath[xpath.length - 1] === '/') {
498                    xpath = xpath.slice(0, -1);
499                }
500            }
501
502            return xpath;
503        },
504
505        /**
506         * Converts an xPathResult of type iterator to an array
507         * @param xPathResult
508         * @returns {Array}
509         */
510        iteratorToArray: function (xPathResult) {
511            var result = [];
512            // in some browsers, if xpath is invalid xPath result is null whereas some browsers return XpathResult with empty iterator
513            var node = xPathResult ? xPathResult.iterateNext() : null;
514            while (node != null) {
515                result.push(node);
516                node = xPathResult.iterateNext();
517            }
518            return result;
519        },
520        /**
521         * Wrapper API for document.evaluate to provide cross-browser support.
522         * @param xpath
523         * @param node
524         * @param nsResolver
525         * @param resultType
526         * @param result
527         * @returns {Object|*}
528         */
529        evaluateXPath: function (xpath, node, nsResolver, resultType, result) {
530            try {
531                if(_.isEmpty(xpath) || !_.isString(xpath) || !(node instanceof Node)) {
532                    return null;
533                }
534
535                // Determine the appropriate document context for searching.
536                var searchContext = node instanceof Document ? node : node.ownerDocument;
537                // Check if the document.evaluate function is undefined or if we're in a server-side context.
538                var isEvaluateUndefined = typeof searchContext.evaluate === 'undefined';
539                var isServerSide = window.guideBridge && window.guideBridge.hostName === "server";
540                var needsXPathPolyfill = isEvaluateUndefined || isServerSide;
541                if (needsXPathPolyfill) {
542                    // Install the wgxpath polyfill to provide evaluate functionality.
543                    wgxpath.install(window, true);
544                    // Assign the newly installed evaluate function to the search context.
545                    searchContext.evaluate = window.document.evaluate;
546                }
547
548                var documentToEval = searchContext.evaluate ? searchContext : document;
549                xpath = this.sanitizeXPath(xpath);
550
551                return documentToEval.evaluate(xpath, node, nsResolver, resultType, result);
552
553            } catch (exception) {
554                xfalib.ut.XfaUtil.prototype.getLogger().error("Could not evaluate xpath: " + xpath  + exception);
555
556            }
557
558        },
559         /**
560         *Removes all [*] other than ['numeric'] from xpath
561         *@param xpath
562         *@returns xpath after removing "[*]"
563         */
564         sanitizeXPath: function(xpath) {
565             var xpathArray=xpath.split("/"),
566                 resultXpath = _.map(xpathArray, function (path) {
567                 return path.replace(/\[(.*\D+.*)\]|\[\]/g,"");
568             }).join("/");
569             return resultXpath;
570         },
571
572        /**
573         * Creates all the Elements (if they don't exist) in the xpath leading to the node being searched for in the
574         * xpath relative to the element. Optionally creates the node as well if bParentsOnly is false
575         * @param xpath
576         * @param element
577         * @param bParentsOnly whether to create only the parents or the node as well
578         * @returns node that is being represented by the xpath relative to the element.
579         */
580        createElementsFromXPath: function (xpath, element, bParentsOnly) {
581            if (xpath != null || element != null) {
582                var parts = xpath.split("/"),
583                    actualParts = bParentsOnly ? _.initial(parts) : parts,
584                    el = element;
585                _.each(actualParts, function (part, index) {
586                    var som = part.match(/^([^[]+)(\[(\d+)\])?/),
587                        childEl;
588                    if (som == null) {
589                        xfalib.ut.XfaUtil.prototype.getLogger().error("Unsupported expression in Bindref " + part);
590                        return null;
591                    }
592                    //only the last element can be attribute
593                    childEl = this.findOrCreateElement(part, el, index === actualParts.length - 1);
594                    el = childEl;
595                }, this);
596                return el;
597            }
598            return null;
599        },
600
601        /**
602         * Form an xpath part returns the index as well as the tagName. Index can be * as well
603         * @param xpathName
604         * @returns {*}
605         * @private
606         */
607        _getElementNameAndIndexFromXPathPart: function (xpathName) {
608            var som  =  xpathName.match(/^([^[]+)(?:\[(\d+|\*)\])?/);
609            if (som !== null) {
610                return {
611                    name: som[1],
612                    index: som[2] || 0
613                };
614            }
615            return null;
616        },
617
618        /**
619         * create an element with the tagName elementName for the ownerDocument of element.
620         * @param elementName
621         * @param element
622         * @returns {HTMLElement}
623         */
624        createElement: function (elementName, element) {
625            var el = element.ownerDocument.createElement(elementName);
626            return el;
627        },
628
629        /**
630         * Searches for the nodeXpath relative to element. If it doesn't exists creates it and returns the node
631         * @param element
632         * @param nodeXpath
633         * @param bAttribute if true then check for attribute otherwise not.
634         * @returns {Node|*}
635         */
636        findOrCreateElement: function (nodeXpath, element, bAttribute) {
637            try {
638                if (element == null) {
639                    return null;
640                }
641                var result = this.evaluateXPath(nodeXpath, element, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null),
642                    el = result.iterateNext(),
643                    res;
644                if (el == null) {
645                    res = this._getElementNameAndIndexFromXPathPart(nodeXpath);
646                    if (res != null) {
647                        if (bAttribute && res.name.match(/^@/)) {
648                            var attrName = res.name.replace(/^@/, "");
649                            el = element.ownerDocument.createAttribute(attrName);
650                            element.setAttributeNode(el);
651                        } else {
652                            el = element.ownerDocument.createElement(res.name);
653                            element.appendChild(el);
654                        }
655                    }
656                }
657                return el;
658
659            } catch (exception) {
660                xfalib.ut.XfaUtil.prototype.getLogger().error("Following exception "
661                    +  "occurred while executing findOrCreateElement " + exception);
662            }
663
664        },
665
666        /**
667         * Returns the Root Form Elment from the xmlDocumentElement
668         * @param xmlDocumentElement It can be a document or Element. If the root element is xdp element, it returns
669         *        the grand grand child of that element. otherwise the root element is returned. The root
670         *        Element can be either the element itself or documentElement of the element.
671         */
672        getXFARootFormElementFromXML: function (xmlDocumentElement) {
673            if(_.isUndefined(document.evaluate)) {
674                wgxpath.install();
675            }
676            var isElement = xmlDocumentElement instanceof Element,
677                docElemName = isElement ? xmlDocumentElement.nodeName : xmlDocumentElement.documentElement.nodeName,
678                rootElement = isElement ? xmlDocumentElement : xmlDocumentElement.documentElement,
679                nodeList;
680
681            if ("xdp:xdp" === docElemName || "xdp" === docElemName) {
682                if (xfalib.ut.XfaUtil.prototype.isIE()) {
683                    //IE doesn't support evaluating namespace elements
684                    var datasets = rootElement.firstElementChild,
685                        data = datasets.firstElementChild;
686                    rootElement = data.firstElementChild;
687                } else {
688                    // assumption is that the xml will be of format <xdp><datasets><data><form1>
689                    // TODO: change first * to xfa:datasets
690                    nodeList = this.evaluateXPath("*/xfa:data/*", rootElement, formBridge.nsResolver,
691                                            XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
692                    rootElement = nodeList.iterateNext();
693                }
694            }
695            return rootElement;
696        },
697
698        /**
699         * Returns an object containing the prefix and namespaces present in the rootElement. For default namespace the
700         * prefix is "_default"
701         * @param rootElement {Element} xml element which has to be looked for namespaces
702         * @returns {object} object whose keys are the prefix and values are the namespace
703         */
704        getNamespaces: function (rootElement) {
705            var namespaces = {
706                "_default" : null
707            };
708            _.each(rootElement.attributes, function (attr) {
709                var name = attr.name,
710                    parsedAttrName = name.match(/^xmlns(?:\:(.*))?/),
711                    isNamespace = parsedAttrName != null,
712                    namespaceName = isNamespace ? parsedAttrName[1] || "_default" : null;
713                if (namespaceName) {
714                    namespaces[namespaceName] = attr.value;
715                }
716            });
717            return namespaces;
718        },
719
720        /**
721         * Returns a namespace resolver given a element. The nsResolver returns the namespace given a prefix by
722         * using the namespaces mentioned in the element.
723         * @param rootElement element from which to create the nsResolver
724         * @returns {function} the function returns the namespace given a prefix.
725         */
726        getNsResolver: function (rootElement) {
727            var namespaces = this.getNamespaces(rootElement),
728                nsResolver = (function (namespaces) {
729                    return function (nsPrefix) {
730                        var namespace = formBridge.nsResolver(nsPrefix) || namespaces[nsPrefix];
731                        return namespace;
732                    };
733                }(namespaces));
734            return nsResolver;
735        },
736
737        /**
738         * Removes default namespaces from xml, basically the namespace defined as xmlns="some namespace". The
739         * side-effect of the API is it removes the string "xmlns='some namespace'" from any attribute value as well.
740         * @param xml {string}
741         * @returns {string}
742         */
743        removeDefaultNamespace: function (xml) {
744            var stringRegex = "(\\s+)" + // any number of spaces
745                             "(xmlns=" + // then xmlns=
746                            "('[^']*'|\"[^\"]*\"))" + // then value in single quotes ('[^']') or
747                                                    //                 double quotes ("[^"]")
748                            "(?=[^<>]*>)",  // followed by closing tag (implies attribute) and before another
749                                           // opening tag(implies text)
750                regex = new RegExp(stringRegex, "g");
751            return xml.replace(regex, "$1");
752        }
753    };
754    xfalib.ut.XMLUtils = XMLUtils;
755}(_, xfalib));
756/**
757 * @package xfalib.ut.Logger
758 * @import xfalib.ut.Class
759 */
760
761(function(_, xfalib, $){
762    var categoryAcronyms = {
763                            "a": "xfa",
764                            "b": "xfaView",
765                            "c": "xfaPerf"
766        },
767        loggerTypes = ["off", "console", "server", "consoleServer"];
768    var Logger = xfalib.ut.Logger = xfalib.ut.Class.extend({
769
770//      Count of log messages so far.
771        LOG_COUNT : {
772            level : {
773                "FATAL" : 0,
774                "ERROR" : 0,
775                "WARN" : 0,
776                "INFO" : 0,
777                "DEBUG" : 0,
778                "TRACE" : 0,
779                "ALL" : 0
780            },
781            category : {
782                "xfa" : 0,
783                "xfaView" : 0,
784                "xfaPerf" : 0,
785                "Unknown" : 0
786           }
787        },
788
789        /**
790         * Log level to turn logging off (default).
791         * @static
792         * @final
793         * @type Number
794         */
795        OFF : 0,
796
797        /**
798         * Log level for fatal error messages.
799         * @static
800         * @final
801         * @type Number
802         */
803        FATAL : 1,
804
805        /**
806         * Log level for error messages.
807         * @static
808         * @type Number
809         * @final
810         */
811        ERROR : 2,
812
813        /**
814         * Log level for warning messages.
815         * @static
816         * @type Number
817         * @final
818         */
819        WARN : 3,
820
821        /**
822         * Log level for info messages.
823         * @static
824         * @type Number
825         * @final
826         */
827        INFO : 4,
828
829        /**
830         * Log level for debug messages.
831         * @static
832         * @type Number
833         * @final
834         */
835        DEBUG : 5,
836
837        /**
838         * Log level for trace messages.
839         * @static
840         * @type Number
841         * @final
842         */
843        TRACE : 6,
844
845        /**
846         * Log level for all messages.
847         * @static
848         * @type Number
849         * @final
850         */
851        ALL : 7,
852
853
854        logLevelNames : ["OFF", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", "ALL"],
855
856        initialize : function(){
857            var str = "",
858                that =this;
859            Logger._super.initialize.call(this);
860            this.logs = {};
861            this.logMessages = "";
862            this.logServiceProxy = this.options.logServiceProxy;
863            this.contextPath = this.options.contextPath;
864            this.renderContext =  this.options.renderContext;
865            if(this.jsonModel.logConfigString) {
866                _.extend(this.jsonModel, this.parse(this.jsonModel.logConfigString));
867            }
868            _.each(this.jsonModel.category, function(category) {
869                that.LOG_COUNT.category[category] = 0;
870            })
871        },
872
873        /**
874         * parses a log config string of the form <0,1,2,3>-<category string><level integer>-<category string><level integer>..
875         * and returns an a config object that logger uses. The function is a private and not to be called outside
876         * this function
877         *
878         * category can not contain numbers and only valid characters are a-zA-Z
879         * level can be any integer.
880         *
881         * category string is converted into actual category for the logger by using default categoryAcronyms
882         * [a : xfa, b: xfaView, c: xfaPerf} and the categoryAcronyms passed to the options while instantiating the
883         * object. If not found in both the acronyms then the value category string is used as actual category
884         *
885         * For example for the input string 1-a9-b9-c9 return object is
886         * {on: true, category: [xfa,xfaView, xfaPerf], level: [9, 9, 9], type: console}
887         *
888         * For the input string 1-a9-b9-c9-d9-e11 with options.categoryAcronyms {a:a, d:AF} return object is
889         * {on: true, category: [xfa,xfaView, xfaPerf, AF, e], level: [9, 9, 9, 9, 11], type: console}
890         */
891        parse : function(configString) {
892            var arr = configString.split("-"),
893                logType = _.first(arr),
894                logConfig = _.rest(arr),
895                res = {
896                    on: logType === "0" ? "false": "true",
897                    category: [],
898                    level:[],
899                    type:loggerTypes[parseInt(logType)]
900                };
901           _.each(logConfig, function(item, index) {
902                var config = item.match(/^([A-Za-z]+)(\d+)$/),
903                    category;
904                if (config && config.length === 3) {
905                    category = this.getOrElse(categoryAcronyms, config[1],
906                                    this.getOrElse(this.jsonModel, "categoryAcronyms." + config[1], config[1]));
907                    res.category.push(category);
908                    res.level.push(parseInt(config[2]));
909                } else {
910                    //calling this because logger is not initialized as of now
911                    this.consoleHandler(this.resolveMessage(xfalib.locale.LogMessages["ALC-FRM-901-020"],
912                                                    [item, configString]))
913                }
914            }, this);
915            return res;
916        },
917
918        /*
919         *
920         */
921        resolveMessage : function(message, snippets) {
922            snippets = snippets || [];
923            return message.replace(/{(\d+)}/g, function(match, number) {
924                return typeof snippets[number] != 'undefined'
925                    ? snippets[number]
926                    : match
927                    ;
928            });
929        },
930
931        /**
932         * Writes a message to the console.
933         * @private
934         * @param {Number} level The log level
935         * @param {String} message The log message
936         * @param {String/String[]} snippets (optional) The texts replacing
937         *        <code>{n}</code>
938         * @return The log message
939         * @type String
940         */
941        log : function(category, level, message, snippets) {
942            var d= new Date();
943            var day = d.getDate();
944            var month = d.getMonth() + 1;
945            var year = d.getFullYear();
946            var mili = d.getMilliseconds();
947            var sec = d.getSeconds();
948            var min = d.getMinutes();
949            var hour = d.getHours();
950            var date = day + "." + month + "." + year +" " + hour + ":" + min + ":" + sec + ":" + mili;
951            if(this.jsonModel && this.jsonModel.category) {
952                for(var i = 0; i<this.jsonModel.category.length; i++) {
953                    if (level != 0 && this.jsonModel.level[i] >= level && this.jsonModel.category[i] == category && this.jsonModel.on == "true") {
954
955                        var resolvedMessage = message;
956                        if(snippets){
957                            //resolve message with snippet
958                            resolvedMessage = this.resolveMessage(message, snippets);
959                        }
960
961                        var text = "";
962                        text += date ;
963                        text += " *" + this.logLevelNames[level] + "*";
964                        text += " [" +  category + "]" ;
965                        text += "  " + resolvedMessage + "\r\n" ;
966                        this.logMessages += text ;
967                        if(this.jsonModel.type == "console" || this.jsonModel.type == "consoleServer" ) {
968                            ++this.LOG_COUNT.category[category || 'Unknown'];
969                            ++this.LOG_COUNT.level[this.logLevelNames[parseInt(level) < 8? level:7]];
970                            this.consoleHandler(text, level);
971                        }
972                    }
973                }
974            }
975        },
976
977        consoleHandler : function(text, level){
978            if(typeof console != "undefined") {
979                var levelName = typeof this.logLevelNames[level] === "string"
980                    ? this.logLevelNames[level].toLowerCase()
981                    : "log",
982                    logFunction = console.log;
983                if (typeof console[levelName] === "function") {
984                    logFunction = console[levelName]
985                }
986                logFunction.call(console, "\n\n\n" + text);
987                //Error log already shows the call stack for debugging.
988                if(levelName !== "error") {
989                    try {
990                        n.test
991                    } catch (exception) {
992                        if (exception.stack) {
993                            logFunction.call(console, exception.stack.replace("ReferenceError: n is not defined", ""));
994                        }
995                    }
996                }
997            }
998
999        },
1000
1001        /*
1002         *  Helper function to ger submit service proxy url
1003         */
1004        _getLogServiceProxyUrl: function() {
1005            var logServiceProxyUrl = "";
1006            if(this.logServiceProxy)
1007                logServiceProxyUrl += this.logServiceProxy;
1008            else //finally hard code it
1009                logServiceProxyUrl += ((this.contextPath && this.contextPath != "/") ? this.contextPath : "") + "/libs/xfaforms/profiles/default.log.html";
1010            return logServiceProxyUrl;
1011        },
1012
1013        _invokeAtServer: function(options) {
1014            var localSubmitUrl =  this._getLogServiceProxyUrl();
1015            var params = {
1016                    async: true,
1017                    url: localSubmitUrl,
1018                    type: 'POST',
1019                    contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
1020                    data: options
1021                };
1022            $.ajax(params);
1023        },
1024
1025        isServerLoggingEnabled : function(){
1026            if((this.jsonModel.on == "true") && (this.jsonModel.type == "server" || this.jsonModel.type == "consoleServer"))
1027                return true;
1028            else
1029                return false;
1030        },
1031
1032        serverHandler :function() {
1033            var options = {'logMessages' : this.logMessages, 'renderContext' : this.renderContext};
1034            this._invokeAtServer(options);
1035            this.logMessages = "" ;
1036        },
1037
1038        /**
1039         * Writes a message to the console if log level is set to
1040         * {@link #FATAL} or higher.
1041         * @static
1042         * @param {String} message The log message
1043         * @param {String/String[]} snippets (optional) The texts replacing
1044         *        <code>{n}</code>
1045         */
1046        fatal : function(category, message, snippets) {
1047            this.log(category, this.FATAL, message, snippets);
1048        },
1049
1050        /**
1051         * Writes a message to the console if log level is set to
1052         * {@link #ERROR} or higher.
1053         * @static
1054         * @param {String} message The log message
1055         * @param {String/String[]} snippets (optional) The texts replacing
1056         *        <code>{n}</code>
1057         */
1058        error : function(category, message, snippets) {
1059            this.log(category, this.ERROR, message, snippets);
1060        },
1061
1062        /**
1063         * Writes a message to the console if log level is set to
1064         * {@link #WARN} or higher.
1065         * @static
1066         * @param {String} message The log message
1067         * @param {String/String[]} snippets (optional) The texts replacing
1068         *        <code>{n}</code>
1069         */
1070        warn : function(category, message, snippets) {
1071            this.log(category, this.WARN, message, snippets);
1072        },
1073
1074        /**
1075         * Writes a message to the console if log level is set to
1076         * {@link #INFO} or higher.
1077         * @static
1078         * @param {String} message The log message
1079         * @param {String/String[]} snippets (optional) The texts replacing
1080         *        <code>{n}</code>
1081         */
1082        info : function(category, message, snippets) {
1083            this.log(category, this.INFO, message, snippets);
1084        },
1085
1086        /**
1087         * Writes a message to the console if log level is set to
1088         * {@link #DEBUG} or higher.
1089         * @static
1090         * @param {String} message The log message
1091         * @param {String/String[]} snippets (optional) The texts replacing
1092         *        <code>{n}</code>
1093         */
1094        debug : function(category, message, snippets) {
1095            this.log(category, this.DEBUG, message, snippets);
1096        },
1097
1098        /**
1099         * Writes a message to the console if log level is set to
1100         * {@link #TRACE} or higher.
1101         * @static
1102         * @param {String} message The log message
1103         * @param {String/String[]} snippets (optional) The texts replacing
1104         *        <code>{n}</code>
1105         */
1106        trace :  function(category, message, snippets) {
1107            this.log(category, this.TRACE, message, snippets);
1108        },
1109
1110        isLogEnabled : function(category, level) {
1111            if(this.jsonModel.on == "true") {
1112                var pos = this.jsonModel.category.indexOf(category) ;
1113                if(this.jsonModel.level[pos] >= level)
1114                    return true;
1115            }
1116            return false;
1117        }
1118
1119    });
1120})(_, xfalib, $);
1121/**
1122 * @package xfalib.ut.EventClass
1123 * @import xfalib.ut.Class
1124 */
1125(function(_, xfalib){
1126    // Regular expression used to split event strings
1127    // Regular expression used to split event strings
1128    var eventSplitter = /\s+/;
1129
1130    // A module that can be mixed in to *any object* in order to provide it with
1131    // custom events. You may bind with `on` or remove with `off` callback functions
1132    // to an event; trigger`-ing an event fires all callbacks in succession.
1133    //
1134    var EventClass = xfalib.ut.EventClass =  xfalib.ut.Class.extend({
1135
1136        // Bind one or more space separated events, `events`, to a `listener`
1137        // object. The object should implement `handleEvent` function which will be
1138        // called on event dispatch
1139        on: function(event, listener, context) {
1140
1141            var calls, list,retVal = true;
1142            var fnCallback = _.isFunction(listener) ? listener : null;
1143            if (!listener || (!listener["handleEvent"] && !fnCallback)) return false;
1144
1145            calls = this._callbacks || (this._callbacks = {});
1146
1147            list = calls[event] || (calls[event] = []);
1148            if(fnCallback){
1149                context = context || this;
1150                var found = _.find(list, function(callback){
1151                    return (callback.fn == fnCallback && callback.context == context);
1152                }, this);
1153                if(found)
1154                    return false;
1155                else {
1156                    list.push({"fn" : fnCallback, "context": context});
1157                }
1158            }
1159            else{
1160                if(~list.indexOf(listener))
1161                    return false;
1162                else
1163                    list.push(listener);
1164            }
1165
1166            return  true;
1167        },
1168
1169        // Remove one or many callbacks. If `listener` is null, removes all listener for the
1170        // event. If `events` is null, removes all bound callbacks for all events.
1171        off: function(events, listener, context) {
1172            var event, calls, node;
1173
1174            // No events, or removing *all* events.
1175            if (!(calls = this._callbacks)) return;
1176            if (!(events || listener)) {
1177                delete this._callbacks;
1178                return this;
1179            }
1180
1181            var fnCallback = _.isFunction(listener) ? listener : null;
1182            // Loop through the listed events and contexts and remove the required ones.
1183            events = events ? events.split(eventSplitter) : _.keys(calls);
1184            while (event = events.shift()) {
1185                node = calls[event];
1186                calls[event] = _.filter(calls[event],function(elem) {
1187                    if(typeof(listener) !== "undefined"){
1188                        if(fnCallback && elem.fn == fnCallback && elem.context == context)
1189                            return false;
1190                        else if(!fnCallback && listener === elem)
1191                            return false;
1192                    }
1193                    else{
1194                        return false;
1195                    }
1196                    return true;
1197                });
1198                if(!calls[event].length)
1199                    delete calls[event];
1200            }
1201
1202            return this;
1203        },
1204
1205        // Trigger one or many events, firing all bound callbacks. Callbacks are
1206        // passed the same arguments as `trigger` except the first
1207        trigger: function(events) {
1208            var event, calls, rest;
1209            if (!(calls = this._callbacks)) return this;
1210            events = events.split(eventSplitter);
1211            var payLoad = _.rest(arguments);
1212            while (event = events.shift()) {
1213                _.each(calls[event],function(callback) {
1214                    if(callback.fn && callback.context){
1215                        callback.fn.apply(callback.context, payLoad);
1216                    }
1217                    else if (_.isFunction(callback.handleEvent)){
1218                        callback.handleEvent.apply(callback, payLoad);
1219                    }
1220                });
1221            }
1222
1223            return this;
1224        }
1225
1226    });
1227
1228
1229})(_, xfalib);
1230
1231
1232(function (_, $, xfalib) {
1233    var XfaUtil = xfalib.ut.XfaUtil = function () {
1234        },
1235        registeredLocaleProperties = null,
1236        timeoutListenerAttached = false,
1237        timeouts = [],
1238        attachClearTimeoutListener = function (timeout) {
1239            timeouts.push(timeout);
1240            if (timeoutListenerAttached === false) {
1241                $(window).one("destroy.xfa", function () {
1242                    _.each(timeouts, function (_timeout) {
1243                        clearTimeout(_timeout);
1244                    });
1245                    timeouts = [];
1246                    timeoutListenerAttached = false;
1247                });
1248                timeoutListenerAttached = true;
1249            }
1250        };
1251    _.extend(XfaUtil.prototype, {
1252        _globalUniqueId: (new Date()).getTime(),
1253        logger: null,
1254
1255        formScaleFactor: 1,      // used to appropriately scale the form when contained inside an iframe
1256
1257        getOrElse: xfalib.ut.Class.prototype.getOrElse,
1258        //map of event names between XTG and Mobile Form
1259        //Mobile Form uses different names for some the event and let's fix those names before sending them to XTG.
1260        _xtgEventName: {
1261            "$formready": "ready",
1262            "$layoutready": "ready"
1263        },
1264
1265        generateUID: function () {
1266            return "UID" + (++XfaUtil.prototype._globalUniqueId);
1267        },
1268
1269        matchJsonType: function (jsonModel, _class) {   //TODO: handle getOrElse
1270            return (jsonModel && _class && XfaUtil.prototype.getOrElse(jsonModel._class, "").toLowerCase() == ("" + _class).toLowerCase());
1271        },
1272
1273        $data: function (elem, name, data) {
1274            if (!$.data(elem, "_xfaInitialized")) {
1275                //Initialized data- attributes parse for once using this call.
1276                // Next onward don't use this. Instead use $.data which is cheap/
1277                $(elem).data();
1278                $.data(elem, "_xfaInitialized", true); //Mark the element to say that data has been initialized.
1279            }
1280            return $.data(elem, name, data);
1281        },
1282
1283        /*
1284         * alternative to jQuery.css which sets style properties directly through element.style. This is much faster then
1285         * corresponding jQuery.css alternative.
1286         *
1287         * Warning: this only supports standard css property names and does not do any pre-processing of name and value.
1288         * So calling this, make sure the style names are compatible.
1289         */
1290        $css: function (elem, stylesObj) {
1291            // Exclude the following css properties to add px. copied from jquery.cssNumber to add hyphenated style names
1292            var cssNumber = {
1293                "fillOpacity": true,
1294                "fill-opacity": true,
1295                "fontWeight": true,
1296                "font-weight": true,
1297                "lineHeight": true,
1298                "line-height": true,
1299                "zIndex": true,
1300                "z-index": true,
1301                "opacity": true,
1302                "orphans": true,
1303                "widows": true,
1304                "zoom": true
1305            };
1306
1307            for (var prop in stylesObj) {
1308                var value = stylesObj[prop];
1309                // If a number was passed in, add 'px' to the (except for certain CSS properties)
1310                if (_.isNumber(value) && !cssNumber[ prop ]) {
1311                    value += "px";
1312                }
1313                elem.style[prop] = value;
1314            }
1315        },
1316
1317        isTableHF: function (iChildNode) {
1318            //model can be a Node object or simply a json
1319            var assistJson = _.find(iChildNode.children, function (jChild) {
1320                return jChild._class == "assist";
1321            }, this);
1322            var childRole = (assistJson || {}).role;
1323            if (childRole == "TH" || childRole == "TF")
1324                return true;
1325            else
1326                return false;
1327        },
1328
1329        getUiOneOfChildTag: function (uiParent) {
1330            var uiEl = _.find(uiParent.children, function (child) {
1331                return child._class == "ui";
1332            });
1333            if (!uiEl)
1334                return undefined;
1335            var uiOneOfChildMap = xfalib.runtime.xfa._templateSchema._getOneOfChild("ui");
1336            var uiOneOfChild = _.find(uiEl.children, function (child) {
1337                return uiOneOfChildMap[child._class] == true;
1338            });
1339            if (!uiOneOfChild)
1340                return undefined;
1341            return uiOneOfChild._class;
1342        },
1343
1344        //TODO: this should be removed. One of the worst function.
1345        dIndexOf: function (searchArray, item2Find) {
1346            var ind = -1;
1347            _.find(searchArray, function (item, index) {
1348                return item == item2Find && (ind = index)
1349            });
1350            return ind;
1351        },
1352
1353        splitStringByWidth: function (value, width, refEl) {
1354            var i = value.length , expectedWidth;
1355            do {
1356                expectedWidth = xfalib.view.util.TextMetrics.measureExtent(value.slice(0, i), {"refEl": refEl, maxWidth: -1}).width;
1357                i--;
1358            } while (expectedWidth > width)
1359            if (i != value.length - 1)
1360                return value.slice(0, i + 1);
1361            return value;
1362        },
1363
1364        isRepeatabeEl: function (elTag) {
1365            if (elTag == "subform" || elTag == "subformSet")
1366                return true;
1367            else
1368                return false;
1369        },
1370
1371        /**
1372         * @function
1373         * stripOrCall(toStrip, diffFunc, fArgs)
1374         * @description
1375         * common utility function to handle final submission payload stripping
1376         * @param {bool} toStrip : flag to signify whether to optimize jsonModelDiff size, by stripping off unnecessary properties
1377         * @param {function} diffFunc : callback func. call in case submit is not on
1378         * @param {Array} fArgs : arguments to be passed to the diff func.
1379         * @returns {object} object containing the jsonDiff
1380         */
1381        // should ALWAYS be called with a flag signifying if a submission is in progress,
1382        // and a callback function to compute the json to be sent back during submission, usually an apt '_computeJsonDiff'
1383        stripOrCall: function (toStrip, diffFunc, fArgs) {
1384            if (toStrip) {
1385                return {
1386                    "changed": false,
1387                    "jsonDifference": {}
1388                };
1389            }
1390            else if (_.isFunction(diffFunc)) {
1391                return diffFunc.apply(this, fArgs);
1392            }
1393        },
1394
1395        /**
1396         * @function
1397         * partialStripOrCall(stripLvl, diffFunc, fArgs)
1398         * @description
1399         * common utility function to handle final submission payload stripping or for output of getFormState.
1400         * @param {int} diff_level : flag to signify whether to optimize jsonModelDiff size, by stripping off unnecessary properties
1401         *                        must be 0,1, or 2, as with "diff_level" param of _computeJsonDiff.
1402         * @param {function} diffFunc : callback func. call in case submit is not on
1403         * @returns {object}
1403 object containing the jsonDiff
1404         */
1405        partialStripOrCall: function (diff_level, diffFunc) {
1406            var diffObj = diffFunc.call(this, diff_level);
1407
1408            if (!diffObj.changed) {
1409                if(diff_level === 1) {
1410                    diffObj = {
1411                        "changed": true,
1412                        "jsonDifference": {
1413                            "_class": this.jsonModel._class,
1414                            "name": this.jsonModel.name
1415                        }
1416                    };
1417                } else {
1418                    diffObj.jsonDifference = {};  // don't need stuff for other cases
1419                }
1420            }
1421
1422            return diffObj;
1423        },
1424
1425        /**
1426         * @function
1427         * stripObject(obj, exceptionNames)
1428         * @description
1429         * Utility function to strip unnecessary properties from an object
1430         * @param {object} obj : the object to strip
1431         * @param {Array} exceptionNames : array holding names of important properties to preserve
1432         * @returns {boolean} : true if this obj, or any of it's descendant is returned un-stripped
1433         */
1434        stripObject: function (obj, exceptionNames) {
1435            if (_.isEmpty(obj) || !_.isObject(obj)) {
1436                return true;
1437            } else {
1438                var dontStrip = false;
1439                _.each(_.keys(obj), function (propName) {
1440                    var keepProp = false;
1441                    if (!_.contains(exceptionNames, propName)) {
1442                        if (_.isArray(obj[propName])) {
1443                            _.each(obj[propName], function (arrElem) {
1444                                var isUnStripped = XfaUtil.prototype.stripObject(arrElem, exceptionNames);
1445                                keepProp = keepProp || isUnStripped;
1446                            });
1447                        } else if (_.isObject(obj[propName])) {
1448                            keepProp = XfaUtil.prototype.stripObject(obj[propName], exceptionNames);
1449                        }
1450
1451                        if (!keepProp) {
1452                            delete obj[propName];
1453                        } else {
1454                            dontStrip = true;
1455                        }
1456                    } else {
1457                        dontStrip = true;
1458                    }
1459                });
1460                return dontStrip;
1461            }
1462        },
1463
1464        computeDomJsonDiff: function (domNode, diff_level) {
1465            var changed = true;
1466            if (domNode.hasOwnProperty("_modelChanged")) {
1467                changed = domNode._modelChanged;
1468            }
1469            var jsonDiff = {};
1470            if (changed) {
1471                this.copyObject(domNode.jsonModel, jsonDiff, {"exceptions": ["children", "{default}", "extras"]});
1472            } else {
1473                jsonDiff = {_class: domNode.className};
1474            }
1475            if (!changed && domNode.jsonModel.hasOwnProperty("name")) {
1476                jsonDiff.name = domNode.jsonModel.name;
1477            }
1478            if (domNode.name === "FS_EXTRAS" && diff_level === 3) {
1479                domNode._childModified = true;
1480            }
1481            return {
1482                "changed": changed,
1483                jsonDifference: jsonDiff
1484            };
1485        },
1486
1487        getLogger: function () {
1488            return XfaUtil.prototype.logger || XfaUtil.prototype.getOrElse(xfalib, "runtime.xfa.Logger", null);
1489        },
1490
1491        getErrorManager: function () {
1492            return XfaUtil.prototype.getOrElse(xfalib, "runtime.xfa.ErrorManager", null);
1493        },
1494
1495        XFA_CLICK_EVENT: "xfaclick",
1496        XFA_EXIT_EVENT: "xfaexit",
1497        XFA_ENTER_EVENT: "xfaenter",
1498        XFA_CHANGE_EVENT: "xfachange",
1499        XFA_PREOPEN_EVENT: "xfapreopen",
1500
1501        btwn: function (val, a, b) {
1502            return val > a && val < b;
1503        },
1504
1505        // function to detect if Browser is chrome / safari (webkit)
1506        isWebkit: function () {
1507            return  !!$.browser.webkit || /webkit/.test(navigator.userAgent.toLowerCase()) || !!window.chrome || !!$.browser.chrome || /chrom(e|ium)/.test(navigator.userAgent.toLowerCase()) || !!$.browser.safari || !!window.webkitURL ||
1508                ( /safari/.test(navigator.userAgent.toLowerCase()) &&
1509                    /apple computer/.test(navigator.vendor.toLowerCase()) );
1510
1511            // TODO : find a better way to do this as $.browser is deprecated and
1512            // userAgent may be spoofed
1513        },
1514
1515        clearTimeoutOnDestroy: function (timeout) {
1516            attachClearTimeoutListener(timeout);
1517        },
1518
1519        // function to detect if Browser is  safari
1520        isSafari: function () {
1521            return ( /safari/.test(navigator.userAgent.toLowerCase()) &&
1522                    /apple computer/.test(navigator.vendor.toLowerCase()) );
1523        },
1524
1525        getLocaleStrings: function () {
1526            return xfalib.locale.Strings;
1527        },
1528
1529        getLogMessages: function () {
1530            return xfalib.locale.LogMessages;
1531        },
1532
1533        /*
1534         * This function should not be added in the prototype of any Object
1535         * as in the case of other functions
1536         */
1537        registerLocaleProperties: function (props) {
1538            registeredLocaleProperties = props;
1539        },
1540
1541        /*
1542         * This function should not be added in the prototype of any Object
1543         * as in the case of other functions
1544         */
1545        getDefaultLocaleProperty: function (property) {
1546            var localeProps = registeredLocaleProperties || this.getOrElse(xfalib, "script.Xfa._defaultLocale", null);
1547            return this.getOrElse(localeProps, property, null);
1548        },
1549
1550        /**
1551         * Encodes <script> and </script> with &lt;script&gt; and &lt;/script&gt;
1552         * Does same with img, video and audio tags also.
1553         * These tags are being removed since scripts can be run through
1554         * <img onerror="script" /> (same for audio and video).
1555         */
1556        encodeScriptableTags: function (str) {
1557            var index;
1558            if (_.isString(str)) {
1559                return str.replace(/<(\/?)(script[^<>]*)>/gi, '&lt;$1$2&gt;')
1560                    .replace(/<(\/?)(img[^<>]*)>/gi, '&lt;$1$2&gt;')
1561                    .replace(/<(\/?)(video[^<>]*)>/gi, '&lt;$1$2&gt;')
1562                    .replace(/<(\/?)(audio[^<>]*)>/gi, '&lt;$1$2&gt;')
1563            }
1564        },
1565
1566        /**
1567         *
1568         * @param id : a string representing an HTML element id.
1569         *
1570         * return after applying an escaping '\' before each # . : [ ]
1571         */
1572        jqId: function(id) {
1573            return "#" + id.replace(/(#|:|\.|\[|\])/g, "\\$1");
1574        },
1575
1576        _triggerOnBridge: function (eventName, target, property, oldVal, newVal) {
1577            var evnt = xfalib.script.XfaModelEvent.createEvent(eventName, target,
1578                property, oldVal, newVal);
1579            if(formBridge){
1580                window.formBridge.trigger(eventName, evnt);
1581            }
1582        },
1583
1584        /*
1585         * pads the passed in String str by pre-pending padChars to convert it to a string of given width.
1586         * If string length is already greater that equal to given width, original string is returned.
1587         */
1588        padString : function (str, width, padChar) {
1589            padChar = padChar || '0';
1590            str = str + '';
1591            return str.length >= width ? str : new Array(width - str.length + 1).join(padChar) + str;
1592        },
1593
1594        /**
1595         * returns true if the browser is IE otherwise false
1596         * @returns {boolean}
1597         */
1598        isIE: function () {
1599            return $.browser.msie || (navigator.appName === "Netscape" && navigator.userAgent.match(/Trident\//))
1600        },
1601
1602        /**
1603         * returns false if other browser
1604         * if ie tries to return browser version (non falsy)
1605         * @returns {*}
1606         */
1607
1608        detectIE: function () {
1609            // 1st try jq
1610            if($.browser.msie) {
1611                if($.browser.version && parseInt($.browser.version, 10)) {
1612                    return parseInt($.browser.version, 10);
1613                }
1614            }
1615
1616            var ua = window.navigator.userAgent;
1617
1618            // IE 10
1619            // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
1620
1621            // IE 11
1622            // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';
1623
1624            // IE 12 / Spartan
1625            // 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';
1626
1627            // Edge (IE 12+)
1628            // 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';
1629
1630            var msie = ua.indexOf('MSIE ');
1631            if (msie > 0) {
1632                // IE 10 or older => return version number
1633                return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
1634            }
1635
1636            var trident = ua.indexOf('Trident/');
1637            if (trident > 0) {
1638                // IE 11 => return version number
1639                var rv = ua.indexOf('rv:');
1640                return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
1641            }
1642
1643            var edge = ua.indexOf('Edge/');
1644            if (edge > 0) {
1645                // Edge (IE 12+) => return version number
1646                return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
1647            }
1648
1649            // other browser
1650            return false;
1651        },
1652        /**
1653         * returns true if the browser is chrome otherwise false
1654         * @returns {boolean}
1655         */
1656        detectChrome : function () {
1657            return (!!window.chrome || !!$.browser.chrome || /chrom(e|ium)/.test(navigator.userAgent.toLowerCase()));
1658        },
1659
1660        /**
1661        * @param {String} val: value to be verified
1662        * @returns {boolean}
1663        * returns true if the provided string contains DOM element
1664        */
1665        isHTML: function(val) {
1666            //check whether string contains tags, so that $val does not contain result of the val used as selector
1667            // eg: val = "a" will return result for $(val) which is not required
1668            if(val && /<[a-z][\s\S]*>/.test(val)) {
1669                try {
1670                    var $val = $(val);
1671                    return $val.length > 0;
1672                } catch (exception) {
1673                    // if jquery throws exception that means string is not a proper HTML
1674                    return false;
1675                }
1676            } else {
1677                return false;
1678            }
1679        },
1680
1681        /**
1682         * returns true if passed key is non printable, false otherwise.
1683         * @param {String} key event.key property of a Keyboard event
1684         */
1685        isNonPrintableKey : function (key) {
1686            return (key   // In IE, event.key returns words instead of actual characters for some keys.
1687               && !_.contains(['MozPrintableKey','Divide','Multiply','Subtract','Add','Enter','Decimal','Spacebar','Del'],key)
1688               && key.length != 1 )
1689        },
1690
1691        /**
1692        * returns true for ipad
1693        * @returns {boolean}
1694        */
1695        _isIpad : function () {
1696            return navigator.userAgent.match(/iPad/i) != null;
1697        },
1698
1699        /**
1700        * returns true if the subform is table or having role table else false
1701        * @param {Object} view
1702        */
1703        _tableCheckForAccessibility : function (view) {
1704            var assist = view.model.getElement("assist", 0, true);
1705            return this.getOrElse(view, "layoutModel.layout", null) == xfalib.view.LayoutConst.LAYOUT_TABLE
1706                || this.getOrElse(assist, "role", null) == "Table";
1707        },
1708
1709        /**
1710        * returns value of tooltip to be assigned as title based on values provided in accessibility
1711        * @param {Object} model
1712        * @returns toolTipText
1713        */
1714        _getToolTipText : function (model) {
1715            var assist = model.getElement("assist", 0, true),
1716                toolTipText = "";
1717            // going against xfa spec, on hover show tooltip or speak text or element name, don't show caption as it's already visible
1718            // assist priority doesn't matter, but selecting none will disable tooltip on hover
1719            if (this.getOrElse(assist, "speak.disable", 0) != 1) { // loose compare str
1719ing value
1720                toolTipText = this.getOrElse(assist, "toolTip.value", "") ||
1721                    this.getOrElse(assist, "speak.value", "")   ||
1722                    this.getOrElse(model, "jsonModel.name", "");
1723            }
1724            return toolTipText;
1725        },
1726
1727        /**
1728        * returns value of mandatory message
1729        * @param {Object} model
1730        * @returns mandatoryMessage
1731        */
1732        _getMandatoryMessage : function (model) {
1733            var defaultMessage = model._defaults.validate.message.defaultMessage,
1734                msg = this.getOrElse(model, "validate.message.nullTest", defaultMessage);
1735            return (msg && msg.value) ? msg.value : defaultMessage.value;
1736        },
1737        /**
1738        * returns boolean based on val1, val2, checkEqual
1739        * For comparing date, use date object
1740        */
1741        _compareVal : function (val1, val2, checkEqual) {
1742            if(!val1 || !val2) {
1743                return false;
1744            }
1745
1746            if(checkEqual) {
1747                return val1 >= val2;
1748            } else {
1749                return val1 > val2;
1750            }
1751        }
1752    });
1753
1754    //Special handling for IE.
1755    if ($.browser.msie || $.browser.mozilla) {
1756        XfaUtil.prototype.$css = function (elem, stylesObj) {
1757            $(elem).css(stylesObj);
1758        }
1759    }
1760})(_, $, xfalib);
1761/*************************************************************************
1762 *
1763 * ADOBE CONFIDENTIAL
1764 * ___________________
1765 *
1766 *  Copyright 2013 Adobe Systems Incorporated
1767 *  All Rights Reserved.
1768 *
1769 * NOTICE:  All information contained herein is, and remains
1770 * the property of Adobe Systems Incorporated and its suppliers,
1771 * if any.  The intellectual and technical concepts contained
1772 * herein are proprietary to Adobe Systems Incorporated and its
1773 * suppliers and are protected by trade secret or copyright law.
1774 * Dissemination of this information or reproduction of this material
1775 * is strictly forbidden unless prior written permission is obtained
1776 * from Adobe Systems Incorporated.
1777 **************************************************************************/
1778
1779
1780
1781(function (_, $, xfalib) {
1782    xfalib.ut.Utilities = {
1783
1784        isIE11: function () {
1785            return !!navigator.userAgent.match(/Trident.*rv\:11\./);
1786        },
1787
1788        checkMinMozillaVersion: function (version) {
1789            return (!this.isIE11() && $.browser.mozilla && parseInt($.browser.version) >= version);
1790        },
1791
1792        getObjectFromKeyValueStringList: function (list) {
1793            var key, value, object = {}, tempArray;
1794            _.each(list, function (keyValuePair, index) {
1795                tempArray = keyValuePair.split("=");
1796                if (tempArray && tempArray.length > 1) {
1797                    object[tempArray[0]] = tempArray[1];
1798                }
1799            });
1800            return object;
1801        },
1802
1803        _getNameWithoutMarker: function (fileName) {
1804            var markerIndex = fileName.indexOf("__afAttachment__");
1805            if (markerIndex !== -1) {
1806                fileName = fileName.substring(markerIndex + "__afAttachment__".length, fileName.length);
1807            }
1808            return fileName;
1809        },
1810
1811        /*
1812         * This is to check support of multiple files selection in one add new dialog
1813         */
1814        _isDataContainerSupported : function () {
1815            try {
1816                var dataContainer = new DataTransfer() || (new ClipboardEvent("")).clipboardData;
1817                if (dataContainer && dataContainer.items) {
1818                    return true;
1819                }
1820            } catch(err) {
1821                // if err comes then dataContainer is not supported
1822            }
1823            return false;
1824        }
1825    };
1826})(_, $, xfalib);
1827/**
1828 * @package xfalib.ut.Scanner
1829 * @fileOverview helper class to scan over a string.
1830 * @version 0.0.1
1831 */
1832
1833/**
1834 * @constructor
1835 * @param Object {jsonModel:{_str: String}}
1836 */
1837
1838(function(_,xfalib){
1839    var Scanner = xfalib.ut.Scanner = xfalib.ut.Class.extend({
1840
1841        initialize: function() {
1842            this._pos = 0;
1843        },
1844
1845        isEOF : function(){
1846            return (this.jsonModel._str.length <= this._pos);
1847        },
1848
1849        peek : function(){
1850            return (this.isEOF()) ? null : this.jsonModel._str.charAt(this._pos);
1851        },
1852
1853        optionalConsumeChar : function(aChar){
1854            if(this.jsonModel._str.charAt(this._pos) == aChar){
1855                this._pos++;
1856                return aChar;
1857            }else{
1858                return null;
1859            }
1860        },
1861
1862        /**
1863         * Gets next char ignore quoted string.
1864         *    |
1865         *   abc returns c.
1866         *     |
1867         *   abc'de'f returns f.
1868         * @param aChar
1869         */
1870        getNCharIQS : function(){
1871            this._pos++;
1872            if(this.jsonModel._str.length <= this._pos){
1873                var current = this.jsonModel._str.charAt(this._pos);
1874                if(current != '\''){
1875                    return current;
1876                }else{
1877                    if(moveNextExpectedChar('\'')){
1878                        return this.jsonModel._str.charAt(this._pos);
1879                    }
1880                }
1881            }
1882            return null;
1883        },
1884
1885        moveNextExpectedChar : function(aChar){
1886            this._pos++;// currently point to '
1887            while(this._pos< this.jsonModel._str.length && this.jsonModel._str.charAt(this._pos) != aChar){
1888                this._pos++;
1889            }
1890            return this._pos < this.jsonModel._str.length;
1891        },
1892
1893        readInteger : function(len){
1894            if(this.pos+len >this.jsonModel._str.length){
1895                return null;
1896            }
1897            var integer = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._str,this._pos,len);
1898            this._pos+=len;
1899            return integer;
1900        }
1901    });
1902
1903    Scanner.lookupNext = function(pat, patPos, filter){
1904        var patLen = pat.length;
1905        if(patPos >= patLen){
1906            return null;
1907        }
1908
1909        var token = {};
1910        token.startPos = patPos;
1911
1912        var firstChar = pat.charAt(patPos);
1913        var patValid = false;
1914        //
1915        if (firstChar == '\''){
1916            for (var i = patPos+1; i < patLen;i++ ){
1917                var chr = pat.charAt(i);
1918                if(chr =='\''){
1919                    token.type=1;
1920                    token.len = i - patPos + 1;
1921                    patValid = true;
1922                    break;
1923                }
1924            }
1925
1926        }else if( ('a' <= firstChar && firstChar <= 'z' || 'A' <= firstChar && firstChar <= 'Z') || filter.call(null, firstChar)){
1927            var endPos = patLen;//end is exclusive
1928            for (var i = 1; patPos+i < patLen;i++ ){
1929                if(pat.charAt(patPos+i)!=firstChar){
1930                    endPos = patPos+i;
1931                    break;
1932                }
1933            }
1934            token.type=2;
1935            token.len = endPos - patPos;
1936            token.patChar = firstChar;
1937            token.patPos = patPos;
1938            patValid = true;
1939        }else{
1940            if (firstChar == '?' || firstChar == '+' || firstChar == '*') {
1941                token.type=3;
1942                token.len = 1;
1943            }else{
1944                token.type=4;
1945                token.len = 1;
1946            }
1947            patValid = true;
1948        }
1949        if(patValid){
1950            return token;
1951        }else{
1952            throw "Picture is invalid.";
1953        }
1954    }
1955})(_,xfalib);
1956
1957
1958/**
1959 * @package xfalib.ut.PictureFmt
1960 * @fileOverview The file defines methods to parse and format data
1961 * according to XFA picture patterns.
1962 * @version 0.0.1
1963 */
1964(function(_,xfalib) {
1965
1966    var PictureFmt = xfalib.ut.PictureFmt = function() {};
1967    PictureFmt.DatePicturePattern =  /^date(?:\([a-zA-Z]*_[a-zA-Z]*\))?\{([\w\W]*?)\}$/;
1968    PictureFmt.TimePicturePattern =  /^time(?:\([a-zA-Z]*_[a-zA-Z]*\))?\{([\w\W]*?)\}$/;
1969    PictureFmt.TextPicturePattern =  /^text\{([\w\W]*?)\}$/;
1970    PictureFmt.NumPicturePattern =  /^num\{([\w\W]*?)\}$/;
1971
1972    /**
1973     * Parses a given data source according to the given picture.
1974     * @param sSource {string}
1975     * @param sPicture {string}
1976     * @param sLocale {string}
1977     * @returns {object}
1978     */
1979    PictureFmt.parse  = function(sSource, sPicture,sLocale){
1980        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
1981
1982        var match = PictureFmt.DatePicturePattern.exec(sPicture);
1983        if(match && match[1]){
1984            return PictureEngine.parseDate(sSource, match[1]);
1985        }
1986        match = PictureFmt.TimePicturePattern.exec(sPicture);
1987        if(match && match[1]){
1988            return PictureEngine.parseTime(sSource, match[1]);
1989        }
1990        match = PictureFmt.TextPicturePattern.exec(sPicture);
1991        if(match && match[1]){
1992            return PictureEngine.parseText(sSource, match[1]);
1993        }
1994        match = PictureFmt.NumPicturePattern.exec(sPicture);
1995        if(match && match[1]){
1996            return PictureEngine.parseNumeric(sSource, match[1]);
1997        }
1998        throw "Invalid picture clause "+sPicture;
1999    };
2000
2001    /**
2002     * Formats a given data source according to the given picture.
2003     * @param date {object}
2004     * @param sPicture {string}
2005     * @param sLocale {string}
2006     * @returns {string}
2007     */
2008    PictureFmt.format  = function(sSource, sPicture, sLocale,bRelaxed,bFormatNumberFromasDefaultPC){
2009        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2010
2011        var match = PictureFmt.DatePicturePattern.exec(sPicture);
2012        if(match && match[1]){
2013            return PictureEngine.formatDate(sSource, match[1]);
2014        }
2015        match = PictureFmt.TimePicturePattern.exec(sPicture);
2016        if(match && match[1]){
2017            return PictureEngine.formatTime(sSource, match[1]);
2018        }
2019        match = PictureFmt.TextPicturePattern.exec(sPicture);
2020        if(match && match[1]){
2021            return PictureEngine.formatText(sSource, match[1],bRelaxed);
2022        }
2023        match = PictureFmt.NumPicturePattern.exec(sPicture);
2024        if(match && match[1]){
2025            return PictureEngine.formatNumeric(sSource, match[1],sLocale,bRelaxed,bFormatNumberFromasDefaultPC);
2026        }
2027            throw "Invalid picture clause "+sPicture;
2028    };
2029
2030    /**
2031     * Checks if a given data source is formatted according to the given picture.
2032     * @param date {object}
2033     * @param sPicture {string}
2034     * @param sLocale {string}
2035     * @returns {boolean}
2036     */
2037    PictureFmt.formatTest = function (sSource, sPicture, sLocale, bRelaxed, bFormatNumberFromasDefaultPC) {
2038        var formattedData;
2039        try {
2040            formattedData = PictureFmt.format(sSource, sPicture, sLocale, bRelaxed, bFormatNumberFromasDefaultPC);
2041        }catch(e) {
2042            return false;
2043        }
2044
2045        if(!_.isString(formattedData)) {
2046            return false;
2047        } else {
2048            var parsedData;
2049            try {
2050                parsedData = PictureFmt.parse(formattedData, sPicture, sLocale);
2051            } catch (e) {
2052                return false;
2053            }
2054            if(!_.isString(parsedData) && parsedData !== formattedData) {
2055                return false;
2056            }
2057        }
2058        return true;
2059    };
2060
2061    /**
2062     * Parses a given data source according to the given date picture
2063     * under the given sLocale.
2064     * @param sSource {string}
2065     * @param sPicture {string}
2066     * @param sLocale {string}
2067     * @returns {string}
2068     */
2069    PictureFmt.parseDate  = function(sSource, sPicture,sLocale){
2070        var picRegexp = PictureFmt.DatePicturePattern;
2071        var match = picRegexp.exec(sPicture);
2072        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2073        if(match && match[1]){
2074            return PictureEngine.parseDate(sSource, match[1]);
2075        }else{
2076            return PictureEngine.parseDate(sSource, sPicture);
2077        }
2078    };
2079
2080
2081    /**
2082     * Formats a given data source according to the given date picture
2083     * * under the given sLocale.
2084     * @param date {string}
2085     * @param sPicture {string}
2086     * @param sLocale {string}
2087     * @returns {string}
2088     */
2089    PictureFmt.formatDate  = function(date, sPicture, sLocale){
2090        var picRegexp =  PictureFmt.DatePicturePattern;
2091        var match = picRegexp.exec(sPicture);
2092        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2093        if(match && match[1]){
2094            return PictureEngine.formatDate(date, match[1]);
2095        }else{
2096            return PictureEngine.formatDate(date, sPicture);
2097        }
2098    };
2099
2100    /**
2101     * Parses a given data source according to the given date picture
2102     * under the given sLocale.
2103     * @param sSource {string}
2104     * @param sPicture {string}
2105     * @param sLocale {string}
2106     * @returns {date}
2107     */
2108    PictureFmt.parseTime  = function(sSource, sPicture,sLocale){
2109        var picRegexp = PictureFmt.TimePicturePattern;
2110        var match = picRegexp.exec(sPicture);
2111        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2112        if(match && match[1]){
2113            return PictureEngine.parseTime(sSource, match[1]);
2114        }else{
2115            return PictureEngine.parseTime(sSource, sPicture);
2116        }
2117        return null;
2118    };
2119
2120
2121    /**
2122     * Formats a given data source according to the given date picture
2123     * * under the given sLocale.
2124     * @param date {string}
2125     * @param sPicture {string}
2126     * @param sLocale {string}
2127     * @returns {string}
2128     */
2129    PictureFmt.formatTime  = function(date, sPicture, sLocale){
2130        var picRegexp =  PictureFmt.TimePicturePattern;
2131        var match = picRegexp.exec(sPicture);
2132        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2133        if(match && match[1]){
2134            return PictureEngine.formatTime(date, match[1]);
2135        }else{
2136            return PictureEngine.formatTime(date, sPicture);
2137        }
2138    };
2139
2140    /**
2141     * Parses a given data source according to the given text picture
2142     * under the given sLocale.
2143     * @param sSource {string}
2144     * @param sPicture {string}
2145     * @param sLocale {string}
2146     * @returns {string}
2147     */
2148    PictureFmt.parseText  = function(sSource, sPicture,sLocale){
2149        var picRegexp = PictureFmt.TextPicturePattern;
2150        var match = picRegexp.exec(sPicture);
2151        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2152        if(match && match[1]){
2153            return PictureEngine.parseText(sSource, match[1]);
2154        }else{
2155            return PictureEngine.parseText(sSource, sPicture);
2156        }
2157    };
2158
2159    /**
2160     * Formats a given data source according to the given text picture
2161     *  under the given sLocale.
2162     * @param sSource {string}
2163     * @param sPicture {string}
2164     * @param sLocale {string}
2165     * @returns {string}
2166     */
2167    PictureFmt.formatText  = function(sSource, sPicture, sLocale,bRelaxed){
2168        var picRegexp =  PictureFmt.TextPicturePattern;
2169        var match = picRegexp.exec(sPicture);
2170        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2171        if(match && match[1]){
2172            return PictureEngine.formatText(sSource, match[1],bRelaxed);
2173        }else{
2174            return PictureEngine.formatText(sSource, sPicture,bRelaxed);
2175        }
2176        return null;
2177    };
2178
2179    /**
2180     * Parses a given data source according to the given numeric picture
2181     * under the given sLocale.
2182     * @param sSource {string}
2183     * @param sPicture {string}
2184     * @param sLocale {string}
2185     * @returns {string}
2186     */
2187    PictureFmt.parseNumeric  = function(sSource, sPicture,sLocale){
2188        var picRegexp = PictureFmt.NumPicturePattern;
2189        var match = picRegexp.exec(sPicture);
2190        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2191        if(match && match[1]){
2192            return PictureEngine.parseNumeric(sSource, match[1]);
2193        }else{
2194            return PictureEngine.parseNumeric(sSource, sPicture);
2195        }
2196        return null;
2197    };
2198
2199    /**
2200     * Formats a given data source according to the given numeric picture
2201     *  under the given sLocale.
2202     * @param sSource {string}
2203     * @param sPicture {string}
2204     * @param sLocale {string}
2205     * @returns {string}
2206     */
2207    PictureFmt.formatNumeric  = function(sSource, sPicture, sLocale){
2208        var picRegexp =  PictureFmt.NumPicturePattern;
2209        var match = picRegexp.exec(sPicture);
2210        var PictureEngine = new xfalib.ut.PictureEngine({jsonModel:{locale:sLocale}});
2211        if(match && match[1]){
2212            return PictureEngine.formatNumeric(sSource, match[1]);
2213        }else{
2214            return PictureEngine.formatNumeric(sSource, sPicture);
2215        }
2216    };
2217
2218
2219
2220
2221    /**
2222     * Parses a given data source according to the given datetime picture
2223     * under the given sLocale.
2224     * @param sSource {string}
2225     *            the source data.
2226     * @param sPicture {string}
2227     *            the datetime picture.
2228     * @param sDateMask {string}
2229     *            the date sub-picture.
2230     * @param sTimeMask {string}
2231     *            the time sub-picture.
2232     * @param sLocale
2233     *            the locale name.
2234     *
2235     */
2236    PictureFmt.parseDateTime  = function(sSource, sPicture, sDateMask, sTimeMask, sLocale){
2237
2238    };
2239    /**
2240     * Formats a given data source according to the given datetime picture
2241     * under the given locale.
2242     *
2243     * @param sSource {string}
2244     *            the source data.
2245     * @param sPicture {string}
2246     *            the datetime picture.
2247     * @param sDateMask {string}
2248     *            the date sub-picture.
2249     * @param sTimeMask {string}
2250     *            the time sub-picture.
2251     * @param sLocale {string}
2252     *            the locale name.
2253     */
2254    PictureFmt.formatDateTime  = function(sSource, sPicture, sDateMask, sTimeMask, sLocale){
2255
2256    };
2257
2258})(_,xfalib);
2259/**
2260 * @package xfalib.ut.PictureUtils
2261 * @fileOverview The file defines static utilities methods.
2262 * @version 0.0.1
2263 */
2264
2265(function(_,xfalib){
2266    var PictureUtils = xfalib.ut.PictureUtils = function() {}
2267
2268    PictureUtils.padding = function(number, digits, isFw, zero){
2269        var leading = ["0","00","000","0000"];
2270        var numStr = leading[digits-1] + number;
2271        return numStr.slice(- digits);
2272    };
2273
2274    PictureUtils.parseIntAggressive = function(dateString, startPos,len){
2275        var result = new Object();
2276        var parsedNum = 0; //The number value parsed from dateString
2277        var parsedLen = -1; //How many chars parsed according to this pattern;
2278        for(var idx=0; idx<len && (startPos + idx) < dateString.length; idx++){
2279            var chr = dateString.charAt(startPos + idx);
2280            if(chr >='0' && chr <='9'){
2281                parsedNum = parsedNum *10 + (chr- '0');
2282            }else{
2283                parsedLen = idx;
2284                break;
2285            }
2286        }
2287        if(parsedLen == -1) {
2288            parsedLen = len;
2289        }
2290        result.value = parsedNum;
2291        result.len = parsedLen;
2292        return result;
2293    };
2294
2295    PictureUtils.parseIntExact = function(dateString, startPos,len){
2296        var result = 0;
2297        PictureUtils.assert(startPos+ len <= dateString.length, "mismatch");
2298        for(var idx=0; idx<len ; idx++){
2299            var chr = dateString.charAt(startPos + idx);
2300            if(chr >='0' && chr <='9'){
2301                result = result *10 + (chr- '0');
2302            }else{
2303                throw "unexpected currentChar in PictureUtils.parseInt";
2304            }
2305        }
2306        return result;
2307    };
2308
2309    PictureUtils.isDigit = function(chr){
2310        return /[0-9]/.test(chr) ;
2311    };
2312
2313    PictureUtils.inString = function(chr,aString){
2314        return (aString.indexOf(chr) >=0) ;
2315    };
2316
2317
2318    var regExpIsLetter = /[\u0041-\u005a\u0061-\u007a\u00aa-\u00aa\u00b5-\u00b5\u00ba-\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u0236\u0250-\u02
2318c1\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]/
2319
2320    /**
2321     * TODO Implement method equivalent to Character.isLetter.
2322     */
2323    PictureUtils.isLetter = function(chr){
2324        return regExpIsLetter.test(chr);
2325    };
2326
2327    PictureUtils.isLetterOrDigit = function(chr){
2328        return this.isLetter(chr) || this.isDigit(chr);
2329    };
2330
2331    /**
2332     * Scan this string for the first character in the given set. Similar to
2333     * strcspn().
2334     *
2335     * @param src{String}
2336     *            the string to scan
2337     * @param sSkip{String}
2338     *            the characters to scan for
2339     * @param nOffset{number}
2340     *            the position where to start the scan. Default = 0.
2341     * @return The position, relative to nOffset, for the first character found
2342     *         in the given set
2343     */
2344    PictureUtils.skipUntil = function(srcStr, sSkip, nOffset) {
2345        var nCharsSkipped = nOffset;
2346
2347        // starting at the offset position, scan the characters in this string
2348        // until it matches one of the characters in the given set.
2349        while (nCharsSkipped < srcStr.length) {
2350            var i = nCharsSkipped;
2351            if (sSkip.indexOf(srcStr.charAt(i++)) >= 0)
2352                break;
2353            nCharsSkipped = i;
2354        }
2355
2356        return nCharsSkipped - nOffset;
2357    };
2358
2359    PictureUtils.matchString = function(str, startPos, target){
2360        if(startPos + target.length > str.length){
2361            return false;
2362        }else{
2363            for(var idx = 0; idx<target.length; idx++){
2364                if(target.charAt(idx) != str.charAt(startPos + idx)) return false;
2365            }
2366            return true;
2367        }
2368    };
2369
2370    PictureUtils.assert = function(condition, message){
2371        if(!condition){
2372            throw message;
2373        }
2374    };
2375
2376    PictureUtils.getLocaleObject = function(locale,property) {
2377        if(locale !== null && xfalib.runtime.xfa) {
2378            return xfalib.runtime.xfa._getLocaleSymbols(locale, property);
2379        } else {
2380            return xfalib.ut.XfaUtil.prototype.getDefaultLocaleProperty(property)
2381        }
2382    }
2383
2384    PictureUtils.getHashOfLocaleObject = function(locale,property) {
2385          if(!PictureUtils.getHashOfLocaleObject[locale+"_"+property]) {
2386              var hashObj = {};
2387              _.each(PictureUtils.getLocaleObject(locale,property), function(val) {
2388                  var sVal = (val+"").toLowerCase();
2389                  var hash = 0;
2390                  for(var i =0;i<sVal.length;i++) {
2391                      hash+=(i+1)*sVal.charCodeAt(i)
2392                  }
2393                  hashObj[hash] = hashObj[hash] || [];
2394                  hashObj[hash].push(sVal);
2395              })
2396              PictureUtils.getHashOfLocaleObject[locale+"_"+property] = hashObj;
2397          }
2398          return PictureUtils.getHashOfLocaleObject[locale+"_"+property]
2399    }
2400
2401    PictureUtils.convertNumberToLocale = function(locale,number) {
2402        var zero = PictureUtils.getLocaleObject(locale,"numberSymbols.zero");
2403        var zeroCode = zero.charCodeAt(0);
2404        number += "";
2405        var newNumber = [];
2406        for(var i = 0;i < number.length;i++) {
2407            newNumber.push(String.fromCharCode(zeroCode + parseInt(number.charAt(i))));
2408        }
2409        return newNumber.join("");
2410    }
2411
2412    PictureUtils.parsePictureClause = function (clause){
2413        if(clause === null || clause === undefined) {
2414            return [];
2415        }
2416        var insidePattern = false,
2417            insideQuote=false,
2418            insideLocale = false,
2419            locale = "",
2420            type = "",
2421            pattern = "",
2422            flag = false,
2423            currentChar = "",
2424            result = [],
2425            matchType = /^num$|^text$|^date$/,
2426            matchLocale = /^[a-zA-Z]*_[a-zA-Z]*$/,
2427            i = 0,
2428            bracketOpenCount = 0;
2429        for(;i<clause.length;i++) {
2430            currentChar = clause.charAt(i);
2431            if(insideQuote && currentChar !== "'") {
2432                pattern += currentChar;
2433                continue;
2434            }
2435            switch(currentChar) {
2436               case "'":
2437                   if(!insidePattern) {
2438                       // ' is not allowed except insidePattern
2439                       return null;
2440                   }
2441                   insideQuote = !insideQuote;
2442                   pattern += currentChar;
2443                   break;
2444               case "{":
2445                    if(insidePattern || insideLocale || type === "") {
2446                        // { is not allowed insidePattern or insideLocale
2447                        return null;
2448                    }
2449                   insidePattern = true;
2450                    break;
2451                case "}":
2452                    if(!insidePattern || (insideLocale && pattern === "") || type === "") {
2453                        // { is allowed only insidePattern and not insideLocale
2454                        return null;
2455                    } else {
2456                        bracketOpenCount = 0;
2457                        insidePattern = false;
2458                        if(matchType.exec(type) === null) {
2459                            return null;
2460                        }
2461                        if(locale !== "" && matchLocale.exec(locale) === null) {
2462                            return null;
2463                        }
2464                        result.push({
2465                            category: type,
2466                            mask: pattern,
2467                            locale: locale
2468                        })
2469                    }
2470                    break;
2471                case "|":
2472                    if(type === "" || insidePattern || insideLocale) {
2473                        return null;
2474                    } else {
2475                        type = pattern = locale = "";
2476                        insidePattern = insideLocale = false;
2477                    }
2478                    break;
2479                case "(" :
2480                    if(type === "" || bracketOpenCount === 1) {
2481                        // ( is not allowed inside Locale
2482                        return null;
2483                    } else {
2484                        if(!insidePattern) {
2485                            insideLocale = true;
2486                        } else {
2487                            pattern += currentChar;
2488                        }
2489                        bracketOpenCount++;
2490                    }
2491                    break;
2492                case ")" :
2493                    if((!insideLocale && !insidePattern) || bracketOpenCount === 0) {
2494                        return null;
2495                    } else {
2496                        if(insidePattern) {
2497                            pattern += currentChar;
2498                        }
2499                        insideLocale = false;
2500                        bracketOpenCount--;
2501                    }
2502                    break;
2503                default:
2504                    if(insidePattern) {
2505                        pattern += currentChar;
2506                    } else if(insideLocale) {
2507                        locale += currentChar;
2508                    } else if(type !== "" && (pattern !== "" || locale !== "")){
2509                        return null;
2510                    } else {
2511                        type += currentChar;
2512                    }
2513                    break;
2514           }
2515       }
2516       if(insidePattern || insideLocale || insideQuote || bracketOpenCount !== 0) {
2517           return null;
2518       }
2519       return result;
2520    }
2521
2522})(_,xfalib);
2523
2524/**
2525 * @package xfalib.ut.VisitorBase
2526 * @import xfalib.ut.Class
2527 * @fileOverview Base class for visitor
2528 * @version 0.0.1
2529 */
2530
2531/**
2532 * @constructor
2533 * @param Object {jsonModel: {_sPicture: String}}
2534 */
2535
2536(function(_,xfalib) {
2537    var VisitorBase = xfalib.ut.VisitorBase = xfalib.ut.Class.extend({
2538        consume : function(token){
2539            switch (token.type)
2540            {
2541                case 1:
2542                    this.consumeStringLiteral(token);
2543                    break;
2544                case 2:
2545                    this.consumeSubPattern(token);
2546                    break;
2547                case 3:
2548                    this.consumeStringWildCard(token);
2549                    break;
2550                case 4:
2551                    this.consumeCharLiteral(token);
2552                    break;
2553            }
2554        },
2555        acceptPatternChar : function(chr){
2556            return false;
2557        },
2558        getPicture : function(){
2559            return this.jsonModel._sPicture;
2560        },
2561        abstractMethod : function(){
2562            throw "Not implemented";
2563        },
2564        consumeStringWildCard : this.abstractMethod,
2565        consumeStringLiteral: this.abstractMethod,
2566        consumeCharLiteral: this.abstractMethod,
2567        consumeSubPattern: this.abstractMethod,
2568        getResult: this.abstractMethod
2569    });
2570})(_,xfalib);
2571
2572/**
2573 * @package xfalib.ut.NumPictureDesc
2574 * @import xfalib.ut.Class
2575 * @fileOverview Pre-process Numeric Picture.
2576 * @version 0.0.1
2577 */
2578
2579/**
2580 * @constructor
2581 * @param Object {jsonModel: {_sPicture: String}}
2582 */
2583
2584(function(_,xfalib){
2585    var NumPictureDesc = xfalib.ut.NumPictureDesc = xfalib.ut.Class.extend({
2586
2587        initialize: function() {
2588            this.hasRadix = false;
2589            this.hasExpon = false;
2590            this.hasSign = false;
2591            this.hasPercent = false;
2592            this.fracDigit = 0;
2593            this.intDigit = 0;
2594
2595            this._mbLeftParenSeen = false;
2596            this._mbRightParenSeen = false;
2597            this._compactPattern();
2598            this._xlatePattern();
2599            NumPictureDesc._super.initialize.call(this);
2600        },
2601        
2602        getPicture : function(){
2603            return this.jsonModel._sPicture;
2604        },
2605
2606        _match2Char : function (char1, char2, idx){
2607            if(idx+1 < this.jsonModel._sPicture.length){
2608                return (this.jsonModel._sPicture.charAt(idx) ==char1 && this.jsonModel._sPicture.charAt(idx+1) ==char2);
2609            }else{
2610                return false;
2611            }
2612        },
2613
2614        _xlatePattern : function(){
2615            var patPos = 0;
2616            for(var token = xfalib.ut.Scanner.lookupNext(this.jsonModel._sPicture, patPos, this._acceptPatternChar); token != null;  ){
2617                this._consume(token);
2618                patPos = patPos + token.len;
2619                token = xfalib.ut.Scanner.lookupNext(this.jsonModel._sPicture, patPos, this._acceptPatternChar);
2620            }
2621        },
2622        
2623        _compactPattern : function(){
2624            var buf = new Array();
2625            for(var index =0, len = this.jsonModel._sPicture.length; index <len; index++){
2626                if(this._match2Char('D','B',index)){
2627                    buf.push('D');
2628                    index++;
2629                }else if(this._match2Char('d','b',index)){
2630                    buf.push('d');
2631                    index++;
2632                }else if(this._match2Char('C','R',index)){
2633                    buf.push('C');
2634                    index++;
2635                }else if(this._match2Char('c','r',index)){
2636                    buf.push('c');
2637                    index++;
2638                }else{
2639                    buf.push(this.jsonModel._sPicture.charAt(index));
2640                }
2641            }
2642            this.jsonModel._sPicture = buf.join("");
2643        },
2644
2645        _acceptPatternChar : function(chr){
2646            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
2647        },
2648
2649        _consume : function(token){
2650            if(token.type == 2){
2651                this._subConsume(token.patChar, token.len);
2652            }// else not a pattern
2653        },
2654
2655        _subConsume : function(chr, chrCnt){
2656            switch (chr) {
2657                case'E' :
2658                    if (chrCnt > 1 || this.hasExpon || (this.fracDigit + this.intDigit)==0)
2659                        throw "Illegal Numeric Picture: more than one Expon";
2660                    this.hasExpon = true;
2661                    break;
2662                case '(':
2663                    if (chrCnt > 1 || this._mbLeftParenSeen	|| this.fracDigit + this.intDigit >0 )
2664                        throw "Illegal Numeric Picture:  ()";
2665                    this._mbLeftParenSeen = true;
2666                    break;
2667
2668                case ')':
2669                    if (chrCnt > 1 || ! this._mbLeftParenSeen || this._mbRightParenSeen)
2670                        throw "Illegal Numeric Picture:  ()";
2671                    this._mbRightParenSeen = true;
2672                    if(this.fracDigit + this.intDigit >0) this.hasSign = true;
2673                    break;
2674                case 'S':
2675                case 's':
2676                case 'C': //CR
2677                case 'c': //cr
2678                case 'D': //DB
2679                case 'd': //db
2680                    this.hasSign = true;
2681                    break;
2682                case '%' :
2683                    this.hasPercent = true;
2684                    break;
2685                case '.':
2686                case 'V':
2687                case 'v':
2688                    if (chrCnt > 1 || this.hasRadix)
2689                        throw "Illegal Numeric Picture: too many vV.";
2690                    this.hasRadix = true;
2691                    this._mbFracStartSeen = true;
2692                    break;
2693                case '8' :
2694                case '9' :
2695                case 'Z':
2696                case 'z':
2697                    if (this.hasRadix){
2698                        this.fracDigit += chrCnt;
2699                    } else{
2700                        this.intDigit += chrCnt;
2701                    }
2702                    break;
2703            }
2704        },
2705
2706        parseNumberInfo : function(msText){
2707            var text=msText,
2708                num = Number(text),
2709                negative = false
2710            if(num < 0){
2711                negative = true;
2712                num = -num;
2713                text = text.replace("-","");
2714            }
2715            if(this.hasPercent){
2716                num *= 100;
2717                text = ""+num;
2718            }
2719            var shift = 0;
2720            if(this.hasExpon){
2721                var threshold = Math.pow(10,this.intDigit);
2722                if(num < threshold){
2723                    while(num*10 < threshold) {
2724                        num *= 10;
2725                        shift--;
2726                    }
2727                }else{
2728                    while(num > threshold){
2729                        num /= 10;
2730                        shift++;
2731                    }
2732                }
2733                text = num+"";
2734            }
2735            var radixPos = text.indexOf(".", 0),
2736                fractionDigit = radixPos<0 ? 0 : text.length - radixPos - 1
2737
2738            if(this.fracDigit < fractionDigit) {
2739                num = num.toFixed(this.fracDigit);
2740                text = num +""
2741            }
2742
2743            if(text.indexOf("0") == 0 && msText.indexOf("0") != 0) {
2744                text = text.substring(1);
2745            }
2746
2747            radixPos = text.indexOf(".", 0)
2748            var integerDigit = radixPos < 0 ? text.length : radixPos,
2749                offset = this.intDigit - integerDigit
2750
2751            if(offset <0 ){
2752                throw "Exit: most significant " + offset +" digit lost";
2753            }
2754            return {
2755                "integerDigit" : integerDigit,
2756                "radixPos" : radixPos ,
2757                "fractionDigit" :  radixPos<0 ? 0 : text.length - radixPos - 1,
2758                "msText" : text,
2759                "shift" : shift,
2760                "isNegative" : negative,
2761                "padding" :offset
2762            };
2763        }
2764    });
2765
2766    NumPictureDesc.gsDB = "DB";
2767    NumPictureDesc.gsCR = "CR";
2768    NumPictureDesc.gsE = "E";
2769    NumPictureDesc.gsDSP = "  ";
2770    NumPictureDesc.gsSSP = " ";
2771
2772})(_,xfalib);
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784    /**
2785 * @package xfalib.ut.TimeInfo
2786 * @import xfalib.ut.Class
2787 * @fileOverview A wrapper class for date related information.
2788 * @version 0.0.1
2789 */
2790
2791/**
2792 * @constructor
2793 */
2794(function(_,xfalib){
2795    var TimeInfo = xfalib.ut.TimeInfo = xfalib.ut.Class.extend({
2796
2797        initialize: function() {
2798            this.mHourOfMeriDiem = -1;
2799            this.mHourOfDay = -1;
2800            this.mMinuteOfHour = -1;
2801            this.mSecondOfMinute = -1;
2802            this.mThousandthOfSecond = -1;
2803        },
2804
2805        getISOTime : function(){
2806            var timeStr = "";
2807            if(this.mThousandthOfSecond>0){
2808                timeStr = "-" + this.formatNum(this.mThousandthOfSecond,3);
2809            }
2810            if(this.mSecondOfMinute>0 || timeStr!=""){
2811                timeStr = this.formatNum(this.mSecondOfMinute,2)+timeStr;
2812                timeStr = ":"+timeStr;
2813            }
2814            if(this.mMinuteOfHour>0 || timeStr!=""){
2815                timeStr = this.formatNum(this.mMinuteOfHour,2)+timeStr;
2816                timeStr = ":"+timeStr;
2817            }
2818            timeStr = this.formatNum(this.mHourOfDay,2) + timeStr;
2819
2820            return timeStr;
2821        },
2822
2823        formatNum : function(num, digits){
2824            if(num<0){
2825                num = 0;
2826            }
2827            return xfalib.ut.PictureUtils.padding(num, digits);
2828        },
2829
2830        getDate : function(){
2831            var date = new Date();
2832            this.setTime(date);
2833            return date;
2834        },
2835
2836        setTime : function(date){
2837            date.setHours(this.mHourOfDay);
2838            date.setMinutes(this.mMinuteOfHour);
2839            date.setSeconds(this.mSecondOfMinute);
2840            date.setMilliseconds(this.mThousandthOfSecond);
2841        }
2842    });
2843
2844    /**
2845     *
2846     * <p>Valid ISO8601/XFA time strings are in any one
2847     * of the following time patterns:
2848     * <ul>
2849     * <li> HH[MM[SS[.FFF][z]]]
2850     * <li> HH[MM[SS[.FFF][+HH[MM]]]]
2851     * <li> HH[MM[SS[.FFF][-HH[MM]]]]
2852     * <li> HH[:MM[:SS[.FFF][z]]]
2853     * <li> HH[:MM[:SS[.FFF][+HH[:MM]]]]
2854     * <li> HH[:MM[:SS[.FFF][-HH[:MM]]]]
2855     * </ul>
2856     */
2857    TimeInfo.Parse = function(isoDateStr, locale){
2858        var scanner = new xfalib.ut.Scanner({jsonModel:{_str:isoDateStr}});
2859        var hours = scanner.readInteger(2);
2860        var minitues = -1;
2861        if(!scanner.isEOF()){
2862            scanner.optionalConsumeChar(':');
2863            minitues = scanner.readInteger(2);
2864        }
2865        var seconds = -1;
2866        if(!scanner.isEOF()){
2867            scanner.optionalConsumeChar(':');
2868            seconds = scanner.readInteger(2);
2869        }
2870        var milliseconds = -1;
2871        if(!scanner.isEOF()){
2872            scanner.optionalConsumeChar('-');
2873            milliseconds = scanner.readInteger(3);
2874        }
2875        //TODO timezone
2876        var info = new xfalib.ut.TimeInfo();
2877       TimeInfo.setPropertyIfNotNull(info,hours,"mHourOfDay");
2878       TimeInfo.setPropertyIfNotNull(info,minitues,"mMinuteOfHour");
2879       TimeInfo.setPropertyIfNotNull(info,seconds,"mSecondOfMinute");
2880       TimeInfo.setPropertyIfNotNull(info,milliseconds,"mThousandthOfSecond");
2881        return info;
2882    };
2883
2884    /**
2885     *
2886     * static method
2887     */
2888    TimeInfo.setPropertyIfNotNull = function(object, value, proName){
2889        if(value!=null){
2890            var d = Number(value);
2891            if(!isNaN(d)){
2892                object[proName] = d;
2893            }
2894        }
2895    };
2896
2897})(_,xfalib);
2898/**
2899 * @package xfalib.ut.DateInfo
2900 * @import xfalib.ut.Class
2901 * @fileOverview A wrapper class for date related information.
2902 * @version 0.0.1
2903 */
2904
2905/**
2906 * @constructor
2907 */
2908
2909(function(_,xfalib) {
2910    var DateInfo = xfalib.ut.DateInfo = xfalib.ut.Class.extend({
2911
2912        initialize: function(options) {
2913            if (options && !options.isParsingCall ) { // skip setting internal values when called while parsing date formats
2914                this.date = new Date();
2915                this._year = this.date.getFullYear();
2916                this._month = this.date.getMonth() + 1;
2917                this._day = this.date.getDay();
2918            }
2919            DateInfo._super.initialize.call(this);
2920        },
2921
2922        formatNum : function(num, digits){
2923            if(num<0)
2924                num = 0;
2925            return xfalib.ut.PictureUtils.padding(num, digits);
2926        },
2927
2928        getDate : function(){
2929            return this.date;
2930        },
2931        setDate : function() {
2932          this.date = new Date(this._year,this._month-1,this._day)
2933        },
2934        getISODate : function(){
2935            var isoDate = [];
2936
2937            isoDate.push(this.formatNum(this._year, 4));
2938            isoDate.push("-");
2939            isoDate.push(this.formatNum(this._month, 2));
2940            isoDate.push("-");
2941            isoDate.push(this.formatNum(this._day, 2));
2942
2943            return isoDate.join("");
2944        },
2945
2946        year : function(y) {
2947            if(y && y > 0 && y <= 9999)
2948                this._year = y;
2949            else
2950                throw "undefined year";
2951        },
2952
2953        month : function(m) {
2954            if(m && m>0 && m < 13) {
2955               this._month = m;
2956            }
2957            else
2958                throw "Invalid month " + m;
2959        },
2960
2961        _leapYear : function() {
2962            var year = this._year;
2963            return year % 400 == 0 || (year % 100 != 0 && year % 4 == 0);
2964        },
2965
2966        _maxDate : function(m) {
2967              if(this._leapYear() && m == 2)
2968                 return 29;
2969              else return DateInfo.dates[m-1];
2970        },
2971
2972        day : function(d) {
2973            if(d && d > 0 && d <= this._maxDate(this._month || 0))
2974                this._day = d;
2975            else
2976                throw "Invalid Date "+ d + " for the month "+(this._month);
2977        },
2978
2979        validate : function(y, m, d) {
2980                this.year(y);
2981                this.month(m);
2982                this.day(d);
2983        }
2984    });
2985
2986    DateInfo.ParseIsoString = function(isoDateStr, locale){
2987		var isDateRegexp = /^(\d{4})(?:-?(\d{1,2})(?:-?(\d{1,2}))?)?(?:T((\d{2}):(\d{2}):(\d{2}))Z)?$/;
2988        var match = isDateRegexp.exec(isoDateStr);
2989        if(match && match.length >= 4){
2990            var dateInfo = new DateInfo();
2991            var date = new Date(isoDateStr);
2992            // TODO - check if date is invalid.
2993            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
2994                dateInfo.year(date.getFullYear());
2995                dateInfo.month(date.getMonth()+1);
2996                dateInfo.day(date.getDate());
2997            } else {
2998                try {
2999                    dateInfo.year(Number(match[1]));
3000                    dateInfo.month(Number(match[2]));
3001                    dateInfo.day(Number(match[3]));
3002                } catch(e) {
3003                    return null;
3004                }
3005            }
3006            dateInfo.setDate();
3007            return dateInfo;
3008        }
3009        return null;
3010    };
3011
3012    DateInfo.Parse = function(dateStr, locale, validateWithDefaultPatterns){
3013        locale = locale || "en_US";
3014        var patterns = xfalib.ut.PictureUtils.getLocaleObject(locale,"datePatterns"),
3015            isoDate = this.ParseIsoString(dateStr, locale);
3016        if(!_.isEmpty(isoDate)) {
3017            return isoDate;  // in case edit pattern is present, it'll be parsed by the widget during input and return an iso date string.
3018        }
3019        //if edit pattern is present then don't try to match it from default locale patterns.
3020        if(validateWithDefaultPatterns === false){
3021            _.find(patterns, function(pattern) {
3022                try {
3023                    isoDate = xfalib.ut.PictureFmt.parseDate(dateStr,pattern,locale);
3024                    return true;
3025                } catch(exception) {
3026                    return false;
3027                }
3028            });
3029        }
3030        isoDate = isoDate || dateStr;
3031        return DateInfo.ParseIsoString(isoDate);
3032    };
3033
3034    DateInfo.dates = [31,28,31,30,31,30,31,31,30,31,30,31];
3035    DateInfo.daysOfWeek = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
3036})(_,xfalib);
3037/**
3038 * @package xfalib.ut.PictureEngine
3039 * @import xfalib.ut.Scanner
3040 * @fileOverview The file is a facade to assembly all components together.
3041 * @version 0.0.1
3042 */
3043(function(_,xfalib) {
3044
3045    var PictureEngine = xfalib.ut.PictureEngine = xfalib.ut.Class.extend({
3046
3047        _lookupNext: xfalib.ut.Scanner.lookupNext,
3048
3049        MAX_XFA_PREC	: 8,		// Max no. of fractional digits in XFA.
3050        MAX_DBL_DIG	:18,		// Max no. of significant digits in a double.
3051        MAX_INT_DIG	:10,		// Max no. of significant digits in an integer.
3052        MAX_DBL_WIDTH	:15,		// Max width before precision loss in a double.
3053        INTEGRAL_FMT :  0,
3054        DECIMAL_FMT : 1,
3055        CURRENCY_FMT : 2,
3056        PERCENT_FMT : 3,
3057
3058        parseDate : function(sSource, sPicture, locale){
3059            return this._acceptVisitor(new xfalib.ut.DateParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource,_locale:this.jsonModel.locale}}));
3060        },
3061
3062        formatDate : function(dDate, sPicture){
3063            var validateWithDefaultPatterns = typeof sPicture !== 'undefined';
3064            var dateInfo = xfalib.ut.DateInfo.Parse(dDate, this.jsonModel.locale, validateWithDefaultPatterns);
3065            if(dateInfo == null){
3066                return null;
3067            }else{
3068                return this._acceptVisitor(new xfalib.ut.DateFormattingVisitor({jsonModel:{_sPicture:sPicture,_dateInfo:dateInfo,_locale:this.jsonModel.locale}}));
3069            }
3070        },
3071
3072        parseTime : function(sSource, sPicture){
3073            return this._acceptVisitor(new xfalib.ut.TimeParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource}}));
3074        },
3075
3076        formatTime : function(dDate, sPicture){
3077            var timeInfo = xfalib.ut.TimeInfo.Parse(dDate, this.jsonModel.locale);
3078            if(timeInfo == null){
3079                return null;
3080            }else{
3081                return this._acceptVisitor(new xfalib.ut.TimeFormattingVisitor({jsonModel:{_sPicture:sPicture,_timeInfo:timeInfo}}));
3082            }
3083        },
3084
3085        parseText : function(sSource, sPicture){
3086            return this._acceptVisitor(new xfalib.ut.TextParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource}}));
3087        },
3088
3089        formatText : function(sSource, sPicture,bRelaxed){
3090            return this._acceptVisitor(new xfalib.ut.TextFormattingVisitor({jsonModel:{_sPicture:sPicture,_text:sSource,relaxed:bRelaxed}}));
3091        },
3092
3093        parseNumeric : function(sSource, sPicture){
3094            var visitor = new xfalib.ut.NumParsingVisitor({jsonModel:{_sPicture:sPicture,_dataString:sSource,_locale:this.jsonModel.locale}}); // TODO : Is locale required
3095            visitor.parse();
3096            return visitor.getResult();
3097        },
3098
3099       formatNumeric : function(sSource, sPicture,locale,bRelaxed,bFormatNumberFromasDefaultPC){
3100
3101             var sFormatPicture =sPicture;
3102             if( bRelaxed && bFormatNumberFromasDefaultPC){
3103                 sFormatPicture = this.getNumberFormat(sPicture,1, {formatOption: "WITH_GROUPINGS",
3104                                      "precision"  : this.getNumberPrecision(sSource),
3105                                    "width"      : sSource.length
3106                                   });
3107             }
3108             return this._acceptVisitor(new xfalib.ut.NumFormattingVisitor({jsonModel:{_sPicture:sFormatPicture,_locale:this.jsonModel.locale},text:sSource}));
3109        },
3110
3111        _acceptVisitor : function(visitor){
3112            this._scanPattern(visitor);
3113            return visitor.getResult();
3114        },
3115
3116        _scanPattern : function(visitor){
3117            var patPos = 0;
3118            var sPicture = visitor.getPicture();
3119            for(var token = this._lookupNext(sPicture, patPos, visitor.acceptPatternChar); token != null;  ){
3120                visitor.consume(token);
3121                patPos = patPos + token.len;
3122                token = this._lookupNext(sPicture, patPos, visitor.acceptPatternChar);
3123            }
3124        },
3125
3126       /**
3127          * Removes n bytes from this string starting at position nOffset.
3128         *
3129          * @param nOffset - start position for the remove
3130          * @param nLength - the number of characters to remove
3131          * @return This string
3132          */
3133
3134         _swallow : function(sString , nOffset, nLenToSwallow)
3135         {
3136             if(_.isEmpty(sString) || nLenToSwallow ==0){
3137                 return sString;
3138             }
3139
3140             if( (nOffset + nLenToSwallow)> sString.length ) {
3141                 nLenToSwallow = (nOffset + nLenToSwallow) - sString.length;
3142             }
3143            var subStr = sString.substr(0,nOffset) + sString.substr(offset + nLenToSwallow);
3144
3145             return subStr
3146         },
3147         /**
3148         * Replace some portion of one string with another String.
3149          * @param sString - the String where it has to be replaced.
3150          * @param sReplacement - the replacement string.
3151          * @param nOffset - start position for the replacement. Default value = 0.
3152          * @param nCutLength - the number of bytes to remove from the
3153          * original string.
3154          */
3155
3156         _replaceAll : function(sString ,sReplacement , nOffset ,nCutlength) {
3157             return sString.substr(0,nOffset) + sReplacement  + sString.substr(nOffset + nCutlength)
3158         },
3159
3160         //----------------------------------------------------------------------
3161         // SkipOver
3162         //
3163         // Scan this string for the first byte of the character not in the given set.
3164         // Similar to strspn().
3165         //----------------------------------------------------------------------
3166         _skipOver : function(fromString,sSkip, nOffset)
3167         {
3168             // starting at the offset position, scan the characters in this string
3169             // until it does not match any of the characters in the given set.
3170            var nCharsSkipped = nOffset;
3171             var i = 0;
3172             while (nCharsSkipped < fromString.length)
3173             {
3174                 i = nCharsSkipped;
3175                 if (sSkip.indexOf(fromString[i]) ==-1) {
3176                     break;
3177                 }
3178                 i++;
3179                 nCharsSkipped = i;
3180             }
3181
3182             return nCharsSkipped - nOffset;
3183         },
3184
3185         /*
3186          * Get the numeric format in the given style.
3187          * @param style in the range of values 0-2,
3188          * where (0 = integral, 1 = decimal, 2 = currency).
3189          * @param option in the set of format options:
3190          */
3191         getNumberFormat : function(format , style, option)
3192        {
3193             if (style < this.INTEGRAL_FMT || this.PERCENT_FMT < style) {
3194                 style = this.DECIMAL_FMT;
3195             }
3196
3197             var sFormat = format;
3198
3199             //
3200             // Use any alternate part because they handle negative values.
3201             //
3202             var  nBar = 0;
3203             if ((nBar = sFormat.indexOf('|')) != -1) {
3204                 sFormat = this._swallow(sFormat, 0, nBar + 1);
3205             }
3206             //
3207             // Determine position of radix (or anything like it)
3208             // and the replicating part of the pattern, i.e., from
3209             // the separator to this radix.
3210            //
3211             var nDot;
3212             if ( (nDot = sFormat.indexOf('.')) == -1) {
3213                 if ((nDot = sFormat.indexOf('v')) == -1) {
3214                     if ((nDot = sFormat.indexOf('V')) == -1) {
3215                         if ((nDot = sFormat.indexOf('E')) == -1) {
3216                             if ((nDot = sFormat.indexOf(' ')) == -1) {
3217                                 if ((nDot = sFormat.indexOf('%')) == -1) {
3218                                     nDot = sFormat.length;
3219                                 }
3220                             }
3221                         }
3222                     }
3223                 }
3224             }
3225             if (nDot) {
3226                 if (this._skipOver(sFormat,"89zZ", nDot - 1) != 1) {
3227                     nDot = sFormat.length;
3228                 }
3229             }
3230             var sZZZ;
3231             var nZed;
3232             if ( (nZed = sFormat.indexOf("z,")) != -1) {
3233                 //
3234                 // Watson 1230768.  Handle locales, like India, that have
3235                 // pictures with more than one grouping symbol.
3236                //
3237                 var nSep = nDot;
3238                 var nComma;
3239                 if ((nComma = sFormat.indexOf(',', nZed + 2)) !=-1) {
3240                    nSep = nComma;
3241                 }
3242                 if (nSep > nZed + 2) {
3243                     sZZZ = Array(nSep - nZed).join('z');
3244                 }
3245                 else {
3246                     sZZZ = Array(1).join('z');
3247                 }
3248             }
3249             else {
3250                nZed = 0;
3251             }
3252             //
3253             // If non-integral styles Then determine width and precision.
3254             //
3255             var nPrec = 0;
3256             var nWidth = this.MAX_INT_DIG;
3257             if (style != this.INTEGRAL_FMT) {
3258                 nPrec = option.precision; // (option >> 8) & 0xff;
3259                 var trim = ((nPrec & 0x80) == 0);
3260                 nPrec &= 0x7f;
3261                 if (nPrec == 0x7f) {
3262                     nPrec = this._skipOver(sFormat, "89zZ", nDot + 1);
3263                 }
3264                 if ((option.width) != undefined) {
3265                     nWidth = option.width;
3266                 }
3267                 else {
3268                     nWidth = this.MAX_DBL_DIG;
3269                 }
3270                 //
3271                 // Fix for Watson 1229423.  If the locale's format contains
3272                 // any sign pictures Then widen accordingly.  Also widen if
3273                 // precision of locale's picture format is greater than requested.
3274                 //
3275                 if (sFormat.indexOf('s')!=-1) {
3276                     nWidth += 1;
3277                 }
3278                 if (sFormat.indexOf('(')!=-1) {
3279                     nWidth += 1;
3280                 }
3281                 if (sFormat.indexOf(')') !=-1) {
3282                     nWidth += 1;
3283                 }
3284                var nFmtPrec = this._skipOver(sFormat,"89zZ", nDot + 1);
3285                 if (0 < nPrec && nPrec < nFmtPrec) {
3286                     nWidth += nFmtPrec - nPrec;
3287                 }
3288
3289                 //
3290                 // Pare down the precision if the width is big enough to yield
3291                 // IEEE 754 64-bit double precision errors, which appears to be
3292                 // anything over 14 significant digits.
3293                 //
3294                 if (trim && nPrec > 0 && nWidth > nPrec) {
3295                     //
3296                     // Fix for Watson 1211481.  If the given precision is less
3297                     // than what the locale's format dictates then widen the given
3298                     // width.
3299                    //
3300                     if (nPrec <= sFormat.length - 1 - nDot) {
3301                         nWidth += sFormat.length - 1 - nDot - nPrec;
3302                     }
3303                     for (var i = nWidth - 1; i > this.MAX_DBL_WIDTH; i--) {
3304                         //
3305                         // Never pare down the precision below what the locale's
3306                         // format dictates.
3307                         //
3308                         if (nPrec <= sFormat.length - 1 - nDot)
3309                            break;
3310                         nPrec--;
3311                     }
3312                 }
3313             }
3314             //Watson 1483675 - If the locale's format contains
3315             // a dollar sign or a space then widen accordingly.
3316             if (style == this.CURRENCY_FMT) {
3317                 if (sFormat.indexOf('$')!=-1) {
3318                     nWidth++;
3319                 }
3320
3321                 if (sFormat.indexOf(' ')!=-1) {
3322                     nWidth += 1;
3323                }
3324             }
3325
3326             //
3327             // If percent style was wanted Then truncate after the percent character.
3328             //
3329             if (style == this.PERCENT_FMT) {
3330                 var nTrim = this._skipOver(sFormat,"89zZ", nDot + 1);
3331                 sFormat = this._replaceAll(sFormat,"",nTrim,0)
3332                 //sFormat.Replace(jfString::EmptyString(), nDot + 1, nTrim);
3333
3334                 //Watson 1483675 - If the locale's format contains
3335                 // a percent sign then widen accordingly.
3336                 if (sFormat.indexOf('%')!=-1) {
3337                     nWidth++;
3338                 }
3339             }
3340             //
3341             // Else if integral style was wanted Then truncate at the radix character.
3342             //
3343             //
3344             // If integral style was wanted Then truncate at the radix character.
3345             //
3346             else if (style == this.INTEGRAL_FMT || nPrec == 0){// && option.formatOption == "WITHOUT_RADIX") {
3347                 var nTrim = this._skipOver(sFormat,"89zZ", nDot + 1);
3348                 sFormat = this._replaceAll(sFormat,"",nDot,nTrim+1);
3349             }
3350             //
3351             // Otherwise for decimal and currency styles Do
3352             // replace fractional 'z' pictures with '8's to requested precision,
3353             //
3354             else if (option.formatOption == "WITH_EIGHTS") {
3355                 var nEight = nDot + 1;
3356                 while ((nEight =sFormat.indexOf('z'))!=-1) {
3357                     this._replaceAll(sFormat, '8', nEight,'8'.length);
3358                 }
3359                 while (sFormat.Length() - nDot <= nPrec) {
3360                     sFormat = this._replaceAll(sFormat, "8", nDot + 1, 0);
3361                 }
3362             }
3363             //
3364             // Or replace fractional '9' pictures with 'z's to requested precision
3365             // Watson 1322850 - add option to keep nines, previously this function
3366             // would force frac. digits to be either z's or 8's with no option for 9's.
3367             //
3368             else if ((option.formatOption) == "WITH_ZEDS" && !((option.formatOption) == "KEEP_NINES")) {
3369                 var nNine = nDot + 1;
3370                 while ((nNine = sFormat.indexOf('9'))!=-1) {
3371                     this._replaceAll(sFormat, 'z', nNine,1);
3372                 }
3373                 while (sFormat.Length() - nDot <= nPrec) {
3374                     this._replaceAll(sFormat, "z", nDot + 1, 0);
3375                 }
3376             }
3377             //
3378             // Replicate section from separator to radix to requested width.
3379             //
3380             if (!sZZZ) {
3381                 sZZZ = "z";
3382             }
3383            else if ((option.formatOption) == "WITHOUT_GROUPINGS" ) {
3384                 //
3385                 // Watson 1230768.  Handle locales, like India, that have
3386                 // pictures with more than one grouping symbol.
3387                 //
3388                 var nComma = nZed + 1 ;
3389                 this._replaceAll(sFormat, 'z' ,nComma,1);
3390                 while ( nComma!= -1 && (nComma < nDot)) {
3391                     nComma = sFormat.indexOf(',');
3392                     sFormat = this._replaceAll(sFormat,'z',nComma,1);
3393                 }
3394             }
3395             else if ((option.formatOption == "WITH_GROUPINGS")) {
3396                 sZZZ = this._replaceAll(sZZZ,',',0,1);
3397                 nWidth += (nWidth + sZZZ.length) / sZZZ.length;
3398             }
3399             while (sFormat.length < nWidth) {
3400                 sFormat = this._replaceAll(sFormat, sZZZ, nZed + 1, 0);
3401             }
3402             return sFormat;
3403         },
3404
3405         /**
3406          * Get the decimal precision of the given numeric string.
3407          * @return the decimal precision or 0 for integral values.
3408          */
3409         getNumberPrecision: function(sVal)
3410         {
3411             var nRadix = 0;
3412             var i = -1;
3413             // Reason for not using the commented line. We are always storing the value in model with . as decimal separator
3414             // Passing field locale/ browser locale would lead to precision width being zero for non-english locales where
3415             // decimal separater may be different.
3416             // var rIndex = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel.locale,"numberSymbols").decimal;
3417             // so hardcoding . for now
3418             var rIndex = ".";
3419             if( (nRadix = sVal.indexOf(rIndex))!=-1)
3420             {
3421                     for(; nRadix <=sVal.length ;nRadix++) {
3422                         i++;
3423                     }
3424
3425                 return i;
3426             }
3427             return 0;
3428          }
3429    })
3430})(_,xfalib);
3431/**
3432 * @package xfalib.ut.FormattingVisitorBase
3433 * @import xfalib.ut.VisitorBase
3434 * @fileOverview Base class for visitor
3435 * @version 0.0.1
3436 */
3437
3438/**
3439 * @constructor
3440 * @param Object {jsonModel: {_sPicture: String]}
3441 */
3442
3443(function(_,xfalib) {
3444    var FormattingVisitorBase = xfalib.ut.FormattingVisitorBase = xfalib.ut.VisitorBase.extend({
3445
3446        initialize: function() {
3447            this._buffer = []; //TODO: ASK Ren where does this _buffer comes from
3448            FormattingVisitorBase._super.initialize.call(this);
3449        },
3450
3451        consumeStringWildCard : function(token){
3452            //'?' '*' '+
3453            this._buffer.push(" ");
3454        },
3455
3456        consumeStringLiteral : function(token){
3457            this._buffer.push(this.jsonModel._sPicture.substr(token.startPos+1,token.len-2));
3458        },
3459
3460        consumeCharLiteral : function(token){
3461            this._buffer.push(""+ this.jsonModel._sPicture.charAt(token.startPos));
3462        }
3463    })
3464
3465})(_,xfalib);
3466/**
3467 * @package xfalib.ut.ParsingVisitorBase
3468 * @import xfalib.ut.VisitorBase
3469 * @fileOverview Base class for visitor
3470 * @version 0.0.1
3471 */
3472
3473/**
3474 * @constructor
3475 * @param Object {jsonModel: {_sPicture: String,_dataString: String}}
3476 */
3477
3478(function(_,xfalib){
3479    var ParsingVisitorBase = xfalib.ut.ParsingVisitorBase = xfalib.ut.VisitorBase.extend({
3480
3481        initialize: function() {
3482            this._strLen = this.jsonModel._dataString.length;
3483            this._strPos = 0;
3484            ParsingVisitorBase._super.initialize.call(this);
3485        },
3486
3487        consumeStringWildCard : function(token){
3488            if (chr == '?') {
3489                if (this._strPos < this._strLen)//&& Character.isDefined(str.charAt(strPos))
3490                    this._strPos += 1;
3491            } else if (chr == '+') {
3492                if (this._strPos >= this._strLen)// || ! Character.isWhitespace(str.charAt(strPos)))
3493                    throw "Mismatch";
3494                this._strPos += 1;
3495                while (this._strPos < this._strLen)// && Character.isWhitespace(str.charAt(strPos)))
3496                    this._strPos += 1;
3497            } else if (chr == '*') {
3498                while (this._strPos < this._strLen)// && Character.isWhitespace(str.charAt(strPos)))
3499                    this._strPos += 1;
3500            }
3501
3502        },
3503
3504        consumeStringLiteral : function(token){
3505            for(var offset=0; offset<token.len-2 ;offset++){ //-2, heading and trailing quote
3506                if(this.jsonModel._sPicture.charAt(token.startPos+offset+1) != this.jsonModel._dataString.charAt(this._strPos+offset)){
3507                    throw ("Mismatch" + this.jsonModel._sPicture.substr(token.startPos, token.len));
3508                }
3509            }
3510            this._strPos += token.len-2;
3511
3512        },
3513
3514        consumeCharLiteral : function(token){
3515            if(this.jsonModel._sPicture.charAt(token.startPos) == this.jsonModel._dataString.charAt(this._strPos)){
3516                this._strPos += 1;
3517            }else{
3518                throw "Mismatch";
3519            }
3520        }
3521    })
3522})(_,xfalib);
3523
3524/**
3525 * @package xfalib.ut.DateFormattingVisitor
3526 * @import xfalib.ut.FormattingVisitorBase
3527 * @fileOverview The file provides formating logic on date pattern characters.
3528 * @version 0.0.1
3529 */
3530
3531
3532/**
3533 * @constructor
3534 * @param object {jsonModel: {_sPicture:String,_dateInfo: xfalib.ut.DateInfo}}
3535 */
3536
3537(function(_,xfalib) {
3538    var PictureUtils =  xfalib.ut.PictureUtils;
3539    var DateFormattingVisitor = xfalib.ut.DateFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3540
3541        consumeSubPattern : function(token){
3542            var chr = token.patChar;
3543            var chrCnt = token.len;
3544
3545            switch (chr) {
3546                case 'D':
3547                    var dayOfMonth=this.jsonModel._dateInfo.date.getDate();
3548                    switch(chrCnt){
3549                        case 1:
3550                            break;
3551                        case 2:
3552                            dayOfMonth = PictureUtils.padding(dayOfMonth,2);
3553                            break;
3554                    }
3555                    this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,dayOfMonth));
3556                    break;
3557                case 'J':
3558
3559                    //this._mDayOfYear;
3560                    break;
3561                case 'M':
3562                    var monthOfYear = this.jsonModel._dateInfo.date.getMonth();
3563                    switch(chrCnt){
3564                        case 1:
3565                            this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,monthOfYear+1));
3566                            break;
3567                        case 2:
3568                            this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,PictureUtils.padding(monthOfYear+1,2)));
3569                            break;
3570                        case 3:
3571                            var monthNames = PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.abbrmonthNames");
3572                            this._buffer.push(monthNames[monthOfYear]);
3573                            break;
3574                        case 4:
3575                            var monthNames = PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.monthNames");
3576                            this._buffer.push(monthNames[monthOfYear]);
3577                            break;
3578                    }
3579
3580                    break;
3581                case 'E':
3582                    var dayOfWeek = this.jsonModel._dateInfo.date.getDay();
3583                    var dayNames;
3584                    switch(chrCnt) {
3585                        case 1:
3586                            this._buffer.push(dayOfWeek);
3587                            break;
3588                        case 3:
3589                            dayNames =  PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.abbrdayNames");
3590                            this._buffer.push(dayNames[dayOfWeek]);
3591                            break;
3592                        case 4:
3593                            dayNames =   PictureUtils.getLocaleObject(this.jsonModel._locale,"calendarSymbols.dayNames");
3594                            this._buffer.push(dayNames[dayOfWeek]);
3595                            break;
3596                        default:
3597                            throw "unsupported Picture Clause ";
3598                    }
3599                    break;
3600                case 'e':
3601                    break;
3602                case 'G':
3603                    break;
3604                case 'Y':
3605
3606                    var yearOfEra = this.jsonModel._dateInfo.date.getFullYear()
3607                    switch(chrCnt){
3608                        case 2:
3609                            if(yearOfEra>2029 || yearOfEra < 1930){
3610                                throw "unsupported " + yearOfEra + " by pattern YY";
3611                            }
3612                            yearOfEra = PictureUtils.padding(yearOfEra % 100, 2);
3613                            break;
3614                        case 4:
3615                            yearOfEra = PictureUtils.padding(yearOfEra, 4); // 2 digit(0000-9999)
3616                            break;
3617                    }
3618                    this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,yearOfEra));
3619                    break;
3620                case 'w':
3621                    break;
3622                case 'W':
3623                    break;
3624                default: throw "Unsupported pattern";
3625            }
3626
3627        },
3628        /**
3629         *
3630         * @override
3631         */
3632        getResult : function(){
3633            return this._buffer.join("");
3634        }
3635
3636    });
3637})(_,xfalib);
3638
3639
3640/**
3641 * @package xfalib.ut.TextFormattingVisitor
3642 * @import xfalib.ut.FormattingVisitorBase
3643 * @fileOverview Formats a string according to Text Picture.
3644 * @version 0.0.1
3645 */
3646
3647/**
3648 * @constructor
3649 * @param Object { jsonModel:{_sPicture: String, _text: String}}
3650 */
3651(function(_,xfalib){
3652    var TextFormattingVisitor = xfalib.ut.TextFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3653
3654        initialize: function() {
3655            this._textPos = 0;
3656            this._relaxed = typeof this.jsonModel.relaxed === "undefined" ? true: this.jsonModel.relaxed;
3657            TextFormattingVisitor._super.initialize.call(this);
3658        },
3659
3660        consumeSubPattern : function(token){
3661            var chr = token.patChar;
3662            var chrCnt = token.len;
3663            for(var index = 0; index < chrCnt && (!this._relaxed || this._textPos < this.jsonModel._text.length); index++){
3664                switch (chr) {
3665                    case '9': // Numeric
3666                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3667                        if(!xfalib.ut.PictureUtils.isDigit(cUni)){
3668                            throw "TextFormatting: not a digit as expected";
3669                        }
3670                        this._buffer.push(cUni);
3671                        break;
3672                    case 'A': // Alphebetic
3673                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3674                        if(!xfalib.ut.PictureUtils.isLetter(cUni)){
3675                            throw "TextFormatting: not a character as expected";
3676                        }
3677                        this._buffer.push(cUni);
3678                        break;
3679                    case 'O': // Alphanumeric
3680                    case '0':
3681                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3682                        // cUni === "" is a hack for LC-6152
3683                        // To prevent extra loop[one more time than the length of the string] for which cUni was ""
3684                        // which was neither a letter nor a digit
3685                        // so we were getting textformatting error
3686                        //which caused email id validation to fail for chars less than picture clause
3687                        if(!(cUni ==="" || xfalib.ut.PictureUtils.isLetter(cUni) || xfalib.ut.PictureUtils.isDigit(cUni))){
3688                            throw "TextFormatting: not a character or digit as expected";
3689                        }
3690                        this._buffer.push(cUni);
3691                        break;
3692                    case 'X':
3693                        var cUni = this.jsonModel._text.charAt(this._textPos++);
3694                        this._buffer.push(cUni);
3695                        break;
3696                    case 't':
3697                        this._buffer.push("\t");
3698                        break;
3699                    default: this._buffer.push(chr);
3700                }
3701            }
3702
3703        },
3704
3705        /**
3706         *
3707         * @override
3708         */
3709        getResult : function(){
3710            if(this._textPos < this.jsonModel._text.length)
3711                throw "TextFormatting: picture clause smaller than input Text";
3712            return this._buffer.join("");
3713        },
3714
3715        /**
3716         *
3717         * @override
3718         */
3719        acceptPatternChar : function(chr){
3720            return xfalib.ut.PictureUtils.inString(chr, "9AO0Xt");
3721        },
3722
3723        consumeCharLiteral : function(token){
3724         this._buffer.push(""+ this.jsonModel._sPicture.charAt(token.startPos));
3725         // LC-3869 : forward the text pointer after literal is present and matched with the picture.
3726         if(this.jsonModel._sPicture.charAt(token.startPos) == this.jsonModel._text.charAt(token.startPos))
3727             this._textPos++;
3728        }
3729    })
3730
3731})(_,xfalib);
3732
3733
3734/**
3735 * @package xfalib.ut.TextFormattingVisitor
3736 * @import xfalib.ut.FormattingVisitorBase
3737 * @fileOverview The file provides formating logic on date pattern characters.
3738 * @version 0.0.1
3739 */
3740
3741/**
3742 * @constructor
3743 * @param object {jsonModel: {_sPicture:String,_timeInfo: xfalib.ut.TimeInfo}}
3744 */
3745
3746(function(_,xfalib){
3747    var TimeFormattingVisitor = xfalib.ut.TimeFormattingVisitor=  xfalib.ut.FormattingVisitorBase.extend({
3748
3749        consumeSubPattern : function(token){
3750            var chr = token.patChar;
3751            var chrCnt = token.len;
3752
3753            switch (chr) {
3754                case 'H':
3755                case 'K':
3756                    var hourOfDay = this.jsonModel._timeInfo.mHourOfDay;
3757                    if(chr=='K'){
3758                        hourOfDay += 1;
3759                    }
3760                    switch(chrCnt){
3761                        case 1:
3762                            this._buffer.push(hourOfDay);
3763                            break;
3764                        case 2:
3765                            this._buffer.push(xfalib.ut.PictureUtils.padding(hourOfDay,2));
3766                            break;
3767                    }
3768                    break;
3769
3770                case 'M':
3771                    var minuteOfHour = this.jsonModel._timeInfo.mMinuteOfHour;
3772                    switch(chrCnt){
3773                        case 1:
3774                            this._buffer.push(minuteOfHour);
3775                            break;
3776                        case 2:
3777                            this._buffer.push(xfalib.ut.PictureUtils.padding(minuteOfHour,2));
3778                            break;
3779                    }
3780
3781                    break;
3782                case 'S':
3783                    var secondOfMinute = this.jsonModel._timeInfo.mSecondOfMinute;
3784                    switch(chrCnt){
3785                        case 1:
3786                            this._buffer.push(secondOfMinute);
3787                            break;
3788                        case 2:
3789                            this._buffer.push(xfalib.ut.PictureUtils.padding(secondOfMinute,2));
3790                            break;
3791                    }
3792                    break;
3793                case 'F':
3794                    var Milliseconds =this.jsonModel._timeInfo.mThousandthOfSecond;
3795                    this._buffer.push(xfalib.ut.PictureUtils.padding(Milliseconds,3));
3796                    break;
3797
3798                default: throw "Unsupported pattern";
3799            };
3800
3801        },
3802
3803        /**
3804         *
3805         * @override
3806         */
3807        getResult : function(){
3808            return this._buffer.join("");
3809        }
3810
3811    });
3812
3813})(_,xfalib);
3814
3815
3816/**
3817 * @package xfalib.ut.NumFormattingVisitor
3818 * @import xfalib.ut.FormattingVisitorBase
3819 * @fileOverview Formats a string according to Text Picture.
3820 * @version 0.0.1
3821 */
3822
3823/**
3824 * @constructor
3825 * @param Object { jsonModel:{_sPicture: String}, text: String}
3826 */
3827
3828(function(_,xfalib){
3829    var PictureUtils =  xfalib.ut.PictureUtils;
3830    var NumFormattingVisitor = xfalib.ut.NumFormattingVisitor = xfalib.ut.FormattingVisitorBase.extend({
3831
3832        initialize: function(options) {
3833            NumFormattingVisitor._super.initialize.call(this);
3834            this._textPos = 0;
3835
3836            //boolean value used for internal state track
3837            this._mbDigitAddedToOutput = false; // at least one digit has been added to output
3838            this._mbSignAddedToOutput = false;
3839            this._nScannedPatternDigit = 0; //how many digit(98Zz) characters scanned in pattern, reset to 0 after '.Vv'
3840            this._mbRadixSeen = false;
3841
3842            this._pictureDesc = new xfalib.ut.NumPictureDesc({jsonModel:{_sPicture:this.jsonModel._sPicture}});
3843            this.jsonModel._sPicture= this._pictureDesc.getPicture();
3844            this._numberInfo = this._pictureDesc.parseNumberInfo(options.text);
3845
3846            this._mbNegative = this._numberInfo.isNegative;
3847            this._msText = this._numberInfo.msText;
3848            this._leadingPadding = this._numberInfo.padding;
3849            //
3850            this._mNumberSymbols = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale,"numberSymbols");
3851            this._mCurrencySymbols = xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale,"currencySymbols");
3852        },
3853
3854        _checkAndAddDecimalPoint: function(fw) {
3855            if(this._mAddRadix) {
3856                this._buffer.push(this._fmtStr(this._mNumberSymbols.decimal, fw));
3857                this._mAddRadix = false;
3858            }
3859        },
3860
3861        consumeSubPattern : function(token){
3862            var chr = token.patChar,
3863                chrCnt = token.len;
3864            switch (chr) {
3865                case '9':
3866                case '8':
3867                case 'Z': // Digit or space if zero.
3868                case 'z':// Digit or nothing if zero.
3869                    if(!this._mbSignAddedToOutput)
3870                        this._ensureSignIsAdded();
3871                    while (chrCnt-- > 0 ) {
3872                        if(!this._mbRadixSeen){
3873                            if(this._leadingPadding > this._nScannedPatternDigit++){
3874                                var placeHolder = null;
3875                                if(this._mbDigitAddedToOutput){
3876                                    placeHolder = this._mNumberSymbols.zero;
3877                                }else{
3878                                    if(chr == '9' || chr =='8') {
3879                                        placeHolder = this._mNumberSymbols.zero;
3880                                        this._mbDigitAddedToOutput = true;
3881                                    }else if(chr == 'Z'){
3882                                        placeHolder = " ";
3883                                    }
3884                                }
3885                                if(placeHolder){
3886                                    this._buffer.push(this._matchChr(placeHolder));
3887                                }
3888                            }else {
3889                                var cValue = this._msText.charAt(this._textPos++);
3890                                this._ensureCharIsDigit(cValue);
3891                                this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3892                                this._mbDigitAddedToOutput = true;
3893                            }
3894                        }else{  //handling fractional part
3895                            if(this._nScannedPatternDigit++  < this._numberInfo.fractionDigit ){
3896                                var cValue = this._msText.charAt(this._textPos++);
3897                                this._ensureCharIsDigit(cValue);
3898                                this._checkAndAddDecimalPoint();
3899                                this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3900                                this._mbDigitAddedToOutput = true;
3901                            }else{
3902                                if(chr == '9'|| chr =='Z') {
3903                                    this._checkAndAddDecimalPoint();
3904                                    this._buffer.push(this._matchChr(this._mNumberSymbols.zero));
3905                                } else if(chr == '8') {
3906                                    var cValue = this._msText.charAt(this._textPos++);
3907                                    if(cValue != '' && this._ensureCharIsDigit(cValue)) {
3908                                        this._checkAndAddDecimalPoint();
3909                                        this._buffer.push(PictureUtils.convertNumberToLocale(this.jsonModel._locale,cValue));
3910                                        this._mbDigitAddedToOutput = true;
3911                                    }
3912                                }
3913                            }
3914                        }
3915
3916                    }
3917
3918                    break;
3919                case 'E': // Exponent.
3920                    this._buffer.push('E');
3921                    this._buffer.push("" + this._numberInfo.shift);
3922                    break;
3923                case 'C': // CR symbol if negative and spaces if positive.
3924                    this._buffer.push((this._mbNegative) ? xfalib.ut.NumPictureDesc.gsCR : xfalib.ut.NumPictureDesc.gsDSP);
3925                    break;
3926                case 'c': // CR symbol if negative and nothing if positive.
3927                    if (this._mbNegative){
3928                        this._buffer.push(xfalib.ut.NumPictureDesc.gsCR);
3929                    }
3930                    break;
3931                case 'D': // DB symbol if negative and spaces if positive.
3932                    this._buffer.push((this._mbNegative) ? xfalib.ut.NumPictureDesc.gsDB : xfalib.ut.NumPictureDesc.gsDSP);
3933                    break;
3934                case 'd': // DB symbol if negative and nothing if positive.
3935                    if (this._mbNegative){
3936                        this._buffer.push(xfalib.ut.NumPictureDesc.gsDB);
3937                    }
3938                    break;
3939                case 'S': // Minus sign if negative and a space if positive.
3940                case 's':
3941                    if (this._mbNegative){
3942                        this._buffer.push(this._fmtStr(	this._mNumberSymbols.minus));
3943                    }else{
3944                        if('S' == chr){
3945                            this._buffer.push(this._matchChr(' '));
3946                        }
3947                    }
3948                    break;
3949                case 'V': // Implied decimal sign if parsing.
3950                case '.':
3951                case 'v': // Implied decimal sign.
3952                    if (this._textPos < this._msText.length && this._msText.charAt(this._textPos) == '.'){
3953                        this._textPos++; //consume a '.'
3954                    }
3955                    if (chr == 'V' || chr == '.'){
3956                        this._mAddRadix = true;
3957                        //this._buffer.push(this._fmtStr(this._mNumberSymbols.decimal, ));
3958                    }
3959                    this._mbRadixSeen = true;
3960                    this._nScannedPatternDigit = 0;
3961                    break;
3962
3963                case 0xFF0C: // Fullwidth ','.
3964                case ',': // Grouping separator.
3965                    while (chrCnt-- > 0) {
3966                        if (this._mbDigitAddedToOutput){
3967                            this._buffer.push(this._fmtStr(	this._mNumberSymbols.grouping ));
3968                        }
3969                        this._mbCommaSeen = true;
3970                    }
3971                    break;
3972                case 0xFF04: // Fullwidth '$'.
3973                case '$': // Currency name or symbol.
3974                    while (chrCnt-- > 0) {
3975                        this._buffer.push(this._fmtStr(	this._mCurrencySymbol
3975s.symbol ));
3976                    }
3977                    break;
3978                case 0xFF05: // Fullwidth '%'.
3979                case '%': // Percent symbol.
3980                    while (chrCnt-- > 0) {
3981                        this._buffer.push(this._fmtStr(	this._mNumberSymbols.percent));
3982                    }
3983                    break;
3984                case 0xFF08: // Fullwidth '('.
3985                case 0xFF09: // Fullwidth ')'.
3986                case '(': // Left parenthesis.
3987                case ')': // Right parenthesis.
3988                    this._buffer.push(this._matchChr((this._mbNegative) ? chr : ' '));
3989                    break;
3990                default:
3991            }
3992        },
3993
3994        _ensureCharIsDigit : function(cValue){
3995            if ('0' > cValue || cValue > '9'){
3996                throw "Nuberic Formatting: not a digit as expected " + cValue;
3997            }
3998        },
3999
4000
4001        _fmtStr : function(str){
4002            return str;
4003        },
4004
4005        _matchStr : function(str){
4006            return str;
4007        },
4008
4009        _matchChr : function(str){
4010            return str;
4011        },
4012
4013        _ensureSignIsAdded : function(){
4014            if (this._mbNegative && ! this._mbDigitAddedToOutput && ! this._pictureDesc.hasSign) {
4015                this._buffer.push(this._mNumberSymbols.minus);
4016                this._mbSignAddedToOutput = true;
4017            }
4018        },
4019
4020        /**
4021         *
4022         * @override
4023         */
4024        getResult : function(){
4025            return this._buffer.join("");
4026        },
4027
4028        /**
4029         *
4030         * @override
4031         */
4032        acceptPatternChar : function(chr){
4033            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
4034        }
4035
4036    });
4037
4038})(_,xfalib);
4039
4040
4041/**
4042 * @package xfalib.ut.TimeParsingVisitor
4043 * @import xfalib.ut.ParsingVisitorBase
4044 * @fileOverview The file provides parsing/formating logic on date pattern characters.
4045 * @version 0.0.1
4046 */
4047
4048/**
4049 * @constructor
4050 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
4051 */
4052
4053(function(_,xfalib){
4054    var TimeParsingVisitor = xfalib.ut.TimeParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4055
4056        initialize: function() {
4057            this._timeInfo = new xfalib.ut.TimeInfo();
4058            TimeParsingVisitor._super.initialize.call(this);
4059        },
4060
4061        consumeSubPattern : function(token){
4062            var chr = token.patChar;
4063            var chrCnt = token.len;
4064            var curPos = this._strPos;
4065            var scannedChar = chrCnt;
4066            this._assert(curPos+chrCnt <=this.jsonModel._dataString.length, "Mismatch");
4067
4068            switch (chr) {
4069                case 'h':
4070                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
4071                        throw "ambiguity time string";
4072                    }
4073                    var hourOfMeriDiem=-1;
4074                    switch(chrCnt){
4075                        case 1:
4076                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
4077                            hourOfMeriDiem = parsed.value;
4078                            scannedChar = parsed.len;
4079                            break;
4080                        case 2:
4081                            hourOfMeriDiem = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
4082                            break;
4083                    }
4084
4085                    this._timeInfo.mHourOfMeriDiem = hourOfMeriDiem -1;
4086                    this._assert(this._timeInfo.mHourOfMeriDiem>=0 && this._timeInfo.mHourOfMeriDiem<=11, "Invalid Hour Of MeriDiem value.");
4087                    break;
4088
4089                case 'k':
4090                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
4091                        throw "ambiguity time string";
4092                    }
4093                    var hourOfMeriDiem=-1;
4094                    switch(chrCnt){
4095                        case 1:
4096                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-11)
4097                            hourOfMeriDiem = parsed.value;
4098                            scannedChar = parsed.len;
4099                            break;
4100                        case 2:
4101                            hourOfMeriDiem = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-11)
4102                            break;
4103                    }
4104
4105                    this._timeInfo.mHourOfMeriDiem = hourOfMeriDiem;
4106                    this._assert(this._timeInfo.mHourOfMeriDiem>=0 && this._timeInfo.mHourOfMeriDiem<=11, "Invalid hour of meriDiem value.");
4107                    break;
4108
4109                case 'H':
4110                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
4111                        throw "ambiguity time string";
4112                    }
4113                    var hourOfDay=-1;
4114                    switch(chrCnt){
4115                        case 1:
4116                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4117                            hourOfDay = parsed.value;
4118                            scannedChar = parsed.len;
4119                            break;
4120                        case 2:
4121                            hourOfDay = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4122                            break;
4123                    }
4124
4125                    this._timeInfo.mHourOfDay = hourOfDay;
4126                    this._assert(this._timeInfo.mHourOfDay>=0 && this._timeInfo.mHourOfDay<=23, "Invalid hour of day value.");
4127                    break;
4128
4129                case 'K':
4130                    if(this._timeInfo.mHourOfMeriDiem != -1 || this._timeInfo.mHourOfDay != -1){
4131                        throw "ambiguity time string";
4132                    }
4133                    var hourOfDay=-1;
4134                    switch(chrCnt){
4135                        case 1:
4136                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4137                            hourOfDay = parsed.value;
4138                            scannedChar = parsed.len;
4139                            break;
4140                        case 2:
4141                            hourOfDay = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-23)
4142                            break;
4143                    }
4144
4145                    this._timeInfo.mHourOfDay = hourOfDay - 1;
4146                    this._assert(this._timeInfo.mHourOfDay>=0 && this._timeInfo.mHourOfDay<=23, "Invalid hour of day value.");
4147                    break;
4148                case 'M':
4149                    if(this._timeInfo.mMinuteOfHour != -1){
4150                        throw "ambiguity time string";
4151                    }
4152                    var minuteOfHour=-1;
4153                    switch(chrCnt){
4154                        case 1:
4155                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4156                            minuteOfHour = parsed.value;
4157                            scannedChar = parsed.len;
4158                            break;
4159                        case 2:
4160                            minuteOfHour = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4161                            break;
4162                    }
4163
4164                    this._timeInfo.mMinuteOfHour = minuteOfHour;
4165                    this._assert(this._timeInfo.mMinuteOfHour>=0 && this._timeInfo.mMinuteOfHour<=59, "Invalid minute of hour.");
4166                    break;
4167                case 'S':
4168                    if(this._timeInfo.mSecondOfMinute != -1){
4169                        throw "ambiguity time string";
4170                    }
4171                    var secondOfMinute=-1;
4172                    switch(chrCnt){
4173                        case 1:
4174                            var parsed = this.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4175                            secondOfMinute = parsed.value;
4176                            scannedChar = parsed.len;
4177                            break;
4178                        case 2:
4179                            secondOfMinute = this.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(0-59)
4180                            break;
4181                    }
4182
4183                    this._timeInfo.mSecondOfMinute = secondOfMinute;
4184                    this._assert(this._timeInfo.mSecondOfMinute>=0 && this._timeInfo.mSecondOfMinute<=59, "Invalid second of minute.");
4185                    break;
4186                case 'F':
4187
4188                    this._assert(chrCnt==3, "Invalid pattern F.");
4189                    this._timeInfo.mThousandthOfSecond = this.parseIntExact(this.jsonModel._dataString, curPos, 3);
4190                    this._assert(this._timeInfo.mThousandthOfSecond>=0 && this._timeInfo.mThousandthOfSecond<=999, "Invalid thousand of second.");
4191                    break;
4192
4193                default: throw "Unsupported pattern";
4194            }
4195
4196            this._strPos += scannedChar;
4197        },
4198
4199        parseIntAggressive : xfalib.ut.PictureUtils.parseIntAggressive,
4200
4201        parseIntExact : xfalib.ut.PictureUtils.parseIntExact,
4202
4203        getResult : function(){
4204            return this._timeInfo.getISOTime();
4205        },
4206
4207        getTimeInfo : function(){
4208            return this._timeInfo;
4209        },
4210
4211        _assert : function(condition, message){
4212            if(!condition){
4213                throw message;
4214            }
4215        }
4216    });
4217})(_,xfalib);
4218
4219
4220
4221/**
4222 * @package xfalib.ut.TextParsingVisitor
4223 * @import xfalib.ut.ParsingVisitorBase
4224 *
4225 * @fileOverview Parses a string according to Text Picture.
4226 * @version 0.0.1
4227 */
4228
4229/**
4230 * @constructor
4231 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
4232 */
4233(function(_,xfalib){
4234    var TextParsingVisitor = xfalib.ut.TextParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4235
4236        initialize: function() {
4237            TextParsingVisitor._super.initialize.call(this);
4238            this._buffer = [];
4239        },
4240
4241        consumeSubPattern : function(token){
4242            var chr = token.patChar;
4243            var chrCnt = token.len;
4244            for(var index = 0; index < chrCnt; index++){
4245                switch (chr) {
4246                    case '9': // Numeric
4247                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4248                        if(!xfalib.ut.PictureUtils.isDigit(cUni)){
4249                            throw "TextParsing: not a digit as expected";
4250                        }
4251                        this._buffer.push(cUni);
4252                        break;
4253                    case 'A': // Alphebetic
4254                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4255                        if(!xfalib.ut.PictureUtils.isLetter(cUni)){
4256                            throw "TextParsing: not a character as expected";
4257                        }
4258                        this._buffer.push(cUni);
4259                        break;
4260                    case 'O': // Alphanumeric
4261                    case '0':
4262                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4263                        if(!xfalib.ut.PictureUtils.isLetterOrDigit(cUni)){
4264                            throw "TextParsing: not a character or digit as expected";
4265                        }
4266                        this._buffer.push(cUni);
4267                        break;
4268                    case 'X':
4269                        var cUni = this.jsonModel._dataString.charAt(this._strPos++);
4270                        this._buffer.push(cUni);
4271                        break;
4272                    case 't':
4273                        if(this.jsonModel._dataString.charAt(this._strPos++)=="\t"){
4274                            this._buffer.push("\t");
4275                        }else{
4276                            throw "TextParsing: not a Tab as expected";
4277                        }
4278                        break;
4279                    default:
4280                        if(this.jsonModel._dataString.charAt(this._strPos++)== chr){
4281                            this._buffer.push(chr);
4282                        }else{
4283                            throw "TextParsing: not '" + chr+"' as expected";
4284                        }
4285                }
4286            }
4287
4288        },
4289        /**
4290         *
4291         * @override
4292         */
4293        getResult : function(){
4294            if(this._strPos < this.jsonModel._dataString.length)
4295                throw "TextParsing: picture clause smaller than input Text";
4296            return this._buffer.join("");
4297        },
4298        /**
4299         *
4300         * @override
4301         */
4302        acceptPatternChar : function(chr){
4303            return xfalib.ut.PictureUtils.inString(chr, "9AO0Xt");
4304        }
4305
4306    });
4307})(_,xfalib);
4308
4309
4310/**
4311 * @package xfalib.ut.NumParsingVisitor
4312 * @import xfalib.ut.ParsingVisitorBase
4313 * @fileOverview Parses a string according to Text Picture.
4314 * @version 0.0.1
4315 */
4316
4317/**
4318 * @constructor
4319 * @param Object {jsonModel: {_sPicture: String,_dataString: String}}
4320 */
4321
4322(function(_,xfalib){
4323    var NumParsingVisitor = xfalib.ut.NumParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4324
4325        initialize: function(options) {
4326            this._pictureDesc = new xfalib.ut.NumPictureDesc({jsonModel:{_sPicture:this.jsonModel._sPicture}});
4327            this.jsonModel._sPicture = this._pictureDesc.getPicture();
4328            this._buffer = [];
4329            this._strPos = 0;
4330            this._hasRadix = false;
4331            this._mbNegative = false;
4332            this._mbDigitSeen = false; // at least one digit has been added to output
4333            this._mbSignSeen = false;
4334            this._mBacktrack = null;
4335            this._hasPercent = false;
4336            this._mbExponSeen = false;
4337
4338            this._mNumberSymbols = xfalib.ut.PictureUtils.getLocaleObject(this.options._locale,"numberSymbols");
4339            this._mCurrencySymbols = xfalib.ut.PictureUtils.getLocaleObject(this.options._locale,"currencySymbols");
4340        },
4341
4342        _lookupNext : xfalib.ut.Scanner.lookupNext,
4343
4344        parse : function(){
4345            var patPos = 0;
4346            while(true){
4347                try{
4348                    for(var token = this._lookupNext(this.jsonModel._sPicture, patPos, this.acceptPatternChar); token != null;  ){
4349                        this.consume(token);
4350                        patPos = patPos + token.len;
4351                        token = this._lookupNext(this.jsonModel._sPicture, patPos, this.acceptPatternChar);
4352                    }
4353                }catch(e){
4354                    //mismatch, try again!
4355                    if(this._mBacktrack){
4356                        patPos = this._mBacktrack.patPos;
4357                        this._buffer.length = 0;
4358                        this._strPos = this._mBacktrack.strPos;
4359                        this._mbDigitSeen = false;
4360                        this._mBacktrack = null;
4361                        continue;
4362                    }
4363                }
4364                break;
4365            }
4366        },
4367        consumeSubPattern : function(token){
4368
4369            var chr = token.patChar;
4370            var chrCnt = token.len;
4371            var fw = false;
4372            switch (chr) {
4373                case '9':
4374                case '8':
4375                case 'Z': // Digit or space if zero.
4376                case 'z':// Digit or nothing if zero.
4377                    while (chrCnt-- > 0 ) {
4378                        if(!this._mbDigitSeen){
4379                            var cUni = this.jsonModel._dataString.charAt(this._strPos);
4380                            if(cUni == '-'){
4381                                this._mbNegative = true;
4382                                cUni = this.jsonModel._dataString.charAt(++this._strPos);
4383                            }
4384                            if(chr== '9' || chr == '8'){
4385                                if(!xfalib.ut.PictureUtils.isDigit(cUni)){
4386                                    throw "TextParsing: not a digit as expected";
4387                                }
4388                                this._buffer.push(cUni);
4389                                this._mbDigitSeen =true;
4390                            }else if(chr =='Z'){
4391                                if(xfalib.ut.PictureUtils.isDigit(cUni)){
4392                                    this._buffer.push(cUni);
4393                                    this._mbDigitSeen =true;
4394                                }else if(cUni != ' '){
4395                                    throw "TextParsing: not a digit or space as expected";
4396                                }
4397                            }else {
4398                                // has to be 'z', eagerly try to match a digit, if a mismatch is latterly found, backtrack
4399                                if(xfalib.ut.PictureUtils.isDigit(cUni)){
4400                                    this._buffer.push(cUni);
4401                                    this._mbDigitSeen =true;
4402                                    this._mBacktrack = {
4403                                        "patPos" : token.patPos + token.len - chrCnt, //new position from next char after 'z'
4404                                        "strPos" : this._strPos
4405                                    };
4406                                }else {
4407                                    throw "TextParsing: not a digit or space as expected";
4408                                }
4409                            }
4410                            ++this._strPos;
4411                        }else{
4412                            var cUni = this.jsonModel._dataString.charAt(this._strPos);
4413                            if(xfalib.ut.PictureUtils.isDigit(cUni)){
4414                                this._buffer.push(cUni);
4415                                ++this._strPos;
4416                            }else{
4417                                if(chr !='z'){
4418                                    throw "TextParsing: not a digit as expected";
4419                                }else{
4420                                    ++this._strPos;
4421                                }
4422                            }
4423                        }
4424                    }
4425
4426                    break;
4427                case 'V' :
4428                case 'v' :
4429                case '.' :
4430                    if(this._matchStr(this._mNumberSymbols.decimal)){
4431                        this._hasRadix = true;
4432                        this._buffer.push('.');
4433                        this._mbDigitSeen =true;
4434                    }else{
4435                        throw "TextParsing: not a radix as expected";
4436                    }
4437                    break;
4438                case 'E': // Exponent.
4439                    if(this._matchStr('E')){
4440                        this._buffer.push('E');
4441                        if(this._matchStr('+')){
4442                            //
4443                        }else if(this._matchStr('-')){
4444                            this.jsonModel._buffer.push('-');
4445                        }
4446                        var strLen = this.jsonModel._dataString.length;
4447                        while(this._strPos < strLen &&
4448                            xfalib.ut.PictureUtils.isDigit(this.jsonModel._dataString.charAt(this._strPos))){
4449                            this._buffer.push(this.jsonModel._dataString.charAt(this._strPos++));
4450                        }
4451                    }
4452                    break;
4453
4454                case 'C': // CR symbol if negative and spaces if positive.
4455                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsCR)){
4456                        this._mbNegative = true;
4457                    }else if(!this._matchStr(xfalib.ut.NumPictureDesc.gsDSP)){
4458                        throw "TextParsing: not a CR as expected";
4459                    }
4460                    break;
4461                case 'c': // CR symbol if negative and nothing if positive.
4462                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsCR)){
4463                        this._mbNegative = true;
4464                    }
4465                    break;
4466                case 'D': // DB symbol if negative and spaces if positive.
4467                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsDB)){
4468                        this._mbNegative = true;
4469                    }else if(!this._matchStr(xfalib.ut.NumPictureDesc.gsDSP)){
4470                        throw "TextParsing: not a CR as expected";
4471                    }
4472                    break;
4473                case 'd': // DB symbol if negative and nothing if positive.
4474                    if(this._matchStr(xfalib.ut.NumPictureDesc.gsDB)){
4475                        this._mbNegative = true;
4476                    }
4477                    break;
4478                case 'S': // Minus sign if negative and a space if positive.
4479                    if(this._matchStr(this._mNumberSymbols.negative,fw)){
4480                        this._mbNegative = true;
4481                    }else if(!this._matchStr(" ")){
4482                        throw "TextParsing: not a CR as expected";
4483                    }
4484                    break;
4485                case 's':
4486                    if(this._matchStr(this._mNumberSymbols.negative,fw)){
4487                        this._mbNegative = true;
4488                    }
4489                    break;
4490                case 0xFF0C: // Fullwidth ','.
4491                case ',': // Grouping separator.
4492                    while (chrCnt-- > 0) {
4493                        if(!this._matchStr(this._mNumberSymbols.grouping, fw)){
4494                            throw "TextParsing: not a grouping symbol as expected";
4495                        }
4496                    }
4497                    break;
4498                case 0xFF04: // Fullwidth '$'.
4499                case '$': // Currency name or symbol.
4500                    while (chrCnt-- > 0) {
4501                        if(!this._matchStr(this._mCurrencySymbol
4501s.symbol, fw)){
4502                            throw "TextParsing: not a grouping symbol as expected";
4503                        }
4504                    }
4505                    break;
4506                case 0xFF05: // Fullwidth '%'.
4507                case '%': // Percent symbol.
4508                    while (chrCnt-- > 0) {
4509                        if(!this._matchStr(this._mNumberSymbols.percent, fw)){
4510                            throw "TextParsing: not a grouping symbol as expected";
4511                        }
4512                    }
4513                    this._hasPercent = true;
4514                    break;
4515                case 0xFF08: // Fullwidth '('.
4516                case 0xFF09: // Fullwidth ')'.
4517                case '(': // Left parenthesis.
4518                case ')': // Right parenthesis.
4519                    if(this._matchStr(chr,fw)){
4520                        this._mbNegative = true;
4521                    }else if(!this._matchStr(" ")){
4522                        throw "TextParsing: not parentesis as expected";
4523                    }
4524                    break;
4525                case 't': // tab.
4526                    while (chrCnt-- > 0) this._matchStr('\t',fw);
4527            }
4528        },
4529        getResult : function(){
4530            var stringNum =  this._buffer.join("");
4531            if(this._hasPercent) {
4532                var buf = new Array();
4533                stringNum = Number(stringNum).toString();
4534                var dot = stringNum.indexOf('.');
4535
4536                var pos = dot-2;
4537                if(pos ==0) buf.push("0");
4538                else if(pos ==-1) buf.push("0.0");
4539                else if(pos ==-3) pos = stringNum.length - 2;
4540                for(var index=0;index < stringNum.length; index++){
4541                    if(index == pos){
4542                        buf.push(".");
4543                    }
4544                    if(index != dot){
4545                        buf.push(stringNum.charAt(index));
4546                    }
4547                }
4548                stringNum = buf.join("");
4549            }
4550            var number = Number(stringNum);
4551            if(this._mbNegative) number = -number;
4552            return number.toString();
4553        },
4554
4555        _matchStr : function(target){
4556            if(xfalib.ut.PictureUtils.matchString(this.jsonModel._dataString, this._strPos, target)){
4557                this._strPos+= target.length;
4558                return true;
4559            }else{
4560                return false;
4561            }
4562        },
4563
4564        /**
4565         *
4566         * @override
4567         */
4568        acceptPatternChar : function(chr){
4569            return xfalib.ut.PictureUtils.inString(chr, "(%$,.)89BCDERSVZbcdrsvzt");
4570        }
4571    });
4572})(_,xfalib);
4573/**
4574 * @package xfalib.ut.DateParsingVisitor
4575 * @import xfalib.ut.ParsingVisitorBase
4576 * @fileOverview The file provides parsing/formating logic on date pattern characters.
4577 * @version 0.0.1
4578 */
4579
4580/**
4581 * @constructor
4582 * @param Object {jsonModel: {_sPicture: String, _dataString: String]}
4583 */
4584
4585(function(_,xfalib) {
4586    var DateParsingVisitor = xfalib.ut.DateParsingVisitor = xfalib.ut.ParsingVisitorBase.extend({
4587
4588        initialize: function() {
4589            this._dateInfo = new xfalib.ut.DateInfo({isParsingCall : true});
4590            this._dayOfMonth = this._monthOfYear = this._yearOfEra = null; // used to validate date once all sub patterns are consumed
4591            DateParsingVisitor._super.initialize.call(this);
4592        },
4593
4594        consumeSubPattern : function(token){
4595            var chr = token.patChar;
4596            var chrCnt = token.len;
4597            var curPos = this._strPos;
4598            var scannedChar = chrCnt;
4599
4600            //TODO: need to remove this assert.
4601            this._assert(curPos+chrCnt <=this.jsonModel._dataString.length, "Mismatch");
4602
4603            switch (chr) {
4604                case 'D':
4605                    switch(chrCnt){
4606                        case 1:
4607                            var parsed = xfalib.ut.PictureUtils.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-31)
4608                            this._dayOfMonth = parsed.value;
4609                            scannedChar = parsed.len;
4610                            break;
4611                        case 2:
4612                            this._dayOfMonth = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-31)
4613                            break;
4614                    }
4615                    this._assert(this._dayOfMonth <= 31 && this._dayOfMonth >0, "Invalid date string1");
4616                    break;
4617                case 'J':
4618
4619                    //this._mDayOfYear;
4620                    break;
4621                case 'M':
4622                    var symbol = "";
4623                    switch(chrCnt){
4624                        case 1:
4625                            var parsed = xfalib.ut.PictureUtils.parseIntAggressive(this.jsonModel._dataString, curPos, 2); // 1-2 digit(1-12)
4626                            this._monthOfYear = parsed.value;
4627                            scannedChar = parsed.len;
4628                            break;
4629                        case 2:
4630                            this._monthOfYear = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 2 digit(01-12)
4631                            break;
4632                        case 3:
4633                            symbol = "calendarSymbols.abbrmonthNames";
4634                            break;
4635                        case 4:
4636                            symbol = "calendarSymbols.monthNames"
4637                            break;
4638
4639                    }
4640                    if(symbol) {
4641                        var hashObj = xfalib.ut.PictureUtils.getHashOfLocaleObject(this.jsonModel._locale,symbol),
4642                            str = this.jsonModel._dataString.toLowerCase(),
4643                            hash = 0,
4644                            curStr = ""
4645                        scannedChar = 0;
4646                        while(curPos+scannedChar < str.length) {
4647                            hash += (scannedChar+1)*str.charCodeAt(curPos+scannedChar)
4648                            curStr+= str.charAt(curPos+scannedChar);
4649                            scannedChar++;
4650                            if(hashObj[hash] && hashObj[hash].indexOf(curStr) > -1 ) break;
4651                        }
4652                        var monthNames = _.map(xfalib.ut.PictureUtils.getLocaleObject(this.jsonModel._locale, symbol), function (str) {
4653                            return str.toLowerCase();
4654                        });
4655                        this._monthOfYear = monthNames.indexOf(curStr) + 1; // months are from 1 to 12
4656                    }
4657                    //TODO: remove this assert
4658                    this._assert(this._monthOfYear <= 12 && this._monthOfYear >0, "Invalid date string2");
4659                    break;
4660                case 'E':
4661                    var symbol = ""
4662                    switch(chrCnt) {
4663                        case 1:
4664                            scannedChar = 1;
4665                            break;
4666                        case 3:
4667                            symbol = "calendarSymbols.abbrdayNames";
4668                            break;
4669                        case 4:
4670                            symbol = "calendarSymbols.dayNames"
4671                            break;
4672                        default:
4673                            throw "unsupported Picture Clause ";
4674                    }
4675                    if(symbol) {
4676                        var hashObj = xfalib.ut.PictureUtils.getHashOfLocaleObject(this.jsonModel._locale,symbol);
4677                        scannedChar = 0;
4678                        var str = this.jsonModel._dataString.toLowerCase();
4679                        var hash = 0;
4680                        var curStr = "";
4681                        while(curPos+scannedChar < str.length) {
4682                            hash += (scannedChar+1)*str.charCodeAt(curPos+scannedChar)
4683                            curStr+= str.charAt(curPos+scannedChar);
4684                            scannedChar++;
4685                            if(hashObj[hash] && hashObj[hash].indexOf(curStr) > -1) break;
4686                        }
4687                    }
4688                    break;
4689
4690                case 'e':
4691                    break;
4692                case 'G':
4693                    break;
4694                case 'Y':
4695
4696                    switch(chrCnt){
4697                        case 2:
4698                            this._yearOfEra = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 2); // 2 digit(00-99)
4699                            this._yearOfEra+=2000;
4700                            if(this._yearOfEra >= 2029){
4701                                this._yearOfEra -=100;
4702                            }
4703                            break;
4704                        case 4:
4705                            this._yearOfEra = xfalib.ut.PictureUtils.parseIntExact(this.jsonModel._dataString, curPos, 4); // 2 digit(0000-9999)
4706                            break;
4707                    }
4708
4709                    this._assert(this._yearOfEra <= 9999 && this._yearOfEra >=0, "Invalid date string3");
4710                    break;
4711                case 'w':
4712                    break;
4713                case 'W':
4714                    break;
4715                default: throw "Unsupported pattern";
4716            }
4717
4718            if(this._yearOfEra && this._monthOfYear && this._dayOfMonth){
4719                this._dateInfo.validate(this._yearOfEra, this._monthOfYear, this._dayOfMonth);
4720            }
4721
4722            this._strPos += scannedChar;
4723        },
4724
4725        getDate : function(){
4726            return this._dateInfo.date;
4727        },
4728
4729        getResult: function(){
4730            if (this._strPos < this.jsonModel._dataString.length) {
4731                throw "DateParsing: picture clause smaller than input Date";
4732            }
4733            return this._dateInfo.getISODate();
4734        },
4735
4736        _assert : function(condition, message){
4737            if(!condition){
4738                throw message;
4739            }
4740        }
4741    });
4742})(_,xfalib);
4743
4744/*************************************************************************
4745 *
4746 * ADOBE CONFIDENTIAL
4747 * ___________________
4748 *
4749 *  Copyright 2013 Adobe Systems Incorporated
4750 *  All Rights Reserved.
4751 *
4752 * NOTICE:  All information contained herein is, and remains
4753 * the property of Adobe Systems Incorporated and its suppliers,
4754 * if any.  The intellectual and technical concepts contained
4755 * herein are proprietary to Adobe Systems Incorporated and its
4756 * suppliers and are protected by trade secret or copyright law.
4757 * Dissemination of this information or reproduction of this material
4758 * is strictly forbidden unless prior written permission is obtained
4759 * from Adobe Systems Incorporated.
4760 **************************************************************************/
4761
4762
4763
4764(function(_, $, xfalib){
4765
4766    var LocalizationUtil = xfalib.ut.LocalizationUtil = xfalib.ut.Class.extend({
4767
4768        getLocalizedMessage: function(category, message, snippets){
4769            var resolvedMessage = message;
4770            if(snippets){
4771                //resolve message with snippet
4772                resolvedMessage = resolvedMessage.replace(/{(\d+)}/g, function(match, number) {
4773                    return typeof snippets[number] != 'undefined'
4774                        ? snippets[number]
4775                        : match
4776                        ;
4777                });
4778            }
4779            var text = "";
4780            if (category) {
4781                text += " [" + category + "]";
4782            }
4783            text += "  " + resolvedMessage + "\r\n" ;
4784            return text;
4785        }
4786
4787    });
4788})(_, $, xfalib);
4789
4790
4791/*************************************************************************
4792 * ADOBE CONFIDENTIAL
4793 * ___________________
4794 *
4795 *  Copyright 2013 Adobe Systems Incorporated
4796 *  All Rights Reserved.
4797 *
4798 * NOTICE:  All information contained herein is, and remains
4799 * the property of Adobe Systems Incorporated and its suppliers,
4800 * if any.  The intellectual and technical concepts contained
4801 * herein are proprietary to Adobe Systems Incorporated and its
4802 * suppliers and are protected by all applicable intellectual property
4803 * laws, including trade secret and copyright laws.
4804 * Dissemination of this information or reproduction of this material
4805 * is strictly forbidden unless prior written permission is obtained
4806 * from Adobe Systems Incorporated.
4807 **************************************************************************/
4808
4809
4810
4811
4812(function(_, $, xfalib){
4813    xfalib.view.util.TextMetrics = {
4814        xfaUtil : xfalib.ut.XfaUtil.prototype,
4815        ERROR_MARGIN : 1,
4816        $measureEl : null,
4817        initialize : function(divEl){
4818            if(!divEl){
4819                var $div = $("<div></div>");
4820                $div.attr("id", "textMetrics");
4821                var divStyles = {};
4822                divStyles.left = -1000;
4823                divStyles.top = -1000;
4824                divStyles.position = "absolute";
4825                divStyles.visibility = "hidden";
4826                this.xfaUtil.$css($div.get(0), divStyles);
4827                this.$measureEl = $div;
4828                $("body").append(this.$measureEl);
4829            }else{
4830                this.$measureEl = divEl;
4831            }
4832        },
4833
4834        measureExtent : function(text, options){
4835            text = text + " ";
4836            if(!this.$measureEl){
4837                this.initialize();
4838            }
4839            options = options || {};
4840            var textStyles = {};
4841            var $refEl =  $(options.refEl || "<div></div>") ;
4842            var refEl = $refEl.get(0);
4843            textStyles.fontSize = $refEl.css("fontSize") || options["font-size"] || options["fontSize"];
4844            textStyles.fontStyle = $refEl.css("fontStyle") || options["font-style"] || options["fontStyle"];
4845            textStyles.fontWeight = $refEl.css("fontWeight") || options["font-weight"] || options["fontWeight"];
4846            textStyles.fontFamily = $refEl.css("fontFamily") || options["font-family"] || options["fontFamily"];
4847            textStyles.lineHeight = refEl.style.lineHeight || options["line-height"] || options["lineHeight"];
4848            textStyles.letterSpacing = $refEl.css("letterSpacing") || options["letter-spacing"] || options["letterSpacing"];
4849            textStyles.whiteSpace =  $refEl.css("whiteSpace") || options["white-space"] || options["whiteSpace"] || "pre-wrap";
4850            if( $.browser.mozilla && $refEl.is("textarea"))      // for Bug #3621180
4851                textStyles.whiteSpace = "pre-wrap";
4852            textStyles.wordBreak =  $refEl.css("wordBreak") || options["word-break"] || options["wordBreak"] || "break-all";
4853            textStyles.wordWrap =  $refEl.css("wordWrap") || options["word-wrap"] || options["wordWrap"] || "break-word";
4854            textStyles.width = this._elWidth(refEl, options);
4855            textStyles.height = this._elHeight(refEl, options);
4856            textStyles.minWidth = this._elMinWidth(refEl, options);
4857            textStyles.minHeight = this._elMinHeight(refEl, options);
4858            textStyles.maxWidth = this._elMaxWidth(refEl, options);
4859            textStyles.maxHeight = this._elMaxHeight(refEl, options);
4860            this.xfaUtil.$css(this.$measureEl.get(0), textStyles);
4861            // for text fields/areas and draw requiring rich text support
4862            if(options.contentType === "text/html"){
4863              // retaining for future use . If we use the above property for other rich text
4864               if(options.skipXSSProtection) {
4865                 this.$measureEl.html(text);
4866               } else {
4867                 this.$measureEl.html(xfalib.ut.XfaUtil.prototype.encodeScriptableTags(text));
4868               }
4869            }else {
4870               text = text.replace(/\n\r/g,"\n").replace(/\r\n/g,"\n").replace(/\r/g, "\n");
4871               this.$measureEl.text(text);
4872            }
4873            var measuredWidth =  this.$measureEl.width();
4874            var measuredHeight =  this.$measureEl.height();
4875
4876            if(measuredWidth == Math.ceil(options["width"]) || measuredWidth == Math.floor(options["width"])){
4877                measuredWidth = options["width"];
4878            }
4879            /*
4880             FORMS-11363 : fix for height calculation of table cell
4881             Enable this toggle for old behaviour (if any regression comes)
4882             */
4883            else if ((window.FD && window.FD.isToggleEnabled("FT_FORMS-11363")) && (options["maxWidth"] > measuredWidth || (measuredWidth > options["minWidth"] > 0 && (options["maxWidth"] || -1) < 0))) {
4884                //complicated, please simplify if below hurts you:  Add error margin if there is scope of further extension of extent
4885                measuredWidth = measuredWidth + 1;
4886            } else if (options["maxWidth"] > measuredWidth || (measuredWidth > options["minWidth"] > 0 && (options["maxWidth"] || -1) < 0)) {
4887                //complicated, please simplify if below hurts you:  Add error margin if there is scope of further extension of extent
4888                measuredWidth = measuredWidth;
4889            }
4890
4891            if(measuredHeight == Math.ceil(options["height"]) || measuredHeight == Math.floor(options["height"])){
4892                measuredHeight = options["height"];
4893            }
4894            else if( $refEl.is("textarea") && (options["maxHeight"] > measuredHeight || (measuredHeight > options["minHeight"] > 0 && (options["maxHeight"] || -1) < 0))){
4895                measuredHeight = measuredHeight +1;
4896            }
4897            this.$measureEl.empty();
4898            return {width : measuredWidth, height : measuredHeight};
4899        },
4900
4901        _elWidth : function(refEl, options){
4902            if(options["minWidth"] && options["minWidth"] > -1)
4903                return "auto";
4904            else if(options["maxWidth"] && options["maxWidth"] > -1)
4905                return "auto";
4906            else
4907                return options["width"] || "auto";
4908        },
4909
4910        _elHeight : function(refEl, options){
4911            // TODO: check for calculations here for floating field and other cases.
4912            if(options["contentType"] === "text/html")
4913                return "auto";
4914            if(options.isDraw) { // for handling the case of draw having floating fields
4915                return "auto";
4916            }
4917            if(!$(refEl).is("textarea"))
4918                return options["height"] || "auto";
4919            if(options["minHeight"] && options["minHeight"] > -1)
4920                return "auto";
4921            else if(options["maxHeight"] && options["maxHeight"] > -1)
4922                return "auto";
4923            else
4924                return options["height"] || "auto";
4925        },
4926
4927        _elMinWidth : function(refEl, options){
4928            if(options["minWidth"] && options["minWidth"] > -1)
4929                return options["minWidth"];
4930            else
4931                return "0"; //default css value
4932        },
4933
4934        _elMinHeight : function(refEl, options){
4935            if(options["minHeight"] && options["minHeight"] > -1)
4936                return options["minHeight"];
4937            else
4938                return "0"; //default css value
4939        },
4940
4941        _elMaxWidth : function(refEl, options){
4942            if(options["maxWidth"] && options["maxWidth"] > -1)
4943                return options["maxWidth"];
4944            else
4945                return "none"; //default css value
4946        },
4947
4948        _elMaxHeight : function(refEl, options){
4949            if(options["maxHeight"] && options["maxHeight"] > -1)
4950                return options["maxHeight"];
4951            else
4952                return "none"; //default css value
4953        },
4954
4955        _destroy : function() {
4956            $("#textMetrics").remove();
4957            this.$measureEl = null;
4958        }
4959    }
4960})(_, $, xfalib);
4961(function($, _) {
4962
4963	$.alertBox = {
4964
4965		verticalOffset: -75,
4966		horizontalOffset: 0,
4967		repositionOnResize: true,
4968		overlayOpacity: 0.01,
4969		overlayColor: '#FFF',
4970		draggable: false,
4971		dialogClass: null,
4972		imageDirectory: "..",
4973		images: ["A_Warning_Lg_N.png", "A_Alert2_Lg_N.png", "C_QuestionBubble_Xl_N.png", "A_InfoBlue_32x32_N.png"],
4974
4975		alert: function(img, message, title, callback) {
4976			this._show(img, title, message, null, 'OK', function(result) {
4977				if( callback ) callback(result);
4978			});
4979		},
4980
4981		okCancel: function(img, message, title, callback) {
4982			this._show(img, title, message, null, 'OK-Cancel', function(result) {
4983				if( callback ) callback(result);
4984			});
4985		},
4986		yesNo: function(img, message, title, callback) {
4987			this._show(img, title, message, null, 'Yes-No', function(result) {
4988				if( callback ) callback(result);
4989			});
4990		},
4991
4992		yesNoCancel: function(img, message, title, callback) {
4993			this._show(img, title, message, null, 'Yes-No-Cancel', function(result) {
4994				if( callback ) callback(result);
4995			});
4996		},
4997
4998		_createBox: function(msgBox_message,buttons,callback) {
4999			var that = this;
5000			$("#"+msgBox_message).after("<div id='msgBox_panel'>");
5001			_.each(buttons.split("-"),function(val,i) {
5002                var dispval = xfalib.locale.Strings[val.toLowerCase()] ? xfalib.locale.Strings[val.toLowerCase()] : val;  // keys in loaclization files are in lower-case
5003                $("#msgBox_panel").append("<input type='button' value='"+dispval+"' id = 'msgBox_"+val+"' class=msgbox_input />");
5004				$("#msgBox_"+val).click( function() {
5005					that._hide();
5006					callback(!i);
5007				});
5008				if(!i) $("msgBox_"+val).focus();
5009			});
5010		},
5011
5012		_show: function(img, title, msg, value, type, callback) {
5013
5014			this._hide();
5015			this._overlay('show');
5016
5017			$("BODY").append(
5018			  '<div id="msgBox_container">' +
5019			    '<h1 id="msgBox_title"></h1>' +
5020			    '<div id="msgBox_content">' +
5021			      '<div id="msgBox_message"></div>' +
5022				'</div>' +
5023			  '</div>');
5024
5025			if( this.dialogClass ) $("#msgBox_container").addClass($.alertBox.dialogClass);
5026
5027			$("#msgBox_container").css({
5028				position: 'absolute',
5029				zIndex: 99999,
5030				padding: 0,
5031				margin: 0
5032			});
5033
5034			$("#msgBox_title").text(title);
5035			$("#msgBox_content").addClass("msgBoxType"+img);//css("background-image","url("+this.imageDirectory+ this.images[img]+")");
5036			msg = xfalib.ut.XfaUtil.prototype.encodeScriptableTags(msg.replace(/\n/g, '<br />'));
5037            $("#msgBox_message").html(msg);
5038
5039			$("#msgBox_container").css({
5040				minWidth: $("#msgBox_container").outerWidth(),
5041				maxWidth: $("#msgBox_container").outerWidth()
5042			});
5043
5044			this._reposition();
5045			this._maintainPosition(true);
5046
5047			this._createBox("msgBox_message",type,callback);
5048
5049			//TODO: Make keyboard input work
5050			/*$("#msgBox_ok").keypress( function(e) {
5051				if( e.keyCode == 13 || e.keyCode == 27 ) $("#msgBox_ok").trigger('click');
5052			});
5053			$("#msgBox_cancel").keypress( function(e) {
5054				if( e.keyCode == 13 ) $("#msgBox_ok").trigger('click');
5055				if( e.keyCode == 27 ) $("#msgBox_cancel").trigger('click');
5056			});
5057			$("#msgBox_yes, #msgBox_no").keypress( function(e) {
5058				if( e.keyCode == 13 ) $("#msgBox_yes").trigger('click');
5059					if( e.keyCode == 27 ) $("#msgBox_no").trigger('click');
5060				});*/
5061
5062		},
5063
5064		_hide: function() {
5065			$("#msgBox_container").remove();
5066			this._overlay('hide');
5067			this._maintainPosition(false);
5068		},
5069
5070		_overlay: function(status) {
5071			switch( status ) {
5072				case 'show':
5073					this._overlay('hide');
5074					$("BODY").append('<div id="msgBox_overlay"></div>');
5075					$("#msgBox_overlay").css({
5076						position: 'absolute',
5077						zIndex: 99998,
5078						top: '0px',
5079						left: '0px',
5080						width: '100%',
5081						height: $(document).height(),
5082						background: this.overlayColor,
5083						opacity: this.overlayOpacity
5084					});
5085				break;
5086				case 'hide':
5087					$("#msgBox_overlay").remove();
5088				break;
5089			}
5090		},
5091
5092		_reposition: function() {
5093            var windowHeight = $(window).height() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
5094                windowWidth = $(window).width() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
5095                windowScrollTop =  $(window).scrollTop() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
5096                windowScrollLeft =  $(window).scrollLeft() / xfalib.ut.XfaUtil.prototype.formScaleFactor,
5097			    top = ((windowHeight / 2) - ($("#msgBox_container").outerHeight() / 2)) + this.verticalOffset,
5098			    left = ((windowWidth / 2) - ($("#msgBox_container").outerWidth() / 2)) + this.horizontalOffset;
5099			if( top < 0 ) top = 0;
5100			if( left < 0 ) left = 0;
5101
5102			// IE6 fix
5103			if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + windowScrollTop;
5104
5105			$("#msgBox_container").css({
5106				top: top + windowScrollTop + 'px',
5107				left:  left + windowScrollLeft + 'px'
5108			});
5109			$("#msgBox_overlay").height( $(document).height() );
5110		},
5111
5112		_maintainPosition: function(status) {
5113			if( this.repositionOnResize ) {
5114				switch(status) {
5115					case true:
5116						$(window).on('resize', this._reposition);
5117					break;
5118					case false:
5119						$(window).off('resize', this._reposition);
5120					break;
5121				}
5122			}
5123		}
5124
5125	};
5126})($, window._);/*************************************************************************
5127 * ADOBE CONFIDENTIAL
5128 * ___________________
5129 *
5130 *  Copyright 2016 Adobe Systems Incorporated
5131 *  All Rights Reserved.
5132 *
5133 * NOTICE:  All information contained herein is, and remains
5134 * the property of Adobe Systems Incorporated and its suppliers,
5135 * if any.  The intellectual and technical concepts contained
5136 * herein are proprietary to Adobe Systems Incorporated and its
5137 * suppliers and are protected by all applicable intellectual property
5138 * laws, including trade secret and copyright laws.
5139 * Dissemination of this information or reproduction of this material
5140 * is strictly forbidden unless prior written permission is obtained
5141 * from Adobe Systems Incorporated.
5142 **************************************************************************/
5143
5144
5145(function(_, $, xfalib){
5146    xfalib.view.util.HtmlUtil = {
5147        /*
5148        * Most of the time it returns undefined while accessing an undefined attribute of a dom element.
5149        * But some browsers can throw specific exceptions while accessing an attribute which is un-supported for a specific case.
5150        * This API is to make this behaviour consistent across browsers and return undefined for un-supported attributes.
5151        * */
5152        getHTMLSupportedAttr : function($domElement, attr){
5153           try{
5154               return $domElement[attr];
5155            }
5156           catch (err){
5157               return undefined;
5158            }
5159        },
5160
5161        /**
5162         * Checks if the attribute is supported for the given HTML element.
5163         * This is primarily useful to support HTML5 features in widgets
5164         * @param element       name of HTML element
5165         * @param attribute     attribute to check on the element
5166         * @returns {boolean}
5167         */
5168        elementSupportsAttribute : function (element, attribute) {
5169            var test = document.createElement(element);
5170            if (attribute in test) {
5171                $(test).remove();
5172                test = null;
5173                return true;
5174            } else {
5175                $(test).remove();
5176                test = null;
5177                return false;
5178            }
5179        }
5180    }
5181})(_, $, xfalib);
5182/*************************************************************************
5183*
5184* ADOBE CONFIDENTIAL
5185* ___________________
5186*
5187*  Copyright 2013 Adobe Systems Incorporated
5188*  All Rights Reserved.
5189*
5190* NOTICE:  All information contained herein is, and remains
5191* the property of Adobe Systems Incorporated and its suppliers,
5192* if any.  The intellectual and technical concepts contained
5193* herein are proprietary to Adobe Systems Incorporated and its
5194* suppliers and are protected by trade secret or copyright law.
5195* Dissemination of this information or reproduction of this material
5196* is strictly forbidden unless prior written permission is obtained
5197* from Adobe Systems Incorporated.
5198**************************************************************************/
5199
5200
5201
5202(function(_, $, xfalib){
5203    xfalib.view.util.Styles = {
5204        xfaUtil : xfalib.ut.XfaUtil.prototype,
5205        _deviceResolution :  144.0, //DPI
5206        _in2mmFactor : 25.4,
5207        _pdfResolution : 72.0 ,
5208        getStyleForEdge : function (edgeElement, str, cssStyleObj){
5209            var style = { "raised" : "outset" ,
5210                "dashDot" : "dashed" ,
5211                "dashDotDot" : "dashed" ,
5212                "dashed" : "dashed" ,
5213                "dotted" : "dotted" ,
5214                "embossed" : "groove" ,
5215                "etched" : "inset" ,
5216                "lowered" : "ridge",
5217                "solid" : "solid"};
5218            if(edgeElement && edgeElement.jsonModel.presence != "hidden" && edgeElement.jsonModel.presence !="invisible") {
5219                cssStyleObj['border'+str+'width'] = this._subPixelValue(this._convertToPx(edgeElement.getAttribute('thickness'))) || "1px";
5220                if(edgeElement.getElement("color") && edgeElement.getElement("color").getAttribute("value") !="")  {
5221                    var color =   edgeElement.getElement("color").getAttribute("value");
5222                    color = "rgb(" + color + ")";
5223                    cssStyleObj['border'+str+'color']   = color  ;
5224                }
5225                else {
5226                    cssStyleObj['border'+str+'color'] = "rgb(0,0,0)"  ;
5227                }
5228                cssStyleObj['border'+str+'style']   = style[edgeElement.getAttribute('stroke')] || "solid" ;
5229            } else {
5230                cssStyleObj['border'+str+'width'] =  "0px";
5231                return 1;
5232            }
5233
5234        },
5235
5236        getStyleForBorder : function (border) {
5237            if(border) {
5238                var edge  =  border.getElement('edge', 0, true),
5239                    edge1 = border.getElement('edge', 1, true),
5240                    edge2 = border.getElement('edge', 2, true),
5241                    edge3 = border.getElement('edge', 3, true);
5242                if(edge || edge1 || edge2 || edge3) {
5243                    var cssStyleObj = {} ;
5244                    var e0 = this.getStyleForEdge(edge, "-top-",cssStyleObj);
5245                    var e1 = this.getStyleForEdge(edge1 || edge,"-right-",cssStyleObj);
5246                    var e2 = this.getStyleForEdge(edge2|| edge,"-bottom-",cssStyleObj);
5247                    var e3 = this.getStyleForEdge(edge3 || edge,"-left-",cssStyleObj);
5248                    if(e0 !=1|| e1 !=1|| e2 !=1|| e3!=1)
5249                        return cssStyleObj ;
5250                }
5251            }
5252                return null;
5253        },
5254
5255        _convertToPx : function(size){
5256            if(!size)
5257                return 0;
5258            size = "" + size;
5259            var pxSize = size;
5260            if(size.indexOf("in") >=0){
5261                pxSize = this._mm2px(parseFloat(size) * this._in2mmFactor);
5262            }
5263            else if(size.indexOf("mm") >=0){
5264                pxSize = this._mm2px(size);
5265            }
5266            else if(size.indexOf("cm") >=0){
5267                pxSize = this._mm2px(parseFloat(size) * 10);
5268            }
5269            else if(size.indexOf("pt") >=0){
5270                pxSize = parseFloat(size) * (this._deviceResolution/this._pdfResolution);
5271            }
5272            else if(size.indexOf("px") >=0){
5273                pxSize = parseFloat(size);
5274            }
5275            return pxSize;
5276        },
5277
5278        _mm2px : function(mmSize){
5279            var mmSizeNum = 0;
5280            if(_.isNumber(mmSize))
5281                mmSizeNum = mmSize;
5282            else{
5283                mmSizeNum = parseFloat(mmSize)
5284            }
5285            var mm2in = 1/25.4 ;
5286            var pxSize = mmSizeNum*mm2in*this._deviceResolution;
5287            return pxSize;
5288        },
5289
5290        _subPixelValue : function(value){
5291            if(value > 0.01)
5292                return Math.max(value, 1.0);
5293            else
5294                return value;
5295        }
5296    }
5297})(_, $, xfalib);
5298/*************************************************************************
5299 * ADOBE CONFIDENTIAL
5300 * ___________________
5301 *
5302 *  Copyright 2017 Adobe Systems Incorporated
5303 *  All Rights Reserved.
5304 *
5305 * NOTICE:  All information contained herein is, and remains
5306 * the property of Adobe Systems Incorporated and its suppliers,
5307 * if any.  The intellectual and technical concepts contained
5308 * herein are proprietary to Adobe Systems Incorporated and its
5309 * suppliers and are protected by all applicable intellectual property
5310 * laws, including trade secret and copyright laws.
5311 * Dissemination of this information or reproduction of this material
5312 * is strictly forbidden unless prior written permission is obtained
5313 * from Adobe Systems Incorporated.
5314 **************************************************************************/
5315
5316
5317
5318
5319(function(_, $, xfalib){
5320    xfalib.view.util.traversalManager = {
5321
5322        // compute tabIndex for the provided page
5323        _computTabIndex : function (pageView) {
5324            var pageNum = pageView._pageNumber(),
5325                tabIndex = this._tabIndexBasedOnRange(pageNum);
5326            this.geographicalOrder = [];
5327            this._createGeographicalOrder(pageView);
5328            this._createFinalTraversalOrder(tabIndex); // assign tab index using traversal element and geographicalOrder
5329            // 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
5330            this._lastFieldTabbed = null;
5331        },
5332
5333        _tabIndexBasedOnRange : function (pageNum) {
5334            var behaviorConfig = new xfalib.ut.Version(formBridge.userConfig["behaviorConfig"]),
5335                tabIndexConfig = (behaviorConfig.isOn('mfRangeTabIndex')|| behaviorConfig.isOn('rangeTabIndex')),
5336                /*assuming single page can not have more than 1000 fields.[index -> 0 to 999]
5337                  this is also configurable by passing the maximum number of fields allowable in the page
5338                  in the config parameter */
5339                maxFieldInPageForTabIndex = tabIndexConfig? parseInt(tabIndexConfig):1000;
5340
5341            return pageNum * maxFieldInPageForTabIndex;
5342        },
5343
5344        // to create geographical order array which will be containing all the views in the geographical order
5345        _createGeographicalOrder : function (currentView) {
5346            var sortedChildViewWrapper = this._sortViewGeographically(currentView.childViews);
5347            _.each(sortedChildViewWrapper, function (wrapper) {
5348                var currentView = wrapper.view,
5349                    instanceCheckMap = this._getMapOfInstanceCheck(currentView),
5350                    isViewEligibleForTabbing = this._isViewEligibleForTabbing(currentView);
5351                //  If the child view is fieldView, drawView, exclGroupView or subformView then we will push these views in this.geographicalOrder array,
5352                //  as we need their traverse object during final traversing
5353                if (((instanceCheckMap.isField && !instanceCheckMap.isChildOfExclGroup) || instanceCheckMap.isSubform || instanceCheckMap.isDraw
5354                    || instanceCheckMap.isExclGroup) && isViewEligibleForTabbing) {
5355                    this.geographicalOrder.push({
5356                        view : currentView,
5357                        visited : false
5358                    });
5359                }
5360                if (instanceCheckMap.isContainer && isViewEligibleForTabbing) {
5361                    this._createGeographicalOrder(currentView);
5362                }
5363            }, this);
5364        },
5365
5366        // to sort provided views in geographical order
5367        _sortViewGeographically : function (views) {
5368            var viewsWrapper = [];   // wrapper of view and their geographical reference
5369            _.each(views, function(view) {
5370                var position = view.$el.offset(),
5371                    paddedX = xfalib.ut.XfaUtil.prototype.padString(parseInt(position.left), 5, '0'),
5372                    marginTop = view._marginTop(),
5373                    paddedY = position.top - parseFloat(marginTop),
5374                    positionalReference = parseInt("" + parseInt(paddedY) + paddedX);
5375                viewsWrapper.push({
5376                    positionalReference: positionalReference,
5377                    view: view
5378                });
5379            });
5380            return _.sortBy(viewsWrapper, function(viewWrapper){ return viewWrapper.positionalReference; });
5381        },
5382
5383        // Walk through views in geographical order and assign tab index honouring traversal object if present
5384        _createFinalTraversalOrder : function (tabIndex) {
5385            var geographicalOrderLength = this.geographicalOrder.length,
5386                currentWrappedObj = null,
5387                index = -1,
5388                traversalIndex = 0,  // index of the element to be traversed
5389                viewTraversed = 0;  // counter of view traversed
5390
5391            while (1) {
5392                if (traversalIndex >= geographicalOrderLength) {
5393                    traversalIndex = 0;
5394                }
5395                currentWrappedObj = this.geographicalOrder[traversalIndex];
5396
5397                if (!currentWrappedObj || currentWrappedObj.visited) {  // if the wrapped object does not exist or it has been visited move to the next one
5398                    traversalIndex++;
5399                } else {
5400                    currentWrappedObj.visited = true;
5401                    viewTraversed++;
5402                    var currentView = currentWrappedObj.view,
5403                        instanceCheckMap = this._getMapOfInstanceCheck(currentView),
5404                        currentModel = currentView.model,
5405                        nextView = null,
5406                        nextViewSom = null;
5407
5408                    // get the first traversal of the subform if traversal object is present, else move to the next geographical element
5409                    // next of the subform will be taken care when we will be finding the next view to be traversed,
5410                    // as we will be checking if the ancestor contain next before moving to geographically next view
5411                    if (instanceCheckMap.isSubform) {
5412                        if (currentModel && currentModel.getTraversalObject()) {
5413                            // get the first element to be traversed and update traversalIndex
5414                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.firstTraversal);
5415                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5416                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5417                        } else {
5418                            traversalIndex++;
5419                        }
5420                    // get the next traversal for the field/draw if traversal object is present, else move to the next geographical element
5421                    // update the tabindex for the field
5422                    } else if (instanceCheckMap.isField || instanceCheckMap.isDraw) {
5423                        if (instanceCheckMap.isField) {
5424                            currentView.updateTabIndex(tabIndex);
5425                            this._lastFieldTabbed = currentView;
5426                            tabIndex++;
5427                        }
5428                        if (currentModel && currentModel.getTraversalObject()) {
5429                            //get next element to be traversed and update traversalIndex
5430                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5431                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5432                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5433                        } else {
5434                            traversalIndex = this._findNextViewToBeTraversed(traversalIndex);
5435                        }
5436                    // if traversal object present get the next element to be traversed, if first is also present then update tab index of the first element
5437                    // else look for the traversal element in the children
5438                    } else if (instanceCheckMap.isExclGroup) {
5439                        if (currentModel && currentModel.getTraversalObject()) {
5440                            // get next element to be traversed and update traversalIndex
5441                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5442                            index = this._findViewInGeographicalOrderArray(nextViewSom);
5443                            traversalIndex = index != -1 ? index : traversalIndex + 1;
5444                            // if first is also present assign tab index to that referred child else assign same tab index to all child
5445                            nextViewSom = currentModel.getNextTraversalSom(xfalib.template.Constants.firstTraversal);
5446                            tabIndex = this._updateTabIndexOfExclGroupChildren(currentView, tabIndex, nextViewSom);
5447                        } else {
5448                            tabIndex = this._updateTabIndexOfExclGroupChildren(currentView, tabIndex);
5449                            traversalIndex = this._findTraversalInExclGroupChildren(currentView, traversalIndex);
5450                        }
5451                    } else {
5452                        traversalIndex++;
5453                    }
5454                }
5455
5456                // if all the view are traversed, we have assigned tab index to all the views
5457                if (viewTraversed >= geographicalOrderLength) {
5458                    this._renderNextPageFuture();
5459                    break;
5460                }
5461            }
5462        },
5463
5464        // Check if the nextView is a sibling of the currentView (shares the same parent)
5465        // if it is not a sibling, check if the parent has a NEXT traversal.
5466        // if so get the node traversed to else recurse to see if nextView is a sibling of our parent
5467        // return -1 if the provided next node is sibling of current node or if no ancestor contain next traversal
5468        // else return index of the next traversal object of parent
5469        _getParentNextTraversal : function (currentView, nextView, traversalIndex) {
5470            var parentView = currentView.parentView,
5471                parentModel = parentView.model,
5472                nextViewParentModel = nextView.parentView.model,
5473                traversalObj = null,
5474                nextIndex = -1;
5475
5476            if (parentModel && nextViewParentModel && parentModel.somExpression != nextViewParentModel.somExpression) {
5477                if(parentView && parentView instanceof xfalib.view.SubformView) {
5478                    if (parentModel.getTraversalObject()) {
5479                        var nextViewSom = parentModel.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5480                        nextIndex = this._findViewInGeographicalOrderArray(nextViewSom);
5481                        if (nextIndex != -1 && !this.geographicalOrder[
5481nextIndex].visited) {
5482                            return nextIndex;
5483                        } else {
5484                            return traversalIndex++;
5485                        }
5486                    } else {
5487                        this._getParentNextTraversal(parentView, nextView, traversalIndex);
5488                    }
5489                } else {  // parentView is not a subform so skip up a level and re-check sibling
5490                    this._getParentNextTraversal(parentView, nextView, traversalIndex);
5491                }
5492            } else {
5493                return -1;  //provided currentView and nextView are sibling
5494            }
5495            return traversalIndex++;
5496        },
5497
5498        // return the index of the view having provided somExpression in the geographicalOrder array
5499        _findViewInGeographicalOrderArray : function (somExpression) {
5500            return _.findIndex(this.geographicalOrder, function (viewWrapper) {
5501                var currentViewModel = viewWrapper.view.model;
5502                return (currentViewModel && currentViewModel.somExpression == somExpression);
5503            });
5504        },
5505
5506        // find the next element to be traversed based on the provided traversalIndex
5507        _findNextViewToBeTraversed : function (traversalIndex) {
5508            var currentView = this.geographicalOrder[traversalIndex].view,
5509                index = this._getNextUnvisited(traversalIndex),   //get next unvisited based on geographical location
5510                nextView = null,
5511                nextIndex = -1;
5512
5513            if (index != -1) {
5514                nextView = this.geographicalOrder[index].view;
5515                //check if both are sibling and if not find the next of the parent and update traversalIndex
5516                nextIndex = this._getParentNextTraversal(currentView, nextView, traversalIndex);
5517                return nextIndex != -1 ? nextIndex : index;
5518            }
5519            return traversalIndex++;
5520        },
5521
5522        // return the next unvisited node based on geographical location
5523        // starting from the traversalIndex and wraps around to check all the views
5524        _getNextUnvisited : function (traversalIndex) {
5525            var geographicalOrderLength = this.geographicalOrder.length,
5526                index = 0,
5527                actualIndex = 0;
5528            while(index < geographicalOrderLength) {
5529                actualIndex = (index + traversalIndex) % geographicalOrderLength;
5530                if(!this.geographicalOrder[actualIndex].visited) {
5531                    return actualIndex;
5532                }
5533                index++;
5534            }
5535            return -1;
5536        },
5537
5538        // assign same tab index to all the child of exclude group
5539        // if exclude group contain first traverse object, then the child being referred as first should have less tabindex
5540        // compared to other child
5541        _updateTabIndexOfExclGroupChildren : function (exclGroupView, tabIndex, firstChildSom) {
5542            _.each(exclGroupView.childViews, function(child){
5543                if (this._isViewEligibleForTabbing(child)) {
5544                    if(firstChildSom && child.model.somExpression == firstChildSom) {
5545                        tabIndex++;
5546                        child.updateTabIndex(tabIndex-1);
5547                        this._lastFieldTabbed = child;
5548                    } else {
5549                        child.updateTabIndex(tabIndex);
5550                    }
5551                }
5552            }, this);
5553            if (!firstChildSom) {
5554                this._lastFieldTabbed = exclGroupView.childViews[0];
5555            }
5556            return ++tabIndex;
5557        },
5558
5559        // find if any child contains next pointer and update traversal index
5560        // start with the last in the geographical order of the children and find child which have next traversal
5561        _findTraversalInExclGroupChildren : function (exclGroupView, traversalIndex) {
5562            var sortedChildView = this._sortViewGeographically(exclGroupView.childViews),
5563                tempObj = null,
5564                childView = null,
5565                childModel = null,
5566                traversalObj = null,
5567                nextViewSom = null,
5568                index = -1;
5569
5570            sortedChildView.reverse();
5571            tempObj = _.find(sortedChildView, function(child) {
5572                childView = child.view;
5573                childModel = childView.model;
5574                if(childModel && (traversalObj = childModel.getTraversalObject())) {
5575                    return traversalObj.length > 0;
5576                }
5577            });
5578
5579            if (tempObj) {
5580                nextViewSom = tempObj.model.getNextTraversalSom(xfalib.template.Constants.nextTraversal);
5581                index = this._findViewInGeographicalOrderArray(nextViewSom);
5582                traversalIndex = index != -1 ? index : traversalIndex + 1;
5583            } else { // else get next unvisited based on geographical location
5584                traversalIndex = this._findNextViewToBeTraversed(traversalIndex);
5585            }
5586            return traversalIndex;
5587        },
5588
5589        // check if the view is initialized and visible
5590        _isViewEligibleForTabbing : function (view) {
5591            if (view._initialized && view.$el.css("visibility") != "hidden") {
5592                return true;
5593            }
5594            return false;
5595        },
5596
5597        // return map of whethter provided view is instance of the various views
5598        _getMapOfInstanceCheck : function (view) {
5599            var instanceCheckMap = {};
5600            instanceCheckMap.isSubform = view instanceof xfalib.view.SubformView;
5601            instanceCheckMap.isField = view instanceof xfalib.view.FieldView;
5602            instanceCheckMap.isDraw = view instanceof xfalib.view.XfaDrawView;
5603            instanceCheckMap.isExclGroup = view instanceof xfalib.view.ExclGroupView;
5604            instanceCheckMap.isChildOfExclGroup = view.parentView instanceof xfalib.view.ExclGroupView;
5605            instanceCheckMap.isContainer = view instanceof xfalib.view.ContainerView;
5606
5607            return instanceCheckMap;
5608        },
5609
5610        // add event handler for rendering next page on tabbing on last field of the page
5611        _renderNextPageFuture : function () {
5612            if (this._lastFieldTabbed) {
5613                this._lastFieldTabbed.$el.one('focusin.traversalManager', function() {
5614                    var pagingManager = window.formBridge ? window.formBridge.pagingManager() : null;
5615                    $(window).on( "keyup.traversalManager", function (e) {
5616                        var code = (e.keyCode ? e.keyCode : e.which);
5617                        if (code == 9 && pagingManager && pagingManager.hasMorePages()) {
5618                            pagingManager.renderNextPage();
5619                            $(window).off("keyup.traversalManager");
5620                        }
5621                    });
5622                });
5623            }
5624        },
5625        _destroy : function() {
5626            this.geographicalOrder = null;
5627        }
5628    }
5629})(_, $, xfalib);
5630/*************************************************************************
5631*
5632* ADOBE CONFIDENTIAL
5633* ___________________
5634*
5635*  Copyright 2013 Adobe Systems Incorporated
5636*  All Rights Reserved.
5637*
5638* NOTICE:  All information contained herein is, and remains
5639* the property of Adobe Systems Incorporated and its suppliers,
5640* if any.  The intellectual and technical concepts contained
5641* herein are proprietary to Adobe Systems Incorporated and its
5642* suppliers and are protected by trade secret or copyright law.
5643* Dissemination of this information or reproduction of this material
5644* is strictly forbidden unless prior written permission is obtained
5645* from Adobe Systems Incorporated.
5646**************************************************************************/
5647
5648
5649
5650(function(_, $, xfalib){
5651
5652    var ErrorManager = xfalib.view.util.ErrorManager = xfalib.ut.Class.extend({
5653
5654        options: {
5655            warningMessageVisible:false,
5656            errorMessageVisible: false
5657        },
5658
5659        initialize: function () {
5660            $(window).on("destroy.xfa", function () {
5661                $("#error-msg").hide();
5662                $("#warning-msg").hide();
5663            });
5664        },
5665
5666        onFieldEnter: function (jqWidget) {
5667            var element = jqWidget.element;
5668            if (jqWidget.option("errorMessage")|| jqWidget.option("warningMessage")) {
5669                var pos = $(element).offset(),
5670                    styles = {};
5671                styles.left = (pos.left * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + element.width() + 5) + "px";
5672                styles.top = pos.top * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + "px";
5673                if (jqWidget.option("errorMessage")) {
5674                    jqWidget.$css($("#error-msg").get(0), styles);
5675                    $("#error-msg").text(jqWidget.option("errorMessage")).show();
5676                    jqWidget.option("errorMessageVisible",true);
5677                }
5678                else if (jqWidget.option("warningMessage")) {
5679                    jqWidget.$css($("#warning-msg").get(0), styles);
5680                    $("#warning-msg").text(jqWidget.option("warningMessage")).show();
5681                    jqWidget.option("warningMessageVisible",true);
5682                }
5683            }
5684        },
5685
5686        onFieldExit: function (jqWidget) {
5687            if (jqWidget.option("errorMessageVisible")) {
5688                $("#error-msg").hide();
5689                jqWidget.option("errorMessageVisible",false);
5690            } else if (jqWidget.option("warningMessageVisible")) {
5691                $("#warning-msg").hide();
5692                jqWidget.option("warningMessageVisible",false);
5693            }
5694        },
5695
5696        markError: function (jqWidget, msg, type) {
5697            // assigning role="alert" so that JAWS reads-out the validation message
5698            if (type != "warning") {
5699                if ($("#error-msg").length < 1)
5700                    $("<div id='error-msg' role='alert'></div>").appendTo('body');
5701                jqWidget.option("errorMessage",msg);
5702                jqWidget.element.addClass("dataInvalid");
5703            } else {
5704                if ($("#warning-msg").length < 1)
5705                    $("<div id='warning-msg' role='alert'></div>").appendTo('body');
5706                jqWidget.option("warningMessage",msg);
5707            }
5708
5709        },
5710
5711        clearError: function (jqWidget) {
5712            this.onFieldExit(jqWidget);
5713            jqWidget.element.removeClass("dataInvalid");
5714            jqWidget.option("errorMessage",null);
5715            jqWidget.option("warningMessage",null);
5716        }
5717    });
5718})(_, $, xfalib);
5719(function(_,$, xfalib) {
5720    var xfaUtil = xfalib.ut.XfaUtil.prototype,
5721        BUFFER_SPC = 20;
5722
5723    /* template for the clear Button */
5724    var clearButtonTemplate = '<div class="dp-clear">' +
5725        '<a></a>' +
5726        '</div>';
5727
5728    /* template for the calendar
5729    * header contains the navigation icons (left and right arrows)
5730    * and the current caption (which can be date, year or month)
5731    *
5732    * monthview displays the grid for showing the dates for a particular
5733    * month
5734    *
5735    * yearview displays all the months of that year
5736    *
5737    * yearsetview displays a grid of 16 years. This can be configured
5738    * through the option: yearsPerView
5739    *
5740    */
5741    var calendarTemplate = '<div class="dp-header">' +
5742        '<div class="dp-leftnav"></div>' +
5743        '<div class="dp-caption"></div>' +
5744        '<div class="dp-rightnav"></div>' +
5745        '</div>' +
5746        '<div role="table" class="view dp-monthview"></div>' +
5747        '<div role="table" class="view dp-yearview"></div>' +
5748        '<div role="table" class="view dp-yearsetview"></div>';
5749
5750    /*template for the timer: not implemented yet */
5751    var watchTemplate = '<div class="dp-header">' +
5752        '<div class="dp-leftnav"></div>' +
5753        '<div class="dp-caption"></div>' +
5754        '<div class="dp-rightnav"></div>' +
5755        '</div>' +
5756        '<div class="view dp-monthview"></div>' +
5757        '<div class="view dp-yearview"></div>' +
5758        '<div class="view dp-yearsetview"></div>';
5759
5760    /** default configuration options
5761     *
5762     * container: the html element where the datepicker template will be added
5763     *
5764     * yearsPerView: number of years to show in the yearset view
5765     *
5766     * width: with of the widget
5767     *
5768     * viewHeight: Height of the month,year and yearset view. This doesn't include
5769     *             the height of the header
5770     *
5771     * locale: locale information for the locale in which to show the datepicker which comprises of
5772     *        days: day names to display in the monthview
5773     *        months: month names to display in the yearview
5774     *        zero: string representation of zero in the locale. Numbers will be
5775     *              displayed in that locale only
5776     *        clearText: Text to display for the reset button
5777     *        name: name of the locale
5778     *
5779     * format: input format for the datepicker (not implemented)
5780     *
5781     * pickerType: type of the datetimepicker (date, datetime and time)
5782     *
5783     * positioning: element around which datepicker will be displayed. if null then it
5784     *              will be displayed around the input element
5785     *
5786     * showCalendarIcon: to show the Calendar on the right of the text field or not
5787     */
5788
5789    var defaults = {
5790        container: "body",
5791        yearsPerView: 16,
5792        width: 340,
5793        viewHeight: 248,
5794        locale: {
5795            days:["S","M","T","W","T","F","S"],
5796            months: ["January","February","March","April","May","June","July","August","September","October","November","December"],
5797            zero: "0",
5798            clearText: "Clear",
5799            name:"en_US"
5800        },
5801        format:"YYYY-MM-DD",
5802        pickerType:"date",
5803        positioning: null,
5804        showCalendarIcon: false
5805    },
5806    dates = [31,28,31,30,31,30,31,31,30,31,30,31],
5807    /*
5808     *  Actions to perform when clicked on the datepicker buttons
5809     *  for different views
5810     *  caption: view to show when clicked on caption
5811     *           (Year/YearSet/Month/null) null means don't change the view
5812     *  li: view to show when clicked on date, month or year element
5813     *  upDown: add(up key) or subtract(down key) current date (for monthview),
5814     *          month(Year View) or year(YearSetView) with the number provided
5815     *  key: identifies the key that needs to be changed for that view
5816     */
5817    viewAction = {
5818        Month: {
5819            caption: 'Year',
5820            li: null,
5821            key:"day",
5822            upDown:7
5823        },
5824        Year: {
5825            caption: "Yearset",
5826            li: "Month",
5827            key:"month",
5828            upDown:3
5829        },
5830        Yearset: {
5831            caption: null,
5832            li: "Year",
5833            key:"year",
5834            upDown:4
5835        }
5836    },
5837    headerClass = "header",
5838
5839    DateTimePicker = function() {
5840        this.initialized = false;
5841    }
5842
5843    $.extend(DateTimePicker.prototype, {
5844        /*
5845         * create the widget using the provided options
5846         */
5847        create: function(options) {
5848            var $dp,self = this,html="",prevNavWidth,nextNavWidth;
5849            if (window.FD && window.FD.isToggleEnabled("FT_FORMS-13599")) {
5850                    defaults.width = 433;
5851                }
5852            this.options = $.extend({},defaults,options);
5853            // prevent memory leak since options.positioning holds reference to HTML DOM
5854            this.options.positioning = null;
5855            // If width of date-picker exceeds screen width then it'll take up the entire screen width in AF
5856            if(window.guideBridge && this.options.width > window.innerWidth && window.innerWidth > 0) {
5857               this.options.width=window.innerWidth - BUFFER_SPC; // buffer
5858            }
5859            if(this.options.pickerType.match(/date/)) {
5860                html += calendarTemplate;
5861            }
5862
5863            if(this.options.pickerType.match(/time/)) {
5864                html += watchTemplate;
5865            }
5866
5867            html += clearButtonTemplate;
5868
5869            $.extend(this, {
5870                selectedDay:0,
5871                selectedMonth:0,
5872                selectedYear:0,
5873                currentDay:0,
5874                currentMonth:0,
5875                currentYear:0,
5876                touchSupported : xfalib.ut.TouchUtil.TOUCH_ENABLED,
5877                _visible:false,
5878                _defaultView:"Month",
5879                _keysEnabled:false,
5880                focusedOnDatepickerItem : false,
5881                keyboardAccessibility : true,
5882                $dp:$("<div></div>").addClass("datetimepicker")
5883                                    .width(this.options.width)
5884                                    .append(html)
5885                                    .addClass("datePickerTarget")
5886                                    .appendTo(this.options.container)
5887                                    .toggleClass("datetimepicker-notouch",this.touchSupported),
5888                $month: $(".dp-monthview",this.$dp).height(this.options.viewHeight),
5889                $year: $(".dp-yearview",this.$dp).height(this.options.viewHeight),
5890                $yearset : $(".dp-yearsetview",this.$dp).height(this.options.viewHeight)
5891            });
5892            this.actualWidth = Math.floor(this.$dp.width());
5893            this.$clear = $('.dp-clear a', this.$dp).on("click", $.proxy(this._clearDate, this));
5894            this.$prevNavWidthBtn = $(".dp-leftnav", this.$dp).on("click",
5895                                                            function(evnt) {
5896                                                                self._adjustDate(-1, self.view, false)
5897                                                            });
5898            this.$nextNavWidthBtn = $(".dp-rightnav", this.$dp).on("click",
5899                                                            function(evnt) {
5900                                                                self._adjustDate(1, self.view, false)
5901                                                            });
5902            prevNavWidth = this.$prevNavWidthBtn.outerWidth(true);
5903            nextNavWidth = this.$nextNavWidthBtn.outerWidth(true);
5904            this.$caption = $(".dp-caption", this.$dp).width(this.actualWidth - prevNavWidth - nextNavWidth)
5905                                                     .on("click",
5906                                                            function(evnt) {
5907                                                                if(!self.$caption.hasClass("disabled")) {
5908                                                                    self._layout(viewAction[self.view].caption);
5909                                                                }
5910                                                      });
5911            if (this.keyboardAccessibility) {
5912                _.each([this.$prevNavWidthBtn, this.$caption, this.$nextNavWidthBtn, this.$clear], function (elem, i) {
5913                    elem.attr("tabIndex", i + 1);
5914                });
5915            }
5916            // attach click event on entire datePicker popup
5917            $(this.$dp).on("click",
5918                function(evnt) {
5919                    //focus only if the device doesn't support touch
5920                    // input otherwise on screen keyboard will popup
5921                    if(!self.touchSupported)
5922                        self._curInstance.$field.focus();
5923                });
5924
5925            $(window).on("touchstart.datetimepicker mousedown.datetimepicker",self._checkWindowClicked);
5926            this._curInstance = null;
5927        },
5928
5929        /*
5930         * attaches the date picker to the field. This is a one time operation
5931         * First creates a configuration object and stores it in the field data attributes
5932         * then attaches event handlers on click, focus (to show the picker) and blur (to hide) events
5933         */
5934        _attachField: function($field,options, value) {
5935            var inst = this._newInst($field,options, value),
5936                self = this,
5937                activateField = function(evnt) {
5938                    var data = xfaUtil.$data(evnt.target,"datetimepicker");
5939                    if(data.access == false) {
5940                        return;
5941                    }
5942                    if(!self._curInstance)
5943                         self._activateField(evnt);
5944
5945                    if(self.options.showCalendarIcon) {
5946                        if (evnt.type === self.getEvent()) {
5947                            if (self._iconClicked) {
5948                                self._iconClicked = false;
5949                                if (self._visible) {
5950                                    self._hide(); // hide the calendar popup if visible when calendar icon is clicked
5951                                    self._curInstance.$field.focus(); // bring back focus in field
5952                                } else {
5953                                    self._show(); //// show the calendar popup if not visible when calendar icon is clicked
5954                                }
5955                            }
5956                        }
5957                    } else {
5958                        /*show the popup only if
5959                         1. click/touch event
5960                         2. focus event in case of non-touch devices and focus is not done using script
5961                         */
5962                        if (evnt.type === self.getEvent() || (evnt.type === "focus" && !self.touchSupported && !self.scriptFocus)) {
5963                            self._show(evnt);
5964                        }
5965                    }
5966
5967                    self._clickedWindow = true;
5968                    self.scriptFocus = false;
5969                },
5970                deactivateField = function(evnt) {
5971                    //deactivate only if clicked outside window
5972                    // on touch devices only keyboard or calander should be active at once, touching keyboard should deactivate calendar
5973                    if ((self._clickedWindow && !self.focusedOnDatepickerItem) && (self.options.showCalendarIcon || !self.touchSupported)) {
5974                        self._hide();
5975                        self._deactivateField();
5976                        self._clickedWindow = true;
5977                    }
5978                };
5979
5980            xfaUtil.$data($field[0],"datetimepicker",inst);
5981
5982            $field.on(this.getEvent(),activateField)
5983                  .focus(activateField)
5984                  .blur(deactivateField);
5985            if(options.showCalendarIcon) {
5986                var calendarIcon = $("<div></div>")
5987                                    .addClass("datepicker-calendar-icon")
5988                                    .css({
5989                                        "width": options.iconWidth + "px",
5990                                        "height": options.iconHeight + "px"
5991                                    });
5992                calendarIcon.insertAfter($field);
5993
5994                if (this.keyboardAccessibility) {
5995                    calendarIcon.attr("tabindex", 0);
5996                }
5997
5998                calendarIcon.on(this.getEvent(), function (evnt) {
5999                                self._iconClicked = true;
6000                                $field.click();
6001                              })
6002                              .on("keydown", function (event) {
6003                                    if (event.keyCode === 32 || event.keyCode === 13) {
6004                                        $field.click();
6005                                    }
6006                              });
6007            }
6008        },
6009
6010        _newInst: function($f,options, value) {
6011            return {
6012                $field:$f,
6013                locale: options.locale,
6014                positioning: options.positioning || $f,
6015                access:options.access,
6016                selectedDate:options.value,
6017                editValue :options.editValue,
6018                minValidDate : options.minValidDate,
6019                maxValidDate : options.maxValidDate,
6020                exclMinDate :  options.exclMinDate,
6021                exclMaxDate : options.exclMaxDate
6022            }
6023        },
6024
6025        /*
6026         * To check where the click happened, if happened outside the datepicker
6027         * then hide the picker. This is checked whether any ancestor of clicked target
6028         * has a class datePickerTarget. This class is added to the attached element as well
6029         */
6030        _checkWindowClicked : function(evnt) {
6031            var self = adobeDateTimePicker;
6032            if(self._curInstance) {
6033                // datepickerTarget class depicts that the component is a part of the Date Field
6034                // and on click of that class, we should not hide the datepicker or fire exit events.
6035                if(!$(evnt.target).closest(".datePickerTarget").length) {
6036                    //non-touch devices do not deactivate on blur. Hence needs to be done here
6037                    if(self.touchSupported) {
6038                        self._hide()
6039                        //clicking outside a field doesn't blur the field in IPad. Doing it by script
6040                        self._curInstance.$field[0].blur()
6041                        self._deactivateField()
6042                    } else{
6043                        self._clickedWindow = true;
6044                        // set focusedOnDatepickerItem to false, it hides the datepicker see method deactivateField.
6045                        self.focusedOnDatepickerItem = false;
6046                        self._curInstance.$field.blur()
6047                    }
6048                }
6049                else {
6050                    self._clickedWindow = false;
6051                }
6052            }
6053        },
6054
6055        /*
6056         * handling of key strokes. All the key strokes prevent the default browser action
6057         * unless specified otherwise
6058         * tab: set focus on calendar icon when dateinput field is active, navigates through date picker buttons when datepicker is open,
6059         * otherwise perform default browser action
6060         * escape: hides the datepicker
6061         * down arrow key: navigate the picker downwards by the number specified in actionView.upDown of the current View
6062         * up arrow key: navigate the picker upwards by the number specified in actionView.upDown of the current View
6063         * left arrow key: navigate the picker one unit of that view backward
6064         * right arrow key: navigate the picker one unit of that view forward
6065         * shift + up: perform the action that happens on clicking the caption (as specified in actionView.caption)
6066         * shift + left: perform the action that happens on clicking the left navigation button
6067         * shift + right: perform the action that happens on clicking the right navigation button
6068         * space/enter: triggers the click event for the current focused element from datepicker/ opens datepicker when calendar icon is focused.
6069         */
6070        _hotKeys: function(evnt) {
6071            var handled = false, date;
6072            switch(evnt.keyCode) {
6073                case 9: //tab
6074                    // CQ-4239352 : Setting clickedWindow property to true on tabbing so that deactivateField logic gets executed
6075                    // When clicking on "x" on input field in in IE and when selecting the content and releasing the mouse select outside the field
6076                    // the click event is not trigerred on the field and hence activateField is not executed, so clickedWindow remains as fal
6076se
6077                    adobeDateTimePicker._clickedWindow = true;
6078                    handled = false;
6079                    break;
6080                case 27://escape
6081                    if(this._visible) {
6082                        adobeDateTimePicker._hide();
6083                        this._curInstance.$field.focus();
6084                        handled = true;
6085                    }
6086                    break;
6087                case 32: //space
6088                case 13: // enter
6089                    if($(evnt.target).hasClass("datepicker-calendar-icon")){
6090                        if(!this._visible) {
6091                            this._show();
6092                            return;
6093                        }
6094                        this.$focusedDate.addClass("dp-focus");
6095                    }
6096                    break;
6097                case 40: //down arrow key
6098                    if(!this._visible) {
6099                        this._show();
6100                        return;
6101                    }
6102                    this.$focusedDate.addClass("dp-focus");
6103                    break;
6104            }
6105
6106            if(adobeDateTimePicker._visible && this._keysEnabled) {
6107                var v = viewAction[this.view].key,
6108                    updown=viewAction[this.view].upDown;
6109                switch(evnt.keyCode) {
6110                    case 9: // tab
6111                        if (evnt.shiftKey) {
6112                            if ($(evnt.target).hasClass("dp-leftnav") || $(evnt.target).hasClass("dp-focus")) {
6113                                this._hide();
6114                                this._curInstance.$field.focus();
6115                                handled = true;
6116                            } else {
6117                                handled = false;
6118                            }
6119                        } else {
6120                            var buttonTabindex = $(evnt.target).attr("tabindex");
6121                            if (buttonTabindex === '0') {
6122                                if (evnt.target.tagName.toLocaleLowerCase() === "input") {
6123                                    this._hide();
6124                                    handled = false;
6125                                } else {
6126                                    this.$prevNavWidthBtn.focus();
6127                                    handled = true;
6128                                }
6129                            } else if (buttonTabindex === '4') {
6130                                this._hide();
6131                                this._curInstance.$field.focus();
6132                                handled = true;
6133                            } else {
6134                                handled = false;
6135                            }
6136                        }
6137                        break;
6138                    case 32: //select on space
6139                    case 13: // select on enter
6140                        this.hotKeyPressed = true;
6141                        this.focusedOnDatepickerItem = false;
6142                        if (!this.focusedOnDatepickerItem) {
6143                            $(evnt.target, this.$dp).triggerHandler("click");
6144                        } else {
6145                            if (this.$focusedDate) {
6146                                this.$focusedDate.trigger("click");
6147                            }
6148                        }
6149                        this.hotKeyPressed = false;
6150                        handled = true;
6151                        break;
6152                    case 37: //left arrow key
6153                        if (evnt.shiftKey) {
6154                            $(".dp-leftnav", this.$dp).triggerHandler("click");
6155                        } else {
6156                            this._adjustDate(-1, v, true);
6157                        }
6158                        handled = true;
6159                        break;
6160                    case 38: //up arrow key
6161                        if (evnt.shiftKey) {
6162                            this.$caption.triggerHandler("click");
6163                        } else {
6164                            this._adjustDate(-updown, v, true);
6165                        }
6166                        handled = true;
6167                        break;
6168                    case 39: //right arrow key
6169                        if (evnt.shiftKey) {
6170                            $(".dp-rightnav", this.$dp).triggerHandler("click");
6171                        } else {
6172                            this._adjustDate(+1, v, true);
6173                        }
6174                        handled = true;
6175                        break;
6176                    case 40: //down arrow key
6177                        this._adjustDate(updown, v, true);
6178                        handled = true;
6179                        break;
6180                    default:
6181                }
6182            }
6183            if(handled) {
6184                evnt.preventDefault();
6185            }
6186        },
6187
6188        /*
6189         * show the datepicker.
6190         */
6191        _show: function() {
6192            if(this._curInstance.access == false)
6193                return;
6194            this.options.locale = this._curInstance.locale;
6195            if(!this._visible) {
6196                var self = this,
6197                    date = new Date(),
6198                    val,
6199                    maxDateInfo,
6200                    minDateInfo,
6201                    validDate;
6202                //Bug#3607735:
6203                // Date constructor in ipad 5.1 doesn't support "YYYY-MM-DD", hence parsing the date on our own
6204                validDate = xfalib.ut.DateInfo.ParseIsoString(this._curInstance.selectedDate);
6205                date = (validDate != null)? validDate.getDate(): new Date();
6206                this.selectedDay = this.currentDay = date.getDate();
6207                this.selectedMonth = this.currentMonth = date.getMonth();
6208                this.selectedYear = this.currentYear = date.getFullYear();
6209                maxDateInfo = this.options.maxValidDate ? xfalib.ut.DateInfo.ParseIsoString(this._curInstance.maxValidDate) : null;
6210                this.maxValidDate = maxDateInfo ? maxDateInfo.getDate() : null;
6211                minDateInfo = this.options.minValidDate ? xfalib.ut.DateInfo.ParseIsoString(this._curInstance.minValidDate) : null;
6212                this.minValidDate = minDateInfo ? minDateInfo.getDate() : null;
6213                this.exclMaxDate = this._curInstance.exclMaxDate;
6214                this.exclMinDate = this._curInstance.exclMinDate;
6215                $('.dp-clear a',this.$dp).text(this.options.locale.clearText);
6216                this._layout('Month');
6217                this._position();
6218                this.$dp.show();
6219                // if li element of datepicker is focused then set focusedOnDatepickerItem to true, it manages the visibility of the datepicker.
6220                this.focusedOnDatepickerItem = false;
6221                this._visible = true;
6222                if (this.options.showCalendarIcon) {
6223                    this._curInstance.$field.attr('readonly', true);    // when the datepicker is active, deactivate the field
6224                }
6225            }
6226
6227            //   Disabling the focus on ipad  due to a bug where value of
6228            // date picker is not being set
6229            // Removing this code will only hamper one use case
6230            // where on ipad if you click on the calander then
6231            // the field becomes read only so
6232            // there is no indication where the current focus is
6233            // And  if you remove this foucs code all together
6234            // then what happens is that on desktop MF in iframe the exit event
6235            // is not getting called hence calander getting remained open even
6236            // when you click somewhere on window or focus into some other field
6237            if (this.options.showCalendarIcon  && !this.touchSupported) {
6238                if(this.$focusedDate && this.$focusedDate.length > 0) {
6239                    this.$focusedDate.focus();  // shift focus on current date or selected date.
6240                } else {
6241                    this._curInstance.$field.focus(); // field loses focus after being marked readonly, causing blur event not to be fired later
6242                }
6243            }
6244        },
6245
6246        /*
6247         * position the datepicker around the positioning element
6248         * provided in the options
6249         */
6250        _position: function() {
6251            var $elem = this._curInstance.positioning,
6252                windowScrollX = window.scrollX/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6253                windowScrollY = window.scrollY/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6254                windowInnerHeight = window.innerHeight/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6255                windowInnerWidth = window.innerWidth/ xfalib.ut.XfaUtil.prototype.formScaleFactor,
6256                height = $elem.outerHeight(true),
6257                width  = $elem.outerWidth(true),
6258                top = $elem.offset().top / xfalib.ut.XfaUtil.prototype.formScaleFactor + height,
6259                left = $elem.offset().left / xfalib.ut.XfaUtil.prototype.formScaleFactor,
6260                styles = {"top": (top+"px"), "left": (left+"px")},
6261                diffBottom = top + this.$dp.outerHeight(true) - windowInnerHeight - windowScrollY,
6262                newLeft,
6263                newTop;
6264            if(diffBottom > 0) {
6265                //can't appear at the bottom
6266                //check top
6267                newTop = top - height - this.$dp.outerHeight(true) - BUFFER_SPC;
6268                if(newTop < windowScrollY) {
6269                    //can't appear at the top as well ... the datePicker pop up overlaps the date field
6270                    newTop = top - diffBottom;
6271                    // Fix for BUG #3626974
6272                    if(xfaUtil.isWebkit() && !this.options.showCalendarIcon) {
6273                        this._curInstance.$field.trigger("onoverlap.datetimepicker");
6274                    }
6275                }
6276                styles.top = newTop + "px";
6277            }
6278            if(left + this.$dp.outerWidth(true) > windowScrollX + windowInnerWidth ) {
6279                //align with the right edge
6280                newLeft = windowScrollX + windowInnerWidth - this.$dp.outerWidth(true) - BUFFER_SPC;
6281                styles.left = newLeft + "px";
6282            }
6283            xfaUtil.$css(this.$dp.get(0), styles);
6284            return this;
6285        },
6286
6287        /*
6288         * layout the nextView. if nextView is null return
6289         *
6290         */
6291        _layout: function(nextView) {
6292            if(nextView == null) {
6293                this._hide();
6294            } else {
6295                if(this.view)
6296                    this['$'+this.view.toLowerCase()].hide();
6297                this.view = nextView;
6298                this.$caption.toggleClass("disabled",!viewAction[this.view].caption);
6299                this['$'+this.view.toLowerCase()].show();
6300                this["show"+this.view]();
6301            }
6302            return this;
6303        },
6304
6305        /*
6306         * show the month view
6307         */
6308        showMonth: function() {
6309            var self = this,
6310                curDate = new Date(this.currentYear, this.currentMonth),
6311                maxDay =   this._maxDate(this.currentMonth),
6312                prevMaxDay = this._maxDate((this.currentMonth + 11)%12),
6313                day1 = new Date(this.currentYear,this.currentMonth,1).getDay(),
6314                data,display;
6315
6316            this.tabulateView(
6317                {
6318                    caption: this.options.locale.months[this.currentMonth] + ", "+ this._convertNumberToLocale(this.currentYear),
6319                    header:this.options.locale.days,
6320                    numRows:7,
6321                    numColumns:7,
6322                    elementAt: function(row,col) {
6323                        var day = (row-1)*7 + col - day1 + 1;
6324                        var monthVal = self.currentMonth + 1;
6325                        display = self._convertNumberToLocale(day);
6326                        data = day;
6327                        if(day < 1) {
6328                            display = self._convertNumberToLocale(prevMaxDay + day);
6329                            data = -1;
6330                            monthVal = self.currentMonth;
6331                        }
6332                        else if(day > maxDay) {
6333                            display = self._convertNumberToLocale(day-maxDay);
6334                            data = -1;
6335                            monthVal = self.currentMonth + 2;
6336                        }
6337                        else {
6338                            curDate.setDate(day);
6339                            var compareFn = xfalib.ut.XfaUtil.prototype._compareVal;
6340                            // check if the currentdate is valid based on max and min valid date
6341                            if(compareFn(curDate, self.maxValidDate, self.exclMaxDate) || compareFn(self.minValidDate, curDate, self.exclMinDate)) {
6342                                data = -1;
6343                            }
6344                        }
6345                        return {
6346                            data : data,
6347                            display : display,
6348                            ariaLabel : self.options.editValue(self.currentYear+"-"+self._pad2(monthVal)+"-"+self._pad2(display))
6349                        };
6350                    }
6351                });
6352        },
6353
6354
6355
6356        /*
6357         * show the year view
6358         */
6359        showYear: function() {
6360            var self = this,
6361                minDate = this.minValidDate ? new Date(this.minValidDate.getFullYear(), this.minValidDate.getMonth()) : null,
6362                maxDate = this.maxValidDate ? new Date(this.maxValidDate.getFullYear(), this.maxValidDate.getMonth()) : null,
6363                curDate = new Date(this.currentYear, 0), //can't omit month, if only one param present it is treated as millisecond
6364                data,
6365                month;
6366            this.tabulateView(
6367                {
6368                    caption : this._convertNumberToLocale(this.currentYear),
6369                    numRows : 4,
6370                    numColumns : 3,
6371                    elementAt : function(row,col) {
6372                        data = month =  row*3 + col;
6373                        curDate.setMonth(month);
6374                        if ((minDate && curDate < minDate) || (maxDate && curDate > maxDate)) {
6375                            data = -1;
6376                        }
6377                        return {
6378                            data : data,
6379                            display : self.options.locale.months[month],
6380                            ariaLabel : self.options.locale.months[month] + " " +self.currentYear
6381                        };
6382                    }
6383                });
6384        },
6385
6386        /*
6387         * show the year set view
6388         */
6389        showYearset: function() {
6390            var year,
6391                minDate = this.minValidDate ? new Date(this.minValidDate.getFullYear(), 0
6391) : null ,
6392                maxDate = this.maxValidDate ? new Date(this.maxValidDate.getFullYear() + 1, 0) : null,
6393                curDate = new Date(),
6394                data,
6395                self = this;
6396            this.tabulateView(
6397                {
6398                    caption: this._convertNumberToLocale(this.currentYear - this.options.yearsPerView/2) +"-"+this._convertNumberToLocale(this.currentYear - this.options.yearsPerView/2 + this.options.yearsPerView - 1),
6399                    numRows:4,
6400                    numColumns:4,
6401                    elementAt: function(row,col) {
6402                        data = year =  self.currentYear - 8 + (row*4 + col);
6403                        curDate.setFullYear(year);
6404                        if ((minDate && curDate < minDate) || (maxDate && curDate > maxDate)) {
6405                            data = -1;
6406                        }
6407                        return {
6408                            "data" : data,
6409                            "display" : self._convertNumberToLocale(year),
6410                            ariaLabel : year
6411                        };
6412                    }
6413                });
6414        },
6415
6416        insertRow :  function(rowNum,rowArray,isHeader,height) {
6417            var $view = this["$"+this.view.toLowerCase()],
6418                width = (this.actualWidth)/rowArray.length,
6419                $row = $("ul",$view).eq(rowNum),
6420                items,$li,element,$tmp,
6421                self= this;
6422            if(!$row.length)
6423                $row = $("<ul></ul>").attr("aria-label", "").attr("role", "row").appendTo($view).toggleClass(headerClass,isHeader);
6424            $row.height(height);
6425            items = $("li",$row).length;
6426            while(items++ < rowArray.length) {
6427                $tmp = $("<li></li>").attr("role", "cell").appendTo($row);
6428                if(!isHeader)
6429                    $tmp.on("click", $.proxy(this._selectDate,this));
6430            }
6431
6432            _.each(rowArray, function(el,index) {
6433                $li = $("li",$row).eq(index);
6434                if(isHeader)
6435                    $li.text(rowArray[index]);
6436                else {
6437                    element = rowArray[index];
6438                    xfaUtil.$data($li.get(0), "value", element.data);
6439                    if(self._checkDateIsFocussed(element.data)) {
6440                        if(self.$focusedDate) {
6441                            self.$focusedDate.removeClass("dp-focus");
6442                            self.$focusedDate.attr("tabindex", "-1");
6443                        }
6444                        self.$focusedDate = $li;
6445                        if(self._keysEnabled)
6446                            self.$focusedDate.addClass("dp-focus")
6447                    }
6448                    $li.toggleClass("dp-selected",self._checkDateIsSelected(element.data))
6449                        .toggleClass("disabled", element.data == -1).text(element.display)
6450                        .attr("title", element.ariaLabel)
6451                        .attr("aria-label", element.ariaLabel)
6452                        .attr("tabindex", -1);
6453                }
6454                $li.css( {"height":height+"px","width":width+"px","line-height":height+"px"});
6455            });
6456            return $row;
6457        },
6458
6459        /*
6460         * creates a tabular view based on the options provided. The options that can be passed are
6461         * numRows: number of rows that needs rendering
6462         * numCols: number of columns that needs rendering
6463         * caption: text for the datepickers caption element
6464         * header: an array of elements that identifies the header row
6465         * elementAt: a function(row, column) that returns an object (data: <data>, display: <display>) where
6466         *            <data> is the value to set for that view when the element at (row,column) is clicked and
6467         *            <display> is the value that will be visible to the user
6468         */
6469        tabulateView : function(options) {
6470            var r = 0,rows = 0,
6471                row = [],
6472                ht =  this.options.viewHeight/options.numRows,
6473                c;
6474            this.$caption.text(options.caption);
6475            if(options.header) {
6476                this.insertRow(r++,options.header,true,ht);
6477            }
6478            while(r < options.numRows) {
6479                c = 0;
6480                while(c < options.numColumns) {
6481                    row[c] = options.elementAt(r,c);
6482                    c++;
6483                }
6484                this.insertRow(r++,row,false,ht);
6485            }
6486        },
6487
6488        _activateField : function(evnt) {
6489            this._curInstance = xfaUtil.$data(evnt.target,"datetimepicker");
6490            this._curInstance.$field.trigger("onfocus1.datetimepicker").addClass("datePickerTarget");
6491            // Issue LC-7049:
6492            // datepickerTarget should be added when activate the field and should be removed
6493            // after the fields gets deactivated.
6494            if (this.options.showCalendarIcon) {
6495                this._curInstance.$field.parent().addClass("datePickerTarget");
6496            }
6497            //enable hot keys only for non touch devices
6498            if(!this.touchSupported && !this._keysEnabled) {
6499                $(window).on("keydown.datetimepicker", $.proxy(this._hotKeys,this));
6500                this._keysEnabled = true;
6501            }
6502        },
6503
6504        _deactivateField: function() {
6505            if(this._curInstance) {
6506                if(this._keysEnabled) {
6507                    $(window).off("keydown.datetimepicker")
6508                    this._keysEnabled = false;
6509                }
6510                //Bug#3607499: on deactivate check the value in the input box, if that is
6511                // different than the selected Date, change the selectedDate
6512                //if (this._curInstance.selectedDate != this._curInstance.$field.val()) {
6513                //    this._curInstance.selectedDate = this._curInstance.$field.val();
6514                //}
6515                this._curInstance.$field.trigger("onfocusout.datetimepicker").removeClass("datePickerTarget");
6516                // Issue LC-7049:
6517                // datepickerTarget should be added when activate the field and should be removed
6518                // after the fields gets deactivated. Otherwise clicking on any other datefield
6519                // will not hide the existing datepicker
6520                if (this.options.showCalendarIcon) {
6521                    this._curInstance.$field.parent().removeClass("datePickerTarget");
6522                }
6523                this._curInstance = null;
6524            }
6525        },
6526
6527        _hide: function() {
6528            if(this._visible) {
6529                this.$dp.hide();
6530                this._curInstance.$field.trigger("onclose.datetimepicker");
6531                this._visible = false;
6532                if (this.options.showCalendarIcon) {
6533                    this._curInstance.$field.attr('readonly', false);    // when the datepicker is deactivated, activate the field
6534                }
6535            }
6536        },
6537
6538        _adjustDate: function(step, view, focus) {
6539            var maxDate,prevMaxDate;
6540            var _focus = focus || false;
6541            switch(view.toLowerCase()) {
6542                case "day":
6543                    this.currentDay += step;
6544                    maxDate = this._maxDate(this.currentMonth)
6545                    if(this.currentDay < 1) {
6546                        prevMaxDate =  this._maxDate((this.currentMonth - 1 + 12)%12);
6547                        this.currentDay = prevMaxDate + this.currentDay;
6548                        return this._adjustDate(-1, "month", _focus);
6549                    }
6550                    if(this.currentDay > maxDate) {
6551                        this.currentDay -= maxDate;
6552                        return this._adjustDate(+1, "month", _focus);
6553                    }
6554                    break;
6555                case "month":
6556                    this.currentMonth += step;
6557                    if(this.currentMonth > 11) {
6558                        this.currentYear++;
6559                        this.currentMonth = 0;
6560                    }
6561                    if(this.currentMonth < 0) {
6562                        this.currentYear--;
6563                        this.currentMonth = 11;
6564                    }
6565                    break;
6566                case "year":
6567                    this.currentYear += step;
6568                    break;
6569                case "yearset":
6570                    this.currentYear += step*this.options.yearsPerView;
6571                    break;
6572            }
6573            this._layout(this.view);
6574            if (_focus) {
6575                this.focusedOnDatepickerItem = true;
6576                this.$focusedDate.attr("tabindex", 0)[0].focus();
6577            }
6578        },
6579
6580        _checkDateIsSelected: function(data) {
6581            switch(this.view.toLowerCase()) {
6582                case "month":
6583                    return this.currentYear == this.selectedYear && this.currentMonth == this.selectedMonth && data == this.selectedDay;
6584                case "year":
6585                    return this.currentYear == this.selectedYear && this.selectedMonth == data;
6586                case "yearset":
6587                    return this.selectedYear == data;
6588            }
6589        },
6590
6591        _checkDateIsFocussed: function(data) {
6592            switch(this.view.toLowerCase()) {
6593                case "month":
6594                    return data == this.currentDay;
6595                case "year":
6596                    return this.currentMonth == data;
6597                case "yearset":
6598                    return this.currentYear == data;
6599            }
6600        },
6601
6602        _convertNumberToLocale : function(number) {
6603            var zeroCode = this.options.locale.zero.charCodeAt(0);
6604            number += "";
6605            var newNumber = [];
6606            for(var i = 0;i < number.length;i++) {
6607                newNumber.push(String.fromCharCode(zeroCode + parseInt(number.charAt(i))));
6608            }
6609            return newNumber.join("");
6610        },
6611
6612        _clearDate: function() {
6613            var isDateEmpty = this._curInstance.$field.val() ? false : true;
6614            this.selectedYear
6615                = this.selectedMonth
6616                = this.selectedYear
6617                = -1;
6618            this._curInstance.selectedDate = "";
6619            this._curInstance.$field.val("");
6620            if (!isDateEmpty) {
6621                this._curInstance.$field.trigger("onvaluechange.datetimepicker", [
6622                    {selectedDate: ""}
6623                ]);
6624            }
6625            $(".dp-selected",this['$'+this.view.toLowerCase()]).removeClass("dp-selected");
6626        },
6627
6628        getEvent : function() {
6629            return "click";//this.touchSupported ? "touchstart" : "click";
6630        },
6631
6632        _pad2: function(m) {
6633            return m = m < 10 ?"0"+m:m;
6634        },
6635
6636        toString : function() {
6637            return this.selectedYear +"-"+this._pad2(this.selectedMonth + 1)+"-"+this._pad2(this.selectedDay);
6638        },
6639
6640        _selectDate : function(evnt) {
6641            var val = xfaUtil.$data(evnt.target, "value"),
6642                nextView = viewAction[this.view].li,
6643                editVal;
6644            //disabled dates have a value of -1. Do nothing in that case
6645            if(val == -1)
6646                return;
6647            switch(this.view.toLowerCase()) {
6648                case "month":
6649                    this.selectedMonth = this.currentMonth;
6650                    this.selectedYear = this.currentYear;
6651                    this.selectedDay = val;
6652                    this._curInstance.selectedDate = this.toString();
6653                    editVal = this._curInstance.editValue(this.toString());
6654                    this._curInstance.$field.val(editVal).focus();
6655                    this._curInstance.$field.trigger("onvaluechange.datetimepicker", [
6656                        {selectedDate: editVal}
6657                    ]);
6658                    $(".dp-selected",this['$'+this.view.toLowerCase()]).removeClass("dp-selected");
6659                    $(evnt.target).addClass("dp-selected");
6660                    break;
6661                case "year":
6662                    this.currentMonth = val;
6663                    break;
6664                case "yearset":
6665                    this.currentYear = val;
6666                    break;
6667            }
6668            this._layout(nextView);
6669            //manually focus on the field if clicked on the popup buttons for non-touch device
6670            if(!this.touchSupported) {
6671                //No need to focus if selection is made by pressing space.
6672                if(!this.hotKeyPressed) {
6673                    this.scriptFocus = true;
6674                    if(nextView == null) {
6675                        this.focusedOnDatepickerItem = false;
6676                    }
6677                }
6678            } else if(nextView == null){
6679                //For touch devices, deactivate the field if a selection is made
6680                this.focusedOnDatepickerItem = false;
6681                this._deactivateField()
6682            }
6683        },
6684
6685        _leapYear : function() {
6686            return this.currentYear % 400 == 0 || (this.currentYear % 100 != 0 && this.currentYear % 4 == 0);
6687        },
6688
6689        _maxDate : function(m) {
6690            if(this._leapYear() && m == 1)
6691                return 29;
6692            else return dates[m];
6693        },
6694
6695        _access: function(val) {
6696            if(typeof val == "undefined")
6697                return this.access
6698            this.access = val;
6699        },
6700
6701        _value:function(val) {
6702            if(typeof val == "undefined")
6703                return this.$field.val()
6704            else {
6705                this.selectedDate = val;
6706                var editValue = this.editValue(val);
6707                // update the field val with provided value instead of null
6708                if (!editValue) {
6709                    editValue = val;
6710                }
6711                this.$field.val(editValue);
6712            }
6713        }
6714    });
6715
6716    var adobeDateTimePicker = new DateTimePicker();
6717
6718    $.fn.adobeDateTimePicker = function(options, value) {
6719        if(!adobeDateTimePicker.initialized) {
6720            adobeDateTimePicker.create(options);
6721            adobeDateTimePicker.initialized = true;
6722        }
6723        if(typeof options === "object") {
6724            adobeDateTimePicker._attachField(this, options);
6725        }
6726        else if(typeof options === "string") {
6727            if(arguments.length == 2)
6728                adobeDateTimePicker["_"+options].apply(xfaUtil.$data(this[0],"datetimepicker"),[value])
6729            else
6730                return adobeDateTimePicker["_"+options].apply(xfaUtil.$data(this[0],"datetimepicker"))
6731        }
6732        return this;
6733    }
6734})(_, $, xfalib);
6735(function (xfalib) {
6736    xfalib.ut.TouchUtil = (function () {
6737        var touchAvailable = !!("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch) ,
6738            pointerEnabled = !!(window.MSPointerEvent || window.PointerEvent) ,
6739            POINTER_DOWN_EVENT = "mousedown",
6740            POINTER_MOVE_EVENT = "mousemove",
6741            POINTER_UP_EVENT = "mouseup",
6742            EVENT_TYPE = "MouseEvent";
6743
6744        if (window.PointerEvent) { //> IE11
6745            POINTER_DOWN_EVENT = "pointerdown";
6746            POINTER_MOVE_EVENT = "pointermove";
6747            POINTER_UP_EVENT = "pointerup";
6748            EVENT_TYPE = "PointerEvent";
6749
6750        } else if (window.MSPointerEvent) { // IE10
6751            POINTER_DOWN_EVENT = "MSPointerDown";
6752            POINTER_MOVE_EVENT = "MSPointerMove";
6753            POINTER_UP_EVENT = "MSPointerUp";
6754            EVENT_TYPE = "MSPointerEvent" ;
6755
6756        } else if (touchAvailable) {  // other touch devices
6757            POINTER_DOWN_EVENT = "touchstart";
6758            POINTER_MOVE_EVENT = "touchmove";
6759            POINTER_UP_EVENT = "touchend";
6760            EVENT_TYPE = "TouchEvent";
6761        }
6762        return {
6763            TOUCH_ENABLED: touchAvailable,
6764            // new MS Pointer Events
6765            POINTER_EVENT: EVENT_TYPE,
6766            POINTER_ENABLED: pointerEnabled,
6767            POINTER_DOWN: POINTER_DOWN_EVENT,
6768            POINTER_MOVE: POINTER_MOVE_EVENT,
6769            POINTER_UP: POINTER_UP_EVENT,
6770            getTouchEvent: function (evt) {
6771                var target;
6772                if (pointerEnabled) {
6773                    target = evt.originalEvent;
6774                } else if (touchAvailable) {
6775                    target = evt.originalEvent || evt;
6776                    target = target.touches[0];
6777                    //if (evt.originalEvent && evt.originalEvent.changedTouches && evt.originalEvent.changedTouches[0]) {
6778                    //    te = evt.originalEvent.changedTouches[0];
6779                    //}
6780                }
6781
6782                return target || evt;
6783            },
6784            getPointerEvent: function (eventType) {
6785                var event = null;
6786                if ((typeof PointerEvent) === "function") {
6787                    event = new PointerEvent(eventType, {
6788                        bubbles: true,
6789                        cancelable: true
6790                    });
6791                } else {
6792                    event = document.createEvent(EVENT_TYPE);
6793                    event.initEvent(eventType, true, true);
6794                }
6795                return event;
6796            },
6797            getTouches:function(evt){
6798                var touches = [];
6799                if(touchAvailable && evt.originalEvent && evt.originalEvent.touches ){
6800                    touches = evt.originalEvent.touches;
6801                }
6802                return touches;
6803            }
6804        };
6805    })();
6806})(xfalib);
6807(function ($, _) {
6808    $.widget("xfaWidget.abstractWidget", {
6809
6810        $userControl: null,
6811
6812        $data: xfalib.ut.XfaUtil.prototype.$data,
6813
6814        $css: xfalib.ut.XfaUtil.prototype.$css,
6815
6816        getOrElse: xfalib.ut.Class.prototype.getOrElse,
6817
6818        dIndexOf: xfalib.ut.XfaUtil.prototype.dIndexOf,
6819
6820        btwn: xfalib.ut.XfaUtil.prototype.btwn,
6821
6822        logger: xfalib.ut.XfaUtil.prototype.getLogger,
6823
6824        localeStrings: xfalib.ut.XfaUtil.prototype.getLocaleStrings,
6825
6826        logMsgs: xfalib.ut.XfaUtil.prototype.getLogMessages,
6827
6828        errorManager: xfalib.ut.XfaUtil.prototype.getErrorManager,
6829
6830        _widgetName: "abstractWidget",
6831
6832        // if there are any specific black listed attributes, each widget should define their own
6833        _blackListedAttributes : ["type"],
6834
6835        options: {
6836            name: "",
6837            value: null,
6838            commitProperty: "value",
6839            displayValue: null,
6840            screenReaderText: null,
6841            tabIndex: 0,
6842            role: null,
6843            paraStyles: null,
6844            dir: null,
6845            errorMessage: null,
6846            warningMessage: null,
6847            hScrollDisabled: false,
6848            placeholder:"",
6849            isValid:true,
6850            mandatory: false
6851        },
6852
6853        getOptionsMap: function () {
6854            return {
6855                "tabIndex": function (val) {
6856                    this.$userControl.attr("tabindex", val);
6857                },
6858                "role": function (val) {
6859                    if (val)
6860                        this.$userControl.attr("role", val);
6861                },
6862                "screenReaderText": function (val) {
6863                    if (val)
6864                        this.$userControl.attr("aria-label", val)
6865                },
6866                "paraStyles": function (val) {
6867                    if (val)
6868                        this.$css(this.$userControl.get(0), val);
6869                },
6870                "dir": function (val) {
6871                    if (val)
6872                        this.$userControl.attr("dir", this.options.dir);
6873                },
6874                "height": function (val) {
6875                    if (val) {
6876                        this.$css(this.$userControl[0], {"height": val})
6877                    }
6878                },
6879                "width": function (val) {
6880                    if (val)
6881                        this.$css(this.$userControl[0], {"width": val})
6882                },
6883                "isValid": function (val) {
6884                    if(val){
6885                      this.$userControl.removeAttr("aria-invalid");
6886                    } else {
6887                      this.$userControl.attr("aria-invalid",true);
6888                    }
6889                },
6890                "color" : function(value) {
6891                    if(!_.isEmpty(value)) {
6892                        var color = "rgb(" + value + ")";
6893                        this.$css(this.$userControl[0], {"color": color});
6894                    }
6895                },
6896                "font-style" : function (value) {
6897                    if (!_.isEmpty(value)) {
6898                        this.$css(this.$userControl[0], {"font-style": value});
6899                    }
6900                },
6901                "mandatory" : function (value) {
6902                    if(value){
6903                        this.$userControl.attr("aria-required", true);
6904                    } else {
6905                        this.$userControl.removeAttr("aria-required");
6906                    }
6907                }
6908            };
6909        },
6910
6911        getEventMap: function () {
6912            return {
6913                "focus": xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
6914                "blur": xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
6915                "click": xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT
6916            };
6917        },
6918
6919        /**
6920         * Copies all the attributes from source jquery object to destination jquery object
6921         * @param $src      source jquery object
6922         * @param $dest     destination jquery object
6923         */
6924        copyAttributesFromSrcToDest : function($src, $dest){
6925            var that = this;
6926            // let's get all the attribute from the src element and copy it to dest jquery object
6927            if($src != null && $src[0] && $src[0].attributes && $dest != null){
6928                $.each($src[0].attributes, function() {
6929                    // we don't add the black listed set of attributes
6930                    if(this.specified && this.value != null && _.isString(this.value) && this.value.length > 0 && that._blackListedAttributes.indexOf(this.name) === -1) {
6931                        $dest.attr(this.name, this.value);
6932                    }
6933                });
6934            }
6935        },
6936
6937        _create: function () {
6938            this.widgetEventPrefix = "";
6939            this.element.addClass(this._widgetName);
6940            this.$userControl = this.render();
6941            this.optionsHandler = this.getOptionsMap();
6942            this.eventMap = this.getEventMap();
6943            this._initializeOptions();
6944            this._initializeEventHandlers();
6945            this.errObj = this.errorManager();
6946            //call it only after render
6947            // Dirty hack to prevent this being called in Guide
6948            if (typeof guidelib === "undefined") {
6949                this.$css(this.$userControl.get(0), {
6950                    "box-sizing": "border-box",
6951                    "position": "absolute"
6952                });
6953            }
6954        },
6955
6956        _initializeEventHandlers: function () {
6957            xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "initialize event handlers for " + this._widgetName);
6958            _.each(this.eventMap, function (xfaevent, htmlevent) {
6959                var self = this;
6960                if (xfaevent) {
6961                    if (!(xfaevent instanceof  Array)) {
6962                        xfaevent = [xfaevent];
6963                    }
6964                    for (var i = 0; i < xfaevent.length; i++) {
6965                        xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "binding " + htmlevent + " with " + xfaevent[i]);
6966                        this.$userControl.on(htmlevent,
6967                            (function (xfevnt) {
6968                                return function (evnt) {
6969                                    xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "trigger " + evnt.type +
6970                                    " xfa-event " + xfevnt);
6971                                    self._preProcessEvent.apply(self, [xfevnt, evnt]);
6972                                    //since the fix https://github.com/jquery/jquery/pull/972, Fix for keeping namespace when triggering an event using an Event #972
6973                                    //we need to clear the namespace and its regular expression of triggering event, as the listeners are registered on un-namespaced events
6974                                    evnt.namespace = "";
6975                                    evnt.namespace_re = "";
6976                                    self._trigger(xfevnt, evnt);
6977                                    self._postProcessEvent.apply(self, [xfevnt, evnt]);
6978                                }
6979                            })(xfaevent[i])
6980                        )
6981
6982                    }
6983                }
6984            }, this)
6985        },
6986
6987        _preProcessEvent: function (xfaevent, htmlevent) {
6988            if (xfaevent == this.options.commitEvent) {
6989                this.preProcessCommit(htmlevent);
6990            }
6991            switch (xfaevent) {
6992                case xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT:
6993                    this.preProcessEnter(htmlevent);
6994                    break;
6995                case xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT:
6996                    this.preProcessExit(htmlevent);
6997                    break;
6998                case xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT:
6999                    this.preProcessChange(htmlevent);
7000                    break;
7001                case xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT:
7002                    this.preProcessClick(htmlevent);
7003                    break;
7004            }
7005
7006        },
7007
7008        _postProcessEvent: function (xfaevent, htmlevent) {
7009            if (xfaevent == this.options.commitEvent) {
7010                this.postProcessCommit(htmlevent);
7011            }
7012            switch (xfaevent) {
7013                case xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT:
7014                    this.postProcessEnter(htmlevent);
7015                    break;
7016                case xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT:
7017                    this.postProcessExit(htmlevent);
7018                    break;
7019                case xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT:
7020                    this.postProcessChange(htmlevent);
7021                    break;
7022                case xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT:
7023                    this.postProcessClick(htmlevent);
7024                    break;
7025            }
7026        },
7027
7028        _initializeOptions: function () {
7029            _.each(this.optionsHandler, function (value, key) {
7030                if (typeof value === "function")
7031                    value.apply(this, [this.options[key]]); // TODO: check whether it is needed for initialization or not
7032            }, this)
7033        },
7034
7035        _setOption: function (key, value) {
7036            if (this.options[key] != value) {
7037                this.options[ key ] = value;
7038                if (typeof this.optionsHandler[key] === "function") {
7039                    this.optionsHandler[key].apply(this, [this.options[key]])
7040                }
7041            }
7042        },
7043
7044        /**
7045         * @override
7046         */
7047        option: function (key, value) {
7048            if (arguments.length === 1 &&
7049                typeof key === "string" &&
7050                this.options.hasOwnProperty(key) &&
7051                this.options[key] === undefined) {
7052                return undefined;
7053            }
7054            return $.Widget.prototype.option.apply(this, arguments)
7055        },
7056
7057        destroy: function () {
7058            this.$userControl.removeClass(this._widgetName);
7059        },
7060
7061
7062        render: function () {
7063            var control;
7064            if (this.element.children().length > 0) {
7065                control = $(this.element.children().get(0));
7066            }
7067            else
7068                control = this.element;
7069            control.attr("name", this.options.name)
7070            return control;
7071        },
7072
7073
7074        preProcessCommit: function (evnt) {
7075            this.options.value = this.getCommitValue();
7076            xfalib.ut.XfaUtil.prototype.getLogger().debug("xfa", "passing commit value " + this.options.value +
7077            "to model ");
7078        },
7079
7080        getCommitValue: function () {
7081
7082        },
7083
7084        preProcessExit: function (evnt) {
7085
7086        },
7087
7088        preProcessEnter: function (evnt) {
7089            //Only focus the enabled widgets
7090            if (this.options.access === "open") {
7091                this._showError();
7092                this.showValue();
7093            }
7094        },
7095
7096        preProcessChange: function (evnt) {
7097
7098        },
7099
7100        preProcessClick: function (evnt) {
7101
7102        },
7103
7104        postProcessCommit: function (evnt) {
7105            this.showDisplayValue();
7106        },
7107
7108        postProcessExit: function (evnt) {
7109            //Only for the enabled widgets
7110            if (this.options.access === "open") {
7111                this.showDisplayValue();
7112                this._hideError();
7113            }
7114        },
7115
7116        postProcessEnter: function (evnt) {
7117        },
7118
7119        postProcessChange: function (evnt) {
7120
7121        },
7122
7123        postProcessClick: function (evnt) {
7124
7125        },
7126
7127        showDisplayValue: function () {
7128            this.$userControl.val(this.options.displayValue)
7129        },
7130
7131        /**
7132         * Checks if the edit value is same as value present in the user control(html form element)
7133         * @returns {boolean}
7134         */
7135        _isValueSame : function(){
7136            return (((this.options.value === null) && (this.$userControl.val() === "")) || (this.options.value === this.$userControl.val()));
7137        },
7138
7139        showValue: function () {
7140            // May be $userControl doesn't have val(), using it as of now
7141            // If the value of the field is not same as edit value, only then set the value, this also solves IE bug of cursor
7142            // moving to the end of field on click
7143            if(!this._isValueSame()) {
7144                this.$userControl.val(this.options.value)
7145            }
7146        },
7147
7148        focus: function () {
7149            var that = this;
7150            // setTimeout added to fix CQ-51141
7151            // While using setFocus API in adaptive form, the focus was not being set in TextBox on chrome
7152            // and also on click of caption of RadioButton/Checkbox, due to fast event execution, he
7152nce adding delay during focus.
7153            setTimeout(function(){
7154                that.$userControl[0].focus();
7155            }, 1);
7156        },
7157
7158        click: function () {
7159            this.focus();
7160            this.$userControl.triggerHandler("click"); // we do not want the exact click as might bubble up to the field.
7161        },
7162
7163        /* widget specific code */
7164
7165        _showError: function () {
7166            if(this.errObj && _.isFunction(this.errObj.onFieldEnter)) {
7167                this.errObj.onFieldEnter(this);
7168            }
7169        },
7170
7171        _calculatePaddingForVAlign:function(diff){
7172           var flagForMoz = $.browser.mozilla && !xfalib.ut.Utilities.isIE11() &&
7173                              this.options.multiLine,
7174               vAlignBottomOrTop = this.options.paraStyles &&
7175                                   (this.options.paraStyles["vertical-align"] == "bottom" ||
7176                                    this.options.paraStyles["vertical-align"] == "top");
7177
7178           if(flagForMoz && vAlignBottomOrTop || $.browser.msie && this.options.multiLine) {
7179              return;
7180           }
7181           // to handle the edge cases, if the diff is like -0.01 the whole operation is getting aborted
7182           // this diff comes mainly due to scroll height getting rounded off when widgetHeight is like x.999999
7183           diff = (diff > -0.01) ? Math.abs(diff) : diff;
7184           if (this.options.paraStyles && diff > 0) {
7185                var vAlign = this.options.paraStyles["vertical-align"];
7186                if (vAlign == "bottom") {
7187                    diff = diff - this.options.paraStyles["padding-bottom"];
7188                    this.$userControl.css("padding-top", diff);
7189                    this.padding = this.$userControl.css("padding-top");
7190                }
7191                else if (vAlign == "top" || (vAlign != "middle" && vAlign == undefined)) {
7192                    if (this.options.paraStyles["padding-top"])
7193                        diff = diff - this.options.paraStyles["padding-top"];
7194                    this.$userControl.css("padding-bottom", diff);
7195                    this.padding = this.$userControl.css("padding-bottom");
7196                }
7197                else if (this.options.multiLine && vAlign == "middle") {
7198                    var newDiff = diff / 2;
7199                    newDiff = newDiff - this.options.paraStyles["padding-bottom"];
7200                    if (this.options.paraStyles["padding-top"])
7201                        newDiff = newDiff + this.options.paraStyles["padding-top"];
7202                    this.$userControl.css("padding-top", newDiff);
7203                }
7204            }
7205        },
7206
7207        _handleVAlignOnExit: function (evnt) {
7208
7209            if (!this.options.paraStyles) {
7210                //vAlign has to be handled only if there is paraStyles
7211                return;
7212            }
7213            var value = this.options.displayValue,
7214                lineHeight = xfalib.view.util.TextMetrics.measureExtent(value, {refEl: this.$userControl.get(0), maxHeight: -1}).height,
7215                widgetHeight = this.options.height,
7216                diff = widgetHeight - lineHeight;
7217            this._calculatePaddingForVAlign(diff);
7218
7219        },
7220
7221        _handleVAlignOnEnter: function (evnt) {
7222            //Only align the enabled widgets
7223            var flagForIE = $.browser.msie && this.options.multiLine;
7224            if (this.options.paraStyles && !flagForIE) {
7225                 var vAlign = this.options.paraStyles["vertical-align"];
7226                 if (vAlign == "bottom" && this.padding)
7227                     this.$userControl.css("padding-top", this.padding);
7228                 else if (vAlign == "top" && this.padding)
7229                     this.$userControl.css("padding-bottom", this.padding);
7230            }
7231        },
7232
7233        _hideError: function () {
7234            if(this.errObj && _.isFunction(this.errObj.onFieldExit)) {
7235                this.errObj.onFieldExit(this);
7236            }
7237        },
7238
7239        markError: function (msg, type) {
7240            if(this.errObj && _.isFunction(this.errObj.markError)) {
7241                this.errObj.markError(this, msg, type);
7242            }
7243        },
7244
7245        clearError: function () {
7246            if(this.errObj && _.isFunction(this.errObj.clearError)) {
7247                this.errObj.clearError(this);
7248            }
7249        },
7250
7251        getEditValue: function(value) {
7252            if(this.options.editPattern == null) {
7253                return value;
7254            }
7255            try {
7256                return xfalib.ut.PictureFmt.format(value, this.options.editPattern);
7257            } catch(e) {
7258                return null;
7259            }
7260        },
7261
7262        parseEditValue: function(value) {
7263            if(this.options.editPattern == null) {
7264                return value;
7265            }
7266            try {
7267                return xfalib.ut.PictureFmt.parse(value, this.options.editPattern);
7268            } catch(e) {
7269                return value;
7270            }
7271        }
7272    });
7273})($, window._);
7274(function($) {
7275    $.widget( "xfaWidget.defaultWidget", $.xfaWidget.abstractWidget, {
7276
7277        _widgetName: "defaultWidget",
7278
7279        getOptionsMap: function() {
7280            var parentOptionsMap = $.xfaWidget.abstractWidget.prototype.getOptionsMap.apply(this,arguments);
7281            return $.extend({},parentOptionsMap,{
7282                "access": function(val) {
7283                    switch(val) {
7284                        case "open" :
7285                            this.$userControl.removeAttr("readOnly");
7286                            this.$userControl.removeAttr("aria-readonly");
7287                            this.$userControl.removeAttr("disabled");
7288                            this.$userControl.removeAttr("aria-disabled");
7289                            break;
7290                        case "nonInteractive" :
7291                        case "protected" :
7292                            this.$userControl.attr("disabled", "disabled");
7293                            this.$userControl.attr("aria-disabled", "true");
7294                            break;
7295                        case "readOnly" :
7296                            this.$userControl.attr("readOnly", "readOnly");
7297                            this.$userControl.attr("aria-readonly", "true");
7298                            break;
7299                        default  :
7300                            this.$userControl.removeAttr("disabled");
7301                            this.$userControl.removeAttr("aria-disabled");
7302                            break;
7303                    }
7304                },
7305
7306                "displayValue": function(val) {
7307                    if(this.options.commitProperty) {
7308                        if($.browser.mozilla && this.options.commitProperty == "value") {
7309                            // on submitting form firefox does not remember autocomplete values, if updated through attr()
7310                            this.$userControl.val(this._displayEmptyStringForIE(this.options.displayValue));
7311                        } else {
7312                            this.$userControl.prop(this.options.commitProperty, this._displayEmptyStringForIE(this.options.displayValue));
7313                            this.$userControl.attr(this.options.commitProperty, this._displayEmptyStringForIE(this.options.displayValue));
7314                        }
7315                    } else {
7316                        this.logger().debug("xfaView", "[DefaultWidget._update], User Control or Commit Property is null");
7317                    }
7318                },
7319
7320                "placeholder": function(value){
7321                    this.$userControl.attr("placeholder", value);
7322                }
7323            });
7324        },
7325
7326        _displayEmptyStringForIE: function(value){
7327            /*CQ-69417: By default "null" is displayed in the comments text box
7328              "null" values shown in IE */
7329            // CQ-69107 included check for edge as well
7330            return (value == null && xfalib.ut.XfaUtil.prototype.detectIE()) ? '' : value;
7331        },
7332
7333        render : function() {
7334            var control = $.xfaWidget.abstractWidget.prototype.render.apply(this,arguments)
7335            this._attachEventHandlers(control)
7336            return control
7337        },
7338
7339        getCommitValue: function() {
7340            var value = this.$userControl.val();
7341            if(this.options.hScrollDisabled && !this.options.multiLine)
7342                var value = xfalib.ut.XfaUtil.prototype.splitStringByWidth(this.$userControl.val(),this.$userControl.width(),this.$userControl.get(0)) ;
7343            return value;
7344        },
7345
7346        _attachEventHandlers: function($control) {
7347            $control.keydown($.proxy(this._handleKeyDown,this));
7348            $control.keypress($.proxy(this._handleKeyPress,this));
7349            $control.on('paste',$.proxy(this._handlePaste,this));
7350            $control.on('cut',$.proxy(this._handleCut,this));
7351        },
7352
7353        _compositionUpdateCallback : function (event) {
7354            return false;
7355        },
7356
7357        _attachCompositionEventHandlers : function($control) {
7358            var isComposing = false; // IME Composing going on
7359            var hasCompositionJustEnded = false; // Used to swallow keyup event related to compositionend
7360            // IME specific handling, to handle japanese languages max limit
7361            // since enter can also be invoked during composing, a special handling is done here
7362            var that = this,
7363                changeCaratPosition = function() {
7364                    // change the carat selection position to further limit input of characters
7365                    var range = window.getSelection();
7366                    range.selectAllChildren(that.$userControl[0]);
7367                    range.collapseToEnd();
7368                };
7369            $control.keyup(function(event) {
7370                if (/*isComposing || */hasCompositionJustEnded) {
7371                    if (that._compositionUpdateCallback(event)) {
7372                        changeCaratPosition();
7373                    }
7374                    // IME composing fires keydown/keyup events
7375                    hasCompositionJustEnded = false;
7376                }
7377            });
7378            $control.on("compositionstart",
7379                function(event) {
7380                    isComposing = true;
7381                })
7382                .on("compositionupdate",
7383                    function(event) {
7384                        // event.originalEvent.data refers to the actual content
7385                        if (that._compositionUpdateCallback(event)) {
7386                            changeCaratPosition();
7387                        }
7388                    })
7389                .on("compositionend",
7390                    function(event) {
7391                        isComposing = false;
7392                        // some browsers (IE, Firefox, Safari) send a keyup event after
7393                        //  compositionend, some (Chrome, Edge) don't. This is to swallow
7394                        // the next keyup event, unless a keydown event happens first
7395                        hasCompositionJustEnded = true;
7396                    })
7397                .on("keydown",
7398                    function(event) {
7399                        // Safari on OS X may send a keydown of 229 after compositionend
7400                        if (event.which !== 229) {
7401                            hasCompositionJustEnded = false;
7402                        }
7403                    });
7404        },
7405
7406        _handleKeyDown : function(event){
7407            if(event.keyCode == 13 || event.charCode == 13 || event.which == 13) // touch devices may return charCode
7408                event.preventDefault();
7409        },
7410
7411        _handleKeyPress : function(event){
7412            if(event.keyCode == 13 || event.charCode == 13 || event.which == 13) // touch devices may return charCode
7413                event.preventDefault();
7414        }
7415    });
7416})($);
7417(function($, _) {
7418    var xfaUtil = xfalib.ut.XfaUtil.prototype;
7419    $.widget( "xfaWidget.dateTimeEdit", $.xfaWidget.defaultWidget, {
7420
7421        _widgetName : "dateTimeEdit",
7422
7423        getEventMap: function() {
7424            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
7425            if(this._nativeWidget === false) {
7426                return $.extend({}, parentOptionsMap, {
7427                    "onfocus1.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
7428                    "onvaluechange.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
7429                    "onfocusout.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
7430                    "onoverlap.datetimepicker": xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT, // Custom Event to fix BUG #3626974
7431                    "input": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT, // TODO : add handler for xfa.event.change
7432                    "focus": null,
7433                    "blur": null
7434                })
7435            } else {
7436                return $.extend({}, parentOptionsMap, {
7437                    "change": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
7438                })
7439            }
7440        },
7441
7442        _getAdobeDatePickerOptionsMap : function(parentOptionsMap) {
7443            return {
7444                "access" : function (val) {
7445                    switch (val) {
7446                        case "open" :
7447                            this.$userControl.adobeDateTimePicker("access", true);
7448                            break;
7449                        case "nonInteractive" :
7450                        case "protected" :
7451                        case "readOnly" :
7452                            this.$userControl.adobeDateTimePicker("access", false);
7453                            break;
7454                    }
7455                    parentOptionsMap.access.apply(this, arguments);
7456                },
7457                "displayValue" : function (val) {
7458                    // set the value in the datepicker plugin
7459                    this.$userControl.adobeDateTimePicker("value", this.options.value);
7460                    // show the display value
7461                    this.showDisplayValue();
7462                }
7463            }
7464        },
7465
7466        _getNativeDatePickerOptionsMap: function (parentOptionsMap) {
7467            return {
7468                "displayValue": function (val) {
7469                    this.showDisplayValue();
7470                }
7471            }
7472        },
7473
7474
7475        getOptionsMap: function() {
7476            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments),
7477                datePickerOptions = this._nativeWidget === false ? this._getAdobeDatePickerOptionsMap(parentOptionsMap)
7478                    : this._getNativeDatePickerOptionsMap(parentOptionsMap),
7479                commonOptions = {
7480                    "paraStyles": function (paraStyles) {
7481                        parentOptionsMap.paraStyles.apply(this, arguments);
7482                        this._handleVAlignOnExit();
7483                    },
7484
7485                     "access": function(val) {
7486                        // update width on change of access (as width of widget is dependent on access)
7487                        // The calender icon should be hidden, and widget should take full space when readOnly
7488                        parentOptionsMap.access.apply(this, arguments);
7489                        this.getOptionsMap().width.apply(this,[this.options.width]);
7490                      },
7491                     "width": function (val) {
7492                        parentOptionsMap.width.apply(this, arguments);
7493                        if (this.options.showCalendarIcon && val && this.options.access == "open") {
7494                            var effectiveWidth = val > this.options.calendarIconWidth ? val - this.options.calendarIconWidth : val;
7495                            this.$userControl.width(effectiveWidth);  // leave space for the cal icon
7496                        }
7497                    },
7498
7499                    "height": function(val) {
7500                        parentOptionsMap.height.apply(this, arguments);
7501                        this._handleVAlignOnExit();
7502                    },
7503                    "screenReaderText": function (val) {
7504                        var editPattern = this.options.editPattern;
7505                        var defaultEditPattern = this._nativeWidget ? "mm/dd/yyyy" : "YYYY-MM-DD";
7506                        var regex = /(?:date){0,1}{(.*)}/;
7506 // date{<pattern>} or {<pattern>} both are valid as per xfa spec
7507                        editPattern = typeof editPattern === "string" ? editPattern.match(regex)[1] : defaultEditPattern;
7508                        var defaultLabel = "Please Enter date in {0} format only";
7509                        if (editPattern) {
7510                            var ariaLabel = xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("",
7511                                xfalib.locale.Strings.datePickerAriaLabel || defaultLabel, [editPattern])
7512                        }
7513                        var finalVal = val !== undefined ? val + " " + ariaLabel : val;
7514                        this.$userControl.attr("aria-label", finalVal);
7515                    }
7516                };
7517            return $.extend({},parentOptionsMap,datePickerOptions, commonOptions);
7518        },
7519
7520        postProcessExit: function(evnt) {
7521            $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
7522            this._handleVAlignOnExit ();
7523        },
7524
7525        preProcessEnter: function(evnt) {
7526            $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
7527            this._handleVAlignOnEnter();
7528        },
7529
7530        preProcessChange: function(evnt) {
7531           //CQ-46332:loss of date value in date-picker , setting the value here or else
7532           //it gets lost during focus
7533           if(this._nativeWidget === true){
7534            this.options.value = this.$userControl.val();
7535           }
7536        },
7537
7538        showDisplayValue: function() {
7539            if(this._nativeWidget === false) {
7540                $.xfaWidget.defaultWidget.prototype.showDisplayValue.apply(this, arguments);
7541            } else {
7542                this.showValue();
7543            }
7544        },
7545
7546
7547        showValue: function () {
7548            if (this._nativeWidget == false) {
7549                this.$userControl.adobeDateTimePicker("value", this.options.value);
7550            } else {
7551                $.xfaWidget.defaultWidget.prototype.showValue.apply(this, arguments);
7552            }
7553            $.xfaWidget.textField.prototype._selectOnFocusInIE.apply(this, arguments);
7554        },
7555
7556        getCommitValue: function() {
7557            if (this._nativeWidget === false) {
7558                var value = this.$userControl.adobeDateTimePicker("value"),
7559                    parsedValue = this.parseEditValue(value);
7560                return parsedValue;
7561            }
7562            return $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
7563        },
7564
7565        render: function() {
7566            var self = this,
7567                textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
7568                $control = $.xfaWidget.abstractWidget.prototype.render.apply(this, arguments),
7569                $source = $control,
7570                id,
7571                existingInlineStyleAttributeValues,
7572                newInlineStyleAttributeValues,
7573                combinedInlineStyleAttributeValues;
7574            existingInlineStyleAttributeValues = this.element.find("input").attr("style") || '';
7575            this._nativeWidget = true;
7576            if(this.options.useNativeWidget === false || $control[0].type !== "date") {
7577                this._nativeWidget = false;
7578                id = this.element.find("input")[0].id;
7579                this.element.children().remove();
7580                $("<div></div>").css({position: "relative", width: "100%", height: "100%"}) // want to fill entire width of containing table cell
7581                    .append($("<input type='text'/>"))
7582                    .appendTo(this.element);
7583                $control = $("input", this.element).
7584                    attr("style", textStyle).
7585                    attr("name", this.options.name).
7586                    attr("id", id).
7587                    adobeDateTimePicker({
7588                        positioning: this.element,
7589                        locale: {
7590                            months: this.options.months,
7591                            days: this.options.days,
7592                            zero: this.options.zero,
7593                            clearText: this.options.clearText
7594                        },
7595                        access: this.options.access,
7596                        value: this.options.value,
7597                        showCalendarIcon: this.options.showCalendarIcon,
7598                        iconWidth: this.options.calendarIconWidth,
7599                        minValidDate : this.options.minValidDate,
7600                        maxValidDate : this.options.maxValidDate,
7601                        exclMinDate :  this.options.exclMinDate,
7602                        exclMaxDate : this.options.exclMaxDate,
7603                        editValue: function (value) {
7604                            return self.getEditValue(value);
7605                        }
7606                    });
7607            }
7608            this._attachEventHandlers($control);
7609            newInlineStyleAttributeValues = this.element.find("input").attr("style") || '';
7610            //append the previous inlineStyleAttributeValues to newInlineStyleAttributeValues so that the inline styles
7611            //added from the dialog are applied.
7612            combinedInlineStyleAttributeValues = newInlineStyleAttributeValues + existingInlineStyleAttributeValues;
7613            this.element.find("input").attr("style", combinedInlineStyleAttributeValues);
7614            // only in case of adaptive form, we would copy the attributes back
7615            if(window.guideBridge) {
7616                // restore the original attribute back to destination object
7617                this.copyAttributesFromSrcToDest($source, this.element.find("input"));
7618            }
7619            return $control;
7620        }
7621    }) ;
7622
7623})($, _);
7624(function($, _) {
7625$.widget("xfaWidget.numericInput", $.xfaWidget.defaultWidget, {
7626
7627    _widgetName: "numericInput",
7628
7629	options : {
7630		value : null,
7631		curValue: null,
7632        pos: 0,
7633        lengthLimitVisible: true,
7634        zero:"0",
7635        decimal:".",
7636        minus:"-"
7637	},
7638
7639    //TODO: to support writing in different locales \d should be replaced by [0-9] for different locales
7640    _matchArray : {
7641                    "integer":"^[+-]?{digits}*$",
7642                    "decimal":"^[+-]?{digits}{leading}({decimal}{digits}{fraction})?$",
7643                    "float":"^[+-]?{digits}*({decimal}{digits}*)?$"
7644                  },
7645
7646    _regex : null,
7647
7648    _engRegex : null,
7649
7650    _writtenInLocale : false,
7651
7652    _previousCompositionVal : "",
7653
7654
7655    _toLatinForm : function (halfOrFullWidthStr) {
7656        // refer http://www.fileformat.info/info/unicode/block/halfwidth_and_fullwidth_forms/utf8test.htm
7657        return halfOrFullWidthStr.replace(
7658            /[\uff00-\uffef]/g,
7659            function(ch) { return String.fromCharCode(ch.charCodeAt(0) - 0xfee0); }
7660        );
7661    },
7662
7663    getOptionsMap: function() {
7664        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
7665        return $.extend({},parentOptionsMap,{
7666            "paraStyles": function(paraStyles){
7667                parentOptionsMap.paraStyles.apply(this,arguments);
7668                this._handleVAlignOnExit ();
7669            } ,
7670
7671            "height": function(val) {
7672                if(val)   {
7673                    this.$css(this.$userControl[0],{"height" :val});
7674                    this._handleVAlignOnExit();    // To Handle the case of expandable Fields
7675                }
7676            }
7677
7678        })
7679    },
7680
7681    getEventMap: function() {
7682        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
7683        return $.extend({},parentOptionsMap,{
7684            "onKeyInput.numericInput" : xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
7685        })
7686    },
7687
7688    _getDigits: function() {
7689        var zeroCode = this.options.zero.charCodeAt(0),
7690            digits = "";
7691        for(var i = 0;i < 10;i++) {
7692            digits += String.fromCharCode(zeroCode + i);
7693        }
7694        return "["+digits+"]"
7695    },
7696
7697    _escape: function(str) {
7698      return str.replace(".","\\.")
7699    },
7700
7701    postProcessExit: function(evnt) {
7702        $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
7703        this._handleVAlignOnExit ();
7704    },
7705
7706    preProcessEnter: function(evnt) {
7707        $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
7708        this._handleVAlignOnEnter();
7709    },
7710
7711	render : function() {
7712        var matchStr =  this._matchArray[this.options.dataType];
7713        if(matchStr) {
7714            var ld = this.options.leadDigits,
7715                fd = this.options.fracDigits,
7716                ldstr = ld && ld != -1 ? "{0,"+ld+"}"
7717                    : "*",
7718                fdstr = fd && fd != -1 ? "{0,"+fd+"}"
7719                    : "*",
7720                matchStr =  matchStr.replace("{leading}",ldstr)
7721                                    .replace("{fraction}",fdstr),
7722                localeStr = matchStr.replace(/{digits}/g,this._getDigits())
7723                                    .replace("{decimal}",this._escape(this.options.decimal)),
7724                engStr = matchStr.replace(/{digits}/g,"[0-9]")
7725                                .replace("{decimal}","\\.")
7726            this._processValue = !(this._getDigits() == "[0123456789]" && this.options.decimal == ".")
7727            this._regex = new RegExp(localeStr, "g");
7728            this._engRegex = new RegExp(engStr, "g");
7729        }
7730        return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
7731    },
7732
7733    getCommitValue: function() {
7734        var value = $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
7735        // we support full width, half width and locale specific numbers
7736        value = this._toLatinForm(value);
7737        if(value.length > 0 && this._processValue && !value.match(this._engRegex)) {
7738            this._writtenInLocale = true;
7739            value = this._convertValueFromLocale(value);
7740        } else {
7741            this._writtenInLocale = false
7742        }
7743        if(value && value.length >= this.options.combCells )
7744            value = value.slice(0,this.options.combCells);
7745        this._previousCompositionVal = value;
7746        return value;
7747    },
7748
7749    _compositionUpdateCallback : function (event) {
7750        var that = this;
7751        var flag = false;
7752        var leadDigits = that.options.leadDigits;
7753        var fracDigits = that.options.fracDigits;
7754        // we don't check use-case where just fracDigits is set since in case of composition update, the value to update is not known
7755        if (leadDigits !== -1) {
7756            var val = that.$userControl.val();
7757            if (event.type === "compositionupdate" && event.originalEvent.data) {
7758                val = val + event.originalEvent.data.substr(event.originalEvent.data.length - 1);
7759            }
7760            // can't use the existing regex (since current regex checks for english digits), rather doing leadDigit compare
7761            var totalLength = leadDigits + (fracDigits !== -1 ? (fracDigits + that.options.decimal.length) : 0);
7762            if (val.indexOf(that.options.decimal) === -1) {
7763                totalLength = leadDigits;
7764            }
7765            var latinVal = this._toLatinForm(val);
7766            // match both since we support full width, half width and locale specific input
7767            var match = latinVal.match(that._regex)|| latinVal.match(this._engRegex);
7768            flag  = !match;
7769            if (match === null) {
7770                // entered invalid character, revert to previous value
7771                that.$userControl.val(that._previousCompositionVal);
7772                flag = true;
7773            } else if (flag) {
7774                // if max reached
7775                var newVal = val.substr(0, totalLength);
7776                that.$userControl.val(newVal);
7777                that._previousCompositionVal = newVal;
7778                flag = true;
7779            } else {
7780                that._previousCompositionVal = val;
7781            }
7782        }
7783        return flag;
7784    },
7785
7786    _attachEventHandlers : function($control) {
7787        $.xfaWidget.defaultWidget.prototype._attachEventHandlers.apply(this, arguments);
7788        // IME specific handling, to handle japanese languages max limit
7789        $.xfaWidget.defaultWidget.prototype._attachCompositionEventHandlers.apply(this, arguments);
7790	},
7791
7792    _handleKeyInput : function(event, character, code){
7793        if(event.ctrlKey && !_.contains(['paste', 'cut'], event.type)) {
7794            return true;
7795        }
7796
7797        $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this,arguments);
7798        this.options.lengthLimitVisible = true;
7799
7800        var val = this.$userControl.prop(this.options.commitProperty) || '',
7801            // if selectionStart attribute isn't supported then its value will be undefined
7802            selectionStart = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionStart"),
7803            isSelectionAttrSupported = !(selectionStart === undefined || selectionStart === null),
7804            selectionStart = selectionStart || 0,
7805            selectionEnd = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionEnd") || 0,
7806            combCells = parseInt(this.options.combCells) || 0,
7807            current,
7808            change = character;
7809
7810        if (combCells > 0 ) {
7811            change = character.substr(0, combCells - val.length + selectionEnd - selectionStart);
7812        }
7813
7814        current = val.substr(0, selectionStart) + change + val.substr(selectionEnd);
7815        // done to handle support for both full width, half width or mixed input in number field
7816        var latinCurrentValue = this._toLatinForm(current);
7817
7818        // we want to check regex first and then see whether it was numeric or not.
7819        if (!(this._regex == null || latinCurrentValue.match(this._regex) || latinCurrentValue.match(this._engRegex))) {
7820            event.preventDefault();
7821            return false;
7822        }
7823
7824        // CQ-4245407 : selectionStart and selectionEnd attributes aren't supported in case of input type = number
7825        // it is used for providing native HTML5 implementation for numeric field, so no further processing is required
7826        // As it is specific to AF and AF doesn't support change event on each keypress, so this change should be fine
7827        if (!isSelectionAttrSupported) {
7828            return true;
7829        }
7830
7831        if (!_.contains(['keydown', 'cut'], event.type) && combCells && (val.length >= combCells || current.length > combCells) && selectionStart === selectionEnd) {
7832            event.preventDefault();
7833            return false;
7834        }
7835
7836        this.options.curValue = val;
7837        this._previousCompositionVal = val;
7838        this.options.pos = selectionStart;
7839
7840        if(this.options.hScrollDisabled && !_.contains(['keydown', 'cut'], event.type)) {
7841            var expectedWidth = xfalib.view.util.TextMetrics.measureExtent(current, {refEl: this.$userControl[0], maxWidth:-1}).width;
7842            if(!event.ctrlKey && expectedWidth > this.$userControl.width() - 5){
7843                event.preventDefault();
7844                this.options.lengthLimitVisible = false;
7845            }
7846        }
7847
7848        this.$userControl.trigger({
7849            type : "onKeyInput.numericInput",
7850            originalType : event.type,
7851            character : character,  // contains the pasted string or pressed key
7852            keyCode : event.keyCode || 0,
7853            charCode : event.charCode || 0,
7854            which : event.which || 0,
7855            ctrlKey : event.ctrlKey || event.metaKey || false,
7856            shiftKey : event.shiftKey || false,
7857            keyDown : false, // This property is available only for list boxes and drop-down lists
7858            selectionStart: selectionStart,
7859            selectionEnd: selectionEnd
7860        });
7861    },
7862
7863    _handleKeyDown : function(event){
7864        if (event) {
7865            var code = event.charCode || event.which || event.keyCode || 0;
7866            if(code == 8 || code == 46) // backspace and del
7867               this._handleKeyInput(event, "", code);
7868            else if(code == 32) { // suppress space
7869                event.preventDefault();
7870                return false;
7871            }
7872        }
7873    },
7874
7875    _isValidChar: function (character) {
7876        character = this._toLatinForm(character);
7877        var lastSingleDigitChar = String.fromCharCode(this.options.zero.charCodeAt(0) + 9);
7878        // we only full width, half width and also locale specific if customer has overlayed the i18n file
7879        return (character >= "0" && character <= "9") || (character>=this.options.zero && character<=lastSingleDigitChar) || character===this.options.decimal || character===this.options.minus;
7880    },
7881
7882    _handleKeyPress : function(event){
7883        if (event) {
7884            var code = event.charCode || event.which || event.keyCode || 0,
7885                character = String.fromCharCode(code);
7886
7887            if(xfalib.ut.XfaUtil.prototype.isNonPrintableKey(event.key)) { // mozilla also generates a keypress, along with keydown
7888                return true;                                               // for all keys, so only handling printable keys in keypress
7889            }
7890
7891            if (this._isValidChar(character))
7892                this._handleKeyInput(event, character, code);
7893            else if (!event.ctrlKey){
7894                event.preventDefault();
7895                return false;
7896            }
7897        }
7898    },
7899
7900    _handlePaste : function(event){
7901        if (event) {
7902            var pastedChar = undefined;
7903            if (window.clipboardData && window.clipboardData.getData) { // IE
7904                pastedChar = window.clipboardData.getData('Text');
7905            } else if (event.originalEvent.clipboardData && event.originalEvent.clipboardData.getData) {
7906                pastedChar = event.originalEvent.clipboardData.getData('text/plain');
7907            }
7908
7909            if(pastedChar) {
7910                var allPastedCharsValid = _.every(pastedChar.split(''), function (character) {
7911                    return this._isValidChar(character);
7912                }, this);
7913                if (allPastedCharsValid) {
7914                    // during paste we support both half width, full width and locale specific numbers
7915                    pastedChar = this._toLatinForm(pastedChar);
7916                    this._handleKeyInput(event, pastedChar, 0);
7917                }
7918                else if (!event.ctrlKey) {
7919                    event.preventDefault();
7920                    return false;
7921                }
7922            }
7923        }
7924    },
7925
7926    _handleCut : function(event) {
7927        if (event) {
7928            this._handleKeyInput(event, "", 0);
7929        }
7930    },
7931    // CQ-107886 : added handling for negative values, as for '-', '-3' was getting returned
7932    _convertValueToLocale: function(val) {
7933        var zeroCode = this.options.zero.charCodeAt(0);
7934        return  _.map(val,function(c) {
7935            if(c == ".") {
7936                return this.options.decimal;
7937            } else if(c == "-") {
7938                return this.options.minus;
7939            } else {
7940                return String.fromCharCode(parseInt(c) + zeroCode);
7941            }
7942        },this).join("");
7943    },
7944
7945    _convertValueFromLocale: function(val) {
7946        val = this._toLatinForm(val);
7947        var zeroCode = this.options.zero.charCodeAt(0);
7948        return  _.map(val,function(c) {
7949            if(c == this.options.decimal) {
7950                return ".";
7951            } else if(c == this.options.minus) {
7952                return "-";
7953            } else {
7954                return (c.charCodeAt(0) - zeroCode).toString();
7955            }
7956        },this).join("");
7957    },
7958
7959    showValue : function() {
7960       // if the value is same, don't do anything
7961       if(!this._isValueSame()){
7962           if(this.options.value && this._writtenInLocale) {
7963               this.$userControl.val(this._convertValueToLocale(this.options.value))
7964           } else {
7965               this.$userControl.val(this.options.value)
7966           }
7967       }
7968       //IE doesn't show selected text if we focus and set its value all the time so force selection
7969       $.xfaWidget.textField.prototype._selectOnFocusInIE.apply(this, arguments);
7970    }
7971});
7972})($, window._);(function ($, _) {
7973    $.widget("xfaWidget.dropDownList", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
7974
7975        _widgetName: "dropDownList",
7976
7977        options: {
7978            value: [],
7979            items: [],
7980            editable: false,
7981            placeholder: "",
7982            displayValue: []
7983        },
7984
7985        widgetSkeleton: '<select name="" style="" size = "1"></select>',
7986        optionSkeleton: '<option data-user-option></option>',
7987        optGroupSkeleton: '<optgroup label=""></optgroup>',
7988        AF_OPTGROUP_NAME: "afOptGroupName",
7989        PLACE_HOLDER_STYLE_CLASS : "placeHolder",
7990
7991        getOptionsMap: function () {
7992            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
7993            return $.extend({}, parentOptionsMap, {
7994                "value": function (val) {
7995                    if (!_.isArray(val)) {
7996                        val = [val];
7997                    }
7998                    var selectedOptionFound = false,
7999                        that = this;
8000                    //sync option selection as per new values
8001                    $("option", this.$userControl).each(function (index) {
8002                        var selectValue = $(this).val();
8003                        //Check if this value is present in options value array
8004                        if (_.contains(val, selectValue)) {
8005                            $(this).prop("selected", true);
8006                            selectedOptionFound = true;
8007                        } else {
8008                            $(this).prop("selected", false);
8009                            if (this.id === "emptyValue") {
8010                                $(this).val("").html(that.options.placeholder);
8011                                //Hiding emptyValue with no placeholder text configured.
8012                                if(that.options.placeholder.length == 0) {
8013                                    $(this).hide();
8014                                }
8015                            }
8016                        }
8017                    });
8018
8019                    /* Add default option if :
8020                    / 1. If placeholder add an extra option
8021                    / 2. If the value is set anything other than the options (and null/"") create a new option
8022                     */
8023                    if ((!selectedOptionFound && val.length != 0 && val[0] != null) || that.options.placeholder.length != 0) {
8024                        if (this.$userControl.children('[data-empty-option]').length == 0) {
8025                            var extraOption = document.createElement("option");
8026                            extraOption.setAttribute("data-empty-option", "");
8027                            extraOption.setAttribute("role", "none");
8028                            extraOption.setAttribute("value", "")
8029                            this.$userControl[0].insertBefore(extraOption, this.$userControl[0].firstChild);
8030                        }
8031                        // If placeholder is present the set value of empty option to placeholder
8032                        if (that.options.placeholder.length != 0) {
8033                            this.$userControl.children('[data-empty-option]').text(that.options.placeholder);
8034                        }
8035                        // If placeholder is present and value is not present then select placeholder
8036                        if (val.length == 0 || val[0] == null) {
8037                            this.$userControl.children('[data-empty-option]').prop("selected", true);
8038                        } // If value is set anything other than option then set empty option to value
8039                        else if (!selectedOptionFound && val.length != 0 && val[0] != null) {
8040                            this.$userControl.children('[data-empty-option]').text(val[0]).
8041                            prop("selected", true).
8042                            val(_.escape(val[0])).
8043                            show();
8044                        }
8045
8046                    }
8047                    else if (that.options.placeholder.length == 0) {
8048                        // Delete default option if value is found in options while adding options
8049                        if (selectedOptionFound && this.$userControl.children('[data-empty-option]').val() != that.options.displayValue) {
8050                            if (this.$userControl.children('[data-empty-option]').length > 0) {
8051                                this.$userControl[0].removeChild(this.$userControl.children('[data-empty-option]')[0]);
8052                            }
8053                        }
8054                        // Reset the value of dropdown based on rule
8055                        else if (!selectedOptionFound && (val.length == 0 || val == null || val[0] == null)) {
8056                            this.$userControl[0].value = "";
8057                        }
8058                    }
8059                    this.$userControl.toggleClass(this.PLACE_HOLDER_STYLE_CLASS, val.length == 0 || val == null);
8060                },
8061
8062                "items": function (val) {
8063                    if (!_.isArray(val)) {
8064                        val = [val];
8065                    }
8066
8067                    var AF_OPTGROUP_NAME = "afOptGroupName";
8068                    var i, j, optgroupOptions = [], element, $viewOptgroup, $preOptgroup;
8069                    var viewOptgroups = $("optgroup", this.$userControl);
8070                    // Removes all options which earlier didn't belong to any optgroup.
8071                    if (viewOptgroups.length == 0) {
8072                        // save selected value because when value is set before items in setWidgetOptions
8073                        // the selected value would get lost in html
8074                        var selectedOption = this.$userControl.find('[selected]');
8075                        this.$userControl.children("option[data-user-option]").remove();
8076                    }
8077                    for (i = 0, j = 0; j < val.length; j++) {
8078                        element = val[j];
8079                        if (element.save != AF_OPTGROUP_NAME) {
8080                            // Add options to String[] which will be later synced to the optgroup.
8081                            optgroupOptions.push(element);
8082                        } else {
8083                            $viewOptgroup = viewOptgroups[i++];
8084                            // When optgroup is less than the required optgroups.
8085                            if (i > viewOptgroups.length) {
8086                                $viewOptgroup = this.addGroup(element.display);
8087                            }
8088                            // Undefined as it may not occur even once when list is purely of options.
8089                            if (!_.isUndefined($viewOptgroup) && $viewOptgroup.label != element.display) {
8090                                $viewOptgroup.label = element.display || '';
8091                            }
8092                            // Check to skip the first optgroup.
8093                            if (j != 0) {
8094                                // Syncs options to the prev optgroup.
8095                                // Prev optgroup because current optgroup marks the end of options of prev.
8096                                this.handleOptions($preOptgroup, optgroupOptions);
8097                                // Clear options of the optgroup for next optgroup.
8098                                optgroupOptions = [];
8099                            }
8100                            $preOptgroup = $viewOptgroup;
8101                        }
8102                    }
8103                    // Removes all extra optgroups.
8104                    while (i < viewOptgroups.length) {
8105                        $viewOptgroup = viewOptgroups[i++];
8106                        this.deleteGroup($viewOptgroup.label);
8107                    }
8108                    //Add remaining options to respective optgroup.
8109                    if (optgroupOptions.length != 0) {
8110                        this.handleOptions($preOptgroup, optgroupOptions, selectedOption);
8111                    }
8112
8113                    //Intentionally left the selection check -> I am relying on the fact that "value" sync event is called after "items" sync.
8114                },
8115
8116                "displayValue": function () {
8117                },
8118                "placeholder": function(value){
8119                    // overriding the default handling of place holder options setter
8120                },
8121                "access": function (val) {
8122                    switch (val) {
8123                        case "open" :
8124                            this.$userControl.removeAttr("disabled");
8125                            this.$userControl.removeAttr("aria-disabled");
8126                            break;
8127                        case "nonInteractive" :
8128                        case "protected" :
8129                        case "readOnly" :
8130                            this.$userControl.attr("disabled", "disabled");
8131                            this.$userControl.attr("aria-disabled", "true");
8132                            break;
8133                        default  :
8134                            this.$userControl.removeAttr("disabled");
8135                            this.$userControl.removeAttr("aria-disabled");
8136                            break;
8137                    }
8138                }
8139            })
8140        },
8141
8142        getEventMap: function () {
8143            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
8144            return $.extend({}, parentOptionsMap, {
8145                "focus": [xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT, xfalib.ut.XfaUtil.prototype.XFA_PREOPEN_EVENT],
8146                "change": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
8147            })
8148        },
8149
8150        render: function () {
8151            var existingInlineStyleAttributeValues = this.element.find("select").attr("style"),
8152                newInlineStyleAttributeValues,
8153                combinedInlineStyleAttributeValues,
8154                size = 1;
8155
8156            this.element.addClass(this._widgetName);
8157            this.element.children().remove();
8158
8159            var inputName = _.uniqueId("select"),  //Unique Id
8160                textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
8161                $widgetSkeleton = $(this.widgetSkeleton)
8162                                    .attr('style', textStyle)
8163                                    .attr('name', inputName);
8164            if(this.options.editable) {
8165                $widgetSkeleton.addClass('combobox');
8166            }
8167
8168            if(this.options.items && this.options.items.length>0){
8169                size = this.options.items.length
8170            }
8171            if(this.options.multiSelect) {
8172                $widgetSkeleton.addClass('multiDropdown');
8173         
8173       $widgetSkeleton.attr('multiple','multiple');
8174                $widgetSkeleton.attr('size',size);
8175                $widgetSkeleton.attr('data-multiple-selection',"true");
8176            }
8177
8178            var $parEl = $widgetSkeleton;
8179            _.each(this.options.items, function(item){
8180                var saveItem = _.isString(item.save) ? item.save.replace(/\"/g, "&quot;") : "";
8181                if (saveItem === this.AF_OPTGROUP_NAME){ // assuming optgroups appear before options
8182                    $parEl = $(this.optGroupSkeleton).attr('label', item.display).appendTo($widgetSkeleton);
8183                } else {
8184                    $(this.optionSkeleton).val(saveItem).text(item.display).appendTo($parEl);
8185                }
8186            },this);
8187
8188            this.element.append($widgetSkeleton);
8189
8190            var control = this.element.children().eq(0).attr("name", this.options.name);
8191            this._attachEventHandlers(control);
8192            newInlineStyleAttributeValues = this.element.find("select").attr("style");
8193            //append the previous inlineStyleAttributeValues to newInlineStyleAttributeValues so that the inline styles
8194            //added from the dialog are applied.
8195            combinedInlineStyleAttributeValues = newInlineStyleAttributeValues + existingInlineStyleAttributeValues;
8196            this.element.find("select").attr("style", combinedInlineStyleAttributeValues);
8197            return control;
8198        },
8199
8200        //syncs the options to the optgroup dynamically.
8201        handleOptions : function ($viewOptgroup, val, selectedOption) {
8202            //When the list so far consists purely of options.
8203            if (_.isUndefined($viewOptgroup)) {
8204                $viewOptgroup = this.$userControl[0];
8205            }
8206            var viewOptions = $("option[data-user-option]", $viewOptgroup);
8207            //Syncs the value of options.
8208            for (var i = 0, j = 0; i < viewOptions.length && j < val.length; i++, j++) {
8209                var $viewOption = viewOptions[i];
8210                var element = val[j];
8211                if ($viewOption.text != element.display) {
8212                    $viewOption.text = element.display || '';
8213                }
8214                if ($viewOption.value != element.save) {
8215                    $viewOption.value = element.save || '';
8216                }
8217            }
8218            //Deletes options if count is more than required.
8219            while (i < viewOptions.length) {
8220                this.deleteOption(viewOptions[i++])
8221            }
8222            //Add options if count is less than required.
8223            while (j < val.length) {
8224                this.addOption($viewOptgroup, val[j++], selectedOption);
8225            }
8226            // Set empty value to dropdown if placeholder and default value is not present
8227            if (this.options.placeholder.length == 0) {
8228            	if (this.checkForEmptyValue(this.options.value)) {
8229            		this.$userControl[0].value = "";
8230            	}
8231            }
8232        },
8233
8234        addOption : function ($viewOptgroup, element, selectedOption) {
8235            var $newOption = $(this.optionSkeleton).val(element.save).text(element.display);
8236            $newOption.appendTo($viewOptgroup);
8237            if(selectedOption) {
8238                if(element.save === selectedOption.val() && element.display === selectedOption.text()) {
8239                    $newOption.prop("selected", true);
8240                }
8241            }
8242            // Since the displayValue is a '\n' separated string of selected values in case of multiSelect,
8243            // we convert it to an array and check whether that array contains the save value of the element
8244            var values;
8245            if (this.options.value && _.isString(this.options.value)) {
8246                values = this.options.value.split('\n');
8247            } else if (_.isArray(this.options.value)) {
8248                // In the case of AF we have value/displayValue as an array
8249                values = this.options.value
8250            }
8251            if (values && values.indexOf(element.save) >= 0) {
8252                //Delete emptyValue with no placeholder text configured and value is found in options
8253                if (this.options.placeholder.length == 0 && this.$userControl.children('[data-empty-option]').length > 0) {
8254                    this.$userControl[0].removeChild(this.$userControl.children('[data-empty-option]')[0]);
8255                }
8256                this.$userControl.children().filter(function() {
8257                    return this.value == element.save;
8258                }).prop("selected", true);
8259            }
8260        },
8261
8262        deleteOption: function ($viewOption) {
8263            this.$userControl.find('option[value='+$viewOption.value+']').remove();
8264        },
8265
8266        checkForEmptyValue: function(value) {
8267            if ((value && _.isArray(value) && value[0] == null) || (this.options.value == null))
8268                return true;
8269            else
8270                return false;
8271        },
8272
8273        addGroup: function(label) {
8274            //Creates a optgroup Node.
8275            var optionGroup = document.createElement("OPTGROUP");
8276            optionGroup.label = label;
8277            this.$userControl[0].appendChild(optionGroup);
8278            return optionGroup;
8279        },
8280
8281        deleteGroup: function(label) {
8282            this.$userControl.children().remove('optgroup[label='+label+']');
8283        },
8284
8285        addItem: function(itemValues) {
8286            var newOption = new Option(itemValues.sDisplayVal || '', itemValues.sSaveVal || ''),
8287                val = this.options.value;
8288
8289            this.$userControl[0].add(newOption, null);
8290
8291            // if item has same value as present in options then mark it as selected
8292            if (_.contains(val, itemValues.sSaveVal)) {
8293                this.$userControl.find("option[value=" + itemValues.sSaveVal + "]").prop("selected", true);
8294                var emptyValue = this.$userControl.children('[data-empty-option]');
8295                if (emptyValue.length > 0 && emptyValue.val() === itemValues.sSaveVal) {
8296                    this.$userControl[0].removeChild(emptyValue[0]);
8297                }
8298            } else if ((val == null || val.length == 0 || val[0] == null) && this.options.placeholder.length == 0) {
8299                // Value should remain empty if option is not already selected & placeholder is empty
8300                this.$userControl[0].value = "";
8301            }
8302        },
8303
8304        clearItems: function () {
8305            //Deleting all the options including optGroup except the empty value.
8306            this.$userControl.children().not('[data-empty-option]').remove();
8307        },
8308
8309        deleteItem: function (nIndex) {
8310            //check for emptyValue instead of blindly doing + 1
8311            if (this.$userControl[0].item(0) && this.$userControl[0].item(0).id == "emptyValue")
8312                nIndex = nIndex + 1;
8313            //if there is emptyValue element then just delete one index higher
8314            //this check is must instead of blindly increasing the index by 1 because NWKListBox extends this class and that doesn't maintain emptyValue
8315            this.$userControl[0].remove(nIndex);
8316        },
8317
8318        getCommitValue: function (event) {
8319            var value = $("option:selected", this.$userControl).map(function () {
8320                return $(this).val();
8321            }).get();
8322            return value;
8323        },
8324
8325        showDisplayValue: function () {
8326        },
8327
8328        destroy: function () {
8329            this.element.
8330                removeClass(this._widgetName).
8331                children().remove().
8332                text("");
8333
8334            // call the base destroy function
8335            $.xfaWidget.defaultWidget.prototype.destroy.apply(this, arguments);
8336        },
8337
8338        _handleKeyDown: function (event) {
8339
8340            if (event.keyCode == 13) {
8341                //do nothing
8342                //just override the return key behaviour and over to defaultWidget for rest of the stuff.
8343                //return key is intercepted to avoid submission of form which is default behavior of html form element
8344                //but as a side effect it also stops the closing of drop down only in IE -> probably I should use IE condition but
8345                // this code works fine in          chrome as well so keeping it that way.
8346                //watson bug#3675141
8347            }
8348            else
8349                $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this, arguments);
8350        },
8351
8352        // CQ-51462 : focus and commit event (change) happen together hence first selection was modifying the value
8353        // we do not want focus to modify the value that is about to be committed
8354        showValue : function() {
8355
8356        }
8357    });
8358})($, _);
8359(function($, _){
8360	$.widget( "xfaWidget.listBox", $.xfaWidget.defaultWidget, {
8361
8362    _widgetName: "listBoxWidget",
8363
8364    options : {
8365        value : [],
8366        items : [],
8367        multiSelect : false
8368    },
8369
8370    getOptionsMap: function() {
8371        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
8372        return $.extend({},parentOptionsMap,{
8373            "width" : function(val) {
8374                //Bug#3597771. setting the height more than 0.95 brings scrollbar
8375                this.options.width = val*0.95
8376                parentOptionsMap.width.apply(this,[this.options.width])
8377            },
8378            "access" : function() {},
8379            "value": function(val) {
8380                var newValues = this.options.value,
8381                    self = this,
8382                    tabSet = false;
8383                if(!_.isArray(newValues))
8384                    newValues = [newValues];
8385                var tabSet
8386                this.$userControl.children().each(function(){
8387                    var saveVal = $(this).attr("data-save");
8388
8389                    // Check if this value is present in options value array
8390                    if(newValues && _.contains(newValues, saveVal)){
8391                        self._selectListItem($(this));
8392                        tabSet = true;
8393
8394                        // Set the selected data attribute to true.
8395                        if (!$.data(this, "_xfaInitialized")) {
8396                            //Initialized data- attributes parse for once using this call.
8397                            // Next onward don't use this. Instead use $.data which is cheap/
8398                            $(this).data();
8399                            $.data(this, "_xfaInitialized", true); //Mark the element to say that data has been initialized.
8400                        }
8401                        $.data(this, "selected", true);
8402
8403                    }
8404                    else{
8405                        $(this).removeClass("item-selected");
8406                        $(this).addClass("item-selectable");
8407                        $(this).attr("tabIndex", "-1");
8408                    }
8409                });
8410                if(!tabSet) {
8411                    $(this.$userControl.children().get(0)).attr("tabIndex", this.options.tabIndex);
8412                }
8413            },
8414
8415            "items" : function(val) {
8416                if(!_.isArray(val))
8417                    val = [val];
8418                var viewItems = this.$userControl.children();
8419
8420                //if number of items are not same in model and view then balance it
8421                if((viewItems.length) > val.length){
8422                    for(var i=viewItems.length; i >  val.length; i--){
8423                        this.deleteItem(i-1);
8424                    }
8425                }
8426                else if((viewItems.length) < val.length){
8427                    for(var i=viewItems.length; i < (val.length); i++){
8428                        this.addItem({sDisplayVal: val[i].display, sSaveVal: val[i].save});
8429                    }
8430                }
8431
8432                _.each(val, function(element, index){
8433                    var $viewItem = $(viewItems[index]);
8434                    if( $viewItem.text() != element.display){
8435                        $viewItem.text(element.display || '');
8436                    }
8437
8438                    if( $viewItem.attr("data-save") != element.save){
8439                        $viewItem.attr("data-save", element.save || '');
8440                    }
8441                });
8442
8443                //Intentionally left the selection check -> I am relying on the fact that "value" sync event is called after "items" sync.
8444            },
8445
8446            "displayValue" : function(){;},
8447
8448            "tabIndex": function() {
8449                var selectedItem = this.$userControl.children(".item-selected"),
8450                    children =this.$userControl.children()
8451                if(selectedItem.length) {
8452                    selectedItem.eq(0).attr("tabIndex", this.options.tabIndex);
8453                }
8454                else if(children.length > 0) {
8455                    children.eq(0).attr("tabIndex", this.options.tabIndex);
8456                }
8457            }
8458        })
8459    },
8460
8461    getEventMap: function() {
8462        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
8463        return $.extend({},parentOptionsMap,{
8464            "listboxenter":xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
8465            "listboxexit":xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT,
8466            "listboxchange":xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
8467            "focus":null,
8468            "blur":null
8469        })
8470    },
8471
8472    showDisplayValue : function() {
8473        },
8474
8475    render : function() {
8476        this.element.addClass( this._widgetName);
8477        this.element.children().remove();
8478
8479        //TODO: add a function for geting textStyle
8480        var textStyle = this.getOrElse(this.$data(this.element.get(0), "xfamodel"), "textstyle", ""),
8481            that = this,
8482            //Bug#3597771 width and height are provided by the view itself.
8483            listElTemplate =
8484            '<ol style="position:absolute;<%=textStyle%>" role="listbox">' +
8485                '<% _.each(items, function(item){ %>' +
8486                '<% var saveItem = item.save ? item.save.replace(/\"/g,"&quot;"):null %>'+
8487                    '<li role="option" data-save="<% print(saveItem) %>" data-selected="false"><% print(item.display) %></li>'+
8488                '<%})%>'+
8489            '</ol>',
8490            compiledListElTemplate = _.template(listElTemplate),
8491            templateOptions = _.extend({
8492                "textStyle" : textStyle
8493                }, this.options),
8494            resolvedListEl = compiledListElTemplate(templateOptions);
8495        that.element.html(xfalib.ut.XfaUtil.prototype.encodeScriptableTags(resolvedListEl));
8496        var control = $(that.element.children().get(0)).attr("name",this.options.name);
8497        this._attachEventHandlers(control);
8498        return control
8499    },
8500
8501    focus: function() {
8502        if(this.$userControl.children(".item-selected").length > 0) {
8503            this.$userControl.children(".item-selected")[0].focus();
8504        }
8505        else if(this.$userControl.children().length > 0) {
8506            this.$userControl.children()[0].focus();
8507        }
8508    },
8509
8510    addItem : function(itemValues){
8511        $("<li></li>")
8512            .attr("data-save", itemValues.sSaveVal || '')
8513            .text(itemValues.sDisplayVal || '')
8514            .appendTo(this.$userControl)
8515            .click($.proxy(this._handleItemClick, this))
8516            .focus($.proxy(this._handleItemFocus, this));
8517
8518        // add new item as selected if the value is already present in options
8519        if (_.contains(this.options.value, itemValues.sSaveVal)) {
8520            this._selectListItem(this.$userControl.find("[data-save=" + itemValues.sSaveVal+ "]"));
8521        }
8522    },
8523
8524    clearItems : function(){
8525        $(this.$userControl).empty();
8526    },
8527
8528    deleteItem : function(nIndex){
8529        $(this.$userControl).children('li').each(function(index,element){
8530            if(index==nIndex){
8531                $(element).off("click").off("focus").remove();
8532            }
8533        })
8534    },
8535
8536
8537    _attachEventHandlers : function($control){
8538        var self = this;
8539        $control.keydown($.proxy(this._hotKeys,this))
8540            .children().on("mousedown",function() {
8541                    if(self.inFocus == true) {
8542                        self.mouseDown = true;
8543                    }
8544                })
8545            .click($.proxy(this._handleItemClick, this))
8546            .focus($.proxy(this._handleItemFocus, this))
8547            .blur($.proxy(this._handleFocusOut,this))
8548
8549    },
8550
8551     _hotKeys : function(event){
8552         if(this.options.access != "open")
8553             return;
8554         if(this.itemInFocus){
8555             switch(event.which) {
8556                 case 38: //arrow up
8557                     var prevSibling = $(this.itemInFocus).prev();
8558                     if(prevSibling){
8559                         this.keyDown = true;
8560                         prevSibling.focus();
8561                         this.keyDown = false;
8562                     }
8563                     event.preventDefault();
8564                     break;
8565                 case 40: //arrow down
8566                     var nextSibling = $(this.itemInFocus).next();
8567                     if(nextSibling){
8568                         this.keyDown = true;
8569                         nextSibling.focus();
8570                         this.keyDown = false;
8571                     }
8572                     event.preventDefault();
8573                     break;
8574                 case 91: //left arrow
8575                 case 92: //right arrow
8576                     event.preventDefault();
8577                     break;
8578                 case 32:
8579                     this._toggleItem(this.itemInFocus);
8580                     event.preventDefault();
8581                     break;
8582                 default:
8583             }
8584         }
8585     },
8586
8587     _toggleItem: function(item) {
8588         var $item = $(item),
8589             multiMode = this.options.multiSelect, // && event.ctrlKey ;
8590             that = this;
8591             //toggle selected state of this item
8592             this.$data(item, "selected", !this.$data(item, "selected"));
8593         var state = this.$data(item, "selected")
8594
8595         if(!multiMode) {
8596             var $selectedItem = this.$userControl.children(".item-selected")
8597             if($selectedItem.length) {
8598                 this.$data($selectedItem[0],"selected",false)
8599                 $selectedItem.removeClass("item-selected").addClass("item-selectable")
8600             }
8601         }
8602         $item.toggleClass("item-selectable",!state).
8603               toggleClass("item-selected",state)
8604
8605         this.$userControl.trigger("listboxchange");
8606     },
8607
8608     getCommitValue: function() {
8609         var that = this,
8610             multiMode = this.options.multiSelect;
8611
8612
8613         return this.$userControl.children().map(function(){
8614             // intentionally using $this.attr("data-save") instead of $this.data("data")
8615             return that.$data(this, "selected") ? $(this).attr("data-save") : null;
8616         }).get();
8617     },
8618
8619      _handleItemFocus : function(event){
8620          if(this.options.access != "open")
8621              return;
8622          var item = event.target;
8623          this.itemInFocus = item;
8624
8625          // overriding default widgets handleFocus
8626          if(!(this.keyDown || this.mouseDown)) {        //we do not need to fire focus event if
8627              this.$userControl.trigger("listboxenter")  // clicked on another li element or pressed a key to move the selectio
8628          }
8629          this.mouseDown = false;
8630          this.inFocus = true;
8631      },
8632
8633     _handleItemClick : function(event){
8634        // Bug#3501811 If clicked onlistbox entry more than once, exit event is not fired
8635        // Clicking on the same entry does not call focus and hence we were not resetting the state. Doing it in onClick
8636        if(this.mouseDown == true)
8637            this.mouseDown = false;
8638        if(this.options.access != "open")
8639             return;
8640        this._toggleItem(event.target)
8641    },
8642
8643    _handleFocusOut: function(){
8644        if(!(this.keyDown || this.mouseDown)) {
8645            this.$userControl.trigger("listboxexit");
8646            this.inFocus = false
8647        }
8648    },
8649
8650    _selectListItem : function ($elem) {
8651        if ($elem && $elem.length) {
8652            $elem.removeClass("item-selectable")
8653                .addClass("item-selected")
8654                .attr("tabIndex", this.options.tabIndex);
8655        }
8656    },
8657
8658    destroy: function() {
8659        this.element.
8660            removeClass(this._widgetName).
8661            children().remove().
8662            text("");
8663
8664        $.xfaWidget.defaultWidget.prototype.destroy.apply(this, arguments);
8665    }
8666});
8667})($, window._);
8668(function($) {
8669    $.widget( "xfaWidget.nwkListBox",  $.xfaWidget.dropDownList, {            //non-webkit listbox
8670
8671        _widgetName : "nwkListBox",
8672
8673        options : {
8674            value : [],
8675            multiSelect : false
8676        },
8677
8678        render : function() {
8679            var $control = $.xfaWidget.dropDownList.prototype.render.apply(this, arguments);
8680            if($control){
8681                $control.children("#emptyValue").remove();
8682                if(this.options.multiSelect)
8683                    $control.attr("multiple", "multiple");
8684            }
8685            this._updateSelectSize($control);
8686            return $control;
8687        },
8688
8689        addItem : function(itemValues){
8690            $.xfaWidget.dropDownList.prototype.addItem.apply(this, arguments);
8691            this._updateSelectSize();
8692        },
8693
8694        clearItems : function(){
8695            $.xfaWidget.dropDownList.prototype.clearItems.apply(this, arguments);
8696            this._updateSelectSize();
8697        },
8698
8699        deleteItem : function(nIndex){
8700            $.xfaWidget.dropDownList.prototype.deleteItem.apply(this, arguments);
8701            this._updateSelectSize();
8702        },
8703
8704        _updateSelectSize : function($control){
8705            $control = $control || this.$userControl;
8706            $control.attr("size", (this.options.items || []).length);
8707        },
8708
8709        // Bug#3597771
8710        // focus and commit event happen together hence first selection was modifying the value
8711        // we do not want focus to modify the value that is about to be committed
8712        showValue : function() {
8713
8714        }
8715
8716  });
8717})($);
8718(function ($) {
8719    $.widget("xfaWidget.xfaButton", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
8720
8721        _widgetName: "xfaButton",
8722
8723        options: {
8724            value: null,
8725            svgCaption: false //option to indicate if button already has an SVG caption
8726        },
8727
8728        getOptionsMap: function () {
8729            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
8730            return $.extend({}, parentOptionsMap, {
8731                "access": function (val) {
8732                    switch (val) {
8733                        case "open" :
8734                            this.$userControl.removeAttr("disabled");
8735                            this.$userControl.removeAttr("aria-disabled");
8736                            break;
8737                        case "nonInteractive" :
8738                        case "protected" :
8739                        case "readOnly" :
8740                            this.$userControl.attr("disabled", "disabled");
8741                            this.$userControl.attr("aria-disabled", "true");
8742                            break;
8743                        default  :
8744                            this.$userControl.removeAttr("disabled");
8745                            this.$userControl.removeAttr("aria-disabled");
8746                            break;
8747                    }
8748                },
8749                "value": function () {
8750                },
8751                "displayValue": function () {
8752                },
8753                "svgCaption": function (val) {
8754                    if (val) {
8755                        this.$userControl.removeAttr("value");
8756                    }
8757                }
8758            })
8759        },
8760
8761        _attachEventHandlers: function ($control) {
8762            $control.click(function () {
8763                this.focus()
8764            });
8765        },
8766
8767        getCommitValue: function () {
8768            return this.options.value;
8769        },
8770
8771        showValue: function () {
8772        },
8773
8774        showDisplayValue: function () {
8775        }
8776    });
8777})($);(function ($) {
8778    $.widget("xfaWidget.XfaCheckBox", $.xfaWidget.defaultWidget, {            //commitEvent: change; commitProperty: value<Array>
8779
8780        _widgetName: "XfaCheckBox",
8781
8782        options: {
8783            value: null,
8784            state: -1,
8785            states: 2,
8786            values: [],
8787            mandatory: false
8788        },
8789
8790        checkedState: false,
8791        clickPending: false,
8792
8793        getOptionsMap: function () {
8794            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this, arguments);
8795            return $.extend({}, parentOptionsMap, {
8796                "access": function (val) {
8797                    switch (val) {
8798                        case "open" :
8799                            this.$userControl.removeAttr("disabled");
8800                            this.$userControl.removeAttr("aria-disabled");
8801                            break;
8802                        case "nonInteractive" :
8803                        case "protected" :
8804                        case "readOnly" :
8805                            this.$userControl.attr("disabled", "disabled");
8806                            this.$userControl.attr("aria-disabled", "true");
8807                            break;
8808                        default  :
8809                            this.$userControl.removeAttr("disabled");
8810                            this.$userControl.removeAttr("aria-disabled");
8811                            break;
8812                    }
8813                },
8814
8815                "displayValue": function (val) {
8816                    this.$userControl.attr(this.options.commitProperty, this.options.value);
8817                    this._state(this.dIndexOf(this.options.values, this.options.value));
8818                    this.$userControl.attr("checked", this.checkedState ? "checked" : null);
8819                    this.$userControl.prop("checked", this.checkedState ? "checked" : null);
8820                    //for accessibility
8821                    this.$userControl.attr("aria-checked", this.checkedState);
8822                    if (this.options.state == 2)
8823                        this.$userControl.addClass("neutral");
8824                    else if (this.options.states == 3)
8825                        this.$userControl.removeClass("neutral");   // since current state != neutral
8826                },
8827
8828                "allowNeutral": function (val) {
8829                    var intVal = parseInt(val);
8830                    if (intVal == 0 || intVal == 1) {
8831                        this.options.states = 2 + intVal;
8832                    }
8833                },
8834
8835                "paraStyles": function (paraStyles) {
8836                    parentOptionsMap.paraStyles.apply(this, arguments);
8837                    this._handleVAlignOnExit();
8838                }
8839            })
8840        },
8841
8842        getEventMap: function () {
8843            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
8844            return $.extend({}, parentOptionsMap, {
8845                 "xfacheckboxchange" :  xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
8846                 "xfacheckboxclick" :   xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT,
8847                 "change": null,
8848                 "click" : null
8849               })
8850        },
8851
8852        _attachEventHandlers: function ($control) {
8853            var that = this;
8854            var focusFunc = function (evnt) {
8855                if (!that.inFocus) {
8856                    that.focus();
8857                    that.inFocus = true;
8858                }
8859            }
8860            var focusOutFunc = function (evnt) {
8861                that.inFocus = false;
8862            }
8863            $control.click(focusFunc).change(focusFunc).blur(focusOutFunc);
8864            $control.change($.proxy(this._handleChange,this)).click($.proxy(this._handleClick,this));   //LC-5106
8865        },
8866
8867        getCommitValue: function () {
8868            this._state((this.options.state + 1) % this.options.states);
8869            this.$userControl.attr("checked", this.checkedState ? "checked" : null);
8870            //for accessibility
8871            this.$userControl.attr("aria-checked", this.checkedState)
8872            if (this.options.state == 2) {
8873                this.$userControl.addClass("neutral");
8874            }
8875            else if (this.options.states == 3)
8876                this.$userControl.removeClass("neutral"); // since current state != neutral
8877
8878            return this.options.values[this.options.state];
8879        },
8880
8881        _handleVAlignOnExit: function (evnt) {
8882            //--this is being kept empty as no other browser (i.e Mozilla and Chrome) take the padding-bottom or padding-top into account.
8883            // the only browser to take it into consideration is IE. And moreover the alignment and padding considerations have already been taken into account in
8884            // calculations in CheckButtonFieldView.js. And on removing the entire function it takes up the _handleVAlignOnExit() of AbstractWidget.
8885
8886        },
8887
8888        _handleChange: function (evnt) {
8889            this.$userControl.trigger("xfacheckboxchange"); //change is always fired
8890            if(this.clickPending === true) {
8891              this.clickPending = false;
8892              this.$userControl.trigger("xfacheckboxclick");
8893            } else {
8894                // handling of this.clickPending is added to handle the case when clicked on checkbox/radiobutton label/caption
8895                this.clickPending = true;
8896            }
8897        },
8898
8899        _handleClick: function (evnt) {
8900             var isChrome = xfalib.ut.XfaUtil.prototype.detectChrome(),
8901                 isIE = xfalib.ut.XfaUtil.prototype.detectIE(),
8902                 isSafari = xfalib.ut.XfaUtil.prototype.isSafari(),
8903                 userControlType = this.$userControl.attr("type");
8904             // click will not be fired if the previous state of the radiobutton is 'on'.
8905             // CQ-4312095: Checkbox movement - Click event works fine on chrome but not in iOS safari for collapsible fields
8906             // CQ-103023 : Click Event on Radio Button not working correctly in Chrome 53
8907             // CQ-103715 : CQ-103715 : Click Event on Check Box not working correctly in Chrome and Firefox, added handling for checkbox also
8908             // handling of this.clickPending is added to handle the case when clicked on checkbox/radiobutton label/caption
8909             if(($.browser.mozilla || isChrome || isSafari) && !isIE && this.clickPending === false && ((userControlType === "radio" && this.checkedState === false) || (userControlType === "checkbox"))) {
8910               this.clickPending = true;
8911             }
8912             else {
8913                this.$userControl.trigger("xfacheckboxclick");
8914                this.clickPending = false;
8915             }
8916        },
8917
8918        _state: function (newState) {
8919            if (newState == undefined)
8920                return this.options.state;
8921            else
8922                this.options.state = newState;
8923            this.checkedState = (newState == 0 || newState == 2);
8924        },
8925
8926        click: function () {
8927            // trigger change for check box and for radio only if it is not selected
8928            // otherwise radio button will go in deselected state
8929            if (this.$userControl.attr("type") !== "radio" || this.options.state !== 0) {
8930                this.$userControl.trigger("change");
8931            }
8932            //we should call only the handler since calling click will trigger change.
8933            this.$userControl.triggerHandler("click");
8934        }
8935    });
8936})($);
8937(function($, _){
8938    $.widget( "xfaWidget.textField", $.xfaWidget.defaultWidget, {
8939
8940        _widgetName: "textField",
8941
8942        options: {
8943            curValue : null ,
8944            pos:0,
8945            lengthLimitVisible: true,
8946            maxChars:0 ,
8947            flag:"",
8948            // by default html5Type is set to true
8949            // we leverage pattern, maxLength support from HTML5 browser for mobile forms
8950            html5Type : "text",
8951            length : null,
8952            minLength : 0,
8953            totalLengthMessage : "",
8954            minimumLengthMessage : "",
8955        },
8956
8957        getOptionsMap: function() {
8958            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
8959            return $.extend({},parentOptionsMap,{
8960                "maxChars": function(maxchars) {
8961                    if(this._maxCharsReached(this.options.value)) {
8962                        var value = this.options.value.slice(0,maxchars)
8963                        this._setOption("value", value);
8964                        this._setOption("displayValue", value);
8965                    }
8966
8967                },
8968
8969                "multiLine ": function(val) {
8970                    if(this.options.multiLine)
8971                        this.$userControl.attr("aria-multiline", "true");
8972                    else
8973                        this.$userControl.removeAttr("aria-multiline", "false");
8974                },
8975
8976                "height": function(val) {
8977                    if(val)   {
8978                        this.$css(this.$userControl[0],{"height" :val})
8979                        this._handleVAlignOnExit();    // To Handle the case of expandable Fields
8980                    }
8981                },
8982                "width": function(val){
8983                    parentOptionsMap.width.apply(this,arguments);
8984                    // handle valign on width change as well
8985                    // as content height(scrollHeight) varies according to width
8986                    this._handleVAlignOnExit();
8987                },
8988                "paraStyles": function(paraStyles){
8989                    parentOptionsMap.paraStyles.apply(this,arguments);
8990                    this._handleVAlignOnExit();
8991                }
8992
8993            })
8994        },
8995
8996        render : function() {
8997            var control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
8998            // use the control to set HTML5 attributes
8999            if (control && control.length > 0 && this.options.html5Type) {
9000                var minLength = this.options.minLength,
9001                    maxLength = this.options.maxChars,
9002                    length = this.options.length;
9003                    isMinLengthSet = minLength != null && minLength > 0,
9004                    isMaxLengthSet = maxLength != null && maxLength > 0,
9005                    isLengthSet = length != null && length > 0,
9006                    isMultiline = this.options.multiLine,
9007                    minLengthMsg = this.options.minimumLengthMessage,
9008                    totLengthMsg = this.options.totalLengthMessage,
9009                    pattern = ""; // html5 pattern is not supported for textarea
9010
9011                // order of execution matters for the below code snippet
9012                if (isMinLengthSet) {
9013                    // add minLength though it is not fully supported in all browsers
9014                    // hence also adding pattern attribute
9015                    control.attr("minlength", parseInt(minLength));
9016                    if(minLengthMsg && minLengthMsg.length > 0) {
9017                        control.attr("title", this.options.minimumLengthMessage); // html5 supported message on pattern validation failure
9018                    }
9019                }
9020
9021                if (isMaxLengthSet) {
9022                    control.attr("maxlength", parseInt(maxLength));
9023                }
9024
9025                // if both min and max length is set
9026                if(isMinLengthSet && isMaxLengthSet){
9027                    pattern += ".{" + minLength + "," + maxLength + "}";
9028                } else if(isMinLengthSet) {
9029                    // if only min length set
9030                    pattern += ".{" + minLength + ",}";
9031                }
9032
9033                // if length is set then set min and max length in pattern equal to length
9034                if (isLengthSet) {
9035                    if(isMultiline){ // set both min and maxlength as pattern is not supported
9036                        control.attr("minlength", parseInt(length));
9037                        control.attr("maxlength", parseInt(length));
9038                    }
9039                    if(totLengthMsg && totLengthMsg.length > 0) {
9040                        control.attr("title", this.options.totalLengthMessage);
9041                    }
9042                    // reset the pattern string
9043                    pattern = ".{" + length + "," + length + "}";
9044                }
9045                // if required is set, set the required attribute, it is necessary else an empty value will be excluded from constraint validation
9046                if (this.options.required) {
9047                    control.attr("required", true);
9048                }
9049                // set the pattern if not empty and check if this is not multiline, since pattern is not supported for textarea
9050                if (pattern && pattern.length > 0 && !isMultiline) {
9051                    control.attr("pattern", pattern);
9052                }
9053            }
9054            return control;
9055        },
9056
9057        /*  This function aligns vAlign when:
9058         1. parastyles is present and the widget contains a value.
9059         2. During initial rendering if no content present fallback to the previous logic.
9060         3. Presence of content in widget.
9061        */
9062        _handleVAlignOnExit: function(){
9063             var value = this.options.displayValue,
9064                 noContentPresent = _.isEmpty(this.$userControl.val() || this.options.displayValue),
9065                 contentHeight,widgetHeight,diff,tempCSS;
9066
9067             //the widget doesn't have value as yet but content exists [ Rendering of widget]
9068             if (!this.options.paraStyles || noContentPresent) {
9069                //vAlign has to be handled only if there is paraStyles and widget has content
9070                return;
9071             }
9072
9073             // mozilla results in vAlign regression hence made this change only for textarea
9074             if($(this.element[0]).find("textarea").length >0 && !noContentPresent)  {
9075               /* measureExtent not returning correct height of content in textarea even with all
9076                 css values */
9077               tempCSS={'height':this.$userControl.css('height'),'padding':this.$userControl.css('padding')};
9078               this.$css(this.$userControl[0],{'height':'1px','padding':'0px'});
9079
9080               contentHeight = this._getContentHeight();
9081               this.$css(this.$userControl[0],tempCSS);
9082               widgetHeight = this.options.height;
9083               diff = widgetHeight - contentHeight;
9084               this._calculatePaddingForVAlign(diff);
9085             } else {
9086                // widget has no initial content or is a textfield.Proceed as before.
9087                $.xfaWidget.defaultWidget.prototype._handleVAlignOnExit.apply(this,arguments);
9088             }
9089        },
9090
9091        getEventMap: function() {
9092            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
9093            return $.extend({},parentOptionsMap,{
9094                "onKeyInput.textField" : xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
9095            })
9096        },
9097
9098        _maxCharsReached: function(val) {
9099            var isMaxLengthSupported = false,
9100                elementName = this.options.multiLine ? "textarea" : "input";
9101            // in browsers, where max length is supported, we don't custom javascript checks, we let HTML do the validation of max length
9102            if(this.options.html5Type && xfalib.view.util.HtmlUtil.elementSupportsAttribute(elementName, "maxLength")){
9103                isMaxLengthSupported = true;
9104            }
9105            return !isMaxLengthSupported && this.options.maxChars
9106                   && this.options.maxChars!=="0"
9107                   && val
9108                   &&  val.length >= this.options.maxChars
9109        },
9110
9111        _handleKeyInput : function(event, character, code) {
9112            if(event.ctrlKey && !_.contains(['paste', 'cut'], event.type)) {
9113                return true;
9114            }
9115
9116            if(!this.options.multiLine) {
9117                $.xfaWidget.defaultWidget.prototype._handleKeyDown.apply(this, arguments);
9118                character = (code == 13) ? '' : character ;
9119            }
9120
9121            var val =  this.$userControl.val(),
9122                selectionStart = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionStart") || 0,
9123                selectionEnd = xfalib.view.util.HtmlUtil.getHTMLSupportedAttr(this.$userControl[0], "selectionEnd") || 0,
9124                pos = selectionStart,
9125                // CQ-4260239 : "&nbsp" taking space of 5 chars for restricting the length to visible area
9126                newVal = (val.substr(0, selectionStart) + character + val.substr(selectionEnd));
9127            this.options.curValue = val;
9128            if(!this.options.multiLine) { //TODO:looks like a bug
9129                this.options.lengthLimitVisible = true;
9130                this.options.pos = pos;
9131                if(this.options.hScrollDisabled && !_.contains(['keydown', 'cut'], event.type)) {
9132                    var expectedWidth = xfalib.view.util.TextMetrics.measureExtent(newVal, {refEl: this.$userControl[0], maxWidth:-1}).width;
9133                    if(!event.ctrlKey && expectedWidth > this.$userControl.width()){   // Why  allowance of 5 required??
9134                        this.options.lengthLimitVisible = false;
9135                        event.preventDefault();
9136                        return false;
9137                    }
9138                }
9139            } else if (this.options.multiLine && this.options.hScrollDisabled) {  // LC-4656 : wait till user input, if it causes an overflow revert to old text
9140                var $textArea = this.$userControl;
9141                $textArea.css("padding", "0px 0px 0px");  // TODO : take care of multiline selection & padding later
9142
9143                // TODO : find a scheme to avoid attaching and detaching listeners, currently $.val() causes 'input' to fire, resulting in an infinite loop
9144                $textArea.one("input", function () {
9145                    if ($textArea.prop('scrollHeight') > $textArea.prop('offsetHeight')) {
9146                        $textArea.val(val)
9147                                 .prop("selectionStart", selectionEnd)
9148                                 .prop("selectionEnd", selectionEnd);  // LC-4656 : reset the cursor pos, afterwards
9149                        character = null;
9150                        code = 0;
9151                    }
9152                });
9153            }
9154
9155            if (!_.contains(['keydown', 'cut'], event.type) && this._maxCharsReached(val) && selectionStart === selectionEnd) {
9156                event.preventDefault();
9157                return false;
9158            }
9159
9160            this.$userControl.trigger({
9161                type : "onKeyInput.textField",
9162                originalType : event.type,
9163                character : character,  // contains the pasted string or pressed key
9164                keyCode : event.keyCode || 0,
9165                charCode : event.charCode || 0,
9166                which : event.which || 0,
9167                ctrlKey : event.ctrlKey || event.metaKey || false,
9168                shiftKey : event.shiftKey || false,
9169                keyDown: false, // This property is available only for list boxes and drop-down lists
9170                selectionStart: selectionStart,
9171                selectionEnd: selectionEnd
9172            });
9173        },
9174
9175        _handleKeyDown : function(event){
9176            if (event) {
9177                var code = event.charCode || event.which || event.keyCode || 0;
9178                if(code == 8 || code == 46) // backspace and del
9179                   this._handleKeyInput(event, "", code);
9180            }
9181        },
9182
9183        _handleKeyPress : function(event){
9184            if (event) {
9185                var code = event.charCode || event.which || event.keyCode || 0,
9186                    character = (code == 13) ? "\n" : String.fromCharCode(code); // modified '\r\n' -> '\n'
9187
9188            if(xfalib.ut.XfaUtil.prototype.isNonPrintableKey(event.key)) { // mozilla also generates a keypress, along with keydown
9189                return true;                                               // for all keys, so only handling printable keys in keypress
9190            }
9191
9192            this._handleKeyInput(event, character, code);
9193            }
9194        },
9195
9196        _compositionUpdateCallback : function (event) {
9197            var that = this;
9198            var val = that.$userControl.val();
9199            if (event.type === "compositionupdate" && event.originalEvent.data) {
9200                // this has been deliberately done to get the actual data in case of max character.
9201                if (that.options.maxChars) {
9202                    val = event.originalEvent.data;
9203                } else {
9204                    val = val + event.originalEvent.data.substr(event.originalEvent.data.length - 1);
9205                }
9206            }
9207            var flag = that._maxCharsReached(val);
9208            if (flag) {
9209                // if max reached
9210                var newVal = val.substr(0, that.options.maxChars);
9211                //in case the value is not changed then we do not need to update value and close the android keyboard.
9212                if (val === newVal) {
9213                    return false;
9214                }
9215                that.$userControl.val(newVal);
9216            }
9217            return flag;
9218        },
9219
9220        _attachEventHandlers: function($control) {
9221            $.xfaWidget.defaultWidget.prototype._attachEventHandlers.apply(this, arguments);
9222            // IME specific handling, to handle japanese languages max limit
9223            $.xfaWidget.defaultWidget.prototype._attachCompositionEventHandlers.apply(this, arguments);
9224        },
9225
9226        _handlePaste : function(event){
9227            if (event) {
9228                var pastedChar = undefined;
9229                if (window.clipboardData && window.clipboardData.getData) { // IE
9230                    pastedChar = window.clipboardData.getData('Text');
9231                } else if (event.originalEvent.clipboardData && event.originalEvent.clipboardData.getData) {
9232                    pastedChar = event.originalEvent.clipboardData.getData('text/plain');
9233                }
9234                if(pastedChar) {
9235                    this._handleKeyInput(event, pastedChar, 0);
9236                }
9237            }
9238        },
9239
9240        _handleCut : function(event) {
9241            if (event) {
9242                this._handleKeyInput(event, "", 0);
9243            }
9244        },
9245
9246        postProcessExit: function(evnt) {
9247            $.xfaWidget.defaultWidget.prototype.postProcessExit.apply(this,arguments);
9248            if (this.options.multiLine && this.options.hScrollDisabled) {
9249                return;
9250            }
9251            this._handleVAlignOnExit();
9252        },
9253
9254        preProcessEnter: function(evnt) {
9255            $.xfaWidget.defaultWidget.prototype.preProcessEnter.apply(this,arguments);
9256            if(this.options.multiLine && this.options.hScrollDisabled)
9257                return;
9258            this._handleVAlignOnEnter();
9259        },
9260
9261        /**
9262         * @brief: Select the given field on focus in Internet Explorer
9263         *
9264         */
9265        _selectOnFocusInIE : function(){
9266            // if the value is not same only then do selection in IE
9267            // For Issue: LC-9895, we check if value not same
9268            if($.browser.msie && !this._isValueSame()) {
9269                this.$userControl.select();
9270            }
9271            else {
9272                //all other browsers behave like a good boy
9273            }
9274        },
9275
9276        showValue : function() {
9277            $.xfaWidget.defaultWidget.prototype.showValue.apply(this,arguments);
9278            //IE doesn't show selected text if we focus and set its value all the time so force selection
9279            this._selectOnFocusInIE();
9280        },
9281
9282        getCommitValue: function() {
9283            var value = $.xfaWidget.defaultWidget.prototype.getCommitValue.apply(this, arguments);
9284
9285            if(this._maxCharsReached(value)) {
9286                value = value.slice(0,this.options.maxChars);
9287            }
9288
9289            this.$userControl.val(this.options.value);
9290
9291            //TODO: ask Sharad whether it is right
9292            if(this.options.multiLine && this.options.hScrollDisabled)  {
9293                //var str= this._checkLines(value);
9294                //if(value != str) {
9295                    return value;
9296                //}
9297            }
9298            return value;
9299        },
9300
9301        /*
9302        ** returns the contentHeight which needs to be considered for padding for valign,
9303        ** if no contentHeight is present then fontSize is returned.
9304        */
9305        _getContentHeight: function () {
9306            var contentHeight = Math.ceil(this.$userControl.get(0).scrollHeight);
9307            return contentHeight ? contentHeight : this.options.fontSize;
9308        }
9309    });
9310})($, window._);
9311/*************************************************************************
9312 *
9313 * ADOBE CONFIDENTIAL
9314 * __________________
9315 *
9316 *  Copyright 2019 Adobe Systems Incorporated
9317 *  All Rights Reserved.
9318 *
9319 * NOTICE:  All information contained herein is, and remains
9320 * the property of Adobe Systems Incorporated and its suppliers,
9321 * if any.  The intellectual and technical concepts contained
9322 * herein are proprietary to Adobe Systems Incorporated and its
9323 * suppliers and may be covered by U.S. and Foreign Patents,
9324 * patents in process, and are protected by trade secret or copyright law.
9325 * Dissemination of this information or reproduction of this material
9326 * is strictly forbidden unless prior written permission is obtained
9327 * from Adobe Systems Incorporated.
9328 **************************************************************************/
9329
9330(function ($) {
9331    $.widget("xfaWidget.richTextField", $.xfaWidget.textField, {
9332
9333        _widgetName : "richTextField",
9334
9335        _richTextWidget : null,
9336
9337        _changeAccess : function (val) {
9338            switch (val) {
9339                case "open":
9340                    if (this._richTextWidget) {
9341                        this._richTextWidget.editor.enable();
9342                        this._richTextWidget.$toolbar.removeClass("hideToolbar");
9343                    }
9344                    break;
9345                case "readOnly":
9346                    if (this._richTextWidget) {
9347                        this._richTextWidget.editor.disable();
9348                        this._richTextWidget.$toolbar.addClass("hideToolbar");
9349                    }
9350                    break;
9351            }
9352        },
9353
9354        getOptionsMap : function () {
9355            var parentOptionsMap = $.xfaWidget.textField.prototype.getOptionsMap.apply(this, arguments);
9356            return $.extend({}, parentOptionsMap, {
9357                "value" : function (val) {
9358                    if (this._richTextWidget) {
9359                        this._richTextWidget.setRichTextEditorContent(val);
9360                    }
9361                },
9362                "access" : function (val) {
9363                    this._changeAccess(val);
9364                }
9365            });
9366        },
9367
9368        getEventMap : function () {
9369            // in case of IE browsers, focus event is delayed, hence adding activate method for content editable
9370            if (xfalib.ut.XfaUtil.prototype.isIE()) {
9371                var parentOptionsMap = $.xfaWidget.textField.prototype.getEventMap.apply(this, arguments);
9372                return $.extend({}, parentOptionsMap, {
9373                    "activate.richTextField" : xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT
9374                });
9375            } else {
9376                return $.xfaWidget.textField.prototype.getEventMap.apply(this, arguments);
9377            }
9378        },
9379
9380        render : function () {
9381            var $richTextWidget = this.element.find("div.richTextWidget").eq(0);
9382            if(!$richTextWidget.length){
9383                var attachedTextareaClasses = this.element.children().attr('class');
9384                var richTextWidgetElement = '<div class="richTextWidget ' + attachedTextareaClasses + '" id="richTextField_' + this.options.name + '_' + attachedTextareaClasses + '"></div>';
9385                this.element.children().remove();
9386                this.element.append(richTextWidgetElement);
9387                $richTextWidget = this.element.find("div.richTextWidget").eq(0);
9388            }else{
9389                $richTextWidget.children().remove();
9390            }
9391            $richTextWidget.append(this.options.value);
9392            return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9393        },
9394
9395        getCommitValue : function () {
9396            var value = "";
9397            if (this._richTextWidget) {
9398                value = this._richTextWidget.getRichTextEditorContent();
9399            }
9400            return value;
9401        },
9402
9403        preProcessEnter : function (evnt) {
9404            $.xfaWidget.textField.prototype.preProcessEnter.apply(this, arguments);
9405            var $richTextDiv = this.$userControl.find("div.richTextWidget").eq(0);
9406            if(!$richTextDiv.length){
9407                $richTextDiv = this.element.find("div.richTextWidget").eq(0);
9408                this.changeDefaultToolbarConfig();
9409                this.$userControl.parents('.richtextsupport').css('z-index', 'auto');
9410            }
9411            if (window.Form === undefined || window.Form.rte === undefined) {
9412                /* Forms RTE is part of Forms Addon package only. Dont do anything if addon is not installed.*/
9413                return;
9414            } else if (this._richTextWidget === null) {
9415                this._initializeRTEToolbar();
9416                this._richTextWidget = new window.Form.rte.RichTextEditor({
9417                    selector : $richTextDiv.attr("id"),
9418                    toolbar : window.Form.rte.RichTextEditor.MFToolbar,
9419                    data : this.options.value,
9420                    locale : $richTextDiv.data("locale")
9421                });
9422                var that = this;
9423                this._richTextWidget.editor.on("blur:composer", function () {
9424                    that.$userControl.trigger("blur");
9425                });
9426                // initialize the access
9427                if (this.options.access) {
9428                    this._changeAccess(this.options.access);
9429                }
9430            }
9431        },
9432
9433        changeDefaultToolbarConfig: function(){
9434            if(window.Form && window.Form.rte){
9435                var toolbarDefaultConfigData = window.Form.rte.DefaultConfig;
9436                toolbarDefaultConfigData.fontSize.defaultValue = this.options.fontSize;
9437                toolbarDefaultConfigData.fontFamily.defaultValue = this.options.fontFamily;
9438
9439                // Adding 'isFontInPx' flag and overriding two utility functions
9440                // 'getDefaultParaStyle' and 'getMissingParaStyle' are responsible for adding RTE font styling attributes to rich text elements
9441                toolbarDefaultConfigData.isFontInPx = true;
9442                this.changeDefaultParaStyleUtility();
9443                this.changeMissingParaStyleUtility();
9444
9445                // Adding dropdown values in default config if not available in options
9446                if(toolbarDefaultConfigData.fontSize.options.indexOf(this.options.fontSize) === -1){
9447                    toolbarDefaultConfigData.fontSize.options.push(this.options.fontSize);
9448                }
9449                if(toolbarDefaultConfigData.fontFamily.options.indexOf(this.options.fontFamily) === -1){
9450                    toolbarDefaultConfigData.fontFamily.options.push(this.options.fontFamily);
9451                }
9452            }
9453        },
9454
9455        changeDefaultParaStyleUtility: function(){
9456            Form.rte.util.HtmlUtils.getDefaultParaStyle = function (config) {
9457                var style = "";
9458                if (config) {
9459                    style += 'font-family:' + config.fontFamily.defaultValue + ';';
9460                    if(config.isFontInPx){
9461                        style += 'font-size:' + config.fontSize.defaultValue + 'px;';
9462                        style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'px;';
9463                    }else{
9464                        style += 'font-size:' + config.fontSize.defaultValue + 'pt;';
9465                        style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'pt;';
9466                    }
9467                    style += 'color:#000000;';
9468                    style += 'text-align:left;';
9469                }
9470
9471                return style;
9472            };
9473        },
9474
9475        changeMissingParaStyleUtility : function(){
9476            Form.rte.util.HtmlUtils.getMissingParaStyle = function (style, config) {
9477                if (style && style.length > 0) {
9478                    if (config) {
9479                        if (!Form.rte.util.StringHelper.endsWith(style, ";")) {
9480                            style += ";";
9481                        }
9482                        if (style.indexOf("font-family") < 0) {
9483                            style += 'font-family:' + config.fontFamily.defaultValue + ';';
9484                        }
9485                        if (style.indexOf("font-size") < 0) {
9486                            if(config.isFontInPx){
9487                                style += 'font-size:' + config.fontSize.defaultValue + 'px;';
9488                            }else{
9489                                style += 'font-size:' + config.fontSize.defaultValue + 'pt;';
9490                            }
9491                        }
9492                        if (style.indexOf("letter-spacing") < 0) {
9493                            if(config.isFontInPx){
9494                                style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'px;';
9495                            }else{
9496                                style += 'letter-spacing:' + config.letterSpacing.defaultValue + 'pt;';
9497                            }
9498                        }
9499                        if (style.indexOf("color") < 0) {
9500                            style += 'color:#000000;';
9501                        }
9502                        if (style.indexOf("text-align") < 0) {
9503                            style += 'text-align:left;';
9504                        }
9505                    }
9506                } else {
9507                    style = Form.rte.util.HtmlUtils.getDefaultParaStyle(config);
9508                }
9509                return style;
9510            };
9511        },
9512
9513        _initializeRTEToolbar : function () {
9514            window.Form.rte.RichTextEditor.MFToolbar = window.Form.rte.RichTextEditor.MFToolbar || {
9515                defaultMode : 'basic',
9516                toolbars : {
9517                    basic : {
9518                        layout : [
9519                            {
9520                                items : [Form.rte.Commands.HEADER]
9521                            },
9522                            {
9523                                items : [Form.rte.Commands.BOLD, Form.rte.Commands.ITALIC, Form.rte.Commands.UNDERLINE]
9524                            },
9525                            {
9526                                command : 'lists',
9527                                icon : 'list',
9528                                title : "List Type",
9529                                type : 'popover',
9530                                placement : 'bottom',
9531                                items : [Form.rte.Commands.INSERT_UNORDERED_LIST,
9532                                    Form.rte.Commands.INSERT_ORDERED_LIST,
9533                                    Form.rte.Commands.INSERT_LOWERCASE_ALPHABET_LIST]
9534                            },
9535                            {
9536                                title : 'Expand',
9537                                command : Form.rte.Commands.MODE,
9538                                value : Form.rte.ToolbarMode.FULL,
9539                                icon : 'resize-full'
9540                            }
9541                        ],
9542                        floating : true
9543                    },
9544                    full : {
9545                        layout : [
9546                            {
9547                                items : [Form.rte.Commands.BOLD, Form.rte.Commands.ITALIC, Form.rte.Commands.UNDERLINE]
9548                            },
9549                            {
9550                                items : [Form.rte.Commands.SUPERSCRIPT, Form.rte.Commands.SUBSCRIPT]
9551                            },
9552                            {
9553                                items : [
9554                                    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
9555                                ]
9556                            },
9557                            {
9558                                items : [Form.rte.Commands.INSERT_UNORDERED_LIST, Form.rte.Commands.INSERT_ORDERED_LIST, Form.rte.Commands.INSERT_LOWERCASE_ALPHABET_LIST
9559                                ]
9560                            },
9561                            {
9562                                title : 'Collapse',
9563                                command : Form.rte.Commands.MODE,
9564                                value : Form.rte.ToolbarMode.BASIC,
9565                                icon : 'resize-small',
9566                                selected : true
9567                            }
9568                        ]
9569                    }
9570                }
9571            };
9572        }
9573    });
9574
9575})($);
9576(function($){
9577	$.widget( "xfaWidget.imageField", $.xfaWidget.defaultWidget, {
9578
9579    _widgetName:"imageField",
9580
9581    options: {
9582        tabIndex: 0,
9583        "role": "img"
9584    },
9585
9586    getEventMap: function () {
9587        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this, arguments);
9588        return $.extend({}, parentOptionsMap, {
9589            "imagechange": xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT
9590        })
9591    },
9592
9593    getOptionsMap: function() {
9594        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
9595        return $.extend({},parentOptionsMap,{
9596            "screenReaderText": function(val) {
9597                if(val)
9598                    this.$userControl.attr("alt", val)
9599            },
9600            "displayValue": function(val) {
9601                var widgetValue;
9602                if (this.options.value) {
9603                    widgetValue = "data:;base64," + this.options.value;
9604                } else {
9605                    widgetValue = "";
9606                }
9607                this.$userControl.prop(this.options.commitProperty, widgetValue);
9608                this.$userControl.attr(this.options.commitProperty, widgetValue);
9609            },
9610            "access" : function() {},
9611
9612            // CQ-85514 : use max-ht & max-wd to honor image's intrinsic ht & wd attributes & prevent distortion
9613            "height" : function (val) {
9614                // in case aspect is actual then we need to crop the image, which will be not possible if max height and width are set
9615                if (val && this.options.aspect != "actual") {
9616                    this.$css(this.$userControl[0], {"max-height": val});
9617                }
9618            },
9619            "width" : function (val) {
9620                if (val && this.options.aspect != "actual") {
9621                    this.$css(this.$userControl[0], {"max-width": val});
9622                }
9623            },
9624            "aspect" : function (val) {
9625                // value of actual turns off scaling, causing the image to be drawn at its native size,
9626                // as per xfa spec Adobe implementations crop the image
9627                if(this.options.aspect == "actual") {
9628                    var right = this.$userControl.attr("width"),
9629                        bottom = this.$userControl.attr("height");
9630                    right = right.indexOf("px") >= 0 ? right : right + "px";
9631                    bottom = bottom.indexOf("px") >= 0 ? bottom : bottom + "px";
9632                    this._cropImage("0px", right, bottom, "0px");
9633                    this.$userControl.removeAttr("height width");
9634                // value of none indicates no aspect ratio
9635                // as per xfa spec image is independently scaled in the horizontal and vertical directions to exactly f
9635ill the field,
9636                // which are already set to fill the field
9637                } else if (this.options.aspect != "none") {
9638                // 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
9639                // without overflowing it in either dimension.
9640                    this.$userControl.attr({"height" : "auto", "width" : "auto"});
9641                }
9642            }
9643        });
9644    },
9645
9646    // crop the image using top,right, bottom, left coordiantes of the image
9647    _cropImage : function (top, right, bottom, left) {
9648        var clipRect = "rect(" + top + "," + right + "," + bottom + "," + left + ")";
9649        var clipPathPolygon = "polygon( 0px 0px, 0px " + bottom + "," + right + " " + bottom +"," + right + " 0px)";
9650        // clip property is deprecated but still supported by all the major browsers
9651        // clip-path replaces the deprecated clip property but still is not fully supported by all major browser
9652        this.$userControl.css({"clip" : clipRect, "clip-path" : clipPathPolygon});
9653    },
9654
9655    render : function() {
9656        var self = this;
9657        if (typeof FileReader !== "undefined") {
9658            this.reader = new FileReader();
9659        } else {
9660            xfalib.ut.XfaUtil.prototype.getLogger().error("Image Field is supported only for HTML5 supported browsers.");
9661        }
9662        if (this.element) {
9663            // change event triggered when new image is selected
9664            this.$widgetInput = this.element.find("input").on("change.imageField", function() {
9665                self._handleInputChange();
9666            }).click(function(event) {
9667                // to stop bubbling of event from input to widget
9668                event.stopPropagation();
9669            });
9670            this.$widgetImg = this.element.on("click.imageField", function() {
9671                self._imageClick();
9672            }).find("img");
9673        }
9674        if (this.reader) {
9675            //load event is triggered each time the reading operation is successfully completed
9676            this.reader.addEventListener("load", function () {
9677                self.$widgetImg.attr("src",self.reader.result);
9678                self.$widgetImg.trigger("imagechange");
9679            }, false);
9680        }
9681        return $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9682    },
9683
9684    getCommitValue: function() {
9685        return this._extractData(this.$userControl.attr("src"));
9686    },
9687
9688    // hidden input change handler, input change will be triggered on selecting a new image
9689    _handleInputChange : function() {
9690        this._displayImage();
9691    },
9692
9693    _imageClick : function(clickEvent) {
9694        //as the input button is hidden we trigger click explicitly on click of the widget
9695        this.$widgetInput.trigger("click");
9696    },
9697
9698    // removes "data\:.*\;base64," from the image base64 string
9699    _extractData : function(value) {
9700        return value.replace(/data\:.*\;base64,/, "");
9701    },
9702
9703    // previews image in the imagefield widget
9704    _displayImage : function() {
9705        var imageFile = this.$widgetInput.get(0).files ? this.$widgetInput.get(0).files[0] : null;
9706        if (imageFile && this._isFileOfImageType(imageFile.name)) {
9707            if (this.reader) {
9708                //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
9709                this.reader.readAsDataURL(imageFile);
9710            }
9711        }
9712    },
9713
9714    // Test for supported image file(jpg,jpeg,png,gif,tif,bmp)
9715    _isFileOfImageType : function(fileName) {
9716        if (fileName) {
9717            return (/\.(jpe?g|png|gif|tif|bmp)$/i.test(fileName));
9718        }
9719        return false;
9720    }
9721});
9722})($);
9723/**
9724 * Created with IntelliJ IDEA.
9725 * User: rpandey
9726 * Date: 12/24/12
9727 * Time: 8:06 PM
9728 * To change this template use File | Settings | File Templates.
9729 */
9730
9731
9732(function($){
9733    $.widget( "xfaWidget.signatureField", $.xfaWidget.defaultWidget, {
9734
9735        _widgetName:"signatureField",
9736
9737        getOptionsMap: function() {
9738            var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
9739            return $.extend({},parentOptionsMap,{
9740                "displayValue": function(val) {},
9741                "access": function(val) {}
9742            })
9743        },
9744
9745        render : function() {
9746            var $control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments);
9747            //pessimistic checks
9748            if($control) {
9749                $control.attr("readOnly","readonly").attr("disabled", true);
9750            }
9751            return $control;
9752        }
9753    });
9754})($);
9755/*
9756 * ADOBE CONFIDENTIAL
9757 * ___________________
9758 *
9759 * Copyright 2011-2012 Adobe Systems Incorporated
9760 * All Rights Reserved.
9761 *
9762 * NOTICE:  All information contained herein is, and remains
9763 * the property of Adobe Systems Incorporated and its suppliers,
9764 * if any.  The intellectual and technical concepts contained
9765 * herein are proprietary to Adobe Systems Incorporated and its
9766 * suppliers and may be covered by U.S. and Foreign Patents,
9767 * patents in process, and are protected by trade secret or copyright law.
9768 * Dissemination of this information or reproduction of this material
9769 * is strictly forbidden unless prior written permission is obtained
9770 * from Adobe Systems Incorporated.
9771 */
9772 
9773/**
9774 * widget definition for scribbleable field
9775 */
9776(function($,xfalib){
9777
9778 var TouchUtil=xfalib.ut.TouchUtil;
9779 var ScribbleUtil=(function(){
9780      return {
9781          localeString:function(id){
9782                    return xfalib.ut.XfaUtil.prototype.encodeScriptableTags($.xfaWidget.abstractWidget.prototype.localeStrings()[id])  || id;
9783          }
9784      };
9785 })();
9786 var DELETE_KEY = 46;
9787 var ESC_KEY = 27;
9788 var ENTER_KEY = 13;
9789/**
9790 * Scribble class definition, used for drawing on canvas using mouse or touch
9791 */
9792function Scribble( canvasID,image,_width,_height, callback) {
9793    this._callback = callback;
9794    this.canvasID = canvasID;
9795    this._lineWidth=5;
9796    this.canvas = $("#"+canvasID);
9797    this.context = this.canvas.get(0).getContext("2d"); 
9798    this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
9799    this._enabled=true;
9800    this.context.strokeStyle = "#000000";
9801    this.canvasBorderWidth = parseInt(this.canvas.css('border-left-width'),10); // assuming top and left borders are same width
9802    this.context.lineWidth = this._lineWidth;
9803    this.lastMousePoint = {x:0, y:0};
9804    
9805    this.canvas[0].width = _width;// this.canvas.parent().innerWidth();
9806    this.canvas[0].height = _height;//this.canvas.parent().innerHeight();
9807    if(!image){
9808        this.context.fillStyle   = '#ffffff';
9809        this.context.clearRect(0,0,_width,_height);
9810    } else {
9811        this.context.drawImage(image,0,0);
9812    }
9813    this.canvas.on( TouchUtil.POINTER_DOWN, this.onCanvasMouseDown() );
9814}
9815Scribble.prototype.setLineWidth=function(w){
9816    this._lineWidth=w;
9817};
9818Scribble.prototype.onCanvasMouseDown = function () {
9819    var self = this;
9820    return function(event) {
9821        if(TouchUtil.getTouches(event).length < 2){
9822            self.mouseMoveHandler = self.onCanvasMouseMove();
9823            self.mouseUpHandler = self.onCanvasMouseUp();
9824            //CQ-4261765 : Scribble sign scroll issue with ios
9825            //https://stackoverflow.com/questions/49500339/cant-prevent-touchmove-from-scrolling-window-on-ios
9826            //https://github.com/jquery/jquery/issues/2871
9827            document.addEventListener(TouchUtil.POINTER_MOVE, self.mouseMoveHandler,{ passive: false });
9828            $(document).on(TouchUtil.POINTER_UP, self.mouseUpHandler );
9829            self.updateMousePosition( event );
9830            self.updateCanvas( event );
9831        }
9832    }
9833};
9834
9835Scribble.prototype.onCanvasMouseMove = function () {
9836    var self = this;
9837    return function(event) {
9838        if(TouchUtil.getTouches(event).length < 2){
9839            self.updateCanvas( event );
9840            event.preventDefault();
9841            return false;
9842        }
9843    }
9844};
9845
9846Scribble.prototype.onCanvasMouseUp = function (event) {
9847    var self = this;
9848    return function(event) {
9849        document.removeEventListener(TouchUtil.POINTER_MOVE, self.mouseMoveHandler,{ passive: false });
9850        $(document).off(TouchUtil.POINTER_UP, self.mouseUpHandler );
9851        self.mouseMoveHandler = null;
9852        self.mouseUpHandler = null;
9853    }
9854};
9855
9856Scribble.prototype.updateMousePosition = function (event) {
9857    if(!this._enabled) return ;
9858    var target = TouchUtil.getTouchEvent(event);
9859
9860    var offset = this.canvas.offset();
9861    /* In IE>=10 pageX values are incorrect when using zoom
9862     so calculate them using clientX and scrollLeft */
9863    this.lastMousePoint.x = target.clientX + $(window).scrollLeft() - offset.left - this.canvasBorderWidth;
9864    this.lastMousePoint.y = target.clientY + $(window).scrollTop() - offset.top - this.canvasBorderWidth;
9865
9866};
9867Scribble.prototype._isInsideCanvas = function(x,y){
9868    return y>=0 && y<this.canvas[0].height && x>=0 && x < this.canvas[0].width;
9869};
9870    Scribble.prototype.updateCanvas = function (event) {
9871    if(!this._enabled) {
9872       return;
9873    }
9874    var oldX,oldY,dX,dY,canDraw,scaleX,scaleY,cssWidth,cssHeight;
9875    cssWidth = parseInt(this.canvas[0].style.width,10);
9876    cssHeight = parseInt(this.canvas[0].style.height,10);
9877    scaleX =  cssWidth?this.canvas[0].width/cssWidth:1;
9878    scaleY = cssHeight?this.canvas[0].height/cssHeight:1;
9879
9880    scaleX /= xfalib.ut.XfaUtil.prototype.formScaleFactor;
9881    scaleY /= xfalib.ut.XfaUtil.prototype.formScaleFactor;
9882
9883    oldX = this.lastMousePoint.x*scaleX;
9884    oldY = this.lastMousePoint.y*scaleY;
9885   
9886    this.updateMousePosition( event );
9887
9888    var newX =  this.lastMousePoint.x*scaleX;
9889    var newY =  this.lastMousePoint.y*scaleY;
9890
9891    dX = Math.abs(newX - oldX );
9892    dY = Math.abs(newY - oldY );
9893
9894    canDraw = ( dX > 0 || dY > 0 ) && this._isInsideCanvas(oldX,oldY) && this._isInsideCanvas(newX,newY);;
9895
9896    if(canDraw){
9897        this.context.beginPath();
9898        this.context.moveTo( oldX, oldY );
9899        this.context.lineTo(newX, newY );
9900        this.context.lineWidth=this._lineWidth;
9901        this.context.lineCap='round';
9902        this.context.stroke();
9903		
9904        this._callback();
9905		
9906    }
9907};
9908
9909Scribble.prototype.toString = function () {
9910
9911    var dataString = this.canvas.get(0).toDataURL("image/png");
9912    //var index = dataString.indexOf( "," )+1;
9913    //dataString = dataString.substring( index );
9914
9915    return dataString;
9916};
9917Scribble.prototype.setEnabled=function(enable){
9918    this._enabled=enable;
9919};
9920Scribble.prototype.clear = function () {
9921
9922    var c = this.canvas[0];
9923    this.context.clearRect( 0, 0, c.width, c.height );
9924};
9925
9926
9927// ImageEdit dialog box
9928var imageEditDialog=(function(_){
9929  
9930    // html used to construct dialog box
9931    var htmlStr=(function(){
9932         var html=[
9933             '<div id="iEBox_container" tabindex="0" role="dialog" aria-label="'+ScribbleUtil.localeString("pleaseSignText")+'">',
9934                  '<div id="iEBox_panel">',
9935                      '<div  id = "iEBox_Cancel" class="iEBox_button" tabindex="0" role="button" aria-label="'+ScribbleUtil.localeString("cancel")+'" title="'+ScribbleUtil.localeString("cancel")+'" ></div>',
9936                  '</div>',
9937                  '<div id="iEBox_content">',
9938                      '<div id="iEBox_canvases" align=center>',
9939                          '<div style="display:inline-block; vertical-align:top;">',
9940                               '<canvas  id="iEBox_canvas" style="margin:0px;border-bottom:0px;" width="696" height="390" ></canvas>' ,
9941                               '<input type="text" id="keyboard_Sign_Box" name="signatureText" placeholder="'+ScribbleUtil.localeString("typeYourSignatureHere")+'">',
9942                               '<fieldset id="iEBox_caption"><legend align="center">
9942'+ScribbleUtil.localeString("pleaseSignText")+'</legend></fieldset>',
9943                          '</div>',
9944                          '<canvas id="iEBox_geoCanvasRight" width="0" height="0" ></canvas>',
9945                          '<div><canvas id="iEBox_geoCanvasBottom" width="0" height="0" ></canvas></div>',
9946                      '</div>',
9947                      '<div>',
9948                          '<div id="iEBox_Brush" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("brushes")+'"  title="'+ScribbleUtil.localeString("brushes")+'"></div>',
9949                          '<div id="iEBox_Clear" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("clear")+'"  title="'+ScribbleUtil.localeString("clear")+'" ></div>',
9950                          '<div id="iEBox_Geo" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("geolocation")+'"  title="'+ScribbleUtil.localeString("geolocation")+'" ></div>',
9951                          '<div id="iEBox_Text" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("typeYourName")+'"  title="'+ScribbleUtil.localeString("typeYourName")+'"></div>',
9952                          '<div id="iEBox_title"></div>',
9953                          '<div id="iEBox_Ok" class="iEBox_button" tabindex="0"  role="button" aria-label="'+ScribbleUtil.localeString("ok")+'"  title="'+ScribbleUtil.localeString("ok")+'" ></div>',
9954                      '</div>' ,
9955                  '</div>' ,
9956                  '<div id="iEBox_moveframe" ></div>',
9957                  '<div id="iEBox_brushList" ></div>',
9958              '</div>'].join("");
9959           return function(){
9960              return html;
9961           };
9962    });
9963	
9964    /**
9965	 *   
9966	 */
9967	
9968    var dialogObj = {
9969        verticalOffset: 0, // removing the magic value of -75 since it was not causing any impact
9970        horizontalOffset: 0,
9971        repositionOnResize: true,
9972        overlayOpacity: .75,
9973        overlayColor: '#CCCCCC',
9974        draggable: true,
9975        _brushes:[2,3,4,5,6,7,8,9,10],
9976		_buttonsEnabled:{},
9977		_isOpen:false,
9978        show:function(title,callback){
9979           this._show(callback);
9980		   this._buttonsEnabled={Geo:true,Clear:true,Ok:true,Cancel:true,Brush:true,Text:true};
9981        },
9982		setEnabled:function(button,enable){
9983		    if(this._buttonsEnabled[button]!=enable){
9984		           this._buttonsEnabled[button]=enable;
9985				   if(enable){
9986				       $('#iEBox_'+button).empty('<div style="background:white;width:100%;height:100%;opacity:0.75;"></div>').
9987				                  removeClass("disable_button");
9988				   } else {
9989				       $('#iEBox_'+button).append('<div style="background:white;width:100%;height:100%;opacity:0.75;"></div>').
9990				                  addClass("disable_button");
9991				   }
9992			       
9993			}
9994		},
9995		enableButtons:function(buttons){
9996		    for(var k in buttons){
9997				   this.setEnabled(k,buttons[k]);
9998			}
9999		},
10000        toggleBrushList:function(event){
10001                var that = this;
10002                if($('#iEBox_brushList').css('display')!='none'){
10003                    $('#iEBox_brushList').css({display:'none'});
10004                    return;
10005                }
10006                 var tmpFn =  document.onselectstart;
10007                 document.onselectstart=function(){return false;};
10008                 $('#iEBox_brushList').css({display:'block',visibility:'hidden'});
10009                    $('#iEBox_brushList').offset($('#iEBox_Brush').offset());
10010                    $('#iEBox_brushList').offset({top:$('#iEBox_Brush').offset().top-$('#iEBox_brushList').height()});
10011                    $('#iEBox_brushList').css({display:'block',visibility:'visible'});
10012                  //  $('#iEBox_brushList').focus();
10013                     $('#iEBox_brushList').one('mouseleave',function(event){
10014                         $('#iEBox_brushList').css({display:'none'});
10015                          document.onselectstart=tmpFn;
10016                     });
10017        },
10018        _attachCallbacks: function(callback) {
10019            var that = this;
10020            var sigCanvas = $('#iEBox_canvas')[0];
10021            var ctx=sigCanvas.getContext("2d");
10022            var minSigCanvasFontSize=10;
10023            var maxSigCanvasFontSize=70;
10024            var sigCanvasFontSize=minSigCanvasFontSize;
10025            var initialSigCanvasFontSize=sigCanvasFontSize;
10026            var initialFontCalculatedFlag=false;
10027            var sigCanvasFontFamily="sans-serif, Georgia";
10028            var sigCanvasFontStyle="italic";
10029           _.each("Cancel-Clear-Geo-Ok-Brush-Text".split("-"),function(val,idx){
10030                    $("#iEBox_"+val).click( function(event) {
10031				       if(that._buttonsEnabled[val]){
10032                          event.stopPropagation();
10033                          callback(val);
10034				       }
10035                    });
10036					$("#iEBox_"+val).keydown( function(event) {
10037				       if(that._buttonsEnabled[val] && (event.keyCode == ENTER_KEY || event.charCode == ENTER_KEY || event.which == ENTER_KEY) ){
10038                          event.stopPropagation();
10039                          callback(val);
10040				       }
10041                    });
10042            });
10043            _.each($("#iEBox_brushList").children(),function(itm,idx){
10044                  $(itm).on(TouchUtil.POINTER_UP,function(event){
10045                         callback("BrushSelect",that._brushes[idx]);
10046                         $('#iEBox_brushList').css({display:'none'});
10047                          // $(itm).css({backgroundColor:'#FFFFFF'});
10048                  });
10049                  $(itm).on(TouchUtil.POINTER_DOWN,function(event){
10050                          // $(itm).css({backgroundColor:'#AAAAAA'});
10051                           event.preventDefault();
10052                  });
10053             });
10054
10055            $('#keyboard_Sign_Box').keydown(function (event){
10056                var inputSign=$('#keyboard_Sign_Box')[0].value;
10057
10058                if(event.key==="Backspace") {
10059                    ctx.font=sigCanvasFontStyle+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10060                    sigCanvasFontSize=dialogObj._increaseFontForSignature(ctx.measureText(inputSign).width,sigCanvas.width,
10061                        sigCanvasFontSize,initialSigCanvasFontSize);
10062                    ctx.font=sigCanvasFontStyle+" "+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10063                    ctx.clearRect(0, 0, sigCanvas.width, sigCanvas.height);
10064                    ctx.fillText(inputSign, 3, sigCanvasFontSize, sigCanvas.width-5);
10065                }
10066                event.stopPropagation();
10067            });
10068
10069            $("#keyboard_Sign_Box").keyup(function (event){
10070                var inputSign=$('#keyboard_Sign_Box')[0].value;
10071                if(inputSign.length==0) {
10072                    dialogObj.enableButtons({Ok: false, Clear: false});
10073                }
10074                if(inputSign.length>=1 && inputSign.trim().length!=0) {
10075                    dialogObj.enableButtons({Ok: true, Clear: true});
10076                }
10077                if(initialFontCalculatedFlag===false){
10078                    sigCanvasFontSize=sigCanvas.height-20;
10079                    sigCanvasFontSize=sigCanvasFontSize<minSigCanvasFontSize?minSigCanvasFontSize:sigCanvasFontSize;
10080                    sigCanvasFontSize=sigCanvasFontSize>maxSigCanvasFontSize?maxSigCanvasFontSize:sigCanvasFontSize;
10081                    initialSigCanvasFontSize=sigCanvasFontSize;
10082                    $('#keyboard_Sign_Box')[0].style.font=sigCanvasFontStyle+" 2rem "+sigCanvasFontFamily;
10083                    initialFontCalculatedFlag=true;
10084                }
10085                ctx.font=sigCanvasFontStyle+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10086                sigCanvasFontSize=dialogObj._decreaseFontForSignature(ctx,inputSign,sigCanvas.width,
10087                    sigCanvasFontSize,sigCanvasFontFamily);
10088                ctx.font=sigCanvasFontStyle+" "+sigCanvasFontSize+"px "+sigCanvasFontFamily;
10089                ctx.clearRect(0, 0, sigCanvas.width, sigCanvas.height);
10090                ctx.fillText(inputSign,3,sigCanvasFontSize,sigCanvas.width-5);
10091                event.stopPropagation();
10092            });
10093
10094            // capture tab key and escape
10095			$('#iEBox_container').keydown(function(event){
10096			    var firstFocusableItem = document.querySelector("#iEBox_container");
10097                var lastFocusableItem = document.querySelector("#iEBox_Ok");
10098                var KEYCODE_TAB = 9;
10099                var isTabPressed = (event.key === 'Tab' || event.keyCode === KEYCODE_TAB);
10100                if((event.keyCode == ESC_KEY || event.charCode == ESC_KEY || event.which == ESC_KEY)) {
10101                    event.stopPropagation();
10102               	    event.preventDefault();
10103               	    callback("Cancel");
10104                } else if (isTabPressed) {
10105                    // Trap focus inside the dialog box
10106                    if (event.shiftKey && document.activeElement === firstFocusableItem) {
10107                        // when shift + tab key is pressed
10108                        lastFocusableItem.focus();
10109                        event.preventDefault();
10110                    } else if (document.activeElement === lastFocusableItem) {
10111                        // when tab key is pressed
10112                        firstFocusableItem.focus();
10113                        event.preventDefault();
10114                    }
10115               }
10116
10117            });
10118
10119            if(this.draggable){
10120                this._makeDraggable(TouchUtil.TOUCH_ENABLED);
10121            }
10122        },
10123
10124        _decreaseFontForSignature:function(ctx,inputSign,sigCanvasWidth,fontSize,sigCanvasFontFamily){
10125            while(ctx.measureText(inputSign).width>sigCanvasWidth-5 && fontSize>20){
10126                fontSize=fontSize-10;
10127                ctx.font=fontSize+"px "+sigCanvasFontFamily;
10128            }
10129            return fontSize
10130        },
10131        _increaseFontForSignature:function(textWidth,sigCanvasWidth,fontSize,initialSigCanvasFontSize){
10132            if(sigCanvasWidth-textWidth>0){
10133                fontSize=initialSigCanvasFontSize;
10134            }
10135            return fontSize;
10136        },
10137        _makeDraggable:function(touchEnabled){
10138              var _isMouseDown=false;
10139              var _that=this;
10140              var dX;
10141              var dY;
10142              var offsetPos;
10143              var _mouseMovFun;
10144              var _mouseUpFun;
10145              $('#iEBox_panel').on(TouchUtil.POINTER_DOWN,function( event ){
10146              
10147                  if(TouchUtil.getTouches(event).length < 2){
10148                      if($(event.target).is('#iEBox_panel')){
10149                          $('body')[0].addEventListener(TouchUtil.POINTER_MO
10149VE,_mouseMovFun=function( event ){
10150                              if(TouchUtil.getTouches(event).length < 2 && _isMouseDown){
10151                                  event.preventDefault();
10152                                  var evt = TouchUtil.getTouchEvent(event);
10153                                  var delX = evt.pageX - dX;
10154                                  var delY = evt.pageY - dY;
10155                                  $('#iEBox_moveframe').offset({
10156                                      top: offsetPos.top+delY,
10157                                      left: offsetPos.left+delX
10158                                  });
10159                              }
10160                          }, { passive: false });
10161                          $('body').on(TouchUtil.POINTER_UP,_mouseUpFun=function(event){
10162                              if(_isMouseDown){
10163                                  var offsetMove = $('#iEBox_moveframe').offset();
10164                                  var topEdge  = $(window).scrollTop();
10165                                  var bottomEdge = topEdge + $(window).height();
10166                                  if(offsetMove.top - topEdge < 1){
10167                                      offsetMove.top = topEdge;
10168                                  }
10169                                  if(offsetMove.top - bottomEdge + $('#iEBox_panel').height() > 0 ){
10170                                      offsetMove.top = bottomEdge - $('#iEBox_panel').height();
10171                                  }
10172                                  $('#iEBox_container').offset(offsetMove );
10173                                  $('#iEBox_moveframe').css({display:'none'}).offset(offsetMove);
10174                                  _isMouseDown=false;
10175                                  $('body')[0].removeEventListener(TouchUtil.POINTER_MOVE,_mouseMovFun,{ passive: false });
10176                                  $('body').off(TouchUtil.POINTER_UP,_mouseUpFun);
10177                              }
10178                          });
10179
10180                          var evt = TouchUtil.getTouchEvent(event);
10181                          _isMouseDown=true; dX = evt.pageX;dY=evt.pageY;
10182                          offsetPos = $('#iEBox_container').offset();
10183                          $('#iEBox_moveframe').css({display:'block'});
10184                          $('#iEBox_moveframe').offset(offsetPos);
10185                          $('#iEBox_moveframe').css('width',$('#iEBox_container').css('width'));
10186                          $('#iEBox_moveframe').css('height',$('#iEBox_container').css('height'));
10187                      }
10188                  }
10189              });
10190             
10191        },
10192        _createBrushes:function(){
10193               var _that=this;
10194              _.each(this._brushes,function(val,idx){
10195                  var divel = document.createElement('DIV');
10196                  var cnv = document.createElement('CANVAS');
10197                  var ctx = cnv.getContext('2d');
10198                  cnv.style.border='1px solid #AAAAAA';
10199                  cnv.width=TouchUtil.TOUCH_ENABLED?200:100;
10200                  cnv.height=TouchUtil.TOUCH_ENABLED?40:20;;
10201                  ctx.lineWidth=val;
10202                  ctx.beginPath();
10203                  ctx.moveTo(10,cnv.height/2);
10204                  ctx.lineTo(cnv.width-10,cnv.height/2);
10205                  ctx.stroke();
10206                  divel.appendChild(cnv);
10207                  $('#iEBox_brushList').append(divel);
10208               });
10209        },
10210		getIsOpen:function(){
10211		    return dialogObj._isOpen;
10212		},
10213		setIsOpen:function(open){
10214		    dialogObj._isOpen = open;
10215		},
10216        _show: function(callback) {
10217            dialogObj.hide();
10218            dialogObj._overlay('show');
10219            
10220            $("BODY").append(htmlStr());
10221            dialogObj.setIsOpen(true);
10222            $('#iEBox_container').focus();
10223            dialogObj._createBrushes();
10224
10225            dialogObj._reposition();
10226
10227            // calculate spacing around canvas area
10228            // this will be used to find canvas dimensions based on available screen area.
10229            var container_el = $('#iEBox_container');
10230            var canvas_el =  $('#iEBox_canvas');
10231            var container_width = $('#iEBox_container').outerWidth(true);
10232            var container_height = $('#iEBox_container').outerHeight(true);
10233            var canvas_width = canvas_el[0].width;
10234            var canvas_height = canvas_el[0].height;
10235            dialogObj.canvas_spacing = { x:container_width - canvas_width, y:container_height-canvas_height};
10236
10237            dialogObj._maintainPosition(true);
10238            
10239            dialogObj._attachCallbacks(callback);
10240        },
10241
10242        hide: function() {
10243            $("#iEBox_container").remove();
10244            this._overlay('hide');
10245            dialogObj.setIsOpen(false);
10246            this._maintainPosition(false);
10247        },
10248        _overlayResize:function(event) {
10249            if($("#iEBox_overlay").height()!= $(document).height()){
10250                $("#iEBox_overlay").height( $(document).height() );
10251            }
10252
10253        },
10254        _disableMove:function(event) {
10255            event.preventDefault();
10256        },
10257        _overlay: function(status) {
10258            switch( status ) {
10259                case 'show':
10260                    this._overlay('hide');
10261                    $("BODY").append('<div id="iEBox_overlay"></div>');
10262                    $("#iEBox_overlay").css({
10263                        position: 'fixed',
10264                        zIndex: 99997,
10265                        top: '0px',
10266                        left: '0px',
10267                        width: '100%',
10268                        height: $(document).height(),
10269                        background: this.overlayColor,
10270                        opacity: this.overlayOpacity
10271                    });
10272                    if(xfalib.ut.XfaUtil.prototype.isSafari()) {
10273                        $("#iEBox_overlay").on('touchmove', this._disableMove);
10274                    }
10275                    $(document).on('scroll',this._overlayResize);
10276                break;
10277                case 'hide':
10278                    if(xfalib.ut.XfaUtil.prototype.isSafari()) {
10279                        $("#iEBox_overlay").off('touchmove');
10280                    }
10281                    $("#iEBox_overlay").remove();
10282                    $(document).off('scroll',this._overlayResize);
10283                break;
10284            }
10285        },
10286        /**
10287         * resize dialog based on available screen area
10288         */
10289        _resize:function(){
10290            // available screen area
10291            var aWidth = $(window).width();
10292            var aHeight = $(window).height();
10293
10294            var sigCnv = $('#iEBox_canvas')[0];
10295            var sigTextBox = $('#keyboard_Sign_Box')[0];
10296            var bGeoCnv = $('#iEBox_geoCanvasBottom')[0];
10297            var rGeoCnv = $('#iEBox_geoCanvasRight')[0];
10298
10299            // calculate amount of width height we need to reduce
10300
10301            var totalCnvWidth = sigCnv.width + rGeoCnv.width;
10302            var totalCnvHeight = sigCnv.height + bGeoCnv.height;
10303
10304
10305
10306
10307
10308            var diffW = totalCnvWidth + dialogObj.canvas_spacing.x - aWidth;
10309            if(diffW < 0) {
10310                diffW = 0;
10311            }
10312            var diffH = totalCnvHeight + dialogObj.canvas_spacing.y - aHeight;
10313            if(diffH < 0){
10314                diffH = 0;
10315            }
10316
10317            var newTotalCnvHeight, newTotalCnvWidth;
10318            if( diffW > 0 || diffH > 0 ){ // does any side need resize
10319
10320                if(diffH * totalCnvWidth > totalCnvHeight * diffW){ // need to reduce height
10321                   newTotalCnvHeight = totalCnvHeight - diffH;
10322                   newTotalCnvWidth = (newTotalCnvHeight * totalCnvWidth)/ totalCnvHeight;
10323                } else {
10324                   newTotalCnvWidth = totalCnvWidth - diffW;
10325                   newTotalCnvHeight = (newTotalCnvWidth * totalCnvHeight)/ totalCnvWidth;
10326                }
10327
10328                // distribute evenly the new dimensions
10329
10330
10331                var newSigCnvWidth   = (newTotalCnvWidth*sigCnv.width)/totalCnvWidth;
10332                var newSigCnvHeight = (newTotalCnvHeight*sigCnv.height)/totalCnvHeight;
10333
10334                sigCnv.style.width = newSigCnvWidth + "px";
10335                sigCnv.style.height = newSigCnvHeight + "px";
10336
10337                sigTextBox.style.width = newSigCnvWidth + "px";
10338                sigTextBox.style.height = newSigCnvHeight + "px";
10339
10340
10341                bGeoCnv.style.width = newSigCnvWidth +"px";
10342                bGeoCnv.style.height = (newTotalCnvHeight - newSigCnvHeight) +"px";
10343
10344                rGeoCnv.style.width = (newTotalCnvWidth - newSigCnvWidth) +"px";
10345                rGeoCnv.style.height = newSigCnvHeight + "px";
10346
10347
10348                $('#iEBox_caption').width(Math.floor(newSigCnvWidth));
10349
10350            } else {
10351                sigCnv.style.width =  sigCnv.width + "px";
10352                sigCnv.style.height = sigCnv.height + "px";
10353
10354                sigTextBox.style.width =  sigCnv.width + "px";
10355                sigTextBox.style.height = sigCnv.height + "px";
10356
10357                bGeoCnv.style.width =  bGeoCnv.width + "px";
10358                bGeoCnv.style.height = bGeoCnv.height + "px";
10359
10360                rGeoCnv.style.width =  rGeoCnv.width + "px";
10361                rGeoCnv.style.height = rGeoCnv.height + "px";
10362
10363                $('#iEBox_caption').width(sigCnv.width);
10364
10365            }
10366        },
10367        _reposition: function() {
10368            var top = (($(window).height() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) / 2) - ($("#iEBox_container").outerHeight() / 2)) + dialogOb
10368j.verticalOffset;
10369            var left = (($(window).width() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) / 2) - ($("#iEBox_container").outerWidth() / 2)) + dialogObj.horizontalOffset;
10370            if( top < 0 ) top = 0;
10371            if( left < 0 ) left = 0;
10372
10373            $("#iEBox_container").css({
10374                top: top + $(window).scrollTop() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + 'px',
10375                left: left + $(window).scrollLeft() * (1 / xfalib.ut.XfaUtil.prototype.formScaleFactor) + 'px'
10376            });
10377            $("#iEBox_container").focus();   // scroll up to the canvas
10378            $("#iEBox_overlay").height( $(document).height() );
10379        },
10380        _maintainDialog:function(){
10381            dialogObj._resize();
10382            dialogObj._reposition();
10383        },
10384        _maintainPosition: function(status) {
10385            if(dialogObj.repositionOnResize ) {
10386                switch(status) {
10387                    case true:
10388                        $(window).on('orientationchange', dialogObj._maintainDialog); // also reposition if device is tilted
10389                    break;
10390                    case false:
10391                        $(window).off('orientationchange', dialogObj._maintainDialog);
10392                    break;
10393                }
10394            }
10395        }
10396        
10397    };
10398    return dialogObj;
10399})(window._);
10400
10401/**
10402 * class definition for GeoLocationQueryRequest
10403 * encapsulated success and error handlers 
10404 */
10405function GeoLocQuery(){}
10406GeoLocQuery.prototype={
10407    init:function(success,failure){
10408        this._successHandler = success;
10409        this._errorHandler = failure;
10410        this._active=true;
10411        return this;
10412    },
10413    _handleSuccess:function(data){
10414        this._successHandler(data); 
10415    },
10416    _handleError:function(err){
10417        this._errorHandler(err);   
10418    },
10419    query:function(){
10420         _that=this;
10421         navigator.geolocation.getCurrentPosition(function(pos){
10422          if(_that._active){
10423             _that._handleSuccess(pos);
10424          }
10425          _that._active=false;
10426       },function(err){
10427          if(_that._active){
10428             _that._handleError(err);
10429          }
10430          _that._active=false;
10431       },{timeout:10000});
10432    },
10433    cancel:function(){
10434        _that._active=false;
10435    }
10436
10437};
10438// GeoLocQuery definition ends here
10439
10440/**
10441*
10442*  Base64 encode / decode
10443*  http://www.webtoolkit.info/
10444*
10445**/
10446 
10447var Base64 = {
10448 
10449	// private property
10450	_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
10451 
10452	// public method for encoding
10453	encode : function (input) {
10454		var output = "";
10455		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
10456		var i = 0;
10457 
10458		while (i < input.length) {
10459 
10460			chr1 = input.charCodeAt(i++);
10461			chr2 = input.charCodeAt(i++);
10462			chr3 = input.charCodeAt(i++);
10463 
10464			enc1 = chr1 >> 2;
10465			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
10466			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
10467			enc4 = chr3 & 63;
10468 
10469			if (isNaN(chr2)) {
10470				enc3 = enc4 = 64;
10471			} else if (isNaN(chr3)) {
10472				enc4 = 64;
10473			}
10474 
10475			output = output +
10476			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
10477			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
10478 
10479		}
10480 
10481		return output;
10482	},
10483 
10484	// public method for decoding
10485	decode : function (input) {
10486		var output = "";
10487		var chr1, chr2, chr3;
10488		var enc1, enc2, enc3, enc4;
10489		var i = 0;
10490 
10491		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
10492 
10493		while (i < input.length) {
10494 
10495			enc1 = this._keyStr.indexOf(input.charAt(i++));
10496			enc2 = this._keyStr.indexOf(input.charAt(i++));
10497			enc3 = this._keyStr.indexOf(input.charAt(i++));
10498			enc4 = this._keyStr.indexOf(input.charAt(i++));
10499 
10500			chr1 = (enc1 << 2) | (enc2 >> 4);
10501			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
10502			chr3 = ((enc3 & 3) << 6) | enc4;
10503 
10504			output = output + String.fromCharCode(chr1);
10505 
10506			if (enc3 != 64) {
10507				output = output + String.fromCharCode(chr2);
10508			}
10509			if (enc4 != 64) {
10510				output = output + String.fromCharCode(chr3);
10511			}
10512 
10513		}
10514 
10515		return output;
10516 
10517	}
10518 
10519	
10520 
10521};
10522
10523/**
10524 * Utility Singleton for handling PNG Data
10525 */
10526var PNGUtil=(function(){
10527    var slf={
10528   _LC_Scribble_MetaDataKey:"LC_SCIBBLE_METADATA",
10529           _isPng:function(b64data){
10530               return  b64data && b64data.replace(/\s+/g, "").indexOf("iVBORw0KGgo") == 0;   // LC-5711 : trim any leading WhiteSpace
10531               // 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
10532           },
10533           _update_crc:function(crc,data){
10534               var c = crc;
10535               var n;
10536               for(n=0;n<data.length;n++){
10537                  c = this._XOR(slf._crc_table[(this._XOR(c,data.charCodeAt(n))&0xff)>>>0],(c>>>8));
10538               }
10539               return c;
10540           },
10541		   _XOR:function(a,b){
10542		       return (a^b)>>>0;
10543		   },
10544           _U32Int2Str:function(n){
10545                return String.fromCharCode((n>>>24)&0xFF)+String.fromCharCode((n>>>16)&0xFF)+String.fromCharCode((n>>>8)&0xFF)+String.fromCharCode(n>>>0&0xFF);
10546            },
10547           _init_crc_table:function(){
10548               var c=0;
10549               var n,k;
10550               slf._crc_table=[];
10551               for(n=0;n<256;n++){
10552                   c = n;
10553                   for(k=0;k<8;k++){
10554                      if(((c&1)>>>0)>0){
10555                          c = slf._XOR(0xedb88320 , (c>>>1));
10556                      } else {
10557                          c = c>>>1;
10558                      }
10559                   }
10560                   slf._crc_table[n]=c;
10561                }
10562           },
10563           _CRC:function(data){
10564                if(!this._crc_table) this._init_crc_table();
10565                return this._XOR(this._update_crc(0xffffffff,data) , 0xffffffff);
10566          },
10567          _prepareTextChunk:function(content,pad){
10568              // pad the data appropriately                      
10569               var len = content.length;
10570               var lenStr = slf._U32Int2Str(len);
10571               var chunkType="tEXt";
10572               var checkSumStr = slf._U32Int2Str(slf._CRC(chunkType+content));
10573               return lenStr+chunkType+content+checkSumStr;
10574           },
10575        _start:function(str){
10576           slf._startTime = new Date().getTime();
10577           slf._startFun=str;
10578        },
10579        _end:function(){
10580           var str = "Time "+slf._startFun+": "+(new Date().getTime()-slf._startTime);
10581          //  $('BODY').append("<p>"+str+"</p><br/>");
10582        },
10583        _readU32Int:function(ctx){
10584            var val=0;
10585            var d=ctx.d;
10586            val=((d.charCodeAt(ctx.p++)<<24)|(d.charCodeAt(ctx.p++)<<16)|(d.charCodeAt(ctx.p++)<<8)|(d.charCodeAt(ctx.p++)))>>>0;
10587             return val;
10588        },
10589       _readChunkType:function(ctx){
10590          var d = ctx.d;
10591          var str = d[ctx.p++]+d[ctx.p++]+d[ctx.p++]+d[ctx.p++];
10592          return str;
10593       },
10594        _makeReadOnly:function(b64data){
10595      slf._start("_makeReadOnly");
10596      // assume a valid png image encoded in base64;
10597      var bindata = slf._atob(b64data.replace(/\s+/g, '')); // remove white spaces that might have been inserted
10598      var pngctx={p:0,d:bindata};
10599      pngctx.p+=8;// skip pngheader
10600      // read IHDR
10601      var size = slf._readU32Int(pngctx);
10602      slf._readChunkType(pngctx); //IHDR
10603      pngctx.p+=size; //Data
10604      slf._readU32Int(pngctx);//CRC
10605      var metadataChunk = slf._prepareTextChunk(slf._LC_Scribble_MetaDataKey+String.fromCharCode(0)+"true");
10606      var newdata = pngctx.d.substring(0,pngctx.p)+metadataChunk+pngctx.d.substring(pngctx.p);
10607      var ret= slf._btoa(newdata);
10608      slf._end();
10609      return ret;
10610   },
10611   _atob:function(inp){
10612      if(window.atob){ return atob(inp); }
10613	  return Base64.decode(inp);
10614   },
10615   _btoa:function(inp){
10616      if(window.btoa){ return btoa(inp); }
10617	  return Base64.encode(inp);
10618   },
10619   _isReadOnly:function(b64data){
10620    slf._start("_isReadOnly");
10621       if(slf._isPng(b64data)){
10622           var testStr = slf._LC_Scribble_MetaDataKey+String.fromCharCode(0)+"true";
10623           var bindata = slf._atob(b64data.replace(/\s+/g, ''));
10623 // strip white spaces
10624           var pngctx={p:0,d:bindata};
10625           pngctx.p+=8;// skip header
10626           while(pngctx.p<pngctx.d.length){
10627               var size = slf._readU32Int(pngctx);
10628               var type = slf._readChunkType(pngctx);
10629               if(type=="tEXt"){
10630                   if(pngctx.d.indexOf(testStr,pngctx.p)==pngctx.p){
10631                       slf._end();
10632                       return true;
10633                   }
10634                  
10635              }
10636              pngctx.p+=size;
10637              slf._readU32Int(pngctx);// 
10638          }// while end
10639       }
10640       slf._end();
10641       return false;
10642   }
10643    };
10644    return slf;
10645})();
10646
10647/**
10648 * JQuery widget definition starts here
10649 */
10650$.widget( "xfaWidget.ScribbleImageField", $.xfaWidget.imageField, {
10651
10652    _widgetName:"ScribbleImageField",
10653    _geoLocQuery:null,
10654   _emptyImageVal:null,// should be null, but for now
10655   _extraInfo:null,
10656   _defaultStatus:"&nbsp;",
10657   _enforceGeoLoc:!!navigator.userAgent.match(/iPad/i),
10658   _sigCanvasWidth:696,
10659   _sigCanvasHeight:390,
10660   _geoCanvId:null,
10661    _geoLocAtBottom:false,
10662   _geoCanvasHeight:100,
10663   _geoCanvasWidth:696,
10664   
10665    _is_readonly:false,
10666	
10667    options: {
10668        tabIndex: 0,
10669        "role": "img"
10670    },
10671
10672    getOptionsMap: function() {
10673        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getOptionsMap.apply(this,arguments);
10674        return $.extend({},parentOptionsMap,{
10675            "displayValue": function(val) {
10676                if(this.options.commitProperty) {
10677                    if(!val){
10678                        this._displayValue(this._extractData(this._createEmptyImageData()));
10679                        this.$userControl.addClass("emptyScribble");
10680                        this._is_readonly=false;
10681                    } else {
10682                        this.$userControl.removeClass("emptyScribble");
10683                        if(PNGUtil._isPng(val)){
10684                            var widgetValue = "data:image/png;base64,"+this.options.value;
10685                        }else {
10686                            var widgetValue = "data:;base64," + this.options.value;
10687                        }
10688                        this._setValue(widgetValue);
10689                    }
10690                }
10691            }
10692        })
10693    },
10694
10695    getEventMap: function() {
10696        var parentOptionsMap = $.xfaWidget.defaultWidget.prototype.getEventMap.apply(this,arguments);
10697        return $.extend({},parentOptionsMap,{
10698            "scribblefocus":xfalib.ut.XfaUtil.prototype.XFA_ENTER_EVENT,
10699            "click":null,
10700            "scribbleclick":xfalib.ut.XfaUtil.prototype.XFA_CLICK_EVENT,
10701            "change":null,
10702            "scribblechange":xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT,
10703            "blur":null,
10704            "scribbleclose":xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT
10705        })
10706    },
10707
10708	/**
10709	 * This function achieves following
10710	 * 1. Calculate dimensions of canvases to be used
10711	 * 2. Findout if right or bottom canvas is to be used for geo location
10712	 */
10713
10714	 aspectRatioToBeUsed :function(){
10715        var aspectRatio ;
10716        if(this.options.aspectRatio && parseFloat(this.options.aspectRatio) > 0){
10717           aspectRatio = 1/parseFloat(this.options.aspectRatio);  //--in MF ratio is computed as height/width instead of width/height
10718        } else {
10719           var imgEl = this.element.children("img"),
10720               width = imgEl.attr('width'),
10721               height = imgEl.attr('height'),
10722               fieldWidth,
10723               fieldHeight;
10724
10725           if(width){
10726              fieldWidth = parseInt(width,10);
10727           } else {
10728              fieldWidth = imgEl.width();
10729           }
10730           if(height){
10731              fieldHeight = parseInt(height,10);
10732           } else {
10733              fieldHeight = imgEl.height();
10734           }
10735           aspectRatio = fieldHeight/fieldWidth;
10736        }
10737	    return aspectRatio;
10738	 },
10739
10740    _setUpCanvas:function(){
10741        var aspectRatio ;
10742		aspectRatio = this.aspectRatioToBeUsed();
10743       
10744        // max width, height of generated image
10745        var maxWidth = 640;
10746        var maxHeight = 480;
10747        
10748        // width of field scaled to fit max image size
10749        var scaledWidth;
10750        var scaledHeight;
10751        
10752        
10753		// approx pixels required for rendering geo loc info in 12pt Arial font 
10754		var approxGeoLocWidth=250;
10755		var approxGeoLocHeight=84;
10756        
10757        scaledWidth = maxWidth;
10758        scaledHeight = maxWidth*aspectRatio;
10759        if(scaledHeight>maxHeight){
10760            scaledHeight = maxHeight;
10761            scaledWidth = maxHeight/aspectRatio;
10762        }
10763        
10764        // set canvas dimensions
10765        if(aspectRatio>=1){
10766			this._geoCanvId='iEBox_geoCanvasBottom';
10767            this._geoLocAtBottom=true;
10768          
10769			
10770             this._geoCanvasWidth = scaledWidth;
10771			 // limit height to 30% of full height;
10772			 this._geoCanvasHeight=Math.min(approxGeoLocHeight,scaledHeight/3);
10773             this._sigCanvasWidth = scaledWidth;
10774             this._sigCanvasHeight= scaledHeight-(this._enforceGeoLoc?this._geoCanvasHeight:0);
10775        } else {
10776			this._geoCanvId='iEBox_geoCanvasRight';
10777            this._geoLocAtBottom=false;
10778           
10779			
10780            this._geoCanvasHeight = scaledHeight;
10781			// limit width to 30% of full width;
10782			this._geoCanvasWidth=Math.min(approxGeoLocWidth,scaledWidth/3);
10783            this._sigCanvasHeight= scaledHeight;
10784            this._sigCanvasWidth= scaledWidth-(this._enforceGeoLoc?this._geoCanvasWidth:0);
10785        }
10786       
10787    },
10788
10789   render : function() {
10790       var geoLocMandatoryOnIpad = this.options.geoLocMandatoryOnIpad;
10791       if(typeof(geoLocMandatoryOnIpad)!="undefined"){
10792           this._enforceGeoLoc= this._enforceGeoLoc && (/^(true|1)$/i).test($.trim(geoLocMandatoryOnIpad));
10793       }
10794       this._wgtId="wid"+~~(Math.random()*2000)+"_"+new Date().getTime();
10795
10796       var $control = $.xfaWidget.defaultWidget.prototype.render.apply(this, arguments)
10797
10798       if(this.options.value || this.options.value != this._emptyImageVal){
10799          this._is_readonly=!!PNGUtil._isReadOnly(this.options.value);
10800       }
10801   
10802       if(this._is_readonly){
10803          $control.after("<div id='"+this._wgtId+"' class='sc_popUpMenu'></div>");
10804       } else {
10805          $control.after("<div id='"+this._wgtId+"' style='display:none;' class='sc_popUpMenu'></div>");
10806       }
10807	   
10808	   this._setUpCanvas();
10809       return $control;
10810    },
10811
10812   click: function() {
10813        this.focus();
10814        var tmpEl = this.element.length?this.element[0]:this.element;
10815        if(this.options.access != "open")
10816          return;
10817       if (TouchUtil.POINTER_ENABLED || TouchUtil.TOUCH_ENABLED) {
10818           // simulate a click event
10819           tmpEl.dispatchEvent(TouchUtil.getPointerEvent(TouchUtil.POINTER_DOWN));
10820           tmpEl.dispatchEvent(TouchUtil.getPointerEvent(TouchUtil.POINTER_UP));
10821        }
10822        else {
10823              this.$userControl.triggerHandler("click");
10824        }
10825   },
10826
10827    _attachEventHandlers:function($control){
10828	     if(TouchUtil.POINTER_ENABLED || TouchUtil.TOUCH_ENABLED){
10829            this._attachTouchEventHandlers($control);
10830         } else {
10831            this._attachMouseEventHandlers($control);
10832         }
10833         $control.keydown($.proxy(this._handleKeyDown,this));
10834    },
10835	_attachEventHandlerForCrossIcon:function($control){
10836	    var _that = this;
10837	    $control.mouseenter(function(event){
10838             if(_that.options.access != "open")
10839                    return;
10840             event.stopPropagation();
10841             if(_that._is_readonly){
10842                $('#'+_that._wgtId).css({display:'block'});
10843                var bodyMoveHandler;
10844                $('body').on('mousemove',bodyMoveHandler=function(event){
10845                    if(event.target!=$('#'+_that._wgtId)[0]&&event.target!=_that.$userControl[0]){
10846                        $('#'+_that._wgtId).css({display:'none'});
10847                         $('body').off('mousemove',bodyMoveHandler);
10848                    }
10849                });
10850              }
10851       });
10852
10853       setTimeout(function(){ $("#"+_that._wgtId).click($.proxy(_that._onCrossClick,_that));},50);  
10854	},
10855    _attachTouchEventHandlers:function($control){
10856        var _timer,_that=this;
10857        var tmpEl = this.element.length?this.element[0]:this.element;
10858       tmpEl.addEventListener(TouchUtil.POINTER_DOWN,function(event){
10859           if(_that.options.access != "open")
10860              return;
10861             event.preventDefault();
10862           _timer = setTimeout(function(){
10863                _timer=0;
10864               _that._onCrossClick(event);
10865            },1000);
10866        });
10867       tmpEl.addEventListener(TouchUtil.POINTER_UP,function(event){
10868            if(_that.options.access != "open")
10869                return;
10870            event.preventDefault();
10871            if(_timer){
10872               clearTimeout(_timer);
10873               _that._onImageClick(event);
10874            } 
10875        });
10876		
10877	   if(TouchUtil.POINTER_ENABLED){
10878		     this._attachEventHandlerForCrossIcon($control);
10879			 setTimeout(function(){ $("#"+_that._wgtId).on(TouchUtil.POINTER_UP,function(event){
10880			        event.stopPropagation();
10881			 });},50);
10882	   }
10883    },
10884
10885    _attachMouseEventHandlers:function($control){
10886         var _timer=0,_that=this,_hoverTimer=0;
10887        $control.dblclick(function(event){
10888            if(_that.options.access != "open")
10889                return;
10890           event.preventDefault();event.stopPropagation();
10891           if(_timer.val){
10892             clearTimeout(_timer);_timer =0;
10893           }
10894           _that._onCrossClick(event);
10895        }).click(function(event){
10896           _that.$userControl.trigger("scribbleclick",event);
10897           if(_that.options.access != "open")
10898                return;
10899           event.preventDefault();
10900           event.stopPropagation();
10901           if(_timer){
10902              clearTimeout(_timer);_timer=0;
10903            } else {
10904              _timer = setTimeout(function(){
10905                 _timer=0;
10906                 _that._onImageClick(event);
10907              },500);
10908            }
10909       });
10910	   
10911	   this._attachEventHandlerForCrossIcon($control);
10912       
10913    },
10914
10915    _onCrossClick:function(event){
10916        if(!this._is_readonly) return;
10917        this.$userControl.trigger("scribblefocus",event);
10918        this.$userControl.trigger("scribbleclick",event);
10919        event.stopPropagation();
10920        $.alertBox.yesNo(null,
10921         this.localeStrings().clearSignatureConfirm,
10922         this.localeStrings().clearSignature,
10923         $.proxy(this._removeSigConfirmationHandler,this));
10924     },
10925
10926     _removeSigConfirmationHandler:function(isYes){
10927        if(isYes){
10928           this._saveValue(this._emptyImageVal);
10929           this._displayValue(this._extractData(this._createEmptyImageData()));
10930           this.$userControl.addClass("emptyScribble").trigger("scribbleclose",{});
10931           this._is_readonly=false;
10932        }
10933     },
10934
10935    _createEmptyImageData:function(){
10936         if(!this._emptyImageData){
10937            var emptyCanvasObj = document.createElement('canvas');
10938            emptyCanvasObj.style.width=this._sigCanvasWidth+'px';
10939            emptyCanvasObj.style.height=this._sigCanvasHeight+'px';
10940            emptyCanvasObj.width=this._sigCanvasWidth;
10941            emptyCanvasObj.height=this._sigCanvasHeight;
10942            var ctx = emptyCanvasObj.getContext('2d');
10943            ctx.fillStyle='#ffffff';
10944            ctx.clearRect(0,0,this._sigCanvasWidth,this._sigCanvasHeight);
10945            this._emptyImageData = emptyCanvasObj.toDataURL("image/png");
10946         }
10947         return this._emptyImageData;
10948     },
10949
10950    getCommitValue: function() {
10951        return this.options.value
10952    },
10953
10954    _saveValue:function(val){
10955        this.options.value=val;
10956        this.$userControl.trigger('scribblechange');
10957    },
10958
10959    _displayValue:function(val){
10960        if(this.options.commitProperty) {
10961            //hardcode the widget VALUE by unknown image type
10962            if(val){
10963              var widgetValue = "data:image/png;base64,"+val;
10964                this._setValue(widgetValue);
10965            }
10966        }
10967        else
10968            this.logger().debug("xfaView","[DefaultWidget._update], User Control or Commit Property is null" );
10969    },
10970
10971    _doOk:function(){
10972        var mainCanvas = document.createElement('CANVAS');
10973        var geoCnv = $('#'+this._geoCanvId)[0];
10974        var sigCnv = $('#iEBox_canvas')[0];
10975        var ctx = mainCanvas.getContext('2d');
10976       
10977        if(geoCnv.width>0&&geoCnv.height>0){
10978            
10979            if(this._geoLocAtBottom){
10980                mainCanvas.width=sigCnv.width;
10981                mainCanvas.height =sigCnv.height+geoCnv.height;
10982                ctx.drawImage(sigCnv,0,0);
10983                ctx.drawImage(geoCnv,0,sigCnv.height);
10984            } else {
10985                mainCanvas.width=sigCnv.width+geoCnv.width;
10986                mainCanvas.height =sigCnv.height;
10987                ctx.drawImage(sigCnv,0,0);
10988                ctx.drawImage(geoCnv,sigCnv.width,0);
10989            }
10990        } else {
10991             mainCanvas.width=sigCnv.width;
10992             mainCanvas.height =sigCnv.height;
10993             ctx.drawImage(sigCnv,0,0);
10994        }
10995        imageEditDialog.hide();
10996        var newdata = mainCanvas.toDataURL("image/png");//(this.myScribbleHandle||"").toString();
10997        
10998         var val,val1;
10999         if((val=/*=*/this._extractData(newdata))){
11000         //  val1 = PNGUtil._makeReadOnly(val);
11001            val = PNGUtil._makeReadOnly(val);
11002            this._saveValue(val);   
11003            this._is_readonly=true;       
11004          }
11005          this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
11006        this.$userControl.trigger("scribbleclose")
11007    },
11008    _handleOk:function(){
11009        if(this._enforceGeoLoc){
11010           this._geoLocQuery = new GeoLocQuery().init($.proxy(function(data){
11011               this._geoQuerySuccessHandler(data);
11012               this._doOk();
11013           },this),$.proxy(this._geoQueryErrorHandler,this));
11014           this._geoLocQuery.query();
11015           this._showMessage(this.localeStrings().fetchGeoLocation);
11016        } else {
11017          this._doOk();
11018        }
11019    },
11020
11021    _handleCancel:function(){
11022         imageEditDialog.hide();
11023         this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
11024        this.$userControl.trigger("scribbleclose")
11025    },
11026
11027    _handleClear:function(){
11028        this.myScribbleHandle.setEnabled(true);
11029        this._is_readonly=false;
11030        this._makeReadOnly(this._is_readonly);
11031        $('#iEBox_canvas')[0].width=this._sigCanvasWidth;
11032         $('#iEBox_caption').width(this._sigCanvasWidth);
11033		$('#iEBox_canvas')[0].height=this._sigCanvasHeight;
11034        $('#keyboard_Sign_Box')[0].value="";
11035        var geoCanv = $('#'+this._geoCanvId)[0];
11036        imageEditDialog.enableButtons({Ok:false,Clear:false});
11037        geoCanv.width=0;
11038        geoCanv.height=0;
11039        imageEditDialog._resize();
11040        this._geoLocQuery&&this._geoLocQuery.cancel();// cancel current geo loc request;
11041    },
11042    _makeReadOnly:function(readonly){
11043       imageEditDialog.enableButtons({Ok:false,Clear:false,Geo:!readonly,Brush:!readonly,Text:!readonly});
11044       if(readonly){
11045		   $('#iEBox_canvas').css({border:'1px solid gray'});
11046           $('#iEBox_caption').css({display:'none'});
11047
11048       }
11049       this._defaultStatus = "&nbsp;";
11050       this._showMessage(this._defaultStatus);
11051    },
11052
11053    _showMessage:function(msg){
11054        var _that = this;
11055        if(this._msgTimeout) { clearTimeout(this._msgTimeout); this._msgTimeout=0; }
11056         $("#iEBox_title").replaceWith('<div id="iEBox_title">'+msg+'</div>');
11057         this._msgTimeout = window.setTimeout(function(){
11058             $("#iEBox_title").replaceWith('<div id="iEBox_title">'+_that._defaultStatus+'</div>');
11059         },15000);
11060    },
11061
11062    _geoQueryErrorHandler:function(err){
11063        this._showMessage(this.localeStrings().errorFetchGeoLocation);
11064    },
11065
11066	_getLogMessage:function(key){
11067		     return this.logMsgs()[key]||key;
11068	},
11069
11070    _handleGeo:function(){
11071          // initiate geolocation 
11072       if(navigator.geolocation){
11073           this._geoLocQuery = new GeoLocQuery().init($.proxy(this._geoQuerySuccessHandler,this),$.proxy(this._geoQueryErrorHandler,this));
11074           this._geoLocQuery.query();
11075           this._showMessage(this.localeStrings().fetchGeoLocation);
11076       } else {
11077           this.logger().debug("xfaView",this._getLogMessage("ALC-FRM-901-011"));
11078       }
11079    },
11080
11081    // This Function is used to fetch the geolocation.
11082    calculateGeolocation: function(){
11083      this._handleGeo();
11084    },
11085
11086    _handleText:function(){
11087        var signBoxEl=document.getElementById("keyboard_Sign_Box");
11088        var signCanvasEl=document.getElementById("iEBox_canvas");
11089        if(signBoxEl.value.length==0){
11090            this._handleClear();
11091        }
11092        this._disableSignatureCanvas();
11093        this._enableSignatureTextBox();
11094        signBoxEl.focus();
11095    },
11096
11097    _disableSignatureTextBox:function(){
11098        document.getElementById("keyboard_Sign_Box").style.display = "none";
11099    },
11100
11101    _enableSignatureTextBox:function(){
11102        document.getElementById("keyboard_Sign_Box").style.display = "inline-block";
11103    },
11104
11105    _disableSignatureCanvas:function(){
11106        document.getElementById("iEBox_canvas").style.display = "none";
11107    },
11108
11109    _enableSignatureCanvas:function(){
11110        document.getElementById("iEBox_canvas").style.display = "inline-block";
11111    },
11112
11113    _handleBrushSelect:function(w){
11114        if(this.myScribbleHandle&&!this._is_readonly) {
11115            this.myScribbleHandle.setLineWidth(w);
11116        }
11117    },
11118
11119    _handleBrush:function(evt){
11120        if($('#keyboard_Sign_Box')[0].value.length>0){
11121            this._handleClear();
11122        }
11123        this._disableSignatureTextBox();
11124        this._enableSignatureCanvas();
11125        imageEditDialog.toggleBrushList(evt);
11126    },
11127	_handleKeyDown:function(event){
11128		if(event.keyCode == ENTER_KEY || event.charCode == ENTER_KEY || event.which == ENTER_KEY) { // touch devices may return charCode
11129		    event.preventDefault();
11130		    this._onImageClick(event);
11131		} else if(event.keyCode == DELETE_KEY || event.charCode == DELETE_KEY || event.which == DELETE_KEY) {
11132		    this._onCrossClick(event);
11133		}
11134    },
11135    _dialogCallback:function(button_val,arg1){
11136           // add back on click handler
11137         //  this.$userControl.click($.proxy(this._onImageClick, this));
11138                     
11139           switch(button_val){
11140               case "Ok":
11141               this._handleOk();
11142               break;
11143               case "Cancel":
11144               this._handleCancel();
11145               break;
11146               case "Clear":
11147               this._handleClear();
11148               break;
11149               case "Geo":
11150               this.calculateGeolocation();
11151               break;
11152               case "BrushSelect":
11153               this._handleBrushSelect(arg1);
11154               break;
11155               case "Brush":
11156               this._handleBrush(arg1);
11157               break;
11158               case "Text":
11159               this._handleText();
11160               break;
11161              
11162           }
11163    },
11164
11165    _geoQuerySuccessHandler:function(data){
11166        this._renderPosition(data);
11167    },
11168
11169	_fitGeoLocText:function(latStr,longStr,timeStr,ctx,maxWidth,maxHeight){
11170	    var fontSize=12;
11171		ctx.font="bold "+fontSize+"pt Arial";
11172		var width = Math.max(ctx.measureText(latStr).width,ctx.measureText(longStr).width,ctx.measureText(timeStr).width);
11173		var lineHeight = ctx.measureText("m").width*1.5;
11174		while((width>maxWidth||3*lineHeight>maxHeight)&&fontSize>1){
11175		    fontSize--;
11176		    ctx.font="bold "+fontSize+"pt Arial";
11177		    width = Math.max(ctx.measureText(latStr).width,ctx.measureText(longStr).width,ctx.measureText(timeStr).width);
11178		    lineHeight = ctx.measureText("m").width*1.5;
11179		}
11180		return {width:width,lineHeight:lineHeight,fontSize:fontSize};
11181	},
11182
11183    _renderPosition:function(position){
11184        if(position&&position.coords){
11185         this._showMessage("&nbsp;");
11186            var latStr = this.localeStrings().latitude+": " + position.coords.latitude;
11187            var longStr = this.localeStrings().longitude+": " + position.coords.longitude;
11188            var dateObj = new Date();
11189            var tZone = (dateObj.getTimezoneOffset()/60*-1);
11190            
11191            var timeStr = this.localeStrings().time+": "+(dateObj.getMonth()+1)+"/"+dateObj.getDate()+"/"+dateObj.getFullYear()+" "+dateObj.getHours()+":"+dateObj.getMinutes()+":"+dateObj.getSeconds()+((tZone>0)?" +":" ")+(tZone);
11192            var canvasObj  = $('#'+this._geoCanvId)[0];
11193			var sigCanvas = $('#iEBox_canvas')[0];
11194            var sigTextBox = $('#keyboard_Sign_Box')[0];
11195			var dummyCanvas = document.createElement('canvas');
11196            if(canvasObj){
11197			   var ctx = canvasObj.getContext('2d');
11198			   ctx.font="bold 12pt Arial";
11199
11200			   canvasObj.width=this._geoCanvasWidth;
11201               canvasObj.height=this._geoCanvasHeight;
11202			   var layout = this._fitGeoLocText(latStr,longStr,timeStr,ctx,canvasObj.width,canvasObj.height);
11203               var aspectRatio ;
11204     		   aspectRatio = this.aspectRatioToBeUsed();
11205			   if(!this._enforceGeoLoc){
11206			       if(this._geoLocAtBottom){
11207                     dummyCanvas.height = this._sigCanvasHeight-canvasObj.height;
11208                     dummyCanvas.width = dummyCanvas.height/aspectRatio;
11209                   } else {
11210                     dummyCanvas.width = this._sigCanvasWidth-canvasObj.width;
11211					 dummyCanvas.height = dummyCanvas.width*aspectRatio;
11212				   }
11213				   // move drawn signature to a temporary canvas and scale it to new dimension
11214                   dummyCanvas.getContext('2d').drawImage(sigCanvas,0,0,dummyCanvas.width,dummyCanvas.height);
11215                   if(this._geoLocAtBottom){
11216                     sigCanvas.height = dummyCanvas.height;
11217                     sigTextBox.height = dummyCanvas.height;
11218                     sigCanvas.getContext('2d').drawImage(dummyCanvas,(sigCanvas.width-dummyCanvas.width)/2,0);
11219                   } else {
11220                     sigCanvas.width = dummyCanvas.width;
11221                     sigTextBox.width = dummyCanvas.width;
11222                     sigCanvas.getContext('2d').drawImage(dummyCanvas,0,(sigCanvas.height-dummyCanvas.height)/2);
11223                   }
11224                   $('#iEBox_caption').width(sigCanvas.width);
11225				   imageEditDialog.enableButtons({Clear:true});
11226			   }
11227			      
11228			   var fwidth = layout.width;
11229               var fheight = layout.lineHeight;
11230			   var bottomMargin=2;
11231               ctx.fillStyle='#555555';
11232               ctx.font="bold "+layout.fontSize+"pt Arial";
11233               ctx.fillText(latStr,0,canvasObj.height-2*fheight-bottomMargin);
11234               ctx.fillText(longStr,0,canvasObj.height-fheight-bottomMargin);
11235               ctx.fillText(timeStr,0,canvasObj.height-bottomMargin);
11236			   
11237			   imageEditDialog._resize();
11238            }
11239        }
11240    },
11241    _scribbleCallback:function(){
11242       imageEditDialog.enableButtons({Clear:true,Ok:true});  //  enable clear and ok buttons
11243    },
11244    _onImageClick:function(){
11245       if(!imageEditDialog.getIsOpen()){
11246           var _that = this;
11247           imageEditDialog.show("&nbsp;",$.proxy(this._dialogCallback, this));
11248           if(!this._enforceGeoLoc){
11249               $('#iEBox_Geo').css({display:'inline-block'});
11250           }
11251           var image = new Image();
11252           image.onload=function(){
11253               _that.myScribbleHandle = new Scribble("iEBox_canvas",image,image.width,image.height,$.proxy(_that._scribbleCallback,_that));
11254               _that.myScribbleHandle.setEnabled(!_that._is_readonly);
11255               $('#iEBox_caption').width(image.width);
11256               $('#iEBox_container').css({display:'table'});
11257               if($('#iEBox_container').length == 1){
11258                   $('#iEBox_container')[0].focus();
11259               }
11260               imageEditDialog._resize();
11261               imageEditDialog._reposition();      // recalculate position, so that the values are updated, esp. in iPad
11262           }
11263           if(!this.options.value||this.options.value==this._emptyImageVal){
11264               this._is_readonly=false;
11265               this.$userControl.addClass("emptyScribble");
11266               image.src = this._createEmptyImageData();
11267           } else {
11268               this.$userControl.removeClass("emptyScribble");
11269               if(PNGUtil._isPng(this.options.value)){
11270                   this._is_readonly = !!PNGUtil._isReadOnly(this.options.value);
11271			       image.src = "data:image/png;base64,"+this.options.value;//this.createBl _that.$userControl.attr(_that.options.commitProperty);
11272               } else {
11273                   image.src = "data:;base64," + this.options.value;//this.createBl _that.$userControl.attr(_that.options.commitProperty);
11274		       }
11275           }
11276           this._makeReadOnly(this._is_readonly);
11277       }
11278    },
11279
11280    _extractData:function(datauri){
11281        var idx;
11282        if(datauri!=null&&datauri.length>0&&datauri.indexOf("data:")==0){
11283            if((idx=datauri.indexOf(","))>0){
11284                return datauri.substr(idx+1);
11285            }
11286        }
11287    },
11288
11289    _setValue:function(val){
11290        this.$userControl.prop(this.options.commitProperty, val);
11291        this.$userControl.attr(this.options.commitProperty, val);
11292        if(this._dummyImg){
11293            this._dummyImg.setAttribute(this.options.commitProperty,val);
11294        }
11295    }
11296});
11297 //hack for IOS5 touch bug
11298  $(function(){
11299         $('body').on('touchstart', function(e) {});
11300  });
11301  
11302})($,xfalib);
11303(function ($, window, _) {
11304
11305    var _defaults = {
11306        placeHolderText : "Enter comments here"
11307    };
11308
11309    var AdobeFileAttachment = function (element, options) {
11310        this.options = options;
11311        this.$elementFileUploadBtn = [];
11312        this.$elementFileList = [];
11313        this.$element = $(element);
11314        if (this.$element.attr("multiple") && !xfalib.ut.Utilities._isDataContainerSupported()) {
11315            // remove multiple attribute if multi file selection in one go is not supported
11316            this.$element.removeAttr("multiple");
11317        }
11318        this.$parent = this.$element.parent();
11319        this.invalidFeature = {
11320            "SIZE":1,
11321            "NAME":2,
11322            "MIMETYPE":3
11323        };
11324        Object.freeze(this.invalidFeature);
11325        // initialize the regex initially
11326        this.regexMimeTypeList  = this.options.mimeType.map(function (value, i) {
11327            try {
11328                return new RegExp(value.trim());
11329            } catch (e) {
11330                // failure during regex parsing, don't return anything specific to this value since the value contains
11331                // incorrect regex string
11332                if(window.console) {
11333                    console.log(e);
11334                }
11335            }
11336        });
11337    };
11338
11339    var isBrowserIE9OrIE10 = ($.browser.msie && ($.browser.version === '9.0' || $.browser.version === '10.0')),
11340        fileLabelsCount = 0;
11341
11342
11343    AdobeFileAttachment.prototype = {
11344        _fileIframeName : "guide-fu-iframe",
11345        _addFile : "Add File",
11346
11347        clear: function () {
11348            this.$element.val('');
11349            this.$elementFileList.empty();
11350        },
11351
11352        destroy: function () {
11353            this.$fileDomElements = $.map(this.$fileDomElements, function(item){
11354                // since item can be null or object, doing this check
11355                if(_.isObject(item) && item.val().length === 0) {
11356                    //TODO: remove item from dom, since there is a memory leak
11357                    return item;
11358                }
11359            });
11360            this.values = [];
11361            if(isBrowserIE9OrIE10){
11362                if(_.last(this.$fileDomElements) == null){
11363                    this.cloneFileInputAndUpdateIdForIE9();
11364                } else {
11365                    this.updateLabelForAttr(_.last(this.$fileDomElements).attr("id"));
11366                }
11367            }
11368            this.$element.trigger("change.fileupload");
11369        },
11370
11371        _setUrl : function(url, index){
11372            this.$elementFileList.find("span.guide-fu-fileName").eq(index).data("key", url);
11373        },
11374
11375        _getUrl : function(index) {
11376            return this.$elementFileList.find("span.guide-fu-fileName").eq(index).data("key");
11377        },
11378        getSetFilePathAndReturnNamePathMap: function(valueList) {
11379
11380            var mapOfObjectsHavingTempPathAndFileNames = {},
11381                $temp,
11382                tempPath;
11383
11384            $.each(this.$elementFileList.children(), function ( index, childLiElement) {
11385                $temp = $(childLiElement).find("span.guide-fu-fileName");
11386                tempPath = $temp.data("key");
11387                if(!tempPath && valueList && valueList[index]) {
11388                    $temp.data("key", valueList[index]);
11389                }
11390                mapOfObjectsHavingTempPathAndFileNames[$temp.html()] = tempPath || $temp.data("key");
11391            });
11392            return mapOfObjectsHavingTempPathAndFileNames;
11393        },
11394
11395
11396        value : function(value) {
11397            if(!_.isUndefined(value)) {
11398                var _self = this,
11399                    comments = this.comment(),
11400                    isChange = false,
11401                    fileNames = _.isArray(this.options.fileNames) ? this.options.fileNames : null,
11402                    oldUrls = {};
11403                // Cache the url before deletion
11404                this.$elementFileList.children().find("span.guide-fu-fileName").each(function(){
11405                    var url = $(this).data("key");
11406                    if(!_.isUndefined(url)){
11407                        var fileName = url.substring(url.lastIndexOf("/") + 1);
11408                        oldUrls[fileName] = url;
11409                    }
11410                });
11411                this.$elementFileList.empty();
11412                if(value != null) {
11413                    var arr = value.split("\n");
11414                    // contruct initial file name and value map
11415                    // this is done only once in entire live cycle, its done here, since we get value here
11416                    if (fileNames && _.isEmpty(this._initialFileValueFileNameMap)) {
11417                        for (var index = 0; index < fileNames.length; index++) {
11418                            _self._initialFileValueFileNameMap[arr[index]] = fileNames[index]
11419                        }
11420                    }
11421                    // Update the value array with the file
11422                    this.values = _.map(arr, function(fileName, index){
11423                        // Check if file Name is a path, if yes get the last part after "/"
11424                        var slash = fileName.lastIndexOf("/"),
11425                            fileUrl = fileName,
11426                            fileUploadUrl = null;
11427                        if(slash !== -1) {
11428                            // Store the cached url here
11429                            fileUrl = fileUploadUrl = fileName;
11430                            fileName = fileName.substring(slash + 1);
11431                            // case: when you click on save second time
11432                            if((_.isObject(_self.$fileDomElements[index]) && _self.$fileDomElements[index].val().length > 0) || _.isString(_self.$fileDomElements[index])){
11433                                isChange = true;
11434                                _self.$fileDomElements[index] = null;
11435                            } else if(_self.$fileDomElements[index] !== null) { // create a dummy file dom for the cached value
11436                                 isChange = true;
11437                                _self.$fileDomElements.splice(index, 0, null);
11438                            }
11439                        } else if (oldUrls[fileName]) {
11440                            fileUploadUrl = oldUrls[fileName];
11441                        }
11442                        // if fileNames options is explicitly passed, use it
11443                        if (fileNames && _self._initialFileValueFileNameMap[fileUrl]) {
11444                            fileName = _self._initialFileValueFileNameMap[fileUrl];
11445                        }
11446                        _self.showFileList(fileName, comments[index], fileUploadUrl);
11447                        return fileUrl;
11448                    });
11449                    if(isChange){
11450                        this.$element.trigger("change.fileupload");
11451                    }
11452                } else {
11453                    if(_.isArray(this.values) && this.values.length !== 0){
11454                        this.destroy();
11455                    }
11456                }
11457            }
11458            else {
11459                return this.values;
11460            }
11461        },
11462
11463        fileAttachment: function(){
11464            return this.values;
11465        },
11466
11467        comment : function(value){
11468            var _self = this,
11469                $elem = null,
11470                comments;
11471            if (!_.isUndefined(value)) {
11472                if(value != null) {
11473                    comments = value.split("\n");
11474                    $elem = this.$elementFileList.find('div.guide-fu-comment');
11475                    $elem.each(function(index){
11476                        $(this).text(comments[index]);
11477                    });
11478                }
11479            }
11480            else {
11481                $elem = this.$elementFileList.find('div.guide-fu-comment');
11482                comments = [];
11483                $elem.each(function(){
11484                    comments.push($(this).text());
11485                });
11486                return comments;
11487            }
11488        },
11489
11490        multiSelect : function(value){
11491            if(value !== undefined)
11492                this.options.multiSelect = value;
11493            else
11494                return this.options.multiSelect;
11495        },
11496
11497        fileSizeLimit : function(value){
11498            if(value !== undefined)
11499                this.options.fileSizeLimit = value;
11500            else
11501                return this.options.fileSizeLimit;
11502        },
11503
11504        mimeType : function(value){
11505            if(value !== undefined)
11506                this.options.mimeType = value;
11507            else
11508                return this.options.mimeType;
11509        },
11510
11511        access : function(value){
11512            if(value == "readOnly") {
11513                this.$element.attr("disabled", "disabled");
11514                //for readOnly hide the delete icon in file list
11515                $(this.$parent).addClass('guide-fu-disabled');
11516            }
11517            else if(value == "open") {
11518                this.$element.removeAttr("disabled");
11519                $(this.$parent).removeClass('guide-fu-disabled');
11520            }
11521        },
11522
11523        fileList : function(value) {
11524            var filtered,
11525                _self = this;
11526            if(value !== undefined){
11527                this.$fileDomElements = [];
11528                _.each(value, function(item, index){
11529                    if((_.isObject(item) && (isBrowserIE9OrIE10 || item.val().length > 0)) || (_.isString(item))){
11530                         // check if index is within the length
11531                         // this is written for delete case
11532                         // if item is a string, then it should be set null
11533                         if(_.isString(item)){
11534                             item = null;
11535                         }
11536                         _self.$fileDomElements[index] = item;
11537                    }
11538                });
11539                filtered = this.$fileDomElements;
11540                // In case of IE9, get the last element of fileDom and update the id for label
11541                if(isBrowserIE9OrIE10 && value !== null){
11542                    // Case: if it is single select, and then we do a restore and then after attaching another file we click save
11543                    if(_.last(this.$fileDomElements) == null){
11544                        this.cloneFileInputAndUpdateIdForIE9();
11545                    } else {
11546                        this.updateLabelForAttr(_.last(this.$fileDomElements).attr("id"));
11547                    }
11548                }
11549            }
11550            else {
11551                // here filtered is a new array
11552                // A new array is returned over here so that the user of this API doesn't try to change the widget array directly
11553                filtered = $.map(this.$fileDomElements, function(item, index){
11554                    if(!item) {
11555                        return _self._getUrl(index);
11556                    } else if((item[0].files && item[0].files.length !== 0)
11557                            || (_self.options.multiSelect || item[0].value.length > 0)) {
11558                        return item;
11559                    }
11560                });
11561            }
11562            return filtered;
11563        },
11564
11565        // file preview html
11566        fileItemPreview: function(){
11567            return $("<span></span>").addClass("guide-fu-filePreview glyphicon glyphicon-ok");
11568        },
11569
11570        // force flag indicates that forcefully set the dom but don't update the options
11571        buttonText: function (value, force) {
11572            if (value !== undefined) {
11573                if(!force)
11574                    this.options.buttonText = value;
11575                this.$elementFileUploadBtn.find('span.guide-fu-label').html(value);
11576            } else {
11577                return this.options.buttonText;
11578            }
11579        },
11580
11581        // To change the icon of the button, the user should customize the class
11582        btnIcon: function () {
11583            return $("<span></span>").addClass("guide-fu-icon glyphicon glyphicon-folder-open");
11584        },
11585
11586        btnLabel: function(){
11587            return $("<span></span>").addClass("guide-fu-label").html(this.options.buttonText);
11588        },
11589
11590        fileItemList: function(){
11591            return this.$parent.find(this.options.fileItemListClass);
11592        },
11593
11594        getNewCommentElementSummary : function(text){
11595            return $("<div title='Click to edit' tabindex='0'></p>").addClass("guide-fu-comment").text(text || _defaults.placeHolderText);
11596        },
11597
11598        getNewCommentElement : function(text){
11599            return $("<div contenteditable='true' tabindex='0'></div>").addClass("guide-fu-comment").text(text || "");
11600        },
11601
11602        fileItem: function(fileName, comment, fileUrl){
11603            var $fileItem = $("<li></li>").addClass("guide-fu-fileItem");
11604            var nameWithoutMarker = xfalib.ut.Utilities._getNameWithoutMarker(fileName);
11605            var $elem = $("<span tabindex='0'></span>").addClass("guide-fu-fileName").attr("aria-label", nameWithoutMarker).text(nameWithoutMarker).appendTo($fileItem).keypress(function(e) {
11606                if (e.keyCode === 13 || e.charCode === 32) {
11607                    $(e.target).click();
11608                }
11609            }).click($.proxy(this.handleFilePreview, this));
11610            if(this.options.disablePreview) {
11611               $elem.addClass('non-preview-fileName');
11612            }
11613            if(fileUrl != null){
11614                $elem.attr("data-key", fileUrl);
11615            }
11616            $("<span tabindex='0'></span>").addClass("guide-fu-fileClose close").attr("role", "button").attr("aria-label", xfalib.locale.Strings.FileCloseAccessText 
11616+ nameWithoutMarker).text("x").appendTo($fileItem).keypress(function(e) {
11617                if (e.keyCode === 13 || e.charCode === 32) {
11618                    $(e.target).click();
11619                }
11620            })
11621                .click($.proxy(this.handleClick, this));
11622
11623            this.fileItemPreview().appendTo($fileItem);
11624
11625            if(this.options.showComment){
11626                this.getNewCommentElementSummary(comment).appendTo($fileItem).focus($.proxy(this.handleCommentClick, this)).click($.proxy(this.handleCommentClick, this));
11627            }
11628            return $fileItem;
11629        },
11630
11631        toggleFileUploadBtn: function(){
11632            if(this.options.multiSelect) {
11633                // Change the look of file upload button
11634                if(this.$elementFileList.children().length > 0){
11635                    // Change the text
11636                    this.buttonText(this._addFile, true);
11637                    // Change the icon too
11638                    this.$elementFileUploadBtn.find('span.guide-fu-icon').removeClass("glyphicon-folder-open").addClass("glyphicon-plus");
11639                } else {
11640                    this.buttonText(this.options.buttonText);
11641                    this.$elementFileUploadBtn.find('span.guide-fu-icon').removeClass("glyphicon-plus").addClass("glyphicon-folder-open");
11642                }
11643            }
11644        },
11645
11646        showInvalidMessage: function(fileName, invalidFeature){
11647            var that = this;
11648            var IS_IPAD = navigator.userAgent.match(/iPad/i) !== null,
11649                IS_IPHONE = (navigator.userAgent.match(/iPhone/i) !== null);
11650            if(IS_IPAD || IS_IPHONE){
11651                setTimeout(function() {
11652                  that.invalidMessage(that,fileName, invalidFeature);
11653                }, 0);
11654            }
11655            else {
11656               this.invalidMessage(this,fileName, invalidFeature);
11657            }
11658        },
11659
11660        invalidMessage: function(refObj,fileName, invalidFeature){
11661            if(invalidFeature === refObj.invalidFeature.SIZE) {
11662                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileSizeGreater"], [fileName, refObj.options.fileSizeLimit]));
11663            } else if (invalidFeature === refObj.invalidFeature.NAME) {
11664                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileNameInvalid"], [fileName]));
11665            } else if (invalidFeature === refObj.invalidFeature.MIMETYPE) {
11666                alert(xfalib.ut.LocalizationUtil.prototype.getLocalizedMessage("", xfalib.locale.Strings["FileMimeTypeInvalid"], [fileName]));
11667            }
11668        },
11669
11670        /***
11671         * 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
11672         * This is done since our model stores the URL too in case of draft restore or clicking on save in guide
11673         * @param text          string representing the text of which the index is to be found
11674         * @param $elem         reference to the jquery element. This is used if there are duplicate file names present in the file upload.
11675         * @returns {number}
11676         * @private
11677         */
11678        _getIndexOfText : function(text, $elem){
11679            var index = -1,
11680                self = this,
11681                isDuplicatePresent = false;
11682            _.find(this.values, function(value, iter){
11683                // if value is a url, then compare with last
11684                var tempValue = value,
11685                    // can't use getOrElse here since value can have "." in URL and getOrElse splits based on period to find key inside object
11686                    fileName =  (_.isObject(self._initialFileValueFileNameMap) && typeof self._initialFileValueFileNameMap[value] !== undefined) ? self._initialFileValueFileNameMap[value] : null;
11687                if(tempValue.match(/\//g) && tempValue.match(/\//g).length > 1){
11688                    tempValue =  value.substring(value.lastIndexOf("/")+1);
11689                    tempValue = xfalib.ut.Utilities._getNameWithoutMarker(tempValue);
11690                }
11691                // we pass file name explicityly as options, if passed use that as fallback to find the URL
11692                if(tempValue === text || fileName === text){
11693                    index = iter;
11694                    isDuplicatePresent = self.values.indexOf(value, index + 1) !== -1;
11695                    if($elem && isDuplicatePresent){
11696                        // now check if duplicate present and get its correct index
11697                        // today all files are wrapped under .guide-fu-fileItem node
11698                        index = $elem.closest(".guide-fu-fileItem").index();
11699                    }
11700                    // check if there is a duplicate
11701                    // this is to just break the loop
11702                    return value;
11703                }
11704            });
11705            return index;
11706        },
11707
11708
11709        /*
11710         * Since input file element might contain multiple files.
11711         * This function takes absolute file index as parameter & returns position of the file w.r.t input file elt
11712         */
11713        _getFileObjIdx : function (index) {
11714            if (index >= 0) {
11715                var currentIdx = 0;
11716                for (var fileInputEltIdx = 0; fileInputEltIdx < this.$fileDomElements.length; fileInputEltIdx++) {
11717                    if (this.$fileDomElements[fileInputEltIdx]) {
11718                        var files = this.$fileDomElements[fileInputEltIdx][0].files;
11719                        if (files) {
11720                            var filesLength =  files.length;
11721                            if ( index <= currentIdx + filesLength - 1 ) {
11722                                return [fileInputEltIdx, index - currentIdx];
11723                            }
11724                            currentIdx+=files.length;
11725                        }
11726                    } else {
11727                        if (index == currentIdx) {
11728                            return [fileInputEltIdx,0];
11729                        }
11730                        currentIdx++;
11731                    }
11732                }
11733            }
11734            return null;
11735        },
11736
11737        /*
11738         * This function returns FileList object of the passed file array
11739         */
11740        _getFileListItem : function (files) {
11741            try {
11742                var dataContainer = new DataTransfer() || (new ClipboardEvent("")).clipboardData;
11743                _.each(files, function (file) {
11744                    dataContainer.items.add(file);
11745                });
11746                return dataContainer.files;
11747            } catch(err) {
11748                console.error(err);
11749                throw err;
11750            }
11751        },
11752
11753        _updateFilesInDom : function($fileDom, files) {
11754            // in safari, a change event is trigged if files property is changed dynamically
11755            // hence adding this check to clear existing state only for safari browsers
11756            this._isFileUpdate = true;
11757            $fileDom[0].files = this._getFileListItem(files);
11758            this._isFileUpdate = false;
11759        },
11760
11761        /*
11762         * This function deletes files at specified indexes from input dom elt
11763         */
11764        _deleteFilesFromInputDom : function ($fileDomElt, deletedIndexes) {
11765            var remainingFiles = [];
11766            _.each($fileDomElt[0].files, function(file,idx){
11767                if(!deletedIndexes.includes(idx)){
11768                    remainingFiles.push(file);
11769                }
11770            });
11771            try {
11772                // in safari, a change event is trigged if files property is changed dynamically
11773                // hence adding this check to clear existing state only for safari browsers
11774                this._updateFilesInDom($fileDomElt, remainingFiles);
11775            } catch(err){
11776                console.error("Deleting files is not supported in your browser");
11777            }
11778        },
11779
11780        /**
11781         * This event listener gets called on click of close button in file upload
11782         *
11783         * @param event
11784         */
11785        handleClick: function(event){
11786
11787            var $elem = $(event.target),
11788                text = $elem.prev().text(),
11789                index = this._getIndexOfText(text, $elem),
11790                url = $elem.prev().data("key"),
11791                objectUrl = $elem.prev().data("objectUrl");
11792            if (index != -1) {
11793                this.values.splice(index, 1);
11794                var fileObjIdx = this._getFileObjIdx(index);
11795                var $fileDomElt = this.$fileDomElements[fileObjIdx[0]];
11796                if (!$fileDomElt || $fileDomElt[0].files.length === 1) {
11797                    this.$fileDomElements.splice(fileObjIdx[0], 1);
11798                } else {
11799                    this._deleteFilesFromInputDom($fileDomElt, [fileObjIdx[1]]);
11800                }
11801                if (isBrowserIE9OrIE10) {
11802                    this.cloneFileInputAndUpdateIdForIE9();
11803                }
11804                if (url != null) {
11805                    // remove the data so that others don't use this url
11806                    $elem.prev().removeData("key");
11807                }
11808                if(objectUrl) {
11809                    // revoke the object URL to avoid memory leaks in browser
11810                    // since file is anyways getting deleted, remove the object URL's too
11811                    window.URL.revokeObjectURL(objectUrl);
11812                }
11813            }
11814            // Remove the dom from view
11815            //All bound events and jQuery data associated with the element are also removed
11816            $elem.parent().remove();
11817            // trigger the change event to update the value
11818            this.$element.trigger("change.fileupload");
11819            // Set the focus on file upload button after click of close
11820            this.$elementFileUploadBtn.focus();
11821
11822        },
11823
11824
11825        displaySVG: function (objectUrl) {
11826            const url = objectUrl;
11827            const img = window.document.createElement('img');
11828            img.src = url;
11829            const newTab = window.open('', '_blank', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11830            newTab.document.body.appendChild(img);
11831        },
11832
11833
11834        _previewFileUsingObjectUrl : function (file) {
11835            if (file) {
11836                if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
11837                    window.navigator.msSaveOrOpenBlob(file, file.name);
11838                } else {
11839                    var url = window.URL.createObjectURL(file);
11840                    if (file.type === 'image/svg+xml') {
11841                        this.displaySVG(url);
11842                    } else {
11843                        window.open(url, '', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11844                    }
11845                    return url;
11846                }
11847            }
11848        },
11849
11850        // this function maintains a map for
11851        handleFilePreview: function(event){
11852            if(!this.options.disablePreview) {
11853                var $elem = $(event.target),
11854                    text = $elem.text(),
11855                    index = this._getIndexOfText(text, $elem),
11856                    fileDom = null,
11857                    fileName = null,
11858                    fileUrl = null,
11859                    timeStamp = new Date().getTime();
11860
11861                // for draft usecase, if text contains "/" in it, it means the file is already uploaded
11862                // text should contain the path, assuming that the fileUrl is stored in data element
11863
11864                if (index != -1) {
11865                    // Store the url of file as data
11866                    if(!_.isUndefined($elem.data("key")))
11867                        fileUrl = $elem.data("key");
11868
11869                    if(fileUrl)  {
11870                        //prepend context path if not already appended
11871                        if (!(fileUrl.lastIndexOf(this.options._getUrl, 0) === 0)) {
11872                            fileUrl =  this.options._getUrl + fileUrl;
11873                        }
11874                        this.previewFile.apply(this, [null, {"fileUrl" : fileUrl}]);
11875                    } else {
11876                        var previewFileObjIdx = this._getFileObjIdx(index);
11877                        var previewFile = this.$fileDomElements[previewFileObjIdx[0]][0].files[previewFileObjIdx[1]];
11878                        var objectUrl = this._previewFileUsingObjectUrl(previewFile);
11879                        if (objectUrl) {
11880                            $elem.data("objectUrl", objectUrl);
11881                        }
11882                    }
11883                }
11884            }
11885        },
11886
11887        previewFile: function(event){
11888            var url = null;
11889            if(_.isUndefined(arguments[1]))
11890                url = this.$element[this.options.uploaderPluginName]("getFileUrl");
11891            else
11892                url = arguments[1].fileUrl;
11893            var lastIndex = url.lastIndexOf('/');
11894            //to make sure url has a slash '/'
11895            // added check for query param since sas url contains query params & does not have file name, encoding is not required in this case
11896            if(lastIndex >= 0 && url.indexOf('?') == -1) {
11897                //encode the filename after last slash to ensure the handling of special characters
11898                url = url.substr(0, lastIndex) +'/'+ encodeURIComponent(url.substr(lastIndex + 1));
11899            }
11900            // this would work for dataURl or normal URL
11901            // todo: add support to preview base 64 encoded image, to preview base64 encoded binary, we would probably need
11902            // todo: the content type in the widget too
11903            window.open(url, '', 'scrollbars=no,menubar=no,height=600,width=800,resizable=yes,toolbar=no,status=no');
11904
11905        },
11906
11907        resetIfNotMultiSelect: function(){
11908            if(!this.options.multiSelect){
11909                // Reset the value and file array
11910                this.values = [];
11911                //this.comments = [];
11912            }
11913        },
11914
11915        showFileList: function(fileName, comment, fileUrl){
11916            if(!this.options.multiSelect || fileName == null || _.isUndefined(fileName)) {
11917                // if not multiselect, remove all the children of file list
11918                this.$elementFileList.empty();
11919            }
11920
11921            // Add the file item
11922            // On click of close, remove the element and update the model
11923            // handle on click of preview button
11924            if(fileName != null) {
11925                this.$fileItem = this.$elementFileList.append(this.fileItem(fileName, comment, fileUrl));
11926            }
11927        },
11928
11929        /**
11930         * Handles the click on comment field
11931         *
11932         * TODO: Implement show/hide behaviour instead of replaceWith
11933         * This may be cause problem during bubble up of event
11934         *
11935         * @param event
11936         */
11937        handleCommentClick : function(event){
11938            var $commentElem = null,
11939                $elem = $(event.target);
11940            if ($elem.text() === _defaults.placeHolderText) {
11941                $commentElem = this.getNewCommentElement()
11942            } else {
11943                $commentElem = this.getNewCommentElement($(event.target).text());
11944            }
11945            $elem.replaceWith($commentElem);
11946            // register the event again
11947            if(isBrowserIE9OrIE10){
11948                $commentElem.focus().focusout($.proxy(this.handleCommentBlur, this));
11949            } else {
11950                $commentElem.focus().blur($.proxy(this.handleCommentBlur, this));
11951            }
11952        },
11953
11954        handleCommentBlur : function(event){
11955            var $commentSummaryElem = null,
11956                $elem = $(event.target);
11957            if ($elem.text() === _defaults.placeHolderText) {
11958                $commentSummaryElem = this.getNewCommentElementSummary();
11959            } else {
11960                $commentSummaryElem = this.getNewCommentElementSummary($(event.target).text());
11961            }
11962            $elem.replaceWith($commentSummaryElem);
11963            $commentSummaryElem.focus($.proxy(this.handleCommentClick,this)).click($.proxy(this.handleCommentClick,this));
11964            // Add a div with the html
11965            this.$element.trigger("change.fileupload");
11966        },
11967
11968        // checks if file name is valid or not to prevent security threats
11969        isValid : function(fname) {
11970            var rg1=/^[^\\/:\*\;\$\%\?"<>\|]+$/; // forbidden characters \ / : * ? " < > | ; % $
11971            var rg2=/^\./; // cannot start with dot (.)
11972            var rg3=/^(nul|prn|con|lpt[0-9]|com[0-9])(\.|$)/i; // forbidden file names
11973            return rg1.test(fname) && !rg2.test(fname) && !rg3.test(fname);
11974        },
11975
11976        handleChange: function (evnt) {
11977            if (!this._isFileUpdate) {
11978                var currFileName = '',
11979                    inValidSizefileNames = '',
11980                    inValidNamefileNames = '',
11981                    inValidMimeTypefileNames = '',
11982                    $elem = $(evnt.target),
11983                    files = $elem[0].files;
11984                // Initially set the invalid flag to false
11985
11986                // if not multiselect then remove the extra domELement clone
11987                if (!this.options.multiSelect && this.$fileDomElements.length > 1) {
11988                    this.$fileDomElements.splice(0, 1)
11989                }
11990
11991                var isInvalidSize = false,
11992                    isInvalidFileName = false,
11993                    isInvalidMimeType = false;
11994                this.resetIfNotMultiSelect();
11995                // Iterate through all the files
11996                if (isBrowserIE9OrIE10) { // IE9 doesn't support FileList, hence files variable is undefined
11997                    currFileName = $elem.val().split("\\").pop();
11998                    //update the last element of array
11999                    if (this.$fileDomElements.length > 0) {
12000                        this.$fileDomElements[this.$fileDomElements.length - 1] = $elem;
12001                    }
12002                    this.cloneFileInputAndUpdateIdForIE9();
12003
12004                    // In case of IE9, only do this
12005                    if (_.isUndefined(files)) {
12006                        this.showFileList(currFileName);
12007                        this.values.push(currFileName);
12008                        // trigger the change event to update the value
12009                        this.$element.trigger("change.fileupload");
12010                    }
12011                }
12012                if (!_.isUndefined(files)) {
12013                    var invalidFilesIndexes = [];
12014                    _.each(files, function (file, fileIndex) {
12015                        var isCurrentInvalidFileSize = false,
12016                            isCurrentInvalidFileName = false,
12017                            isCurrentInvalidMimeType = false;
12018                        currFileName = file.name.split("\\").pop();
12019                        // Now size is in MB
12020                        var size = file.size / 1024 / 1024;
12021                        // check if file size limit is within limits
12022                        if ((size > parseFloat(this.options.fileSizeLimit))) {
12023                            isInvalidSize = isCurrentInvalidFileSize = true;
12024                            inValidSizefileNames = currFileName + "," + inValidSizefileNames;
12025                        } else if (!this.isValid(currFileName)) {
12026                            // check if file names are valid (ie) there are no control characters in file names
12027                            isInvalidFileName = isCurrentInvalidFileName = true;
12028                            inValidNamefileNames = currFileName + "," + inValidNamefileNames;
12029                        } else if (file.type) {
12030                            var isMatch = this.regexMimeTypeList.some(function (rx) {
12031                                return rx.test(file.type);
12032                            });
12033                            if (!isMatch) {
12034                                isInvalidMimeType = isCurrentInvalidMimeType = true;
12035                                inValidMimeTypefileNames = currFileName + "," + inValidMimeTypefileNames;
12036                            }
12037                        }
12038
12039                        // if the file is not invalid, show it and push it to internal array
12040                        if (!isCurrentInvalidFileSize && !isCurrentInvalidFileName && !isCurrentInvalidMimeType) {
12041                            this.showFileList(currFileName);
12042                            this.values.push(currFileName);
12043                        } else {
12044                            invalidFilesIndexes.push(fileIndex);
12045                        }
12046
12047
12048                    }, this);
12049
12050                    if (invalidFilesIndexes.length > 0) {
12051                        var currentFileDomIndex,
12052                            $currentFileDomElement,
12053                            filesCount;
12054                        if (this.$fileDomElements.length > 0) {
12055                            currentFileDomIndex = this.$fileDomElements.length - 1;
12056                            $currentFileDomElement = this.$fileDomElements[currentFileDomIndex];
12057                            if ($currentFileDomElement && $currentFileDomElement.length > 0) {
12058                                filesCount = $currentFileDomElement[0].files.length;
12059                                //if all the files are invalid remove the input element as well otherwise only remove the invalid files.
12060                                if (filesCount === invalidFilesIndexes.length) {
12061                                    this.$fileDomElements.splice(-1, 1);
12062                                } else {
12063                                    this._deleteFilesFromInputDom($currentFileDomElement, invalidFilesIndexes);
12064                                }
12065                            }
12066                        }
12067
12068                        // in case of IE10, create one extra element
12069                        if (isBrowserIE9OrIE10) {
12070                            this.cloneFileInputAndUpdateIdForIE9();
12071                        }
12072                    }
12073
12074                    // trigger the change event to update the value
12075                    this.$element.trigger("change.fileupload");
12076                }
12077
12078                if (isInvalidSize) {
12079                    this.showInvalidMessage(inValidSizefileNames.substring(0, inValidSizefileNames.lastIndexOf(',')), this.invalidFeature.SIZE);
12080                } else if (isInvalidFileName) {
12081                    this.showInvalidMessage(inValidNamefileNames.substring(0, inValidNamefileNames.lastIndexOf(',')), this.invalidFeature.NAME);
12082                } else if (isInvalidMimeType) {
12083                    this.showInvalidMessage(inValidMimeTypefileNames.substring(0, inValidMimeTypefileNames.lastIndexOf(',')), this.invalidFeature.MIMETYPE);
12084                }
12085            }
12086        },
12087
12088        cloneFileInputAndUpdateIdForIE9 : function(){
12089            var elem = _.last(this.$fileDomElements),
12090                elemExists = elem != null,
12091                elemHasValue = elemExists && elem.val().length > 0,
12092                elemId = null,
12093                selector = null;
12094
12095            // CQ-4237903 : create clone to handle the case when user clicks cancel in chrome and for multiselect
12096            // on clicking cancel in chrome file browser, chrome removes all the files from the input element
12097            // remove the extra clone in $fileDomElement on handleChange
12098            if(!elemExists || elemHasValue) {
12099                elem = this.$element.clone();
12100                // copy the data attributes
12101                elem.data(this.$element.data());
12102                if(isBrowserIE9OrIE10){
12103                    elemId = this.$element.attr("id") + (++fileLabelsCount);
12104                    elem.attr("id", elemId);
12105                    elem.css({
12106                        'position' : 'absolute',
12107                        'top' : '-2000px',
12108                        'left': '-2000px'
12109                    });
12110                    elem.appendTo('body');
12111                    this.updateLabelForAttr(elemId);
12112                }
12113                elem.change($.proxy(this.handleChange, this));
12114                this.$fileDomElements.push(elem);
12115            }
12116            // Case: if it is not multiselect and if the first file dom element is null
12117            // this case would hit when we restore a single select file attachment and attach a new file
12118            if(!this.options.multiSelect && this.$fileDomElements[0] === null){
12119                //Splice null out of it, since we are attaching a new file
12120                this.$fileDomElements.splice(0, 1);
12121            }
12122            // if the browser is not IE9, then click it
12123            if(!isBrowserIE9OrIE10) {
12124                elem.click();
12125            }
12126            return true;
12127        },
12128
12129        /**
12130         * In case of IE9, get the last element of fileDom and update the id for label
12131         *
12132         * @param fileInputId
12133         */
12134        updateLabelForAttr : function(fileInputId){
12135            this.$label.attr("for" , fileInputId);
12136        },
12137
12138        createLabelForFileInput : function (fileInputId){
12139            if(isBrowserIE9OrIE10) {
12140                this.$label = $("<label></label>").addClass("guide-fu-attach-button button")
12141                        .text(this.options.buttonText)
12142                        .attr('for',fileInputId);
12143                this.$elementFileUploadBtn.replaceWith(this.$label);
12144                this.$label.parent().attr("tabindex", 0).attr("role", "button").attr("aria-label", this.options.screenReaderText || "");
12145            }
12146        },
12147
12148
12149        constructor: function () {
12150            // Initialize the self instance
12151            var _self = this,
12152                isFirst = true;
12153            //jquery instance of file upload button
12154            this.$elementFileUploadBtn = this.$parent.find(this.options.buttonClass);
12155            this.$elementFileUploadBtn.attr("aria-label", this.options.screenReaderText || "");
12156            if(isBrowserIE9OrIE10){
12157                this.elementId = this.$element.attr("id");
12158                this.createLabelForFileInput(this.$element.attr("id"));
12159            }
12160
12161            // html for file list
12162            this.$elementFileList = $(this.fileItemList());
12163            // Initialize the value and file(Refer FileList class mdn)
12164            this.values = [];
12165            this._initialFileValueFileNameMap = {};
12166            // List of dom elements of input type file
12167            this.$fileDomElements = [];
12168
12169            var flag = false,
12170                $currElem = null;
12171
12172            $(document).mousedown(function(e) {
12173                $currElem = $(e.target);
12174            });
12175            // Enter key should result in click of button
12176            this.$elementFileUploadBtn
12177                .focus(function(){
12178                    _self.$element.trigger("focus.fileupload");
12179                })
12180                .click($.proxy(this.cloneFileInputAndUpdateIdForIE9, this))
12181                .blur(function(event){
12182                    // Check if the currElem does not belong to the fileItemList
12183                    if(!flag && $currElem!= null && $currElem.closest(".guide-fu-fileItemList").length <=0){
12184                        _self.$element.trigger("focusout.fileupload");
12185                    }
12186                    flag = false;
12187                });
12188            //Initialize the filePreview Plugin
12189            this.$element[this.options.uploaderPluginName]({
12190                iframeContainer: this.options.iframeContainer,
12191                _filePath: this.options._filePath,
12192                _uuidGenerator: this.options._uuidGenerator,
12193                _getUrl: this.options._getUrl
12194
12195            });
12196            // Getting input file value
12197            // listening on fileuploaded event
12198            this.$element.change($.proxy(this.handleChange, this))
12199                .on("adobeFileUploader.fileUploaded", $.proxy(this.previewFile, this));
12200        }
12201    };
12202
12203    $.fn.adobeFileAttachment = function (option, value) {
12204        var get = '',
12205            element = this.each(function () {
12206                // in case of input type file
12207                if ($(this).attr('type') === 'file') {
12208                    var $this = $(this),
12209                        data = $this.data('adobeFileAttachment'),
12210                        options = $.extend({}, AdobeFileAttachment.prototype.defaults, typeof option === 'object' && option);
12211
12212                    // Save the adobeFileAttachment data in jquery
12213                    if (!data) {
12214                        $this.data('adobeFileAttachment', (data = new AdobeFileAttachment(this, options)));
12215                        data.constructor();
12216                    }
12217
12218                    // code to get and set an option
12219                    if (typeof option === 'string') {
12220                        get = data[option](value);
12221                    }
12222                }
12223            });
12224
12225        if (typeof get !== 'undefined') {
12226            return get;
12227        } else {
12228            return element;
12229        }
12230    };
12231
12232    // fileSizeLimit is in MB, default value is 2MB
12233    AdobeFileAttachment.prototype.defaults = {
12234        'buttonText': 'Attach',
12235        'multiSelect': false,
12236        'fileSizeLimit': 2,
12237        'uploaderPluginName': "adobeFileUploader",
12238        'mimeType' : ['audio/*', 'video/*', 'image/*', 'text/*', 'application/pdf']
12239    };
12240
12241})($, window, window._);
12242(function($, _) {
12243    var xfaUtil = xfalib.ut.XfaUtil.prototype;
12244    $.widget( "xfaWidget.fileUpload", $.xfaWidget.abstractWidget, {
12245
12246        _widgetName:"fileUpload",
12247        _superPrototype : $.xfaWidget.abstractWidget.prototype,
12248        getOptionsMap: function(){
12249            var parentOptionsMap = this._superPrototype.getOptionsMap.apply(this,arguments),
12250                newMap = $.extend({},parentOptionsMap, $.extend({}, this.options, {
12251                    "value" : function(value) {
12252                        this.$userControl.adobeFileAttachment("value", value);
12253                    },
12254                    "fileList": function(value){
12255                        this.$userControl.adobeFileAttachment("fileList", value);
12256                    },
12257                    "comment" : function(value){
12258                        this.$userControl.adobeFileAttachment("comment", value);
12259                    },
12260                    // "access" can be either open or readonly
12261                    "access" : function(value){
12262                        this.$userControl.adobeFileAttachment("access", value);
12263                    }
12264
12265                }));
12266
12267            return newMap;
12268
12269        },
12270        // TODO: Will need to remove this functions
12271        //  will be tracked by LC-391200
12272
12273        _initializeOptions: function () {
12274            _.each(this.optionsHandler, function (value, key) {
12275                // overriding the behaviour of _initializeOptions
12276                // only for _uuidGenerator
12277                // as we font want getUUID to be called at render time
12278                if (typeof value === "function" && key !== '_uuidGenerator' ) {
12279                        value.apply(this, [this.options[key]])
12280                }
12281            }, this)
12282        },
12283
12284        _getFileList: function(){
12285            return this.$userControl.adobeFileAttachment("fileList");
12286        },
12287
12288        _getComment: function(){
12289            return this.$userControl.adobeFileAttachment("comment");
12290        },
12291        _getFileNamePathMap: function (pathList) {
12292            return this.$userControl.adobeFileAttachment("getSetFilePathAndReturnNamePathMap", pathList);
12293        },
12294        getEventMap: function() {
12295            var parentEventMap = this._superPrototype.getEventMap.apply(this, arguments),
12296                newMap = $.extend({}, parentEventMap,
12297                    {
12298                        "change" : null,
12299                        "focusout.fileupload" : xfaUtil.XFA_EXIT_EVENT,
12300                        "focus.fileupload" : xfaUtil.XFA_ENTER_EVENT,
12301                        "change.fileupload" : xfaUtil.XFA_CHANGE_EVENT
12302                    });
12303            return newMap;
12304        },
12305        render: function() {
12306            var $el = this._superPrototype.render.apply(this,arguments);
12307            $el.adobeFileAttachment(this.getOptionsMap());
12308            return $el;
12309        },
12310        showDisplayValue: function() {
12311             //since value can't be set in file element input, leav
12311ing this fn empty
12312        },
12313        showValue: function() {
12314            //since value can't be set in file element input, leaving this fn empty
12315        },
12316        getCommitValue: function() {
12317            this.options.fileList = this._getFileList();
12318            this.options.comment = this._getComment();
12319            return this.$userControl.adobeFileAttachment("value");
12320        }
12321    });
12322})($, window._);
12323
12324/**
12325 * Adobe FilePreview Widget Plugin
12326 *
12327 * Options expected by file preview is the url
12328 *
12329 * Options Required Are:
12330 *
12331 *  iframeName: Name of the Iframe
12332 *  iframeContainer: Container of the iframe(eg Body)
12333 *  fileUploadPath: Path where the file is to be uploaded
12334 *  fileUploadServlet: Servlet where the file is to be uploaded
12335 *
12336 */
12337(function ($, _) {
12338
12339    var AdobeFileUploader = function (element, options) {
12340        this.options = options;
12341        this.$element = $(element);
12342    };
12343
12344    AdobeFileUploader.prototype = {
12345
12346        _fileIframeName: "guide-fu-iframe",
12347
12348        _filePath: "/tmp/fd/mf",
12349
12350        _iframeContainer: "body#formBody",
12351
12352
12353        fileIframe: function (name) {
12354            return $("<iframe></iframe>").attr({
12355                style: "display:none",
12356                name: name
12357            });
12358        },
12359
12360        uploadFile: function (fileObject) {
12361            var multiple = false,
12362                fileName = null,
12363                actionUrl = null,
12364                fileUploadPath = fileObject.fileUploadPath,
12365                uuid;
12366
12367            if (!fileUploadPath) {
12368                uuid = fileObject._uuidGenerator();
12369            }
12370
12371            // if uuid exists only then upload the file in the current  instance
12372            if (_.isObject(fileObject) && (fileUploadPath || uuid)) {
12373                var fileDom = fileObject.fileDom,
12374                    $form = $(this.options.iframeContainer).find(".filePreview");
12375                fileName = fileObject.fileName;
12376                multiple = fileObject.multiple;
12377                if(!fileUploadPath) {
12378                    fileUploadPath = this.options.fileUploadPath + "/" + uuid;
12379                }
12380                if (fileDom !== null) {
12381                    //prepend contextpath
12382                    actionUrl = fileObject._getUrl + fileUploadPath;
12383                    if (!multiple) {
12384                        if (!(fileUploadPath.lastIndexOf(fileObject._getUrl, 0) === 0)) {
12385                            this.fileUrl = fileObject._getUrl + fileUploadPath + "/" + fileName;
12386                        } else {
12387                            this.fileUrl = fileUploadPath + "/" + fileName;
12388                        }
12389                    } else {
12390                        this.fileUrl = actionUrl;
12391                    }
12392                    // done to solve issue LC-5835
12393                    if($form.length === 0) {
12394                        $form = $("<form method='post' enctype='multipart/form-data'></form>")
12395                            .addClass("filePreview")
12396                            // create id so that it does not intercept with other forms in the page
12397                            .attr({
12398                                id : "form" + new Date().valueOf(),
12399                                action : actionUrl,
12400                                target : this.options.iframeName
12401                            })
12402                            .appendTo(this.options.iframeContainer);
12403                    } else {
12404                        /// first empty all children, using detach so that data is not clear
12405                        $form.children().detach();
12406                        // now update the new attributes
12407                        $form.attr({
12408                            action : actionUrl,
12409                            target : this.options.iframeName
12410                        });
12411                    }
12412                    // this is done so that the other events attached at some other level in DOM Tree don't interfere
12413                    $form.one("submit", function(evnt){
12414                        evnt.stopPropagation();
12415                    });
12416
12417                     var data = new FormData();
12418
12419                    if (multiple) {
12420                        _.each(fileDom, function (fileDomElement, index) {
12421                            // OOTB, this code is still used in dashboard
12422                            if(fileDomElement !== null && !_.isString(fileDomElement)) {
12423                                $(fileDomElement[0]).attr('name', fileName[index]).appendTo($form);
12424                                // fileDomElement might contain multiple files so all the files needs to be added to formdata.
12425                                var currentFileNames = fileName[index].split("\n");
12426                                for(var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
12427                                    data.append(currentFileNames[fileIndex], fileDomElement[0].files[fileIndex]);
12428                                }
12429                            }
12430                        }, this);
12431                    } else {
12432                        fileDom.attr('name', fileName).appendTo($form);
12433                        data.append(fileName, fileDom[0].files[0]);
12434                    }
12435
12436                    /* UseCase: Suppose the fileName is in other language, on click of fileName, it tries to upload the file
12437                     so that it could be preview, this change would ensure that the file is properly previewed supp
12437orting
12438                     the given UTF-8 charset */
12439                    $("<input type='hidden' name='_charset_' value='UTF-8'/>").appendTo($form);
12440                    data.append("_charset_", "UTF-8");
12441                    if (!multiple) {
12442                        this.fileMap[this.fileUrl] = this.$element;
12443                    }
12444                    var self = this;
12445                    $.ajax({
12446                        url: $form.attr("action"),
12447                        data: data,
12448                        cache: false,
12449                        contentType: false,
12450                        processData: false,
12451                        method: 'POST',
12452                        type: 'POST',
12453                        success: function(data){
12454                            if (!multiple) {
12455                                self.handleSingleFileUpload(data);
12456                            } else {
12457                                self.handleMultipleFileUpload(data);
12458                            }
12459                        },
12460                        error: function() {
12461                            this.$element.trigger("adobeFileUploader.fileUploadFailed");
12462                        }
12463                    });
12464                }
12465            }
12466            return this.fileUrl;
12467        },
12468
12469        handleMultipleFileUpload: function (data) {
12470            this.$element.trigger("adobeFileUploader.multipleFileUploaded");
12471        },
12472
12473        getFileUrl: function () {
12474            return this.fileUrl;
12475        },
12476
12477        getUrlContentsFromUploadData: function (data) {
12478            var temp;
12479            if(data != null) {
12480                temp = $(data).find("#ChangeLog").text().split("br", 2)[1];
12481            } else {
12482                var selector = this.options.iframeContainer + " iframe[name='" + this.options.iframeName + "']";
12483                temp = $(selector).contents().find("#ChangeLog").text().split("br", 2)[1];
12484            }
12485            
12486            temp = temp.substring(temp.indexOf("created") + 9, temp.indexOf(";<"));
12487            temp = temp.substring(0, temp.length - 2);
12488            var index = temp.indexOf("/jcr:content");
12489            if (index !== -1)
12490                temp = temp.substring(0, index);
12491            return temp;
12492        },
12493
12494        handleSingleFileUpload: function (data) {
12495            var url = this.getUrlContentsFromUploadData(data);
12496
12497            //prepend context path
12498            url = this.options._getUrl + url;
12499            if (url in this.fileMap) {
12500                this.fileMap[url].trigger("adobeFileUploader.fileUploaded");
12501            }
12502        },
12503
12504        initialize: function () {
12505            // Put iframe inside the iframe container
12506            // On the load of iframe, display the contents of file
12507            // since there is only one iframe for all the file attachments, there may be race condition
12508            if (this.$iframe == null || this.$iframe.length === 0) {
12509                this.$iframe = this.fileIframe(this.options.iframeName).appendTo(this.options.iframeContainer);
12510                // since there is only iframe for the preview of all file attachments
12511                // this map is added in the closure scope
12512                // map contains the url(key) vs fileDomElement(value)
12513                // it helps avoids the race condition
12514                this.fileMap = {};
12515            }
12516        }
12517    };
12518
12519    $.fn.adobeFileUploader = function (option, value) {
12520        var get = '',
12521            element = this.each(function () {
12522                // in case of input type file
12523                if ($(this).attr('type') === 'file') {
12524                    var $this = $(this),
12525                        data = $this.data('adobeFileUploader'),
12526                        options = $.extend({}, AdobeFileUploader.prototype.defaults(option, value), typeof option === 'object' && option);
12527
12528                    // Save the adobeFileAttachment data in jquery
12529                    if (!data) {
12530                        $this.data('adobeFileUploader', (data = new AdobeFileUploader(this, options)));
12531                        data.initialize();
12532                    } else {
12533                        // update elements if not equal, since sometimes one can clone too
12534                        if(data.$element.get(0) !== this) {
12535                            data.$element = $(this);
12536                        }
12537                    }
12538
12539                    // code to get and set an option
12540                    if (typeof option === 'string') {
12541                        get = data[option](value);
12542                    }
12543                }
12544            });
12545
12546        if (typeof get !== 'undefined') {
12547            return get;
12548        } else {
12549            return element;
12550        }
12551    };
12552
12553
12554    AdobeFileUploader.prototype.defaults = function (options,value)  {
12555        var propertyObject = {};
12556        if(typeof options == 'object') {
12557            propertyObject._fileIframeName = options._fileIframeName;
12558            propertyObject._filePath = options._filePath;
12559            propertyObject.actionUrl = options.actionUrl;
12560            propertyObject._getUrl = options._getUrl;
12561        }
12562        if(typeof  value == 'object') {
12563            propertyObject._fileIframeName = value._fileIframeName;
12564            propertyObject._filePath = value._filePath;
12565            propertyObject.actionUrl = value.actionUrl;
12566            propertyObject._getUrl = options._getUrl;
12567        }
12568        return {
12569            'fileUploadPath': propertyObject._filePath || AdobeFileUploader.prototype._filePath,
12570            'iframeName': AdobeFileUploader.prototype._fileIframeName + new Date().valueOf(),
12571            'fileUploadServlet': propertyObject._filePath || AdobeFileUploader.prototype._filePath,
vendor: 74,301 bytes, lines 12572-15082
12572            'iframeContainer': propertyObject._iframeContainer || AdobeFileUploader.prototype._iframeContainer,
12573            '_getUrl': propertyObject._getUrl || ""
12574        };
12575    };
12576
12577})($, window._);
12578
12579/*!
12580 * Bootstrap v3.4.1 (https://getbootstrap.com/)
12581 * Copyright 2011-2019 Twitter, Inc.
12582 * Licensed under the MIT license
12583 */
12584
12585if (typeof jQuery === 'undefined') {
12586  throw new Error('Bootstrap\'s JavaScript requires jQuery')
12587}
12588
12589+function ($) {
12590  'use strict';
12591  var version = $.fn.jquery.split(' ')[0].split('.')
12592  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
12593    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
12594  }
12595}(jQuery);
12596
12597/* ========================================================================
12598 * Bootstrap: transition.js v3.4.1
12599 * https://getbootstrap.com/docs/3.4/javascript/#transitions
12600 * ========================================================================
12601 * Copyright 2011-2019 Twitter, Inc.
12602 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12603 * ======================================================================== */
12604
12605
12606+function ($) {
12607  'use strict';
12608
12609  // CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
12610  // ============================================================
12611
12612  function transitionEnd() {
12613    var el = document.createElement('bootstrap')
12614
12615    var transEndEventNames = {
12616      WebkitTransition : 'webkitTransitionEnd',
12617      MozTransition    : 'transitionend',
12618      OTransition      : 'oTransitionEnd otransitionend',
12619      transition       : 'transitionend'
12620    }
12621
12622    for (var name in transEndEventNames) {
12623      if (el.style[name] !== undefined) {
12624        return { end: transEndEventNames[name] }
12625      }
12626    }
12627
12628    return false // explicit for ie8 (  ._.)
12629  }
12630
12631  // https://blog.alexmaccaw.com/css-transitions
12632  $.fn.emulateTransitionEnd = function (duration) {
12633    var called = false
12634    var $el = this
12635    $(this).one('bsTransitionEnd', function () { called = true })
12636    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
12637    setTimeout(callback, duration)
12638    return this
12639  }
12640
12641  $(function () {
12642    $.support.transition = transitionEnd()
12643
12644    if (!$.support.transition) return
12645
12646    $.event.special.bsTransitionEnd = {
12647      bindType: $.support.transition.end,
12648      delegateType: $.support.transition.end,
12649      handle: function (e) {
12650        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
12651      }
12652    }
12653  })
12654
12655}(jQuery);
12656
12657/* ========================================================================
12658 * Bootstrap: alert.js v3.4.1
12659 * https://getbootstrap.com/docs/3.4/javascript/#alerts
12660 * ========================================================================
12661 * Copyright 2011-2019 Twitter, Inc.
12662 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12663 * ======================================================================== */
12664
12665
12666+function ($) {
12667  'use strict';
12668
12669  // ALERT CLASS DEFINITION
12670  // ======================
12671
12672  var dismiss = '[data-dismiss="alert"]'
12673  var Alert   = function (el) {
12674    $(el).on('click', dismiss, this.close)
12675  }
12676
12677  Alert.VERSION = '3.4.1'
12678
12679  Alert.TRANSITION_DURATION = 150
12680
12681  Alert.prototype.close = function (e) {
12682    var $this    = $(this)
12683    var selector = $this.attr('data-target')
12684
12685    if (!selector) {
12686      selector = $this.attr('href')
12687      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
12688    }
12689
12690    selector    = selector === '#' ? [] : selector
12691    var $parent = $(document).find(selector)
12692
12693    if (e) e.preventDefault()
12694
12695    if (!$parent.length) {
12696      $parent = $this.closest('.alert')
12697    }
12698
12699    $parent.trigger(e = $.Event('close.bs.alert'))
12700
12701    if (e.isDefaultPrevented()) return
12702
12703    $parent.removeClass('in')
12704
12705    function removeElement() {
12706      // detach from parent, fire event then clean up data
12707      $parent.detach().trigger('closed.bs.alert').remove()
12708    }
12709
12710    $.support.transition && $parent.hasClass('fade') ?
12711        $parent
12712            .one('bsTransitionEnd', removeElement)
12713            .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
12714        removeElement()
12715  }
12716
12717
12718  // ALERT PLUGIN DEFINITION
12719  // =======================
12720
12721  function Plugin(option) {
12722    return this.each(function () {
12723      var $this = $(this)
12724      var data  = $this.data('bs.alert')
12725
12726      if (!data) $this.data('bs.alert', (data = new Alert(this)))
12727      if (typeof option == 'string') data[option].call($this)
12728    })
12729  }
12730
12731  var old = $.fn.alert
12732
12733  $.fn.alert             = Plugin
12734  $.fn.alert.Constructor = Alert
12735
12736
12737  // ALERT NO CONFLICT
12738  // =================
12739
12740  $.fn.alert.noConflict = function () {
12741    $.fn.alert = old
12742    return this
12743  }
12744
12745
12746  // ALERT DATA-API
12747  // ==============
12748
12749  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
12750
12751}(jQuery);
12752
12753/* ========================================================================
12754 * Bootstrap: button.js v3.4.1
12755 * https://getbootstrap.com/docs/3.4/javascript/#buttons
12756 * ========================================================================
12757 * Copyright 2011-2019 Twitter, Inc.
12758 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12759 * ======================================================================== */
12760
12761
12762+function ($) {
12763  'use strict';
12764
12765  // BUTTON PUBLIC CLASS DEFINITION
12766  // ==============================
12767
12768  var Button = function (element, options) {
12769    this.$element  = $(element)
12770    this.options   = $.extend({}, Button.DEFAULTS, options)
12771    this.isLoading = false
12772  }
12773
12774  Button.VERSION  = '3.4.1'
12775
12776  Button.DEFAULTS = {
12777    loadingText: 'loading...'
12778  }
12779
12780  Button.prototype.setState = function (state) {
12781    var d    = 'disabled'
12782    var $el  = this.$element
12783    var val  = $el.is('input') ? 'val' : 'html'
12784    var data = $el.data()
12785
12786    state += 'Text'
12787
12788    if (data.resetText == null) $el.data('resetText', $el[val]())
12789
12790    // push to event loop to allow forms to submit
12791    setTimeout($.proxy(function () {
12792      $el[val](data[state] == null ? this.options[state] : data[state])
12793
12794      if (state == 'loadingText') {
12795        this.isLoading = true
12796        $el.addClass(d).attr(d, d).prop(d, true)
12797      } else if (this.isLoading) {
12798        this.isLoading = false
12799        $el.removeClass(d).removeAttr(d).prop(d, false)
12800      }
12801    }, this), 0)
12802  }
12803
12804  Button.prototype.toggle = function () {
12805    var changed = true
12806    var $parent = this.$element.closest('[data-toggle="buttons"]')
12807
12808    if ($parent.length) {
12809      var $input = this.$element.find('input')
12810      if ($input.prop('type') == 'radio') {
12811        if ($input.prop('checked')) changed = false
12812        $parent.find('.active').removeClass('active')
12813        this.$element.addClass('active')
12814      } else if ($input.prop('type') == 'checkbox') {
12815        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
12816        this.$element.toggleClass('active')
12817      }
12818      $input.prop('checked', this.$element.hasClass('active'))
12819      if (changed) $input.trigger('change')
12820    } else {
12821      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
12822      this.$element.toggleClass('active')
12823    }
12824  }
12825
12826
12827  // BUTTON PLUGIN DEFINITION
12828  // ========================
12829
12830  function Plugin(option) {
12831    return this.each(function () {
12832      var $this   = $(this)
12833      var data    = $this.data('bs.button')
12834      var options = typeof option == 'object' && option
12835
12836      if (!data) $this.data('bs.button', (data = new Button(this, options)))
12837
12838      if (option == 'toggle') data.toggle()
12839      else if (option) data.setState(option)
12840    })
12841  }
12842
12843  var old = $.fn.button
12844
12845  $.fn.button             = Plugin
12846  $.fn.button.Constructor = Button
12847
12848
12849  // BUTTON NO CONFLICT
12850  // ==================
12851
12852  $.fn.button.noConflict = function () {
12853    $.fn.button = old
12854    return this
12855  }
12856
12857
12858  // BUTTON DATA-API
12859  // ===============
12860
12861  $(document)
12862      .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
12863        var $btn = $(e.target).closest('.btn')
12864        Plugin.call($btn, 'toggle')
12865        if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
12866          // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
12867          e.preventDefault()
12868          // The target component still receive the focus
12869          if ($btn.is('input,button')) $btn.trigger('focus')
12870          else $btn.find('input:visible,button:visible').first().trigger('focus')
12871        }
12872      })
12873      .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
12874        $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
12875      })
12876
12877}(jQuery);
12878
12879/* ========================================================================
12880 * Bootstrap: carousel.js v3.4.1
12881 * https://getbootstrap.com/docs/3.4/javascript/#carousel
12882 * ========================================================================
12883 * Copyright 2011-2019 Twitter, Inc.
12884 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12885 * ======================================================================== */
12886
12887
12888+function ($) {
12889  'use strict';
12890
12891  // CAROUSEL CLASS DEFINITION
12892  // =========================
12893
12894  var Carousel = function (element, options) {
12895    this.$element    = $(element)
12896    this.$indicators = this.$element.find('.carousel-indicators')
12897    this.options     = options
12898    this.paused      = null
12899    this.sliding     = null
12900    this.interval    = null
12901    this.$active     = null
12902    this.$items      = null
12903
12904    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
12905
12906    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
12907        .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
12908        .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
12909  }
12910
12911  Carousel.VERSION  = '3.4.1'
12912
12913  Carousel.TRANSITION_DURATION = 600
12914
12915  Carousel.DEFAULTS = {
12916    interval: 5000,
12917    pause: 'hover',
12918    wrap: true,
12919    keyboard: true
12920  }
12921
12922  Carousel.prototype.keydown = function (e) {
12923    if (/input|textarea/i.test(e.target.tagName)) return
12924    switch (e.which) {
12925      case 37: this.prev(); break
12926      case 39: this.next(); break
12927      default: return
12928    }
12929
12930    e.preventDefault()
12931  }
12932
12933  Carousel.prototype.cycle = function (e) {
12934    e || (this.paused = false)
12935
12936    this.interval && clearInterval(this.interval)
12937
12938    this.options.interval
12939    && !this.paused
12940    && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
12941
12942    return this
12943  }
12944
12945  Carousel.prototype.getItemIndex = function (item) {
12946    this.$items = item.parent().children('.item')
12947    return this.$items.index(item || this.$active)
12948  }
12949
12950  Carousel.prototype.getItemForDirection = function (direction, active) {
12951    var activeIndex = this.getItemIndex(active)
12952    var willWrap = (direction == 'prev' && activeIndex === 0)
12953        || (direction == 'next' && activeIndex == (this.$items.length - 1))
12954    if (willWrap && !this.options.wrap) return active
12955    var delta = direction == 'prev' ? -1 : 1
12956    var itemIndex = (activeIndex + delta) % this.$items.length
12957    return this.$items.eq(itemIndex)
12958  }
12959
12960  Carousel.prototype.to = function (pos) {
12961    var that        = this
12962    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
12963
12964    if (pos > (this.$items.length - 1) || pos < 0) return
12965
12966    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
12967    if (activeIndex == pos) return this.pause().cycle()
12968
12969    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
12970  }
12971
12972  Carousel.prototype.pause = function (e) {
12973    e || (this.paused = true)
12974
12975    if (this.$element.find('.next, .prev').length && $.support.transition) {
12976      this.$element.trigger($.support.transition.end)
12977      this.cycle(true)
12978    }
12979
12980    this.interval = clearInterval(this.interval)
12981
12982    return this
12983  }
12984
12985  Carousel.prototype.next = function () {
12986    if (this.sliding) return
12987    return this.slide('next')
12988  }
12989
12990  Carousel.prototype.prev = function () {
12991    if (this.sliding) return
12992    return this.slide('prev')
12993  }
12994
12995  Carousel.prototype.slide = function (type, next) {
12996    var $active   = this.$element.find('.item.active')
12997    var $next     = next || this.getItemForDirection(type, $active)
12998    var isCycling = this.interval
12999    var direction = type == 'next' ? 'left' : 'right'
13000    var that      = this
13001
13002    if ($next.hasClass('active')) return (this.sliding = false)
13003
13004    var relatedTarget = $next[0]
13005    var slideEvent = $.Event('slide.bs.carousel', {
13006      relatedTarget: relatedTarget,
13007      direction: direction
13008    })
13009    this.$element.trigger(slideEvent)
13010    if (slideEvent.isDefaultPrevented()) return
13011
13012    this.sliding = true
13013
13014    isCycling && this.pause()
13015
13016    if (this.$indicators.length) {
13017      this.$indicators.find('.active').removeClass('active')
13018      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
13019      $nextIndicator && $nextIndicator.addClass('active')
13020    }
13021
13022    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
13023    if ($.support.transition && this.$element.hasClass('slide')) {
13024      $next.addClass(type)
13025      if (typeof $next === 'object' && $next.length) {
13026        $next[0].offsetWidth // force reflow
13027      }
13028      $active.addClass(direction)
13029      $next.addClass(direction)
13030      $active
13031          .one('bsTransitionEnd', function () {
13032            $next.removeClass([type, direction].join(' ')).addClass('active')
13033            $active.removeClass(['active', direction].join(' '))
13034            that.sliding = false
13035            setTimeout(function () {
13036              that.$element.trigger(slidEvent)
13037            }, 0)
13038          })
13039          .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
13040    } else {
13041      $active.removeClass('active')
13042      $next.addClass('active')
13043      this.sliding = false
13044      this.$element.trigger(slidEvent)
13045    }
13046
13047    isCycling && this.cycle()
13048
13049    return this
13050  }
13051
13052
13053  // CAROUSEL PLUGIN DEFINITION
13054  // ==========================
13055
13056  function Plugin(option) {
13057    return this.each(function () {
13058      var $this   = $(this)
13059      var data    = $this.data('bs.carousel')
13060      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
13061      var action  = typeof option == 'string' ? option : options.slide
13062
13063      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
13064      if (typeof option == 'number') data.to(option)
13065      else if (action) data[action]()
13066      else if (options.interval) data.pause().cycle()
13067    })
13068  }
13069
13070  var old = $.fn.carousel
13071
13072  $.fn.carousel             = Plugin
13073  $.fn.carousel.Constructor = Carousel
13074
13075
13076  // CAROUSEL NO CONFLICT
13077  // ====================
13078
13079  $.fn.carousel.noConflict = function () {
13080    $.fn.carousel = old
13081    return this
13082  }
13083
13084
13085  // CAROUSEL DATA-API
13086  // =================
13087
13088  var clickHandler = function (e) {
13089    var $this   = $(this)
13090    var href    = $this.attr('href')
13091    if (href) {
13092      href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
13093    }
13094
13095    var target  = $this.attr('data-target') || href
13096    var $target = $(document).find(target)
13097
13098    if (!$target.hasClass('carousel')) return
13099
13100    var options = $.extend({}, $target.data(), $this.data())
13101    var slideIndex = $this.attr('data-slide-to')
13102    if (slideIndex) options.interval = false
13103
13104    Plugin.call($target, options)
13105
13106    if (slideIndex) {
13107      $target.data('bs.carousel').to(slideIndex)
13108    }
13109
13110    e.preventDefault()
13111  }
13112
13113  $(document)
13114      .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
13115      .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
13116
13117  $(window).on('load', function () {
13118    $('[data-ride="carousel"]').each(function () {
13119      var $carousel = $(this)
13120      Plugin.call($carousel, $carousel.data())
13121    })
13122  })
13123
13124}(jQuery);
13125
13126/* ========================================================================
13127 * Bootstrap: collapse.js v3.4.1
13128 * https://getbootstrap.com/docs/3.4/javascript/#collapse
13129 * ========================================================================
13130 * Copyright 2011-2019 Twitter, Inc.
13131 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13132 * ======================================================================== */
13133
13134/* jshint latedef: false */
13135
13136+function ($) {
13137  'use strict';
13138
13139  // COLLAPSE PUBLIC CLASS DEFINITION
13140  // ================================
13141
13142  var Collapse = function (element, options) {
13143    this.$element      = $(element)
13144    this.options       = $.extend({}, Collapse.DEFAULTS, options)
13145    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
13146        '[data-toggle="collapse"][data-target="#' + element.id + '"]')
13147    this.transitioning = null
13148
13149    if (this.options.parent) {
13150      this.$parent = this.getParent()
13151    } else {
13152      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
13153    }
13154
13155    if (this.options.toggle) this.toggle()
13156  }
13157
13158  Collapse.VERSION  = '3.4.1'
13159
13160  Collapse.TRANSITION_DURATION = 350
13161
13162  Collapse.DEFAULTS = {
13163    toggle: true
13164  }
13165
13166  Collapse.prototype.dimension = function () {
13167    var hasWidth = this.$element.hasClass('width')
13168    return hasWidth ? 'width' : 'height'
13169  }
13170
13171  Collapse.prototype.show = function () {
13172    if (this.transitioning || this.$element.hasClass('in')) return
13173
13174    var activesData
13175    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
13176
13177    if (actives && actives.length) {
13178      activesData = actives.data('bs.collapse')
13179      if (activesData && activesData.transitioning) return
13180    }
13181
13182    var startEvent = $.Event('show.bs.collapse')
13183    this.$element.trigger(startEvent)
13184    if (startEvent.isDefaultPrevented()) return
13185
13186    if (actives && actives.length) {
13187      Plugin.call(actives, 'hide')
13188      activesData || actives.data('bs.collapse', null)
13189    }
13190
13191    var dimension = this.dimension()
13192
13193    this.$element
13194        .removeClass('collapse')
13195        .addClass('collapsing')[dimension](0)
13196        .attr('aria-expanded', true)
13197
13198    this.$trigger
13199        .removeClass('collapsed')
13200        .attr('aria-expanded', true)
13201
13202    this.transitioning = 1
13203
13204    var complete = function () {
13205      this.$element
13206          .removeClass('collapsing')
13207          .addClass('collapse in')[dimension]('')
13208      this.transitioning = 0
13209      this.$element
13210          .trigger('shown.bs.collapse')
13211    }
13212
13213    if (!$.support.transition) return complete.call(this)
13214
13215    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
13216
13217    this.$element
13218        .one('bsTransitionEnd', $.proxy(complete, this))
13219        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
13220  }
13221
13222  Collapse.prototype.hide = function () {
13223    if (this.transitioning || !this.$element.hasClass('in')) return
13224
13225    var startEvent = $.Event('hide.bs.collapse')
13226    this.$element.trigger(startEvent)
13227    if (startEvent.isDefaultPrevented()) return
13228
13229    var dimension = this.dimension()
13230
13231    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
13232
13233    this.$element
13234        .addClass('collapsing')
13235        .removeClass('collapse in')
13236        .attr('aria-expanded', false)
13237
13238    this.$trigger
13239        .addClass('collapsed')
13240        .attr('aria-expanded', false)
13241
13242    this.transitioning = 1
13243
13244    var complete = function () {
13245      this.transitioning = 0
13246      this.$element
13247          .removeClass('collapsing')
13248          .addClass('collapse')
13249          .trigger('hidden.bs.collapse')
13250    }
13251
13252    if (!$.support.transition) return complete.call(this)
13253
13254    this.$element
13255        [dimension](0)
13256        .one('bsTransitionEnd', $.proxy(complete, this))
13257        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
13258  }
13259
13260  Collapse.prototype.toggle = function () {
13261    this[this.$element.hasClass('in') ? 'hide' : 'show']()
13262  }
13263
13264  Collapse.prototype.getParent = function () {
13265    return $(document).find(this.options.parent)
13266        .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
13267        .each($.proxy(function (i, element) {
13268          var $element = $(element)
13269          this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
13270        }, this))
13271        .end()
13272  }
13273
13274  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
13275    var isOpen = $element.hasClass('in')
13276
13277    $element.attr('aria-expanded', isOpen)
13278    $trigger
13279        .toggleClass('collapsed', !isOpen)
13280        .attr('aria-expanded', isOpen)
13281  }
13282
13283  function getTargetFromTrigger($trigger) {
13284    var href
13285    var target = $trigger.attr('data-target')
13286        || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
13287
13288    return $(document).find(target)
13289  }
13290
13291
13292  // COLLAPSE PLUGIN DEFINITION
13293  // ==========================
13294
13295  function Plugin(option) {
13296    return this.each(function () {
13297      var $this   = $(this)
13298      var data    = $this.data('bs.collapse')
13299      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
13300
13301      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
13302      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
13303      if (typeof option == 'string') data[option]()
13304    })
13305  }
13306
13307  var old = $.fn.collapse
13308
13309  $.fn.collapse             = Plugin
13310  $.fn.collapse.Constructor = Collapse
13311
13312
13313  // COLLAPSE NO CONFLICT
13314  // ====================
13315
13316  $.fn.collapse.noConflict = function () {
13317    $.fn.collapse = old
13318    return this
13319  }
13320
13321
13322  // COLLAPSE DATA-API
13323  // =================
13324
13325  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
13326    var $this   = $(this)
13327
13328    if (!$this.attr('data-target')) e.preventDefault()
13329
13330    var $target = getTargetFromTrigger($this)
13331    var data    = $target.data('bs.collapse')
13332    var option  = data ? 'toggle' : $this.data()
13333
13334    Plugin.call($target, option)
13335  })
13336
13337}(jQuery);
13338
13339/* ========================================================================
13340 * Bootstrap: dropdown.js v3.4.1
13341 * https://getbootstrap.com/docs/3.4/javascript/#dropdowns
13342 * ========================================================================
13343 * Copyright 2011-2019 Twitter, Inc.
13344 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13345 * ======================================================================== */
13346
13347
13348+function ($) {
13349  'use strict';
13350
13351  // DROPDOWN CLASS DEFINITION
13352  // =========================
13353
13354  var backdrop = '.dropdown-backdrop'
13355  var toggle   = '[data-toggle="dropdown"]'
13356  var Dropdown = function (element) {
13357    $(element).on('click.bs.dropdown', this.toggle)
13358  }
13359
13360  Dropdown.VERSION = '3.4.1'
13361
13362  function getParent($this) {
13363    var selector = $this.attr('data-target')
13364
13365    if (!selector) {
13366      selector = $this.attr('href')
13367      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
13368    }
13369
13370    var $parent = selector !== '#' ? $(document).find(selector) : null
13371
13372    return $parent && $parent.length ? $parent : $this.parent()
13373  }
13374
13375  function clearMenus(e) {
13376    if (e && e.which === 3) return
13377    $(backdrop).remove()
13378    $(toggle).each(function () {
13379      var $this         = $(this)
13380      var $parent       = getParent($this)
13381      var relatedTarget = { relatedTarget: this }
13382
13383      if (!$parent.hasClass('open')) return
13384
13385      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
13386
13387      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
13388
13389      if (e.isDefaultPrevented()) return
13390
13391      $this.attr('aria-expanded', 'false')
13392      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
13393    })
13394  }
13395
13396  Dropdown.prototype.toggle = function (e) {
13397    var $this = $(this)
13398
13399    if ($this.is('.disabled, :disabled')) return
13400
13401    var $parent  = getParent($this)
13402    var isActive = $parent.hasClass('open')
13403
13404    clearMenus()
13405
13406    if (!isActive) {
13407      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
13408        // if mobile we use a backdrop because click events don't delegate
13409        $(document.createElement('div'))
13410            .addClass('dropdown-backdrop')
13411            .insertAfter($(this))
13412            .on('click', clearMenus)
13413      }
13414
13415      var relatedTarget = { relatedTarget: this }
13416      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
13417
13418      if (e.isDefaultPrevented()) return
13419
13420      $this
13421          .trigger('focus')
13422          .attr('aria-expanded', 'true')
13423
13424      $parent
13425          .toggleClass('open')
13426          .trigger($.Event('shown.bs.dropdown', relatedTarget))
13427    }
13428
13429    return false
13430  }
13431
13432  Dropdown.prototype.keydown = function (e) {
13433    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
13434
13435    var $this = $(this)
13436
13437    e.preventDefault()
13438    e.stopPropagation()
13439
13440    if ($this.is('.disabled, :disabled')) return
13441
13442    var $parent  = getParent($this)
13443    var isActive = $parent.hasClass('open')
13444
13445    if (!isActive && e.which != 27 || isActive && e.which == 27) {
13446      if (e.which == 27) $parent.find(toggle).trigger('focus')
13447      return $this.trigger('click')
13448    }
13449
13450    var desc = ' li:not(.disabled):visible a'
13451    var $items = $parent.find('.dropdown-menu' + desc)
13452
13453    if (!$items.length) return
13454
13455    var index = $items.index(e.target)
13456
13457    if (e.which == 38 && index > 0)                 index--         // up
13458    if (e.which == 40 && index < $items.length - 1) index++         // down
13459    if (!~index)                                    index = 0
13460
13461    $items.eq(index).trigger('focus')
13462  }
13463
13464
13465  // DROPDOWN PLUGIN DEFINITION
13466  // ==========================
13467
13468  function Plugin(option) {
13469    return this.each(function () {
13470      var $this = $(this)
13471      var data  = $this.data('bs.dropdown')
13472
13473      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
13474      if (typeof option == 'string') data[option].call($this)
13475    })
13476  }
13477
13478  var old = $.fn.dropdown
13479
13480  $.fn.dropdown             = Plugin
13481  $.fn.dropdown.Constructor = Dropdown
13482
13483
13484  // DROPDOWN NO CONFLICT
13485  // ====================
13486
13487  $.fn.dropdown.noConflict = function () {
13488    $.fn.dropdown = old
13489    return this
13490  }
13491
13492
13493  // APPLY TO STANDARD DROPDOWN ELEMENTS
13494  // ===================================
13495
13496  $(document)
13497      .on('click.bs.dropdown.data-api', clearMenus)
13498      .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
13499      .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
13500      .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
13501      .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
13502
13503}(jQuery);
13504
13505/* ========================================================================
13506 * Bootstrap: modal.js v3.4.1
13507 * https://getbootstrap.com/docs/3.4/javascript/#modals
13508 * ========================================================================
13509 * Copyright 2011-2019 Twitter, Inc.
13510 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13511 * ======================================================================== */
13512
13513
13514+function ($) {
13515  'use strict';
13516
13517  // MODAL CLASS DEFINITION
13518  // ======================
13519
13520  var Modal = function (element, options) {
13521    this.options = options
13522    this.$body = $(document.body)
13523    this.$element = $(element)
13524    this.$dialog = this.$element.find('.modal-dialog')
13525    this.$backdrop = null
13526    this.isShown = null
13527    this.originalBodyPad = null
13528    this.scrollbarWidth = 0
13529    this.ignoreBackdropClick = false
13530    this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
13531
13532    if (this.options.remote) {
13533      this.$element
13534          .find('.modal-content')
13535          .load(this.options.remote, $.proxy(function () {
13536            this.$element.trigger('loaded.bs.modal')
13537          }, this))
13538    }
13539  }
13540
13541  Modal.VERSION = '3.4.1'
13542
13543  Modal.TRANSITION_DURATION = 300
13544  Modal.BACKDROP_TRANSITION_DURATION = 150
13545
13546  Modal.DEFAULTS = {
13547    backdrop: true,
13548    keyboard: true,
13549    show: true
13550  }
13551
13552  Modal.prototype.toggle = function (_relatedTarget) {
13553    return this.isShown ? this.hide() : this.show(_relatedTarget)
13554  }
13555
13556  Modal.prototype.show = function (_relatedTarget) {
13557    var that = this
13558    var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
13559
13560    this.$element.trigger(e)
13561
13562    if (this.isShown || e.isDefaultPrevented()) return
13563
13564    this.isShown = true
13565
13566    this.checkScrollbar()
13567    this.setScrollbar()
13568    this.$body.addClass('modal-open')
13569
13570    this.escape()
13571    this.resize()
13572
13573    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
13574
13575    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
13576      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
13577        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
13578      })
13579    })
13580
13581    this.backdrop(function () {
13582      var transition = $.support.transition && that.$element.hasClass('fade')
13583
13584      if (!that.$element.parent().length) {
13585        that.$element.appendTo(that.$body) // don't move modals dom position
13586      }
13587
13588      that.$element
13589          .show()
13590          .scrollTop(0)
13591
13592      that.adjustDialog()
13593
13594      if (transition) {
13595        that.$element[0].offsetWidth // force reflow
13596      }
13597
13598      that.$element.addClass('in')
13599
13600      that.enforceFocus()
13601
13602      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
13603
13604      transition ?
13605          that.$dialog // wait for modal to slide in
13606              .one('bsTransitionEnd', function () {
13607                that.$element.trigger('focus').trigger(e)
13608              })
13609              .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
13610          that.$element.trigger('focus').trigger(e)
13611    })
13612  }
13613
13614  Modal.prototype.hide = function (e) {
13615    if (e) e.preventDefault()
13616
13617    e = $.Event('hide.bs.modal')
13618
13619    this.$element.trigger(e)
13620
13621    if (!this.isShown || e.isDefaultPrevented()) return
13622
13623    this.isShown = false
13624
13625    this.escape()
13626    this.resize()
13627
13628    $(document).off('focusin.bs.modal')
13629
13630    this.$element
13631        .removeClass('in')
13632        .off('click.dismiss.bs.modal')
13633        .off('mouseup.dismiss.bs.modal')
13634
13635    this.$dialog.off('mousedown.dismiss.bs.modal')
13636
13637    $.support.transition && this.$element.hasClass('fade') ?
13638        this.$element
13639            .one('bsTransitionEnd', $.proxy(this.hideModal, this))
13640            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
13641        this.hideModal()
13642  }
13643
13644  Modal.prototype.enforceFocus = function () {
13645    $(document)
13646        .off('focusin.bs.modal') // guard against infinite focus loop
13647        .on('focusin.bs.modal', $.proxy(function (e) {
13648          if (document !== e.target &&
13649              this.$element[0] !== e.target &&
13650              !this.$element.has(e.target).length) {
13651            this.$element.trigger('focus')
13652          }
13653        }, this))
13654  }
13655
13656  Modal.prototype.escape = function () {
13657    if (this.isShown && this.options.keyboard) {
13658      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
13659        e.which == 27 && this.hide()
13660      }, this))
13661    } else if (!this.isShown) {
13662      this.$element.off('keydown.dismiss.bs.modal')
13663    }
13664  }
13665
13666  Modal.prototype.resize = function () {
13667    if (this.isShown) {
13668      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
13669    } else {
13670      $(window).off('resize.bs.modal')
13671    }
13672  }
13673
13674  Modal.prototype.hideModal = function () {
13675    var that = this
13676    this.$element.hide()
13677    this.backdrop(function () {
13678      that.$body.removeClass('modal-open')
13679      that.resetAdjustments()
13680      that.resetScrollbar()
13681      that.$element.trigger('hidden.bs.modal')
13682    })
13683  }
13684
13685  Modal.prototype.removeBackdrop = function () {
13686    this.$backdrop && this.$backdrop.remove()
13687    this.$backdrop = null
13688  }
13689
13690  Modal.prototype.backdrop = function (callback) {
13691    var that = this
13692    var animate = this.$element.hasClass('fade') ? 'fade' : ''
13693
13694    if (this.isShown && this.options.backdrop) {
13695      var doAnimate = $.support.transition && animate
13696
13697      this.$backdrop = $(document.createElement('div'))
13698          .addClass('modal-backdrop ' + animate)
13699          .appendTo(this.$body)
13700
13701      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
13702        if (this.ignoreBackdropClick) {
13703          this.ignoreBackdropClick = false
13704          return
13705        }
13706        if (e.target !== e.currentTarget) return
13707        this.options.backdrop == 'static'
13708            ? this.$element[0].focus()
13709            : this.hide()
13710      }, this))
13711
13712      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
13713
13714      this.$backdrop.addClass('in')
13715
13716      if (!callback) return
13717
13718      doAnimate ?
13719          this.$backdrop
13720              .one('bsTransitionEnd', callback)
13721              .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
13722          callback()
13723
13724    } else if (!this.isShown && this.$backdrop) {
13725      this.$backdrop.removeClass('in')
13726
13727      var callbackRemove = function () {
13728        that.removeBackdrop()
13729        callback && callback()
13730      }
13731      $.support.transition && this.$element.hasClass('fade') ?
13732          this.$backdrop
13733              .one('bsTransitionEnd', callbackRemove)
13734              .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
13735          callbackRemove()
13736
13737    } else if (callback) {
13738      callback()
13739    }
13740  }
13741
13742  // these following methods are used to handle overflowing modals
13743
13744  Modal.prototype.handleUpdate = function () {
13745    this.adjustDialog()
13746  }
13747
13748  Modal.prototype.adjustDialog = function () {
13749    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
13750
13751    this.$element.css({
13752      paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
13753      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
13754    })
13755  }
13756
13757  Modal.prototype.resetAdjustments = function () {
13758    this.$element.css({
13759      paddingLeft: '',
13760      paddingRight: ''
13761    })
13762  }
13763
13764  Modal.prototype.checkScrollbar = function () {
13765    var fullWindowWidth = window.innerWidth
13766    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
13767      var documentElementRect = document.documentElement.getBoundingClientRect()
13768      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
13769    }
13770    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
13771    this.scrollbarWidth = this.measureScrollbar()
13772  }
13773
13774  Modal.prototype.setScrollbar = function () {
13775    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
13776    this.originalBodyPad = document.body.style.paddingRight || ''
13777    var scrollbarWidth = this.scrollbarWidth
13778    if (this.bodyIsOverflowing) {
13779      this.$body.css('padding-right', bodyPad + scrollbarWidth)
13780      $(this.fixedContent).each(function (index, element) {
13781        var actualPadding = element.style.paddingRight
13782        var calculatedPadding = $(element).css('padding-right')
13783        $(element)
13784            .data('padding-right', actualPadding)
13785            .css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
13786      })
13787    }
13788  }
13789
13790  Modal.prototype.resetScrollbar = function () {
13791    this.$body.css('padding-right', this.originalBodyPad)
13792    $(this.fixedContent).each(function (index, element) {
13793      var padding = $(element).data('padding-right')
13794      $(element).removeData('padding-right')
13795      element.style.paddingRight = padding ? padding : ''
13796    })
13797  }
13798
13799  Modal.prototype.measureScrollbar = function () { // thx walsh
13800    var scrollDiv = document.createElement('div')
13801    scrollDiv.className = 'modal-scrollbar-measure'
13802    this.$body.append(scrollDiv)
13803    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
13804    this.$body[0].removeChild(scrollDiv)
13805    return scrollbarWidth
13806  }
13807
13808
13809  // MODAL PLUGIN DEFINITION
13810  // =======================
13811
13812  function Plugin(option, _relatedTarget) {
13813    return this.each(function () {
13814      var $this = $(this)
13815      var data = $this.data('bs.modal')
13816      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
13817
13818      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
13819      if (typeof option == 'string') data[option](_relatedTarget)
13820      else if (options.show) data.show(_relatedTarget)
13821    })
13822  }
13823
13824  var old = $.fn.modal
13825
13826  $.fn.modal = Plugin
13827  $.fn.modal.Constructor = Modal
13828
13829
13830  // MODAL NO CONFLICT
13831  // =================
13832
13833  $.fn.modal.noConflict = function () {
13834    $.fn.modal = old
13835    return this
13836  }
13837
13838
13839  // MODAL DATA-API
13840  // ==============
13841
13842  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
13843    var $this = $(this)
13844    var href = $this.attr('href')
13845    var target = $this.attr('data-target') ||
13846        (href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
13847
13848    var $target = $(document).find(target)
13849    var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
13850
13851    if ($this.is('a')) e.preventDefault()
13852
13853    $target.one('show.bs.modal', function (showEvent) {
13854      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
13855      $target.one('hidden.bs.modal', function () {
13856        $this.is(':visible') && $this.trigger('focus')
13857      })
13858    })
13859    Plugin.call($target, option, this)
13860  })
13861
13862}(jQuery);
13863
13864/* ========================================================================
13865 * Bootstrap: tooltip.js v3.4.1
13866 * https://getbootstrap.com/docs/3.4/javascript/#tooltip
13867 * Inspired by the original jQuery.tipsy by Jason Frame
13868 * ========================================================================
13869 * Copyright 2011-2019 Twitter, Inc.
13870 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13871 * ======================================================================== */
13872
13873+function ($) {
13874  'use strict';
13875
13876  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
13877
13878  var uriAttrs = [
13879    'background',
13880    'cite',
13881    'href',
13882    'itemtype',
13883    'longdesc',
13884    'poster',
13885    'src',
13886    'xlink:href'
13887  ]
13888
13889  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
13890
13891  var DefaultWhitelist = {
13892    // Global attributes allowed on any supplied element below.
13893    '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
13894    a: ['target', 'href', 'title', 'rel'],
13895    area: [],
13896    b: [],
13897    br: [],
13898    col: [],
13899    code: [],
13900    div: [],
13901    em: [],
13902    hr: [],
13903    h1: [],
13904    h2: [],
13905    h3: [],
13906    h4: [],
13907    h5: [],
13908    h6: [],
13909    i: [],
13910    img: ['src', 'alt', 'title', 'width', 'height'],
13911    li: [],
13912    ol: [],
13913    p: [],
13914    pre: [],
13915    s: [],
13916    small: [],
13917    span: [],
13918    sub: [],
13919    sup: [],
13920    strong: [],
13921    u: [],
13922    ul: []
13923  }
13924
13925  /**
13926   * A pattern that recognizes a commonly useful subset of URLs that are safe.
13927   *
13928   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
13929   */
13930  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
13931
13932  /**
13933   * A pattern that matches safe data URLs. Only matches image, video and audio types.
13934   *
13935   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
13936   */
13937  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
13938
13939  function allowedAttribute(attr, allowedAttributeList) {
13940    var attrName = attr.nodeName.toLowerCase()
13941
13942    if ($.inArray(attrName, allowedAttributeList) !== -1) {
13943      if ($.inArray(attrName, uriAttrs) !== -1) {
13944        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
13945      }
13946
13947      return true
13948    }
13949
13950    var regExp = $(allowedAttributeList).filter(function (index, value) {
13951      return value instanceof RegExp
13952    })
13953
13954    // Check if a regular expression validates the attribute.
13955    for (var i = 0, l = regExp.length; i < l; i++) {
13956      if (attrName.match(regExp[i])) {
13957        return true
13958      }
13959    }
13960
13961    return false
13962  }
13963
13964  function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
13965    if (unsafeHtml.length === 0) {
13966      return unsafeHtml
13967    }
13968
13969    if (sanitizeFn && typeof sanitizeFn === 'function') {
13970      return sanitizeFn(unsafeHtml)
13971    }
13972
13973    // IE 8 and below don't support createHTMLDocument
13974    if (!document.implementation || !document.implementation.createHTMLDocument) {
13975      return unsafeHtml
13976    }
13977
13978    var createdDocument = document.implementation.createHTMLDocument('sanitization')
13979    createdDocument.body.innerHTML = unsafeHtml
13980
13981    var whitelistKeys = $.map(whiteList, function (el, i) { return i })
13982    var elements = $(createdDocument.body).find('*')
13983
13984    for (var i = 0, len = elements.length; i < len; i++) {
13985      var el = elements[i]
13986      var elName = el.nodeName.toLowerCase()
13987
13988      if ($.inArray(elName, whitelistKeys) === -1) {
13989        el.parentNode.removeChild(el)
13990
13991        continue
13992      }
13993
13994      var attributeList = $.map(el.attributes, function (el) { return el })
13995      var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
13996
13997      for (var j = 0, len2 = attributeList.length; j < len2; j++) {
13998        if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
13999          el.removeAttribute(attributeList[j].nodeName)
14000        }
14001      }
14002    }
14003
14004    return createdDocument.body.innerHTML
14005  }
14006
14007  // TOOLTIP PUBLIC CLASS DEFINITION
14008  // ===============================
14009
14010  var Tooltip = function (element, options) {
14011    this.type       = null
14012    this.options    = null
14013    this.enabled    = null
14014    this.timeout    = null
14015    this.hoverState = null
14016    this.$element   = null
14017    this.inState    = null
14018
14019    this.init('tooltip', element, options)
14020  }
14021
14022  Tooltip.VERSION  = '3.4.1'
14023
14024  Tooltip.TRANSITION_DURATION = 150
14025
14026  Tooltip.DEFAULTS = {
14027    animation: true,
14028    placement: 'top',
14029    selector: false,
14030    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
14031    trigger: 'hover focus',
14032    title: '',
14033    delay: 0,
14034    html: false,
14035    container: false,
14036    viewport: {
14037      selector: 'body',
14038      padding: 0
14039    },
14040    sanitize : true,
14041    sanitizeFn : null,
14042    whiteList : DefaultWhitelist
14043  }
14044
14045  Tooltip.prototype.init = function (type, element, options) {
14046    this.enabled   = true
14047    this.type      = type
14048    this.$element  = $(element)
14049    this.options   = this.getOptions(options)
14050    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))
14051    this.inState   = { click: false, hover: false, focus: false }
14052
14053    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
14054      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
14055    }
14056
14057    var triggers = this.options.trigger.split(' ')
14058
14059    for (var i = triggers.length; i--;) {
14060      var trigger = triggers[i]
14061
14062      if (trigger == 'click') {
14063        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
14064      } else if (trigger != 'manual') {
14065        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
14066        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
14067
14068        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
14069        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
14070      }
14071    }
14072
14073    this.options.selector ?
14074        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
14075        this.fixTitle()
14076  }
14077
14078  Tooltip.prototype.getDefaults = function () {
14079    return Tooltip.DEFAULTS
14080  }
14081
14082  Tooltip.prototype.getOptions = function (options) {
14083    var dataAttributes = this.$element.data()
14084
14085    for (var dataAttr in dataAttributes) {
14086      if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
14087        delete dataAttributes[dataAttr]
14088      }
14089    }
14090
14091    options = $.extend({}, this.getDefaults(), dataAttributes, options)
14092
14093    if (options.delay && typeof options.delay == 'number') {
14094      options.delay = {
14095        show: options.delay,
14096        hide: options.delay
14097      }
14098    }
14099
14100    if (options.sanitize) {
14101      options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
14102    }
14103
14104    return options
14105  }
14106
14107  Tooltip.prototype.getDelegateOptions = function () {
14108    var options  = {}
14109    var defaults = this.getDefaults()
14110
14111    this._options && $.each(this._options, function (key, value) {
14112      if (defaults[key] != value) options[key] = value
14113    })
14114
14115    return options
14116  }
14117
14118  Tooltip.prototype.enter = function (obj) {
14119    var self = obj instanceof this.constructor ?
14120        obj : $(obj.currentTarget).data('bs.' + this.type)
14121
14122    if (!self) {
14123      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
14124      $(obj.currentTarget).data('bs.' + this.type, self)
14125    }
14126
14127    if (obj instanceof $.Event) {
14128      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
14129    }
14130
14131    if (self.tip().hasClass('in') || self.hoverState == 'in') {
14132      self.hoverState = 'in'
14133      return
14134    }
14135
14136    clearTimeout(self.timeout)
14137
14138    self.hoverState = 'in'
14139
14140    if (!self.options.delay || !self.options.delay.show) return self.show()
14141
14142    self.timeout = setTimeout(function () {
14143      if (self.hoverState == 'in') self.show()
14144    }, self.options.delay.show)
14145  }
14146
14147  Tooltip.prototype.isInStateTrue = function () {
14148    for (var key in this.inState) {
14149      if (this.inState[key]) return true
14150    }
14151
14152    return false
14153  }
14154
14155  Tooltip.prototype.leave = function (obj) {
14156    var self = obj instanceof this.constructor ?
14157        obj : $(obj.currentTarget).data('bs.' + this.type)
14158
14159    if (!self) {
14160      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
14161      $(obj.currentTarget).data('bs.' + this.type, self)
14162    }
14163
14164    if (obj instanceof $.Event) {
14165      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
14166    }
14167
14168    if (self.isInStateTrue()) return
14169
14170    clearTimeout(self.timeout)
14171
14172    self.hoverState = 'out'
14173
14174    if (!self.options.delay || !self.options.delay.hide) return self.hide()
14175
14176    self.timeout = setTimeout(function () {
14177      if (self.hoverState == 'out') self.hide()
14178    }, self.options.delay.hide)
14179  }
14180
14181  Tooltip.prototype.show = function () {
14182    var e = $.Event('show.bs.' + this.type)
14183
14184    if (this.hasContent() && this.enabled) {
14185      this.$element.trigger(e)
14186
14187      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
14188      if (e.isDefaultPrevented() || !inDom) return
14189      var that = this
14190
14191      var $tip = this.tip()
14192
14193      var tipId = this.getUID(this.type)
14194
14195      this.setContent()
14196      $tip.attr('id', tipId)
14197      this.$element.attr('aria-describedby', tipId)
14198
14199      if (this.options.animation) $tip.addClass('fade')
14200
14201      var placement = typeof this.options.placement == 'function' ?
14202          this.options.placement.call(this, $tip[0], this.$element[0]) :
14203          this.options.placement
14204
14205      var autoToken = /\s?auto?\s?/i
14206      var autoPlace = autoToken.test(placement)
14207      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
14208
14209      $tip
14210          .detach()
14211          .css({ top: 0, left: 0, display: 'block' })
14212          .addClass(placement)
14213          .data('bs.' + this.type, this)
14214
14215      this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
14216      this.$element.trigger('inserted.bs.' + this.type)
14217
14218      var pos          = this.getPosition()
14219      var actualWidth  = $tip[0].offsetWidth
14220      var actualHeight = $tip[0].offsetHeight
14221
14222      if (autoPlace) {
14223        var orgPlacement = placement
14224        var viewportDim = this.getPosition(this.$viewport)
14225
14226        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
14227            placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
14228                placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
14229                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
14230                        placement
14231
14232        $tip
14233            .removeClass(orgPlacement)
14234            .addClass(placement)
14235      }
14236
14237      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
14238
14239      this.applyPlacement(calculatedOffset, placement)
14240
14241      var complete = function () {
14242        var prevHoverState = that.hoverState
14243        that.$element.trigger('shown.bs.' + that.type)
14244        that.hoverState = null
14245
14246        if (prevHoverState == 'out') that.leave(that)
14247      }
14248
14249      $.support.transition && this.$tip.hasClass('fade') ?
14250          $tip
14251              .one('bsTransitionEnd', complete)
14252              .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
14253          complete()
14254    }
14255  }
14256
14257  Tooltip.prototype.applyPlacement = function (offset, placement) {
14258    var $tip   = this.tip()
14259    var width  = $tip[0].offsetWidth
14260    var height = $tip[0].offsetHeight
14261
14262    // manually read margins because getBoundingClientRect includes difference
14263    var marginTop = parseInt($tip.css('margin-top'), 10)
14264    var marginLeft = parseInt($tip.css('margin-left'), 10)
14265
14266    // we must check for NaN for ie 8/9
14267    if (isNaN(marginTop))  marginTop  = 0
14268    if (isNaN(marginLeft)) marginLeft = 0
14269
14270    offset.top  += marginTop
14271    offset.left += marginLeft
14272
14273    // $.fn.offset doesn't round pixel values
14274    // so we use setOffset directly with our own function B-0
14275    $.offset.setOffset($tip[0], $.extend({
14276      using: function (props) {
14277        $tip.css({
14278          top: Math.round(props.top),
14279          left: Math.round(props.left)
14280        })
14281      }
14282    }, offset), 0)
14283
14284    $tip.addClass('in')
14285
14286    // check to see if placing tip in new offset caused the tip to resize itself
14287    var actualWidth  = $tip[0].offsetWidth
14288    var actualHeight = $tip[0].offsetHeight
14289
14290    if (placement == 'top' && actualHeight != height) {
14291      offset.top = offset.top + height - actualHeight
14292    }
14293
14294    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
14295
14296    if (delta.left) offset.left += delta.left
14297    else offset.top += delta.top
14298
14299    var isVertical          = /top|bottom/.test(placement)
14300    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
14301    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
14302
14303    $tip.offset(offset)
14304    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
14305  }
14306
14307  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
14308    this.arrow()
14309        .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
14310        .css(isVertical ? 'top' : 'left', '')
14311  }
14312
14313  Tooltip.prototype.setContent = function () {
14314    var $tip  = this.tip()
14315    var title = this.getTitle()
14316
14317    if (this.options.html) {
14318      if (this.options.sanitize) {
14319        title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
14320      }
14321
14322      $tip.find('.tooltip-inner').html(title)
14323    } else {
14324      $tip.find('.tooltip-inner').text(title)
14325    }
14326
14327    $tip.removeClass('fade in top bottom left right')
14328  }
14329
14330  Tooltip.prototype.hide = function (callback) {
14331    var that = this
14332    var $tip = $(this.$tip)
14333    var e    = $.Event('hide.bs.' + this.type)
14334
14335    function complete() {
14336      if (that.hoverState != 'in') $tip.detach()
14337      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
14338        that.$element
14339            .removeAttr('aria-describedby')
14340            .trigger('hidden.bs.' + that.type)
14341      }
14342      callback && callback()
14343    }
14344
14345    this.$element.trigger(e)
14346
14347    if (e.isDefaultPrevented()) return
14348
14349    $tip.removeClass('in')
14350
14351    $.support.transition && $tip.hasClass('fade') ?
14352        $tip
14353            .one('bsTransitionEnd', complete)
14354            .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
14355        complete()
14356
14357    this.hoverState = null
14358
14359    return this
14360  }
14361
14362  Tooltip.prototype.fixTitle = function () {
14363    var $e = this.$element
14364    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
14365      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
14366    }
14367  }
14368
14369  Tooltip.prototype.hasContent = function () {
14370    return this.getTitle()
14371  }
14372
14373  Tooltip.prototype.getPosition = function ($element) {
14374    $element   = $element || this.$element
14375
14376    var el     = $element[0]
14377    var isBody = el.tagName == 'BODY'
14378
14379    var elRect    = el.getBoundingClientRect()
14380    if (elRect.width == null) {
14381      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
14382      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
14383    }
14384    var isSvg = window.SVGElement && el instanceof window.SVGElement
14385    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
14386    // See https://github.com/twbs/bootstrap/issues/20280
14387    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
14388    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
14389    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
14390
14391    return $.extend({}, elRect, scroll, outerDims, elOffset)
14392  }
14393
14394  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
14395    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
14396        placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
14397            placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
14398                /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
14399
14400  }
14401
14402  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
14403    var delta = { top: 0, left: 0 }
14404    if (!this.$viewport) return delta
14405
14406    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
14407    var viewportDimensions = this.getPosition(this.$viewport)
14408
14409    if (/right|left/.test(placement)) {
14410      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
14411      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
14412      if (topEdgeOffset < viewportDimensions.top) { // top overflow
14413        delta.top = viewportDimensions.top - topEdgeOffset
14414      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
14415        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
14416      }
14417    } else {
14418      var leftEdgeOffset  = pos.left - viewportPadding
14419      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
14420      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
14421        delta.left = viewportDimensions.left - leftEdgeOffset
14422      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
14423        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
14424      }
14425    }
14426
14427    return delta
14428  }
14429
14430  Tooltip.prototype.getTitle = function () {
14431    var title
14432    var $e = this.$element
14433    var o  = this.options
14434
14435    title = $e.attr('data-original-title')
14436        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
14437
14438    return title
14439  }
14440
14441  Tooltip.prototype.getUID = function (prefix) {
14442    do prefix += ~~(Math.random() * 1000000)
14443    while (document.getElementById(prefix))
14444    return prefix
14445  }
14446
14447  Tooltip.prototype.tip = function () {
14448    if (!this.$tip) {
14449      this.$tip = $(this.options.template)
14450      if (this.$tip.length != 1) {
14451        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
14452      }
14453    }
14454    return this.$tip
14455  }
14456
14457  Tooltip.prototype.arrow = function () {
14458    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
14459  }
14460
14461  Tooltip.prototype.enable = function () {
14462    this.enabled = true
14463  }
14464
14465  Tooltip.prototype.disable = function () {
14466    this.enabled = false
14467  }
14468
14469  Tooltip.prototype.toggleEnabled = function () {
14470    this.enabled = !this.enabled
14471  }
14472
14473  Tooltip.prototype.toggle = function (e) {
14474    var self = this
14475    if (e) {
14476      self = $(e.currentTarget).data('bs.' + this.type)
14477      if (!self) {
14478        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
14479        $(e.currentTarget).data('bs.' + this.type, self)
14480      }
14481    }
14482
14483    if (e) {
14484      self.inState.click = !self.inState.click
14485      if (self.isInStateTrue()) self.enter(self)
14486      else self.leave(self)
14487    } else {
14488      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
14489    }
14490  }
14491
14492  Tooltip.prototype.destroy = function () {
14493    var that = this
14494    clearTimeout(this.timeout)
14495    this.hide(function () {
14496      that.$element.off('.' + that.type).removeData('bs.' + that.type)
14497      if (that.$tip) {
14498        that.$tip.detach()
14499      }
14500      that.$tip = null
14501      that.$arrow = null
14502      that.$viewport = null
14503      that.$element = null
14504    })
14505  }
14506
14507  Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
14508    return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
14509  }
14510
14511  // TOOLTIP PLUGIN DEFINITION
14512  // =========================
14513
14514  function Plugin(option) {
14515    return this.each(function () {
14516      var $this   = $(this)
14517      var data    = $this.data('bs.tooltip')
14518      var options = typeof option == 'object' && option
14519
14520      if (!data && /destroy|hide/.test(option)) return
14521      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
14522      if (typeof option == 'string') data[option]()
14523    })
14524  }
14525
14526  var old = $.fn.tooltip
14527
14528  $.fn.tooltip             = Plugin
14529  $.fn.tooltip.Constructor = Tooltip
14530
14531
14532  // TOOLTIP NO CONFLICT
14533  // ===================
14534
14535  $.fn.tooltip.noConflict = function () {
14536    $.fn.tooltip = old
14537    return this
14538  }
14539
14540}(jQuery);
14541
14542/* ========================================================================
14543 * Bootstrap: popover.js v3.4.1
14544 * https://getbootstrap.com/docs/3.4/javascript/#popovers
14545 * ========================================================================
14546 * Copyright 2011-2019 Twitter, Inc.
14547 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14548 * ======================================================================== */
14549
14550
14551+function ($) {
14552  'use strict';
14553
14554  // POPOVER PUBLIC CLASS DEFINITION
14555  // ===============================
14556
14557  var Popover = function (element, options) {
14558    this.init('popover', element, options)
14559  }
14560
14561  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
14562
14563  Popover.VERSION  = '3.4.1'
14564
14565  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
14566    placement: 'right',
14567    trigger: 'click',
14568    content: '',
14569    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
14570  })
14571
14572
14573  // NOTE: POPOVER EXTENDS tooltip.js
14574  // ================================
14575
14576  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
14577
14578  Popover.prototype.constructor = Popover
14579
14580  Popover.prototype.getDefaults = function () {
14581    return Popover.DEFAULTS
14582  }
14583
14584  Popover.prototype.setContent = function () {
14585    var $tip    = this.tip()
14586    var title   = this.getTitle()
14587    var content = this.getContent()
14588
14589    if (this.options.html) {
14590      var typeContent = typeof content
14591
14592      if (this.options.sanitize) {
14593        title = this.sanitizeHtml(title)
14594
14595        if (typeContent === 'string') {
14596          content = this.sanitizeHtml(content)
14597        }
14598      }
14599
14600      $tip.find('.popover-title').html(title)
14601      $tip.find('.popover-content').children().detach().end()[
14602          typeContent === 'string' ? 'html' : 'append'
14603          ](content)
14604    } else {
14605      $tip.find('.popover-title').text(title)
14606      $tip.find('.popover-content').children().detach().end().text(content)
14607    }
14608
14609    $tip.removeClass('fade top bottom left right in')
14610
14611    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
14612    // this manually by checking the contents.
14613    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
14614  }
14615
14616  Popover.prototype.hasContent = function () {
14617    return this.getTitle() || this.getContent()
14618  }
14619
14620  Popover.prototype.getContent = function () {
14621    var $e = this.$element
14622    var o  = this.options
14623
14624    return $e.attr('data-content')
14625        || (typeof o.content == 'function' ?
14626            o.content.call($e[0]) :
14627            o.content)
14628  }
14629
14630  Popover.prototype.arrow = function () {
14631    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
14632  }
14633
14634
14635  // POPOVER PLUGIN DEFINITION
14636  // =========================
14637
14638  function Plugin(option) {
14639    return this.each(function () {
14640      var $this   = $(this)
14641      var data    = $this.data('bs.popover')
14642      var options = typeof option == 'object' && option
14643
14644      if (!data && /destroy|hide/.test(option)) return
14645      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
14646      if (typeof option == 'string') data[option]()
14647    })
14648  }
14649
14650  var old = $.fn.popover
14651
14652  $.fn.popover             = Plugin
14653  $.fn.popover.Constructor = Popover
14654
14655
14656  // POPOVER NO CONFLICT
14657  // ===================
14658
14659  $.fn.popover.noConflict = function () {
14660    $.fn.popover = old
14661    return this
14662  }
14663
14664}(jQuery);
14665
14666/* ========================================================================
14667 * Bootstrap: scrollspy.js v3.4.1
14668 * https://getbootstrap.com/docs/3.4/javascript/#scrollspy
14669 * ========================================================================
14670 * Copyright 2011-2019 Twitter, Inc.
14671 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14672 * ======================================================================== */
14673
14674
14675+function ($) {
14676  'use strict';
14677
14678  // SCROLLSPY CLASS DEFINITION
14679  // ==========================
14680
14681  function ScrollSpy(element, options) {
14682    this.$body          = $(document.body)
14683    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
14684    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
14685    this.selector       = (this.options.target || '') + ' .nav li > a'
14686    this.offsets        = []
14687    this.targets        = []
14688    this.activeTarget   = null
14689    this.scrollHeight   = 0
14690
14691    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
14692    this.refresh()
14693    this.process()
14694  }
14695
14696  ScrollSpy.VERSION  = '3.4.1'
14697
14698  ScrollSpy.DEFAULTS = {
14699    offset: 10
14700  }
14701
14702  ScrollSpy.prototype.getScrollHeight = function () {
14703    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
14704  }
14705
14706  ScrollSpy.prototype.refresh = function () {
14707    var that          = this
14708    var offsetMethod  = 'offset'
14709    var offsetBase    = 0
14710
14711    this.offsets      = []
14712    this.targets      = []
14713    this.scrollHeight = this.getScrollHeight()
14714
14715    if (!$.isWindow(this.$scrollElement[0])) {
14716      offsetMethod = 'position'
14717      offsetBase   = this.$scrollElement.scrollTop()
14718    }
14719
14720    this.$body
14721        .find(this.selector)
14722        .map(function () {
14723          var $el   = $(this)
14724          var href  = $el.data('target') || $el.attr('href')
14725          var $href = /^#./.test(href) && $(href)
14726
14727          return ($href
14728              && $href.length
14729              && $href.is(':visible')
14730              && [[$href[offsetMethod]().top + offsetBase, href]]) || null
14731        })
14732        .sort(function (a, b) { return a[0] - b[0] })
14733        .each(function () {
14734          that.offsets.push(this[0])
14735          that.targets.push(this[1])
14736        })
14737  }
14738
14739  ScrollSpy.prototype.process = function () {
14740    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
14741    var scrollHeight = this.getScrollHeight()
14742    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
14743    var offsets      = this.offsets
14744    var targets      = this.targets
14745    var activeTarget = this.activeTarget
14746    var i
14747
14748    if (this.scrollHeight != scrollHeight) {
14749      this.refresh()
14750    }
14751
14752    if (scrollTop >= maxScroll) {
14753      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
14754    }
14755
14756    if (activeTarget && scrollTop < offsets[0]) {
14757      this.activeTarget = null
14758      return this.clear()
14759    }
14760
14761    for (i = offsets.length; i--;) {
14762      activeTarget != targets[i]
14763      && scrollTop >= offsets[i]
14764      && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
14765      && this.activate(targets[i])
14766    }
14767  }
14768
14769  ScrollSpy.prototype.activate = function (target) {
14770    this.activeTarget = target
14771
14772    this.clear()
14773
14774    var selector = this.selector +
14775        '[data-target="' + target + '"],' +
14776        this.selector + '[href="' + target + '"]'
14777
14778    var active = $(selector)
14779        .parents('li')
14780        .addClass('active')
14781
14782    if (active.parent('.dropdown-menu').length) {
14783      active = active
14784          .closest('li.dropdown')
14785          .addClass('active')
14786    }
14787
14788    active.trigger('activate.bs.scrollspy')
14789  }
14790
14791  ScrollSpy.prototype.clear = function () {
14792    $(this.selector)
14793        .parentsUntil(this.options.target, '.active')
14794        .removeClass('active')
14795  }
14796
14797
14798  // SCROLLSPY PLUGIN DEFINITION
14799  // ===========================
14800
14801  function Plugin(option) {
14802    return this.each(function () {
14803      var $this   = $(this)
14804      var data    = $this.data('bs.scrollspy')
14805      var options = typeof option == 'object' && option
14806
14807      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
14808      if (typeof option == 'string') data[option]()
14809    })
14810  }
14811
14812  var old = $.fn.scrollspy
14813
14814  $.fn.scrollspy             = Plugin
14815  $.fn.scrollspy.Constructor = ScrollSpy
14816
14817
14818  // SCROLLSPY NO CONFLICT
14819  // =====================
14820
14821  $.fn.scrollspy.noConflict = function () {
14822    $.fn.scrollspy = old
14823    return this
14824  }
14825
14826
14827  // SCROLLSPY DATA-API
14828  // ==================
14829
14830  $(window).on('load.bs.scrollspy.data-api', function () {
14831    $('[data-spy="scroll"]').each(function () {
14832      var $spy = $(this)
14833      Plugin.call($spy, $spy.data())
14834    })
14835  })
14836
14837}(jQuery);
14838
14839/* ========================================================================
14840 * Bootstrap: tab.js v3.4.1
14841 * https://getbootstrap.com/docs/3.4/javascript/#tabs
14842 * ========================================================================
14843 * Copyright 2011-2019 Twitter, Inc.
14844 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14845 * ======================================================================== */
14846
14847
14848+function ($) {
14849  'use strict';
14850
14851  // TAB CLASS DEFINITION
14852  // ====================
14853
14854  var Tab = function (element) {
14855    // jscs:disable requireDollarBeforejQueryAssignment
14856    this.element = $(element)
14857    // jscs:enable requireDollarBeforejQueryAssignment
14858  }
14859
14860  Tab.VERSION = '3.4.1'
14861
14862  Tab.TRANSITION_DURATION = 150
14863
14864  Tab.prototype.show = function () {
14865    var $this    = this.element
14866    var $ul      = $this.closest('ul:not(.dropdown-menu)')
14867    var selector = $this.data('target')
14868
14869    if (!selector) {
14870      selector = $this.attr('href')
14871      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
14872    }
14873
14874    if ($this.parent('li').hasClass('active')) return
14875
14876    var $previous = $ul.find('.active:last a')
14877    var hideEvent = $.Event('hide.bs.tab', {
14878      relatedTarget: $this[0]
14879    })
14880    var showEvent = $.Event('show.bs.tab', {
14881      relatedTarget: $previous[0]
14882    })
14883
14884    $previous.trigger(hideEvent)
14885    $this.trigger(showEvent)
14886
14887    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
14888
14889    var $target = $(document).find(selector)
14890
14891    this.activate($this.closest('li'), $ul)
14892    this.activate($target, $target.parent(), function () {
14893      $previous.trigger({
14894        type: 'hidden.bs.tab',
14895        relatedTarget: $this[0]
14896      })
14897      $this.trigger({
14898        type: 'shown.bs.tab',
14899        relatedTarget: $previous[0]
14900      })
14901    })
14902  }
14903
14904  Tab.prototype.activate = function (element, container, callback) {
14905    var $active    = container.find('> .active')
14906    var transition = callback
14907        && $.support.transition
14908        && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
14909
14910    function next() {
14911      $active
14912          .removeClass('active')
14913          .find('> .dropdown-menu > .active')
14914          .removeClass('active')
14915          .end()
14916          .find('[data-toggle="tab"]')
14917          .attr('aria-expanded', false)
14918
14919      element
14920          .addClass('active')
14921          .find('[data-toggle="tab"]')
14922          .attr('aria-expanded', true)
14923
14924      if (transition) {
14925        element[0].offsetWidth // reflow for transition
14926        element.addClass('in')
14927      } else {
14928        element.removeClass('fade')
14929      }
14930
14931      if (element.parent('.dropdown-menu').length) {
14932        element
14933            .closest('li.dropdown')
14934            .addClass('active')
14935            .end()
14936            .find('[data-toggle="tab"]')
14937            .attr('aria-expanded', true)
14938      }
14939
14940      callback && callback()
14941    }
14942
14943    $active.length && transition ?
14944        $active
14945            .one('bsTransitionEnd', next)
14946            .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
14947        next()
14948
14949    $active.removeClass('in')
14950  }
14951
14952
14953  // TAB PLUGIN DEFINITION
14954  // =====================
14955
14956  function Plugin(option) {
14957    return this.each(function () {
14958      var $this = $(this)
14959      var data  = $this.data('bs.tab')
14960
14961      if (!data) $this.data('bs.tab', (data = new Tab(this)))
14962      if (typeof option == 'string') data[option]()
14963    })
14964  }
14965
14966  var old = $.fn.tab
14967
14968  $.fn.tab             = Plugin
14969  $.fn.tab.Constructor = Tab
14970
14971
14972  // TAB NO CONFLICT
14973  // ===============
14974
14975  $.fn.tab.noConflict = function () {
14976    $.fn.tab = old
14977    return this
14978  }
14979
14980
14981  // TAB DATA-API
14982  // ============
14983
14984  var clickHandler = function (e) {
14985    e.preventDefault()
14986    Plugin.call($(this), 'show')
14987  }
14988
14989  $(document)
14990      .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
14991      .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
14992
14993}(jQuery);
14994
14995/* ========================================================================
14996 * Bootstrap: affix.js v3.4.1
14997 * https://getbootstrap.com/docs/3.4/javascript/#affix
14998 * ========================================================================
14999 * Copyright 2011-2019 Twitter, Inc.
15000 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
15001 * ======================================================================== */
15002
15003
15004+function ($) {
15005  'use strict';
15006
15007  // AFFIX CLASS DEFINITION
15008  // ======================
15009
15010  var Affix = function (element, options) {
15011    this.options = $.extend({}, Affix.DEFAULTS, options)
15012
15013    var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
15014
15015    this.$target = target
15016        .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
15017        .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
15018
15019    this.$element     = $(element)
15020    this.affixed      = null
15021    this.unpin        = null
15022    this.pinnedOffset = null
15023
15024    this.checkPosition()
15025  }
15026
15027  Affix.VERSION  = '3.4.1'
15028
15029  Affix.RESET    = 'affix affix-top affix-bottom'
15030
15031  Affix.DEFAULTS = {
15032    offset: 0,
15033    target: window
15034  }
15035
15036  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
15037    var scrollTop    = this.$target.scrollTop()
15038    var position     = this.$element.offset()
15039    var targetHeight = this.$target.height()
15040
15041    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
15042
15043    if (this.affixed == 'bottom') {
15044      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
15045      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
15046    }
15047
15048    var initializing   = this.affixed == null
15049    var colliderTop    = initializing ? scrollTop : position.top
15050    var colliderHeight = initializing ? targetHeight : height
15051
15052    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
15053    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
15054
15055    return false
15056  }
15057
15058  Affix.prototype.getPinnedOffset = function () {
15059    if (this.pinnedOffset) return this.pinnedOffset
15060    this.$element.removeClass(Affix.RESET).addClass('affix')
15061    var scrollTop = this.$target.scrollTop()
15062    var position  = this.$element.offset()
15063    return (this.pinnedOffset = position.top - scrollTop)
15064  }
15065
15066  Affix.prototype.checkPositionWithEventLoop = function () {
15067    setTimeout($.proxy(this.checkPosition, this), 1)
15068  }
15069
15070  Affix.prototype.checkPosition = function () {
15071    if (!this.$element.is(':visible')) return
15072
15073    var height       = this.$element.height()
15074    var offset       = this.options.offset
15075    var offsetTop    = offset.top
15076    var offsetBottom = offset.bottom
15077    var scrollHeight = Math.max($(document).height(), $(document.body).height())
15078
15079    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
15080    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
15081    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
15082
15083    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
15084
15085    if (this.affixed != affix) {
15086      if (this.unpin != null) this.$element.css('top', '')
15087
15088      var affixType = 'affix' + (affix ? '-' + affix : '')
15089      var e         = $.Event(affixType + '.bs.affix')
15090
15091      this.$element.trigger(e)
15092
15093      if (e.isDefaultPrevented()) return
15094
15095      this.affixed = affix
15096      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
15097
15098      this.$element
15099          .removeClass(Affix.RESET)
15100          .addClass(affixType)
15101          .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
15102    }
15103
15104    if (affix == 'bottom') {
15105      this.$element.offset({
15106        top: scrollHeight - height - offsetBottom
15107      })
15108    }
15109  }
15110
15111
15112  // AFFIX PLUGIN DEFINITION
15113  // =======================
15114
15115  function Plugin(option) {
15116    return this.each(function () {
15117      var $this   = $(this)
15118      var data    = $this.data('bs.affix')
15119      var options = typeof option == 'object' && option
15120
15121      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
15122      if (typeof option == 'string') data[option]()
15123    })
15124  }
15125
15126  var old = $.fn.affix
15127
15128  $.fn.affix             = Plugin
15129  $.fn.affix.Constructor = Affix
15130
15131
15132  // AFFIX NO CONFLICT
15133  // =================
15134
15135  $.fn.affix.noConflict = function () {
15136    $.fn.affix = old
15137    return this
15138  }
15139
15140
15141  // AFFIX DATA-API
15142  // ==============
15143
15144  $(window).on('load', function () {
15145    $('[data-spy="affix"]').each(function () {
15146      var $spy = $(this)
15147      var data = $spy.data()
15148
15149      data.offset = data.offset || {}
15150
15151      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
15152      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
15153
15154      Plugin.call($spy, data)
15155    })
15156  })
15157
15158}(jQuery);
15159
15160/*
15161 * jQuery Templating Plugin
15162 * Copyright 2010, John Resig
15163 * Dual licensed under the MIT or GPL Version 2 licenses.
15164 */
15165(function( jQuery, undefined ){
15166    var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,
15167        newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];
15168
15169    function newTmplItem( options, parentItem, fn, data ) {
15170        // Returns a template item data structure for a new rendered instance of a template (a 'template item').
15171        // The content field is a hierarchical array of strings and nested items (to be
15172        // removed and replaced by nodes field of dom elements, once inserted in DOM).
15173        var newItem = {
15174            data: data || (parentItem ? parentItem.data : {}),
15175            _wrap: parentItem ? parentItem._wrap : null,
15176            tmpl: null,
15177            parent: parentItem || null,
15178            nodes: [],
15179            calls: tiCalls,
15180            nest: tiNest,
15181            wrap: tiWrap,
15182            html: tiHtml,
15183            update: tiUpdate
15184        };
15185        if ( options ) {
15186            jQuery.extend( newItem, options, { nodes: [], parent: parentItem } );
15187        }
15188        if ( fn ) {
15189            // Build the hierarchical content to be used during insertion into DOM
15190            newItem.tmpl = fn;
15191            newItem._ctnt = newItem._ctnt || newItem.tmpl( jQuery, newItem );
15192            newItem.key = ++itemKey;
15193            // Keep track of new template item, until it is stored as jQuery Data on DOM element
15194            (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem;
15195        }
15196        return newItem;
15197    }
15198
15199    // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core).
15200    jQuery.each({
15201        appendTo: "append",
15202        prependTo: "prepend",
15203        insertBefore: "before",
15204        insertAfter: "after",
15205        replaceAll: "replaceWith"
15206    }, function( name, original ) {
15207        jQuery.fn[ name ] = function( selector ) {
15208            var ret = [], insert = jQuery( selector ), elems, i, l, tmplItems,
15209                parent = this.length === 1 && this[0].parentNode;
15210
15211            appendToTmplItems = newTmplItems || {};
15212            if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
15213                insert[ original ]( this[0] );
15214                ret = this;
15215            } else {
15216                for ( i = 0, l = insert.length; i < l; i++ ) {
15217                    cloneIndex = i;
15218                    elems = (i > 0 ? this.clone(true) : this).get();
15219                    jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
15220                    ret = ret.concat( elems );
15221                }
15222                cloneIndex = 0;
15223                ret = this.pushStack( ret, name, insert.selector );
15224            }
15225            tmplItems = appendToTmplItems;
15226            appendToTmplItems = null;
15227            jQuery.tmpl.complete( tmplItems );
15228            return ret;
15229        };
15230    });
15231
15232    jQuery.fn.extend({
15233        // Use first wrapped element as template markup.
15234        // Return wrapped set of template items, obtained by rendering template against data.
15235        tmpl: function( data, options, parentItem ) {
15236            return jQuery.tmpl( this[0], data, options, parentItem );
15237        },
15238
15239        // Find which rendered template item the first wrapped DOM element belongs to
15240        tmplItem: function() {
15241            return jQuery.tmplItem( this[0] );
15242        },
15243
15244        // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template.
15245        template: function( name ) {
15246            return jQuery.template( name, this[0] );
15247        },
15248
15249        domManip: function( args, table, callback, options ) {
15250            // This appears to be a bug in the appendTo, etc. implementation
15251            // it should be doing .call() instead of .apply(). See #6227
15252            if ( args[0] && args[0].nodeType ) {
15253                var dmArgs = jQuery.makeArray( arguments ), argsLength = args.length, i = 0, tmplItem;
15254                while ( i < argsLength && !(tmplItem = jQuery.data( args[i++], "tmplItem" ))) {}
15255                if ( argsLength > 1 ) {
15256                    dmArgs[0] = [jQuery.makeArray( args )];
15257                }
15258                if ( tmplItem && cloneIndex ) {
15259                    dmArgs[2] = function( fragClone ) {
15260                        // Handler called by oldManip when rendered template has been inserted into DOM.
15261                        jQuery.tmpl.afterManip( this, fragClone, callback );
15262                    };
15263                }
15264                oldManip.apply( this, dmArgs );
15265            } else {
15266                oldManip.apply( this, arguments );
15267            }
15268            cloneIndex = 0;
15269            if ( !appendToTmplItems ) {
15270                jQuery.tmpl.complete( newTmplItems );
15271            }
15272            return this;
15273        }
15274    });
15275
15276    jQuery.extend({
15277        // Return wrapped set of template items, obtained by rendering template against data.
15278        tmpl: function( tmpl, data, options, parentItem ) {
15279            var ret, topLevel = !parentItem;
15280            if ( topLevel ) {
15281                // This is a top-level tmpl call (not from a nested template using {{tmpl}})
15282                parentItem = topTmplItem;
15283                tmpl = jQuery.template[tmpl] || jQuery.template( null, tmpl );
15284                wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level
15285            } else if ( !tmpl ) {
15286                // The template item is already associated with DOM - this is a refresh.
15287                // Re-evaluate rendered template for the parentItem
15288                tmpl = parentItem.tmpl;
15289                newTmplItems[parentItem.key] = parentItem;
15290                parentItem.nodes = [];
15291                if ( parentItem.wrapped ) {
15292                    updateWrapped( parentItem, parentItem.wrapped );
15293                }
15294                // Rebuild, without creating a new template item
15295                return jQuery( build( parentItem, null, parentItem.tmpl( jQuery, parentItem ) ));
15296            }
15297            if ( !tmpl ) {
15298                return []; // Could throw...
15299            }
15300            if ( typeof data === "function" ) {
15301                data = data.call( parentItem || {} );
15302            }
15303            if ( options && options.wrapped ) {
15304                updateWrapped( options, options.wrapped );
15305            }
15306            ret = jQuery.isArray( data ) ?
15307                jQuery.map( data, function( dataItem ) {
15308                    return dataItem ? newTmplItem( options, parentItem, tmpl, dataItem ) : null;
15309                }) :
15310                [ newTmplItem( options, parentItem, tmpl, data ) ];
15311            return topLevel ? jQuery( build( parentItem, null, ret ) ) : ret;
15312        },
15313
15314        // Return rendered template item for an element.
15315        tmplItem: function( elem ) {
15316            var tmplItem;
15317            if ( elem instanceof jQuery ) {
15318                elem = elem[0];
15319            }
15320            while ( elem && elem.nodeType === 1 && !(tmplItem = jQuery.data( elem, "tmplItem" )) && (elem = elem.parentNode) ) {}
15321            return tmplItem || topTmplItem;
15322        },
15323
15324        // Set:
15325        // Use $.template( name, tmpl ) to cache a named template,
15326        // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc.
15327        // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration.
15328
15329        // Get:
15330        // Use $.template( name ) to access a cached template.
15331        // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString )
15332        // will return the compiled template, without adding a name reference.
15333        // If templateString includes at least one HTML tag, $.template( templateString ) 
15333is equivalent
15334        // to $.template( null, templateString )
15335        template: function( name, tmpl ) {
15336            if (tmpl) {
15337                // Compile template and associate with name
15338                if ( typeof tmpl === "string" ) {
15339                    // This is an HTML string being passed directly in.
15340                    tmpl = buildTmplFn( tmpl )
15341                } else if ( tmpl instanceof jQuery ) {
15342                    tmpl = tmpl[0] || {};
15343                }
15344                if ( tmpl.nodeType ) {
15345                    // If this is a template block, use cached copy, or generate tmpl function and cache.
15346                    tmpl = jQuery.data( tmpl, "tmpl" ) || jQuery.data( tmpl, "tmpl", buildTmplFn( tmpl.innerHTML ));
15347                }
15348                return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl;
15349            }
15350            // Return named compiled template
15351            return name ? (typeof name !== "string" ? jQuery.template( null, name ):
15352                (jQuery.template[name] ||
15353                    // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec)
15354                    jQuery.template( null, htmlExpr.test( name ) ? name : jQuery( name )))) : null;
15355        },
15356
15357        encode: function( text ) {
15358            // Do HTML encoding replacing < > & and ' and " by corresponding entities.
15359            return ("" + text).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;");
15360        }
15361    });
15362
15363    jQuery.extend( jQuery.tmpl, {
15364        tag: {
15365            "tmpl": {
15366                _default: { $2: "null" },
15367                open: "if($notnull_1){_=_.concat($item.nest($1,$2));}"
15368                // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions)
15369                // This means that {{tmpl foo}} treats foo as a template (which IS a function).
15370                // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}.
15371            },
15372            "wrap": {
15373                _default: { $2: "null" },
15374                open: "$item.calls(_,$1,$2);_=[];",
15375                close: "call=$item.calls();_=call._.concat($item.wrap(call,_));"
15376            },
15377            "each": {
15378                _default: { $2: "$index, $value" },
15379                open: "if($notnull_1){$.each($1a,function($2){with(this){",
15380                close: "}});}"
15381            },
15382            "if": {
15383                open: "if(($notnull_1) && $1a){",
15384                close: "}"
15385            },
15386            "else": {
15387                _default: { $1: "true" },
15388                open: "}else if(($notnull_1) && $1a){"
15389            },
15390            "html": {
15391                // Unecoded expression evaluation.
15392                open: "if($notnull_1){_.push($1a);}"
15393            },
15394            "=": {
15395                // Encoded expression evaluation. Abbreviated form is ${}.
15396                _default: { $1: "$data" },
15397                open: "if($notnull_1){_.push($.encode($1a));}"
15398            },
15399            "!": {
15400                // Comment tag. Skipped by parser
15401                open: ""
15402            }
15403        },
15404
15405        // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events
15406        complete: function( items ) {
15407            newTmplItems = {};
15408        },
15409
15410        // Call this from code which overrides domManip, or equivalent
15411        // Manage cloning/storing template items etc.
15412        afterManip: function afterManip( elem, fragClone, callback ) {
15413            // Provides cloned fragment ready for fixup prior to and after insertion into DOM
15414            var content = fragClone.nodeType === 11 ?
15415                jQuery.makeArray(fragClone.childNodes) :
15416                fragClone.nodeType === 1 ? [fragClone] : [];
15417
15418            // Return fragment to original caller (e.g. append) for DOM insertion
15419            callback.call( elem, fragClone );
15420
15421            // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data.
15422            storeTmplItems( content );
15423            cloneIndex++;
15424        }
15425    });
15426
15427    //========================== Private helper functions, used by code above ==========================
15428
15429    function build( tmplItem, nested, content ) {
15430        // Convert hierarchical content into flat string array
15431        // and finally return array of fragments ready for DOM insertion
15432        var frag, ret = content ? jQuery.map( content, function( item ) {
15433            return (typeof item === "string") ?
15434                // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM.
15435                (tmplItem.key ? item.replace( /(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2" ) : item) :
15436                // This is a child template item. Build nested template.
15437                build( item, tmplItem, item._ctnt );
15438        }) :
15439            // 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()}}.
15440            tmplItem;
15441        if ( nested ) {
15442            return ret;
15443        }
15444
15445        // top-level template
15446        ret = ret.join("");
15447
15448        // Support templates which have initial or final text nodes, or consist only of text
15449        // Also support HTML entities within the HTML markup.
15450        ret.replace( /^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function( all, before, middle, after) {
15451            frag = jQuery( middle ).get();
15452
15453            storeTmplItems( frag );
15454            if ( before ) {
15455                frag = unencode( before ).concat(frag);
15456            }
15457            if ( after ) {
15458                frag = frag.concat(unencode( after ));
15459            }
15460        });
15461        return frag ? frag : unencode( ret );
15462    }
15463
15464    function unencode( text ) {
15465        // Use createElement, since createTextNode will not render HTML entities correctly
15466        var el = document.createElement( "div" );
15467        el.innerHTML = text;
15468        return jQuery.makeArray(el.childNodes);
15469    }
15470
15471    // Generate a reusable function that will serve to render a template against data
15472    function buildTmplFn( markup ) {
15473        return new Function("jQuery","$item",
15474            "var $=jQuery,call,_=[],$data=$item.data;" +
15475
15476                // Introduce the data as local variables using with(){}
15477                "with($data){_.push('" +
15478
15479                // Convert the template into pure JavaScript
15480                jQuery.trim(markup)
15481                    .replace( /([\\'])/g, "\\$1" )
15482                    .replace( /[\r\t\n]/g, " " )
15483                    .replace( /\$\{([^\}]*)\}/g, "{{= $1}}" )
15484                    .replace( /\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,
15485                    function( all, slash, type, fnargs, target, parens, args ) {
15486                        var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect;
15487                        if ( !tag ) {
15488                            throw "Template command not found: " + type;
15489                        }
15490                        def = tag._default || [];
15491                        if ( parens && !/\w$/.test(target)) {
15492                            target += parens;
15493                            parens = "";
15494                        }
15495                        if ( target ) {
15496                            target = unescape( target );
15497                            args = args ? ("," + unescape( args ) + ")") : (parens ? ")" : "");
15498                            // Support for target being things like a.toLowerCase();
15499                            // In that case don't call with template item as 'this' pointer. Just evaluate...
15500                            expr = parens ? (target.indexOf(".") > -1 ? target + parens : ("(" + target + ").call($item" + args)) : target;
15501                            exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))";
15502                        } else {
15503                            exprAutoFnDetect = expr = def.$1 || "null";
15504                        }
15505                        fnargs = unescape( fnargs );
15506                        return "');" +
15507                            tag[ slash ? "close" : "open" ]
15508                                .split( "$notnull_1" ).join( target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true" )
15509                                .split( "$1a" ).join( exprAutoFnDetect )
15510                                .split( "$1" ).join( expr )
15511                                .split( "$2" ).join( fnargs ?
15512                                    fnargs.replace( /\s*([^\(]+)\s*(\((.*?)\))?/g, function( all, name, parens, params ) {
15513                                        params = params ? ("," + params + ")") : (parens ? ")" : "");
15514                                        return params ? ("(" + name + ").call($item" + params) : all;
15515                                    })
15516                                    : (def.$2||"")
15517                                ) +
15518                            "_.push('";
15519                    }) +
15520                "');}return _;"
15521        );
15522    }
15523    function updateWrapped( options, wrapped ) {
15524        // Build the wrapped content.
15525        options._wrap = build( options, true,
15526            // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string.
15527            jQuery.isArray( wrapped ) ? wrapped : [htmlExpr.test( wrapped ) ? wrapped : jQuery( wrapped ).html()]
15528        ).join("");
15529    }
15530
15531    function unescape( args ) {
15532        return args ? args.replace( /\\'/g, "'").replace(/\\\\/g, "\\" ) : null;
15533    }
15534    function outerHtml( elem ) {
15535        var div = document.createElement("div");
15536        div.appendChild( elem.cloneNode(true) );
15537        return div.innerHTML;
15538    }
15539
15540    // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance.
15541    function storeTmplItems( content ) {
15542        var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m;
15543        for ( i = 0, l = content.length; i < l; i++ ) {
15544            if ( (elem = content[i]).nodeType !== 1 ) {
15545                continue;
15546            }
15547            elems = elem.getElementsByTagName("*");
15548            for ( m = elems.length - 1; m >= 0; m-- ) {
15549                processItemKey( elems[m] );
15550            }
15551            processItemKey( elem );
15552        }
15553        function processItemKey( el ) {
15554            var pntKey, pntNode = el, pntItem, tmplItem, key;
15555            // Ensure that each rendered template inserted into the DOM has its own template item,
15556            if ( (key = el.getAttribute( tmplItmAtt ))) {
15557                while ( pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute( tmplItmAtt ))) { }
15558                if ( pntKey !== key ) {
15559                    // The next ancestor with a _tmplitem expando is on a different key than this one.
15560                    // So this is a top-level element within this template item
15561                    // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment.
15562                    pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute( tmplItmAtt ) || 0)) : 0;
15563                    if ( !(tmplItem = newTmplItems[key]) ) {
15564                        // The item is for wrapped content, and was copied from the temporary parent wrappedItem.
15565                        tmplItem = wrappedItems[key];
15566                        tmplItem = newTmplItem( tmplItem, newTmplItems[pntNode]||wrappedItems[pntNode], null, true );
15567                        tmplItem.key = ++itemKey;
15568                        newTmplItems[itemKey] = tmplItem;
15569                    }
15570                    if ( cloneIndex ) {
15571                        cloneTmplItem( key );
15572                    }
15573                }
15574                el.removeAttribute( tmplItmAtt );
15575            } else if ( cloneIndex && (tmplItem = jQuery.data( el, "tmplItem" )) ) {
15576                // This was a rendered element, cloned during append or appendTo etc.
15577                // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem.
15578                cloneTmplItem( tmplItem.key );
15579                newTmplItems[tmplItem.key] = tmplItem;
15580                pntNode = jQuery.data( el.parentNode, "tmplItem" );
15581                pntNode = pntNode ? pntNode.key : 0;
15582            }
15583            if ( tmplItem ) {
15584                pntItem = tmplItem;
15585                // Find the template item of the parent element.
15586                // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string)
15587                while ( pntItem && pntItem.key != pntNode ) {
15588                    // Add this element as a top-level node for this rendered template item, as well as for any
15589                    // ancestor items between this item and the item of its parent element
15590                    pntItem.nodes.push( el );
15591                    pntItem = pntItem.parent;
15592                }
15593                // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering...
15594                delete tmplItem._ctnt;
15595                delete tmplItem._wrap;
15596                // Store template item as jQuery data on the element
15597                jQuery.data( el, "tmplItem", tmplItem );
15598            }
15599            function cloneTmplItem( key ) {
15600                key = key + keySuffix;
15601                tmplItem = newClonedItems[key] =
15602                    (newClonedItems[key] || newTmplItem( tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent, null, true ));
15603            }
15604        }
15605    }
15606
15607    //---- Helper functions for template item ----
15608
15609    function tiCalls( content, tmpl, data, options ) {
15610        if ( !content ) {
15611            return stack.pop();
15612        }
15613        stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options });
15614    }
15615
15616    function tiNest( tmpl, data, options ) {
15617        // nested template, using {{tmpl}} tag
15618        return jQuery.tmpl( jQuery.template( tmpl ), data, options, this );
15619    }
15620
15621    function tiWrap( call, wrapped ) {
15622        // nested template, using {{wrap}} tag
15623        var options = call.options || {};
15624        options.wrapped = wrapped;
15625        // Apply the template, which may incorporate wrapped content,
15626        return jQuery.tmpl( jQuery.template( call.tmpl ), call.data, options, call.item );
15627    }
15628
15629    function tiHtml( filter, textOnly ) {
15630        var wrapped = this._wrap;
15631        return jQuery.map(
15632            jQuery( jQuery.isArray( wrapped ) ? wrapped.join("") : wrapped ).filter( filter || "*" ),
15633            function(e) {
15634                return textOnly ?
15635                    e.innerText || e.textContent :
15636                    e.outerHTML || outerHtml(e);
15637            });
15638    }
15639
15640    function tiUpdate() {
15641        var coll = this.nodes;
15642        jQuery.tmpl( null, null, null, this).insertBefore( coll[0] );
15643        jQuery( coll ).remove();
15644    }
15645})( jQuery );
15646/*!
15647 * jQuery Mobile 1.4.1
15648 * Git HEAD hash: 18c1e32bfc4e0e92756dedc105d799131607f5bb <> Date: Wed Feb 12 2014 22:15:20 UTC
15649 * http://jquerymobile.com
15650 *
15651 * Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors
15652 * Released under the MIT license.
15653 * http://jquery.org/license
15654 *
15655 */
15656/*!
15657 * code snippet for just swipe-right and swipe-left
15658 */
15659(function( $, window, undefined ) {
15660    var $document = $(document),
15661        TouchUtil = xfalib.ut.TouchUtil,
15662        touchStartEvent = TouchUtil.POINTER_DOWN,
15663        touchStopEvent = TouchUtil.POINTER_UP,
15664        touchMoveEvent = TouchUtil.POINTER_MOVE;
15665
15666    function triggerCustomEvent( obj, eventType, event, bubble ) {
15667        var originalType = event.type;
15668        event.type = eventType;
15669        if ( bubble ) {
15670            $.event.trigger( event, undefined, obj );
15671        } else {
15672            $.event.dispatch.call( obj, event );
15673        }
15674        event.type = originalType;
15675    }
15676
15677    $.event.special.swipe = {
15678
15679        // More than this horizontal displacement, and we will suppress scrolling.
15680        scrollSupressionThreshold: 30,
15681
15682        // More time than this, and it isn't a swipe.
15683        durationThreshold: 1000,
15684
15685        // Swipe horizontal displacement must be more than this.
15686        horizontalDistanceThreshold: 30,
15687
15688        // Swipe vertical displacement must be less than this.
15689        verticalDistanceThreshold: 30,
15690
15691        getLocation: function ( event ) {
15692            var winPageX = window.pageXOffset,
15693                winPageY = window.pageYOffset,
15694                x = event.clientX || event.originalEvent.clientX,
15695                y = event.clientY || event.originalEvent.clientY;
15696
15697            if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) ||
15698                event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) {
15699
15700                // iOS4 clientX/clientY have the value that should have been
15701                // in pageX/pageY. While pageX/page/ have the value 0
15702                x = x - winPageX;
15703                y = y - winPageY;
15704            } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) {
15705
15706                // Some Android browsers have totally bogus values for clientX/Y
15707                // when scrolling/zooming a page. Detectable since clientX/clientY
15708                // should never be smaller than pageX/pageY minus page scroll
15709                x = event.pageX - winPageX;
15710                y = event.pageY - winPageY;
15711            }
15712
15713            return {
15714                x: x,
15715                y: y
15716            };
15717        },
15718
15719        start: function( event ) {
15720            var data = event.originalEvent.touches ?
15721                    event.originalEvent.touches[ 0 ] : event,
15722                location = $.event.special.swipe.getLocation( data );
15723            return {
15724                time: ( new Date() ).getTime(),
15725                coords: [ location.x, location.y ],
15726                origin: $( event.target )
15727            };
15728        },
15729
15730        stop: function( event ) {
15731            var data = event.originalEvent.touches ?
15732                    event.originalEvent.touches[ 0 ] : event,
15733                location = $.event.special.swipe.getLocation( data );
15734            return {
15735                time: ( new Date() ).getTime(),
15736                coords: [ location.x, location.y ]
15737            };
15738        },
15739
15740        handleSwipe: function( start, stop, thisObject, origTarget ) {
15741            if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
15742                Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
15743                Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
15744                var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight";
15745
15746                triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true );
15747                return true;
15748            }
15749            return false;
15750
15751        },
15752
15753        // This serves as a flag to ensure that at most one swipe event event is
15754        // in work at any given time
15755        eventInProgress: false,
15756
15757        setup: function() {
15758            var events,
15759                thisObject = this,
15760                $this = $( thisObject ),
15761                context = {};
15762
15763            // Retrieve the events data for this element and add the swipe context
15764            events = $.data( this, "mobile-events" );
15765            if ( !events ) {
15766                events = { length: 0 };
15767                $.data( this, "mobile-events", events );
15768            }
15769            events.length++;
15770            events.swipe = context;
15771
15772            context.start = function( event ) {
15773                // If its not a touch event on IE, ignore
15774                if (event.originalEvent.pointerType !== undefined && !(event.originalEvent.pointerType === 2 || event.originalEvent.pointerType === "touch")) {
15775                    return;
15776                }
15777
15778                // Bail if we're already working on a swipe event
15779                if ( $.event.special.swipe.eventInProgress ) {
15780                    return;
15781                }
15782                $.event.special.swipe.eventInProgress = true;
15783
15784                var stop,
15785                    start = $.event.special.swipe.start( event ),
15786                    origTarget = event.target,
15787                    emitted = false;
15788
15789                context.move = function( event ) {
15790                    if ( !start ) {
15791                        return;
15792                    }
15793
15794                    stop = $.event.special.swipe.stop( event );
15795                    if ( !emitted ) {
15796                        emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget );
15797                        if ( emitted ) {
15798
15799                            // Reset the context to make way for the next swipe event
15800                            $.event.special.swipe.eventInProgress = false;
15801                        }
15802                    }
15803                    // prevent scrolling
15804                    if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
15805                        event.preventDefault();
15806                    }
15807                };
15808
15809                context.stop = function() {
15810                    emitted = true;
15811
15812                    // Reset the context to make way for the next swipe event
15813                    $.event.special.swipe.eventInProgress = false;
15814                    $document.off( touchMoveEvent, context.move );
15815                    context.move = null;
15816                };
15817
15818                $document.on( touchMoveEvent, context.move )
15819                    .one( touchStopEvent, context.stop );
15820            };
15821            $this.on( touchStartEvent, context.start );
15822        },
15823
15824        teardown: function() {
15825            var events, context;
15826
15827            events = $.data( this, "mobile-events" );
15828            if ( events ) {
15829                context = events.swipe;
15830                delete events.swipe;
15831                events.length--;
15832                if ( events.length === 0 ) {
15833                    $.removeData( this, "mobile-events" );
15834                }
15835            }
15836
15837            if ( context ) {
15838                if ( context.start ) {
15839                    $( this ).off( touchStartEvent, context.start );
15840                }
15841                if ( context.move ) {
15842                    $document.off( touchMoveEvent, context.move );
15843                }
15844                if ( context.stop ) {
15845                    $document.off( touchStopEvent, context.stop );
15846                }
15847            }
15848        }
15849    };
15850    $.each({
15851        swipeleft: "swipe",
15852        swiperight: "swipe"
15853    }, function( event, sourceEvent ) {
15854		// Ignoring mouse events, for all browsers except IE 10>, which has pointer events.
15855        if (TouchUtil.POINTER_DOWN !== "mousedown") {
15856            $.event.special[ event ] = {
15857                setup: function() {
15858                    $( this ).on( sourceEvent, $.noop );
15859                },
15860                teardown: function() {
15861                    $( this ).off( sourceEvent );
15862                }
15863            };
15864        }
15865    });
15866
15867})( jQuery, this );
15868
15869/*************************************************************************
15870 *
15871 * ADOBE CONFIDENTIAL
15872 * __________________
15873 *
15874 *  Copyright 2017 Adobe Systems Incorporated
15875 *  All Rights Reserved.
15876 *
15877 * NOTICE:  All information contained herein is, and remains
15878 * the property of Adobe Systems Incorporated and its suppliers,
15879 * if any.  The intellectual and technical concepts contained
15880 * herein are proprietary to Adobe Systems Incorporated and its
15881 * suppliers and may be covered by U.S. and Foreign Patents,
15882 * patents in process, and are protected by trade secret or copyright law.
15883 * Dissemination of this information or reproduction of this material
15884 * is strictly forbidden unless prior written permission is obtained
15885 * from Adobe Systems Incorporated.
15886 **************************************************************************/
15887
15888(function (window, $) {
15889
15890    var DefaultPanelProvider = {
15891
15892        /**
15893         * Makes an ajax call and returns an object containing the template json of the template ids
15894         * @returns {Object}
15895         * @param options {Object} This object contains the path, the list of templateIds, and success handler
15896         */
15897        getMultipleTemplateJson : function (options) {
15898            var externalizedPath = options.path,
15899                listOfTemplateIds = options.listOfTemplateIds;
15900            if (listOfTemplateIds.length > 0) {
15901                $.ajax({
15902                    url : externalizedPath,
15903                    type : "GET",
15904                    data : {
15905                        listOfTemplateIds : JSON.stringify(listOfTemplateIds),
15906                        fetchMultipleJson : true
15907                    },
15908                    async : false,
15909                    success : function (response) {
15910                        options.success.call(this, JSON.parse(response.multipleJson));
15911                    },
15912                    error : function (error) {
15913                        window.guideBridge._guide().logger().log(error);
15914                    }
15915                });
15916            }
15917        },
15918
15919        /**
15920         * Makes an ajax call and gets json and html of the lazy loaded panel
15921         * @param options {Object}
15921 This object contains the templateId, fetchJson parameter and fetchHtml parameter.
15922         *                         These can be set to true or false depending on whether the respective content
15923         *                         needs to be fetched or not. Options object also contains the success, error, and complete handler as well.
15924         * @returns {JSONObject} The JSON object has two entries, json and html.
15925         */
15926        getHtmlJson : function (options) {
15927            var ajaxOptions = {
15928                url : options.path,
15929                type : "GET",
15930                async : options.async !== undefined ? options.async : false,
15931                success : options.success,
15932                error : options.error,
15933                complete : options.complete
15934            };
15935
15936            // Only add data parameters if they are present in options
15937            if (options.templateId || options.fetchJSON || options.fetchHTML) {
15938                ajaxOptions.data = {};
15939                if (options.templateId) {
15940                    ajaxOptions.data.templateId = options.templateId;
15941                }
15942                if (options.fetchJSON) {
15943                    ajaxOptions.data.fetchJSON = options.fetchJSON;
15944                }
15945                if (options.fetchHTML) {
15946                    ajaxOptions.data.fetchHTML = options.fetchHTML;
15947                }
15948            }
15949
15950            $.ajax(ajaxOptions);
15951        }
15952    };
15953
15954    window.addEventListener("bridgeInitializeStart", function (evnt) {
15955        var bridge = evnt.detail.guideBridge;
15956        if (bridge) {
15957            bridge.registerPanelProvider(DefaultPanelProvider);
15958        }
15959    });
15960
15961}(window, $));
15962
15963// jscs:disable requireDotNotation
15964/*************************************************************************
15965 *
15966 * ADOBE CONFIDENTIAL
15967 * __________________
15968 *
15969 *  Copyright 2014 Adobe Systems Incorporated
15970 *  All Rights Reserved.
15971 *
15972 * NOTICE:  All information contained herein is, and remains
15973 * the property of Adobe Systems Incorporated and its suppliers,
15974 * if any.  The intellectual and technical concepts contained
15975 * herein are proprietary to Adobe Systems Incorporated and its
15976 * suppliers and may be covered by U.S. and Foreign Patents,
15977 * patents in process, and are protected by trade secret or copyright law.
15978 * Dissemination of this information or reproduction of this material
15979 * is strictly forbidden unless prior written permission is obtained
15980 * from Adobe Systems Incorporated.
15981 **************************************************************************/
15982
15983(function ($, _) {
15984    Function.prototype.bind = Function.prototype.bind || function (ctx) {
15985            var that = this;
15986            return function () {
15987                that.call(ctx, arguments);
15988            };
15989        };
15990
15991    var nValidationContext = 0,
15992        /**
15993         * flag to check if adaptive forms is online or not
15994         * @type {boolean}
15995         */
15996        checkAFOffline = false,
15997        _focusedSubmitButtonModel = null,
15998        sValidationContext = "";
15999
16000    /**
16001     * Class representing the result of {@link GuideBridge} API. This class provides API to access the result of the
16002     * GuideBridge API and retrieve any error messages the API has thrown.
16003     * @class GuideResultObject
16004     * @docStatus review 2016-05-03
16005     * @since 6.0
16006     */
16007    var GuideResultObject = function () {
16008        var _message = [];
16009        var _errorCode = [];
16010        var _somExpression = [];
16011        /**
16012         * The value of this property is true if the API succeeded, otherwise false. The
16013         * {@link GuideResultObject#getNextMessage|getNextMessage} API can be used to retrieve the error messages in
16014         * case the value of this property is false.
16015         * @summary whether the API succeeded or failed.
16016         *
16017         * @type {boolean}
16018         * @member errors
16019         * @memberof GuideResultObject
16020         * @instance
16021         * @readonly
16022         * @since 6.0
16023         */
16024        this.errors = false;
16025        /**
16026         * The type of the data is specific to the API and documentation of that API provides more details about the
16027         * data
16028         * @summary data returned by GuideBridge API
16029         *
16030         * @member {*} data
16031         * @memberof GuideResultObject
16032         * @instance
16033         * @readonly
16034         * @since 6.0
16035         */
16036        this.data;
16037
16038        /**
16039         * API to add a message in the GuideResultObject
16040         * @private
16041         * @memberof GuideResultObject
16042         * @instance
16043         * @since 6.0
16044         */
16045        this.addMessage = function (code, msg, som) {
16046            this.errors = true;
16047            _message.push(msg);
16048            _somExpression.push(som);
16049            _errorCode.push(code);
16050        };
16051
16052        /**
16053         * Error Message returned by GuideBridge API
16054         * @typedef {object} GuideResultObject~ErrorMessage
16055         * @property {number} code Error Code
16056         * @property {?string} somExpression Som Expression of the GuideNode the error is related to. It can be null if
16057         * error is not related to a GuideNode. For example, server failure when submitting the form.
16058         * @property {string} message User friendly message for the error.
16059         * @see GuideNode#somExpression
16060         */
16061        /**
16062         * When a GuideBridge API fails, it throws an error message. This is indicated by the
16063         * {@link GuideResultObject#errors|errors} property. To get the errors, one has to call this API. The API can throw
16064         * multiple errors and the user has to call this API until it returns null indicating no more errors.
16065         * @summary Returns the error message thrown by the GuideBridge API.
16066         * @function getNextMessage
16067         * @memberof GuideResultObject
16068         * @instance
16069         * @return {GuideResultObject~ErrorMessage} object containing the error message
16070         * @since 6.0
16071         */
16072        this.getNextMessage = function () {
16073            if (_errorCode.length == 0) {
16074                return null;
16075            }
16076            return {
16077                code : _errorCode.pop(),
16078                somExpression : _somExpression.pop(),
16079                message : _message.pop()
16080            };
16081        };
16082    };
16083
16084    var GUIDE_BRIDGE_VERSION = "1.0";
16085    /*
16086     * Callback to accept result of asynchronous GuideBridge APIs.
16087     * @callback GuideBridge~AsyncAPIResultCallback
16088     * @param {GuideResultObject}
16088 guideResultObject object containing the result of the API
16089     */
16090    /*
16091     * Signature of the input to be passed to GuideBridge asynchronous APIs
16092     * @typedef {object} GuideBridge~AsyncAPIInput
16093     * @property {GuideBridge~AsyncAPIResultCallback} [success] callback which receives the result of the API in case of
16094     * success. The argument this callback will recieve will have its {@link GuideResultObject#errors|errors} property
16095     * as false.
16096     * @property {GuideBridge~AsyncAPIResultCallback} [error] callback which receives the result of the API in case of
16097     * failure. The argument this callback will recieve will have its {@link GuideResultObject#errors|errors} property
16098     * as true.
16099     * @param {object} [context] _this_ object inside the _success_ and _error_ callback will point to this
16100     * object
16101     */
16102    /**
16103     * GuideBridge provides an interface using which, wrapper html (page hosting/embedding adaptive forms) or external
16104     * window scripts like Parent window javascript (in case form is embedded in an iframe), can communicate with
16105     * current Adaptive Form and manipulate or query it's current state.
16106     *
16107     * Some of the use cases for using this API
16108     * * Submit Adaptive Form from a custom button present outside the Form.
16109     * * Get current Adaptive Form state and save it in local storage for restoring it later on.
16110     * * Plugging in custom widgets.
16111     * * Manipulate the Adaptive Form component properties, like value, visibility from outside the Form
16112     * * Listen to bridge events and send data to Analytics server for reporting
16113     *
16114     * ### Accessing the Instance of GuideBridge
16115     * To access the GuideBridge APIs, one needs to get hold of an instance of GuideBridge. The object is
16116     * available on the window after the GuideBridge script is loaded. One can directly access it by using
16117     * `window.guideBridge`. But
16118     * that requires the user script is written after the GuideBridge script is loaded. In certain cases, a user might
16119     * not be
16120     * aware of when their script gets loaded, in those cases the recommended approach is to listen to the
16121     * {@link GuideBridge.event:bridgeInitializeStart|bridgeInitializeStart} event which provides an instance of
16122     * GuideBridge object.
16123     *```
16124     * window.addEventListener("bridgeInitializeStart", function(evnt) {
16125     *      // get hold of the guideBridge object
16126     *      var gb = evnt.detail.guideBridge;
16127     * })
16128     * ```
16129     *
16130     * **Or**, if you are sure that your script will execute after GuideBridge Script is loaded, then you can directly
16131     * use `window.guideBridge`. In cases like your script is present at the bottom of the page or you are executing on
16132     * jquery dom ready event.
16133     * ```
16134     *    $(function () {
16135     *          // one can directly access guideBridge object here.
16136     *          window.guideBridge.connect(function () {
16137     *              //call guideBridge APIs
16138     *          })
16139     *    })
16140     * ```
16141     *
16142     * <a name="wait-form-ready"></a>
16143     * ### Wait for Form to get ready
16144     * After getting the GuideBridge object one needs to wait for the Form to get initialized. This can be done by
16145     * providing a callback to the {@link GuideBridge#connect|connect} API
16146     * ```
16147     * guideBridge.connect(function (){
16148     *    //this callback will be called after adaptive form is initialized
16149     *    // do your custom processing
16150     * })
16151     * ```
16152     *
16153     * _**Note:** There is no link between Dom ready events and the connect API. If one wants to access the HTML DOM
16154     * from inside the connect callback, the recommended approach is to listen on the jQuery
16155     * [ready](https://api.jquery.com/ready/) event or the native
16156     * [DOMContentLoaded](https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded) event. Similarly if one
16157     * wants to access GuideBridge APIs one needs to wait for the connect callback to get fired._
16158     *
16159     * <a name="guidebridge-api-usage"></a>
16160     * ### Using the GuideBridge API
16161     * APIs are provided for external applications to connect with Adaptive Form and FormDom. The APIs can be
16162     * loosely divided into two categories, **synchronous** and **asynchronous**.
16163     *
16164     * The synchronous getter API returns a {@link GuideResultObject} which represents the result of the API whereas
16165     * each setter API throws an exception in case of error(s) and it is the responsibility of the API to catch those
16166     * exceptions. The {@link GuideResultObject} either contains error or the return value of the API and provides easy
16167     * mechanism to access each of them.
16168     *
16169     * ```
16170     * var result = guideBridge.hideGlobalToolbar()
16171     * if (result.errors) {
16172     *     console.error("Unable to hide toolbar");
16173     *     var msg = guideResultObject.getNextMessage();
16174     *     while (msg != null) {
16175     *         console.error(msg.message);
16176     *         msg = guideResultObject.getNextMessage();
16177     *    }
16178     * } else {
16179     *      console.log("toolbar hidden successfully");
16180     * }
16181     * ```
16182     *
16183     * Each asynchronous API provides callback mechanism to return the result of the API. Each API takes a Javascript
16184     * Object having success and error handlers. The success and error handlers receive {@link GuideResultObject} as input.
16185     * In the success callback, the arguments {@link GuideResultObject#data|data} property is set to the return value
16186     * of the API, while in the error callback the {@link GuideResultObject#errors|errors} property is set to _true_.
16187     * Some APIs might need extra input and that will be defined by the API
16188     * ```
16189     * guideBridge.getData({
16190     *     success : function (guideResultObject) {
16191     *          console.log("data received" + guideResultObject.data);
16192     *     }
16193     *     error : function (guideResultObject) {
16194     *          console.error("API Failed");
16195     *          var msg = guideResultObject.getNextMessage();
16196     *          while (msg != null) {
16197     *              console.error(msg.message);
16198     *              msg = guideResultObject.getNextMessage();
16199     *          }
16200     *     }
16201     * });
16202     * ```
16203     * _**Note:** Some APIs do not follow the above norm and it is mentioned in the documentation of that API_
16204     *
16205     * <a name="guidebridge-events"></a>
16206     * ### GuideBridge Events
16207     *
16208     * GuideBridge API triggers a set of events to notify the current action a user has taken. Developers can listen on
16209     * that event using the {@link GuideBridge#on|on} API and perform some tasks. For example a developer can listen on
16210     * {@link GuideBridge.event:elementFocusChanged|elementFocusChanged} and capture for how long a user spends time
16211     * on that field. All the events triggered by GuideBridge are mentioned below.
16212     *
16213     * GuideBridge provides an event object which contains extra information about the event. For
16214     * example _elementFocusChanged_ event provides information about the previous field that was in focus and the
16215     * current field that came to focus.
16216     *
16217     * The {@link GuideBridge#on|on} API takes a {@link GuideBridge~GuideBridgeEventCallback|GuideBridgeEventCallback}
16218     * as input. The callback is passed two arguments, event and payload where the extra information is passed in the
16219     * payload argument. The documentation of each event lists the values of different properties of the payload
16220     * object.
16221     *
16222     * ```
16223     * guideBridge.on(eventName, function (event, payload) {
16224     *      // access payload properties
16225     *      ...
16226     * })
16227     * ```
16228     *
16229     * @class GuideBridge
16230     * @docStatus review 2016-05-03
16231     * @since 6.0
16232     */
16233    var GuideBridge = function () {
16234        this._$target = null;
16235        this._guide = null;
16236        this._guideView = null;
16237        this._version = GUIDE_BRIDGE_VERSION;
16238        this._guideInitHandler = {};
16239        // _guideModelInitHandler is for internal use only
16240        this._guideModelInitHandler = {};
16241        $(window).on("guideModelInitialized", this._guideModelInitialized.bind(this));
16242        $(window).on("guideInitialized", this._guideInitialized.bind(this));
16243        $(window).on("guideInitializationError", this._guideError);
16244        this.userConfig = {};
16245        this.panelProvider = null;
16246        // set the host name whether it is client or server, by default it is client
16247        this.hostName = "client";
16248    };
16249
16250    var _formInstanceUUID;
16251    var GUIDE_TEMP_STORAGE_PATH = "/tmp/fd/af",
16252        FM_DAM_ROOT = "/content/dam/formsanddocuments/",
16253        FM_AF_ROOT = "/content/forms/af/",
16254        _isAutoSaveEnabled = false,
16255        LOCAL_METADATA_SELECTOR = "local";
16256
16257    var defaultErrorHandler = function (obj) {
16258        if (typeof(console) == "undefined") {
16259            return;
16260        }
16261        var d = obj.getNextMessage();
16262        while (d) {
16263            this._guide.logger().log(d.message);
16264            d = obj.getNextMessage();
16265        }
16266    };
16267
16268    /**
16269     *
16270     * Default function to check Validations errors after getting the data from the
16271     * server with getDataXML call.
16272     * @private
16273     */
16274    var defaultValidationChecker = function (validations, obj) {
16275        if (validations && validations.length > 0) {
16276            for (var i = 0; i < validations.length; i++) {
16277                obj.addMessage(0, validations[i], "");
16278            }
16279            return false;
16280        }
16281        return true;
16282    };
16283
16284    function getOrElse() {
16285        return xfalib.ut.XfaUtil.prototype.getOrElse.apply(null, arguments);
16286    }
16287
16288    $.extend(GuideBridge.prototype, {
16289
16290        /**
16291         * Dispatched when the instance of GuideBridge is available. The GuideBridge object
16292         * will be passed to the listener and further communication can be done using that object.
16293         *
16294         * _**Note :** bridgeInitializeStart event is dispatched at window_
16295         *
16296         * @summary Notifies when the instance of GuideBridge is available.
16297         *
16298         * @event bridgeInitializeStart
16299         * @property {Object} detail an object containing guideBridge
16300         * @property {GuideBridge} detail.guideBridge GuideBridge Instance
16301         * @memberof GuideBridge
16302         * @since 6.0
16303         * @example
16304         * window.addEventListener("bridgeInitializeStart", function(evnt) {
16305         *      // get hold of the guideBridge object
16306         *      var gb = evnt.detail.guideBridge;
16307         *      //wait for the completion of adaptive forms
16308         *      gb.connect(function (){
16309         *         //this function will be called after adaptive form is initialized
16310         *      })
16311         * })
16312         */
16313        GUIDE_BRIDGE_INITIALIZE_START : "bridgeInitializeStart",
16314
16315        /**
16316         * @summary Dispatched when the initialization of Adaptive Form is complete.
16317         *
16318         * @name  bridgeInitializeComplete
16319         * @event
16320         * @property {object} payload payload passed to the event listener
16321         * @property {object} payload.target instance of GuideBridge object
16322         * @memberof GuideBridge
16323         * @deprecated since 6.3 this event is deprecated. Please use {@link GuideBridge#connect|connect} API
16324         * @since 6.0
16325         * @example
16326         * guideBridge.on("bridgeInitializeComplete" , function(event, payload) {
16327         *      var gb = payload.target;
16328         *      assert(gb === guideBridge)
16329         * }
16330         */
16331        GUIDE_BRIDGE_INITIALIZE_COMPLETE : "bridgeInitializeComplete",
16332
16333        /**
16334         * @summary Dispatched when visibility of any Adaptive Form component(Panel or Field) changes.
16335         * @name elementVisibleChanged
16336         * @event
16337         * @property {object} payload payload containing more information about the event
16338         * @property {Scriptable} payload.target Adaptive Form component whose {@link Scriptable#visible|visible} property has
16339         * changed.
16340         * @property {boolean} payload.oldText old value of the visible property
16341         * @property {boolean} payload.newText new value of the visible property
16342         * @memberof GuideBridge
16343         * @since 6.0
16344         * @example
16345         * guideBridge.on("elementVisibleChanged" , function(event, payload) {
16346         *      var component = payload.target; // scripting model of the component whose visibility has changed
16347         *      var newValue = payload.newText;
16348         *      if (newValue) {
16349         *          console.log(component.name + " is visible now";
16350         *      } else {
16351         *          console.log(component.name + " is hidden now";
16352         *      }
16353         * }
16354         *
16355         */
16356        GUIDE_ELEMENT_VISIBLE_CHANGED : "elementVisibleChanged",
16357
16358        /**
16359         * @summary Dispatched when any Adaptive Form component is enabled/disabled, i.e.
16360         * {@link Scriptable#enabled|enabled} property of a component changes.
16361         * @name elementEnableChanged
16362         * @event
16363         * @property {object} payload payload containing more information about the event
16364         * @property {Scriptable} payload.target component whose {@link Scriptable#enabled|enabled} property has changed
16365         * @property {boolean} payload.oldText old value of the enabled property
16366         * @property {boolean} payload.newText new value of the enabled property
16367         * @memberof GuideBridge
16368         * @since 6.0
16369         * @example
16370         * guideBridge.on("elementEnableChanged" , function(event, payload) {
16371         *      var component = payload.target; // scripting model of the component whose enabled property has changed
16372         *      var newValue = payload.newText;
16373         *      if (newValue) {
16374         *          console.log(component.name + " is enabled now";
16375         *      } else {
16376         *          console.log(component.name + " is disabled now";
16377         *      }
16378         * }
16379         */
16380        GUIDE_ELEMENT_ENABLE_CHANGED : "elementEnableChanged",
16381
16382        /**
16383         * @summary Dispatched when value of any Field changes.
16384         * @name elementValueChanged
16385         * @event
16386         * @property {object} payload payload containing more information about the event
16387         * @property {Field} payload.target Field whose {@link Field#value|value} has changed
16388         * @property {string|number} payload.oldText old value of the Field
16389         * @property {string|number} payload.newText new value of the Field
16390         * @memberof GuideBridge
16391         * @since 6.0
16392         * @example
16393         * guideBridge.on("elementValueChanged" , function(event, payload) {
16394         *      var component = payload.target; // Field whose value has changed
16395         *      console.log("Value of component " + component.name + " was " + payload.oldText);
16396         *      console.log("Value of component " + component.name + " is " + payload.newText);
16397         * }
16398         */
16399        GUIDE_ELEMENT_VALUE_CHANGED : "elementValueChanged",
16400
16401        /**
16402         * In layouts like Wizard or Tabbed layout, when a user navigates from one tab to another, this event is
16403         * triggered
16404         * @summary Event to notify that the user has navigated from one Panel to another.
16405         *
16406         * @name elementNavigationChanged
16407         * @event
16408         * @property {object} payload payload containing more information about the event
16409         * @property {Panel} payload.target Panel to which the user moved to
16410         * @property {string} payload.prevText SomExpression of the panel from which user moved
16411         * @property {string} payload.newText SomExpression of the panel to which user moved
16412         * @memberof GuideBridge
16413         * @see GuideNode#somExpression
16414         * @since 6.0
16415         * @example
16416         * guideBridge.on("elementNavigationChanged" , function(event, payload) {
16417         *      var component = payload.target;
16418         *      console.log("old panel's SOM Expression: " + payload.oldText);
16419         *      console.log("new panel's SOM Expression: " + payload.newText);
16420         * }
16421         */
16422        GUIDE_ELEMENT_NAVIGATION_CHANGED : "elementNavigationChanged",
16423
16424        /**
16425         * @summary Dispatched whenever a Field/Panel gets Focus
16426         * @name elementFocusChanged
16427         * @event
16428         * @property {object} payload payload containing more information about the event
16429         * @property {Panel|Field} payload.target new focused component
16430         * @property {string} oldText SOM Expression of  component  that was previously in focus or null
16431         * @property {string} newText SOM Expression of the component that is currently in focus or null
16432         * @memberof GuideBridge
16433         * @see GuideNode#somExpression
16434         * @see {@link GuideBridge#setFocus|setFocus API}
16435         * @since 6.0
16436         * @example
16437         * guideBridge.on("elementFocusChanged" , function(event, payload) {
16438         *      var component = payload.target;
16439         *      console.log("old elements's SOM Expression: " + payload.oldText);
16440         *      console.log("new elements's SOM Expression: " + payload.newText);
16441         * }
16442         */
16443        GUIDE_ELEMENT_FOCUS_CHANGED : "elementFocusChanged",
16444
16445        /**
16446         * @summary Dispatched when a user looks at the help description of any Adaptive Form component(Panel or field)
16447         * @name elementHelpShown
16448         * @event
16449         * @property {object} payload payload containing more information about the event
16450         * @property {Panel|Field} payload.target component whose help is being shown
16451         * @property {string} payload._property what kind of help is being shown. The value can be
16452         * * shortDescription (if Short Description becomes visible)
16453         * * longDescription (if Long Description becomes visible)
16454         * @property {string} payload.prevText empty string
16455         * @property {object} payload.newText object containing the help content
16456         * @property {string} payload.newText.help help content of the component
16457         * @memberof GuideBridge
16458         * @since 6.0
16459         * @see {@link https://helpx.adobe.com/aem-forms/6-1/authoring-in-field-help.html|Help Description in Adaptive Form}
16460         * @example
16461         * guideBridge.on("elementHelpShown" , function(event, payload) {
16462         *      var component = payload.target;
16463         *      console.log("component whose help is shown " + payload.target.name);
16464         *      console.log("Help shown: " + payload._property);
16465         *      console.log("Help Content: " + payload.newText.help);
16466         * }
16467         */
16468        GUIDE_ELEMENT_HELP_SHOWN : "elementHelpShown",
16469
16470        /**
16471         * @summary Dispatched when validity of a Field changes.
16472         * @name elementValidationStatusChanged
16473         * @event
16474         * @property {object} payload payload containing more information about the event
16475         * @property {Field} payload.target Field which either became valid/invalid
16476         * @property {boolean} payload.prevText old validation status
16477         * @property {boolean} payload.newText new validation status
16478         * @memberof GuideBridge
16479         * @see Field#validate
16480         * @see Field#validationState
16481         * @since 6.0
16482         * @example
16483         * guideBridge.on("elementValidationStatusChanged" , function(event, payload) {
16484         *      var component = payload.target;
16485         *      if (payload.prevText) {
16486         *          console.log("component became invalid" );
16487         *      } else {
16488         *         console.log("component became valid" );
16489         *      }
16490         * }
16491         */
16492        GUIDE_ELEMENT_VALIDATION_STATUS_CHANGED : "elementValidationStatusChanged",
16493
16494        /**
16495         * Developers must not modify the Form Fields inside the listener. This is mostly use to update the UI outside
16496         * the Form or capture some data for analytics. If you want to modify form field value on the click of a button
16497         * please use the [Click Expression](https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_6)
16498         * provided in the Forms Authoring.
16499         *
16500         * @summary Dispatched when a Button component is clicked.
16501         *
16502         * @name elementButtonClicked
16503         * @event
16504         * @property {object} payload payload containing more information about the event
16505         * @property {Button} payload.target Button which was clicked
16506         * @memberof GuideBridge
16507         * @since 6.0
16508         * @see {@link https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_6|Click Expression in Buttons}
16509         * @example
16510         * guideBridge.on("elementButtonClicked" , function(event, payload) {
16511         *      var component = payload.target; // Button which wass clicked
16512         *      console.log("Button which was clicked " + component.name);
16513         * }
16514         */
16515        GUIDE_ELEMENT_BUTTON_CLICKED : "elementButtonClicked",
16516
16517        /**
16518         * Whenever the full form validations are run via the {@link GuideBridge#validate|val
16518idate} API, this event is triggered.
16519         * @summary Dispatched when the validation of all the Adaptive Form fields are completed.
16520         *
16521         * @name validationComplete
16522         * @event
16523         * @property {object} payload payload containing more information about the event
16524         * @property {GuideContainerNode} payload.target root Node of the Adaptive Form
16525         * @property {boolean} payload.prevText result of running the validation. true if validations are successful,
16526         * false otherwise
16527         * @property {Field~ValidationError[]} payload.newText List of objects containing error messages.
16528         * @memberof GuideBridge
16529         * @since 6.0
16530         * @example
16531         * guideBridge.on("validationComplete" , function(event, payload) {
16532         *      if (payload.prevText) {
16533         *          console.log("validation success");
16534         *      } else {
16535         *          console.log("validation failure");
16536         *          if (payload.newText.length) {
16537         *              payload.newText.forEach(function (error) {
16538         *                 console.log("validation failed for " + error.som + " with message " + error.errorText);
16539         *              })
16540         *          }
16541         *      }
16542         * }
16543         */
16544        GUIDE_VALIDATION_COMPLETE : "validationComplete",
16545
16546        /**
16547         * Adaptive Form can be configured to be saved automatically at regular intervals. This can be controlled
16548         * dynamically based on the values filled in the Form. Authors can write custom scripts which can enable/disable
16549         * auto save functionality dynamically
16550         * @summary Dispatched when auto save gets enabled in the Form
16551         * @name guideAutoSaveStart
16552         * @event
16553         * @property {object} payload payload containing more information about the event
16554         * @property {GuideContainerNode} payload.target root Node of the Adaptive Form
16555         * @memberof GuideBridge
16556         * @since 6.1
16557         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Auto Save an Adaptive Form}
16558         * @example
16559         * guideBridge.on("guideAutoSaveStart" , function(event, payload) {
16560         *      console.log("Forms is now being saved as draft automatically");
16561         * }
16562         */
16563        GUIDE_AUTO_SAVE_START : "guideAutoSaveStart",
16564
16565        /**
16566         * @summary Dispatched when save of adaptive form data has started
16567         * @name saveStarted
16568         * @event
16569         * @memberof GuideBridge
16570         * @since 6.1
16571         * @example
16572         * guideBridge.on("saveStarted" , function(event) {
16573         *      console.log("Save of Adaptive Form data is about to start");
16574         * }
16575         */
16576        GUIDE_SAVE_START : "saveStarted",
16577
16578        /**
16579         * @summary Dispatched when save of adaptive form data is completed
16580         * @name saveCompleted
16581         * @event
16582         * @memberof GuideBridge
16583         * @since 6.1
16584         * @example
16585         * guideBridge.on("saveCompleted" , function(event) {
16586         *      console.log("Save of Adaptive Form data is completed");
16587         * }
16588         */
16589        GUIDE_SAVE_COMPLETED : "saveCompleted",
16590
16591        /**
16592         * Users can add some pre submit code in the listener to this event.
16593         * @summary Dispatched when the user clicks on the submit button
16594         * @name submitStart
16595         * @event
16596         * @memberof GuideBridge
16597         * @since 6.0
16598         * @example
16599         * guideBridge.on("submitStart" , function(event) {
16600         *    // do some pre submit processing
16601         * }
16602         */
16603        GUIDE_SUBMIT_START : "submitStart",
16604        GUIDE_PATH : "guidePath",
16605        GUIDE_NAME : "guideName",
16606        GUIDE_DESC : "guideDesc",
16607        GUIDE_TYPE : "guideType",
16608
16609        /**
16610         * @summary Dispatched when an Adaptive Form fragment is lazily loaded successfully
16611         * @name elementLazyLoaded
16612         * @property {object} payload payload containing more information about the event
16613         * @property {Panel} payload.target Adaptive Form Fragment which is lazily loaded
16614         * @event
16615         * @memberof GuideBridge
16616         * @since 6.1 FP1
16617         * @see {@link https://helpx.adobe.com/aem-forms/6-1/lazy-loading-adaptive-forms.html|Lazy Loading Adaptive Form}
16618         * @example
16619         * guideBridge.on("elementLazyLoaded" , function(event, payload) {
16620         *      var component = payload.target;
16621         *      console.log("Panel " + component.name + " loaded");
16622         * }
16623         */
16624        GUIDE_ELEMENT_LAZY_LOADED : "elementLazyLoaded",
16625
16626        /**
16627         * All GuideBridge APIs (except {@link GuideBridge#connect|connect}) require Adaptive Form to be initialized.
16628         * Checking the return value of this API is not necessary if guideBridge API is called only after the
16629         * <a href="#wait-form-ready">Form is initialized</a>
16630         * @summary Whether the Adaptive Form has been initialized or not
16631         *
16632         * @method
16633         * @memberof GuideBridge
16634         * @returns {boolean} true if the Adaptive Form is ready for interaction, false otherwise
16635         * @since 6.0
16636         * @instance
16637         */
16638        isConnected : function () {
16639            if (this._guide) {
16640                return true;
16641            }
16642            return false;
16643        },
16644
16645        /**
16646         * Specify a callback function which is called/notified when Adaptive Form gets initialized. After Adaptive
16647         * Form is initialized GuideBridge is ready for interaction and one can call any API.
16648         *
16649         * The callback can also be registered after the Form gets initialized. In that case, the callback will be
16650         * called immediately.
16651         *
16652         * @summary Register a callback to be executed when the Adaptive Form gets initialized
16653         * @param handler {function} function that would be called when guideBridge is ready for interaction. The
16654         * signature of the callback should be
16655         * ```
16656         * function() {
16657         *     // app specific code here
16658         * }
16659         * ```
16660         * @param {object} [context] _this_ object in the callback function will point to context
16661         * @since 6.0
16662         * @instance
16663         * @method
16664         * @memberof GuideBridge
16665         * @example
16666         * guideBridge.connect(function() {
16667         *    console.log("Hurrah! Guide Bridge Activated");
16668         * })
16669         */
16670        connect : function (handler, context) {
16671            context = context || guideBridge;
16672            if (this.isConnected()) {
16673                // handle exceptions gracefully since it executes in our thread
16674                try {
16675                    handler.call(context);
16676                } catch (exception) {
16677                    // guide model should be initialized in bridge in connect, still adding a null check
16678                    if (this._guide) {
16679                        this._guide.logger().log(exception);
16680                    }
16681                }
16682            } else {
16683                this._guideInitHandler.handler = this._guideInitHandler.handler || [];
16684                this._guideInitHandler.handler.push(handler);
16685                this._guideInitHandler.context = this._guideInitHandler.context || [];
16686                this._guideInitHandler.context.push(context);
16687            }
16688        },
16689
16690        _viewConnect : function (handler, context) {
16691            // ideally connect should do this but not changing the original function
16692            if (this._guideView && this._guide) {
16693                try {
16694                    handler.call(context);
16695                } catch (exception) {
16696                    // guide model should be initialized in bridge in connect, still adding a null check
16697                    if (this._guide) {
16698                        this._guide.logger().log(exception);
16699                    }
16700                }
16701            } else {
16702                this._guideInitHandler.handler = this._guideInitHandler.handler || [];
16703                this._guideInitHandler.handler.push(handler);
16704                this._guideInitHandler.context = this._guideInitHandler.context || [];
16705                this._guideInitHandler.context.push(context);
16706            }
16707        },
16708
16709        /**
16710         * @private
16711         * @since 6.5
16712         */
16713        _modelConnect : function (handler, context) {
16714            context = context || guideBridge;
16715            if (this.isConnected()) {
16716                // handle exceptions gracefully since it executes in our thread
16717                try {
16718                    handler.call(context);
16719                } catch (exception) {
16720                    // guide model should be initialized in bridge in connect, still adding a null check
16721                    if (this._guide) {
16722                        this._guide.logger().log(exception);
16723                    }
16724                }
16725            } else {
16726                this._guideModelInitHandler.handler = this._guideModelInitHandler.handler || [];
16727                this._guideModelInitHandler.handler.push(handler);
16728                this._guideModelInitHandler.context = this._guideModelInitHandler.context || [];
16729                this._guideModelInitHandler.context.push(context);
16730            }
16731        },
16732
16733        _guideModelInitialized : function (e) {
16734            this._guide = e.guide;
16735            if (this._guideModelInitHandler.handler) {
16736                for (var i = 0; i < this._guideModelInitHandler.handler.length; i++) {
16737                    try {
16738                        this._guideModelInitHandler.handler[i].call(this._guideModelInitHandler.context[i]);
16739                    } catch (exception) {
16740                        // guide model should be initialized in bridge in connect, still adding a null check
16741                        if (this._guide) {
16742                            this._guide.logger().log(exception);
16743                        }
16744                    }
16745                }
16746            }
16747        },
16748
16749        /*
16750         *
16751         * Handler for guideInitialized event which is fired by Adaptive Form library after Adaptive Form Dom is initialized
16752         *
16753         * @private
16754         */
16755        _guideInitialized : function (e) {
16756            if (this._guideInitHandler.handler) {
16757                for (var i = 0; i < this._guideInitHandler.handler.length; i++) {
16758                    try {
16759                        this._guideInitHandler.handler[i].call(this._guideInitHandler.context[i]);
16760                    } catch (exception) {
16761                        // guide model should be initialized in bridge in connect, still adding a null check
16762                        if (this._guide) {
16763                            this._guide.logger().log(exception);
16764                        }
16765                    }
16766                }
16767            }
16768            window.guideBridge.trigger("bridgeInitializeComplete",
16769                guidelib.event.GuideModelEvent.createEvent(
16770                    "bridgeInitializeComplete",
16771                    guideBridge
16772                )
16773            );
16774        },
16775        _setGuideView : function (guideView) {
16776            this._guideView = guideView;
16777        },
16778        _guideError : function (e) {
16779            this._guide.logger().debug("AF", e);
16780        },
16781        _checkGuide : function (obj) {
16782            if (!this._guide) {
16783                obj.addMessage(1, "Guide Dom not Initialized", "");
16784                return false;
16785            }
16786            return true;
16787        },
16788        /**
16789         * @summary returns the version of GuideBridge library
16790         * @returns {string} the version of the GuideBridge library
16791         * @method getBridgeVersion
16792         * @memberof GuideBridge
16793         * @instance
16794         * @since 6.0
16795         */
16796        getBridgeVersion : function () {
16797            return this._version;
16798        },
16799
16800        /**
16801         * Callback to execute when bridgeInitializeStart is triggered.
16802         * @callback GuideBridge~postExternalCallback
16803         * @param {string} name constant string `bridgeInitializeStart`
16804         * @param {object} data object containing the GuideBridge instance
16805         * @param {GuideBridge} data.guideBridge instance of GuideBridge
16806         * @since 6.0
16807         * @deprecated since 6.3 this callback is deprecated. One must do the handling in
16808         * {@link GuideBridge.events:bridgeInitializeStart} event
16809         * @memberof GuideBridge
16810         * @see GuideBridge#registerConfig
16811         * @see GuideBridge~postExternalMessageConfig
16812         */
16813        /**
16814         * @typedef {object} GuideBridge~postExternalMessageConfig
16815         * @property {GuideBridge~postExternalCallback} postExternalHandler callback to be executed when GuideBridge
16816         * instance is available
16817         * @since 6.0
16818         * @deprecated since 6.3 this configuration is deprecated. One must do the handling in
16819         * {@link GuideBridge.events:bridgeInitializeStart} event
16820         * @memberof GuideBridge
16821         * @see GuideBridge#registerConfig
16822         */
16823        /**
16824         * @typedef {object} GuideBridge~submitConfig
16825         * @property {HTMLFormElement} form During submission Adaptive Form creates a new HTMLFormElement and puts all the
16826         * value in that Form. One can provide an existing HTMLFormElement that will be reused for submitting the Form. The
16827         * action and method property of the Form element will be ignored.
16828         * @property {boolean} useAjax submit the form via a XMLHttpRequest rather than using a HTMLFormElement
16829         * instance is available
16830         * @property {function} submitSuccessHandler success Handler to be called post submission. This option is ignored
16831         * if _useAjax_ is set to false
16832         * @since 6.0
16833         * @memberof GuideBridge
16834         * @see GuideBridge#registerConfig
16835         */
16836        /**
16837         * @typedef {object} GuideBridge~renderConfig
16838         * @property {boolean} enableFocusOnFirstField option to enable focus on first field. Default value is true.
16839         * @since 6.5
16840         * @memberof GuideBridge
16841         * @see GuideBridge#registerConfig
16842         */
16843        /**
16844         * Adaptive Form uses some default named configurations to provide its default behaviour. This configurations
16845         * can be modified by providing a new configuration.
16846         *
16847         * The API accepts the name of the configuration and updated configuration. Based on value of the new
16848         * configuration the behaviour of the Form gets changed.
16849         * Currently supported configurations are:
16850         * #### postExternalMessageConfig
16851         *
16852         * <div class="deprecated"><span class="deprecated-heading">Deprecated :</span><span> since 6.2 this
16853         * configuration is deprecated. Use the {@link GuideBridge.events:bridgeInitializeStart} event to do the same
16854         * handling</span>
16855         * </div>
16856         * In case Adaptive Form is embedded inside an iframe, this configuration allows developers to provide
16857         * GuideBridge Instance to parent or child windows.
16858         *
16859         * By default, GuideBridge instance is only available to the current window and to the parent window if it
16860         * doesn't violate the cross-origin policy. Now there may be a case when this doesn't solves the problem, then
16861         * one can take advantage of this configuration to extend this functionality.
16862         *
16863         * For the signature of the configuration see
16864         * {@link GuideBridge~postExternalMessageConfig|postExternalMessageConfig}
16865         * ##### Example
16866         * To provide the GuideBridge instance to a child window
16867         * ```
16868         * window.on("bridgeInitializeStart", function (evnt) {
16869         *      var gb = evnt.detail.guideBridge;
16870         *      gb.registerConfig("postExternalMessageConfig", {
16871         *          "postExternalHandler" : function(data) {
16872         *              // assume we have a child window with an id 'childWindowId'
16873         *              var childWindow = document.getElementById("#childWindowId").contentWindow;
16874         *              var tmpEvent = document.createEvent("CustomEvent");
16875         *              tmpEvent.initCustomEvent(data.name, true, true, data.data);
16876         *              childWindow.dispatchEvent(tmpEvent);
16877         *          }
16878         *      });
16879         * });
16880         * ```
16881         * #### widgetConfig
16882         * The configuration is used to modify the appearance of a specific Field. Adaptive Form allows developers to
16883         * [create custom widgets](http://helpx.adobe.com/aem-forms/6-1/custom-appearance-widget-adaptive-form.html) and
16884         * use them in their Forms.
16885         *
16886         * The signature of the config is
16887         * ```
16888         * { "<component-identifier> : "<widget-name>"}
16889         * ```
16890         * where `<component-identifier>` can be either the name or classname of Adaptive Form Field,
16891         * while widget name is the name of the jQuery Widget.
16892         *
16893         * #### submitConfig
16894         * To modify the default submit behaviour one can provide this configuration. The signature of the config is
16895         * defined {@link GuideBridge~submitConfig|below}
16896         * ```
16897         * guideBridge.registerConfig("submitConfig", {"useAjax" : true});
16898         * ```
16899         *
16900         * #### renderConfig
16901         * To modify the default render behaviour one can provide this configuration. The signature of the config is
16902         * defined {@link GuideBridge~renderConfig|below}
16903         * ```
16904         * guideBridge.registerConfig("renderConfig", {"enableFocusOnFirstField" : false});
16905         * ```
16906         * @summary Registers user/portal specific configurations to GuideBridge
16907         * @returns {GuideResultObject} {@link GuideResultObject} with {@link GuideResultObject#data|data} having the
16908         * old configuration against the same _key_
16909         *
16910         * @param key {string} configuration name. one of the following
16911         * * postExternalMessageConfig
16912         * * widgetConfig
16913         * * submitConfig
16914         * * renderConfig
16915         * @param {widgetConfig|GuideBridge~submitConfig|GuideBridge~renderConfig|GuideBridge~postExternalMessageConfig} [config] configuration object for the configuration
16916         * @method
16917         * @memberof GuideBridge
16918         * @since 6.0
16919         * @instance
16920         */
16921        registerConfig : function (key, config) {
16922            var obj = new GuideResultObject();
16923            obj.data = this.userConfig[key];
16924            this.userConfig[key] = config;
16925            obj.completed = true;
16926            return obj;
16927        },
16928
16929        /**
16930         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16931         * fileAttachmentMap key should be present in the map.
16932         * @name customContextProperty
16933         * @param value {object} object to be replaced with the current customPropertyMap.
16934         * @memberof GuideBridge
16935         * @method
16936         * since 6.0
16937         */
16938
16939        /**
16940         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16941         * fileAttachmentMap key should be present in the map.
16942         * @name customContextProperty
16943         * @param property {string} object to be replaced with the current customPropertyMap.
16944         * @method
16945         * @memberof GuideBridge
16946         * since 6.0
16947         */
16948
16949        /**
16950         * Their exists a customPropertyMap which can be set from the server. For prefilling files
16951         * fileAttachmentMap key should be present in the map.
16952         * @param property {string} property to update in the custom property map
16953         * @param value {*} value of the property
16954         * @return {*} old value of the property
16955         * since 6.0
16956         */
16957        customContextProperty : function (property, value) {
16958            var customPropertyMap = getOrElse(guidelib, "__runtime__.guideContext.customPropertyMap", {});
16959            // use both the customContextProperty map since customers also access that
16960            var newCustomPropertyMap = _.extend({}, customPropertyMap, getOrElse(this._guide, "runtime.guideContext.customPropertyMap", {}));
16961            if (_.isUndefined(value)) {
16962                if (_.isObject(property)) {
16963                    guideBridge._modelConnect((function (newCustomPropertyMap, property) {
16964                        return function () {
16965                            var localMap = _.extend({}, guideBridge._guide.runtime.guideContext.customPropertyMap, newCustomPropertyMap);
16966                            _.extend(localMap, property);
16967                            guideBridge._guide.runtime.guideContext.customPropertyMap = localMap;
16968                        };
16969                    })(newCustomPropertyMap, property));
16970                } else {
16971                    return newCustomPropertyMap[property];
16972                }
16973            } else {
16974                var oldValue = newCustomPropertyMap[property];
16975                guideBridge._modelConnect((function (property, value, newCustomPropertyMap) {
16976                    return function () {
16977                        var localMap = _.extend({}, guideBridge._guide.runtime.guideContext.customPropertyMap, newCustomPropertyMap);
16978                        localMap[property] = value;
16979                        guideBridge._guide.runtime.guideContext.customPropertyMap = localMap;
16980                    };
16981                })(property, value, newCustomPropertyMap));
16982                return oldValue;
16983            }
16984        },
16985
16986        getNavigablePanel : function (somExpression) {
16987            return this._guideView.getSomOnNavigableAncestor(somExpression);
16988        },
16989
16990        /**
16991         * Sets the value of a property for a set of {@link GuideNode} to a different value. Property must be a valid
16992         * writable property for that Node
16993         *
16994         * Each entry in _somList_ should have a corresponding entry in the _valueList_. Mismatch in the length of these
16995         * two arguments will make the function do nothing
16996         * @summary Modify a property for a set of Nodes
16997         * @method setProperty
16998         * @param {string[]} somList an array having someExpression for the nodes. Invalid SomExpressions and
16999         * the corresponding value in the _valueList_ are ignored.
17000         * @param {string} propertyName name of the property which has to be modified
17001         * @param {Array.<*>} valueList an array containing value of the _propertyName_ for each element in _somList_
17002         *
17003         * @memberof GuideBridge
17004         * @instance
17005         * @since 6.0
17006         * @see GuideNode#somExpression
17007         * @example <caption>Modifying the value of a set of fields</caption>
17008         * guideBridge.setProperty(["SOM_OF_FIELD_1", "SOM_OF_FIELD_2"...... "SOM_OF_FIELD_N"]
17009         *                          "value"
17010         *                          [VALUE_1, VALUE_2 .... VALUE_N]);
17011         * @example <caption>Hiding a single field</caption>
17012         * guideBridge.setProperty(["SOM_OF_FIELD_1"]
17013         *                          "visibility"
17014         *                          [false]);
17015         */
17016        setProperty : function (somList, propertyName, valueList) {
17017            if (!propertyName) {
17018                return;
17019            }
17020            if (!_.isArray(somList) || !_.isArray(valueList)) {
17021                return;
17022            }
17023            if (somList.length !== valueList.length) {
17024                return;
17025            }
17026            var gb = this;
17027            _.each(somList, function (som, index) {
17028                var node = gb.resolveNode(som);
17029                if (node) {
17030                    node[propertyName] = valueList[index];
17031                } else {
17032                    gb._guide.logger().log("som not valid:" + som);
17033                }
17034            });
17035            if (!this._guide._currentContext) {
17036                this._guide.runPendingExpressions();
17037            }
17038        },
17039
17040        /**
17041         * Used to retrieve the Form data as XML. The API gets the data xml synchronously/asynchronously based on the
17042         * _async_ option and invokes the success/error handlers passed in the arguments upon completion.
17043         *
17044         * In the success callback the {@link GuideResultObject#data|data} parameter contains the xml string.
17045         *
17046         * The success and error handlers receive {@link GuideResultObject} as input.
17047         * @summary Return Form data as XML.
17048         *
17049         * @param {object} options input to the getDataXML API
17050         * @param {function} [options.success] callback which receives the result of the API
17051         * in case of success.
17052         * @param {function} [options.error] callback which receives the result of the API in
17053         * case of failure.
17054         * {@link GuideResultObject#errors|errors} property as true.
17055         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
17056         * object
17057         * @param {boolean} [options.async=true] whether to make the server call asynchronously or not. If false, the
17058         * browser will wait for the server to return the XML and then execute the success or error callbacks object
17059         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
17060         * @method
17061         * @memberof GuideBridge
17062         * @since 6.0
17063         * @instance
17064         * @example
17065         * guideBridge.getDataXML({
17066         *     success : function (guideResultObject) {
17067         *          console.log("xml data received" + guideResultObject.data);
17068         *     }
17069         *     error : function (guideResultObject) {
17070         *          console.error("API Failed");
17071         *          var msg = guideResultObject.getNextMessage();
17072         *          while (msg != null) {
17073         *              console.error(msg.message);
17074         *              msg = guideResultObject.getNextMessage();
17075         *          }
17076         *     }
17077         * });
17078         *
17079         * @deprecated since 6.3 this API is deprecated. Use getData API instead.
17080         * @param options
17081         */
17082        getDataXML : function (options) {
17083            guideBridge.getData(options);
17084        },
17085
17086        /**
17087         * Used to retrieve the Form data as XML or JSON depending on the Schema Type. Only for JSON Schema based Forms
17088         * and Form Data Model based forms, the data will be in JSON format while for others, the data will be in XML format.
17089         * The API gets the data synchronously/asynchronously based on the
17090         * _async_ option and invokes the success/error handlers passed in the arguments upon completion.
17091         *
17092         * In the success callback the {@link GuideResultObject#data|data} parameter contains the data string.
17093         *
17094         * The success and error handlers receive {@link GuideResultObject} as input.
17095         * @summary Return Form data as XML or JSON depending on the Schema Type.
17096         *
17097         * @param {object} options input to the getData API
17098         * @param {function} [options.success] callback which receives the result of the API
17099         * in case of success.
17100         * @param {function} [options.error] callback which receives the result of the API in
17101         * case of failure.
17102         * {@link GuideResultObject#errors|errors} property as true.
17103         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
17104         * object
17105         * @param {boolean} [options.async=true] whether to make the server call asynchronously or not. If false, the
17106         * browser will wait for the server to return the data (XML or JSON) and then execute the success or error callbacks object
17107         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
17108         * @method
17109         * @memberof GuideBridge
17110         * @since 6.3
17111         * @instance
17112         * @example
17113         * guideBridge.getData({
17114         *     success : function (guideResultObject) {
17115         *          console.log("data received" + guideResultObject.data);
17116         *     }
17117         *     error : function (guideResultObject) {
17118         *          console.error("API Failed");
17119         *          var msg = guideResultObject.getNextMessage();
17120         *          while (msg != null) {
17121         *              console.error(msg.message);
17122         *              msg = guideResultObject.getNextMessage();
17123         *          }
17124         *     }
17125         * });
17126         * @deprecated use {@link GuideBridge#getFormDataString} instead
17127         */
17128        getData : function (options) {
17129            options = options || {};
17130
17131            /* Earlier this API would support boundData for getting data tro be merged in PDF. Now that flag has been renamed to dorData
17132             *  Earlier, boundData flag now maps to boundData for backward compatibility.
17133             * */
17134            options.dorData = options.dorData || options.boundData;
17135
17136            var resultObject = new GuideResultObject();
17137            if (!options.guideState && !this._checkGuide(resultObject)) {
17138                options.error.call(options.context, resultObject);
17139                return;
17140            }
17141
17142            this._submitInternal({
17143                success : function (data) {
17144                    var resultJson = data || {};
17145                    resultObject.completed = true;
17146                    if (options.dorData) {
17147                        resultObject.data = resultJson["dorDataXml"];
17148                    } else {
17149                        resultObject.data = resultJson["data"];
17150                    }
17151                    if (_.isFunction(options.success)) {
17152                        options.success.call(options.context, resultObject);
17153                    }
17154                },
17155                error : function (xhr, txtStatus, errorThrown) {
17156                    var msg = "Error in getData API";
17157                    resultObject.completed = false;
17158                    resultObject.addMessage(2, msg, "");
17159                    if (_.isFunction(options.error)) {
17160                        options.error.call(options.context, resultObject);
17161                    }
17162                },
17163                guideState : options.guideState,
17164                async : options.async,
17165                fileUploadPath : options.fileUploadPath,
17166                excludeFormState : options.excludeFormState || false,
17167                dorData : options.dorData || false
17168            });
17169        },
17170
17171        /**
17172         * returns form data object {@link FormData}
17173         * @returns {*}
17174         * @private
17175         */
17176        _getFormDataObj : function () {
17177            guideBridge._updateAFSubmissionInfo();
17178            guideBridge._guide.internal.liveDataUtils.updateLiveData(null, true); // fetching client side data
17179            guideBridge._guide.internal.liveDataUtils.insertSubmissionInfo(guideBridge._guide.runtime.guideContext.afSubmissionInfo);
17180            var data =  guideBridge._guide.internal.liveDataUtils.getLiveDataStr();
17181            var contentType = "application/xml";
17182            if (guideBridge._guide.internal.liveDataUtils instanceof guidelib.model.LiveJsonUtils) {
17183                contentType = "application/json";
17184            }
17185            return new guidelib.model.FormData({
17186                "data" : data,
17187                "contentType" : contentType,
17188                "attachments" : guideBridge.getFileAttachmentWrapper()
17189            });
17190        },
17191
17192        /**
17193         * invoked inside server-side-validation to return excludeFromDor data.
17194         * @param  {Object} guide input to _getExcludeFromDorData API
17195         * @returns {Array} containing excludeFromDoR info
17196         * */
17197        _getExcludeFromDorData : function (guide) {
17198            var newGuide = guide ? guide : guideBridge._guide;
17199            var excludeFromDorData = null;
17200            window.guideBridge._updateAFSubmissionInfo(newGuide);
17201            var afSubmissionInfo = newGuide.runtime.guideContext.afSubmissionInfo;
17202            if(afSubmissionInfo.excludeFromDoR) {
17203                excludeFromDorData = afSubmissionInfo.excludeFromDoR;
17204            }
17205            return excludeFromDorData;
17206        },
17207
17208        /**
17209         * returns FormData object {@link FormData} containing form data xml or json and attachments
17210         * @param {object} options input to the getFormDataObject API
17211         * @param {function} [options.success] callback which receives the result of the API
17212         * in case of success.
17213         * @method
17214         * @memberof GuideBridge
17215         * @since Forms As A Cloud Service
17216         * @instance
17217         */
17218        getFormDataObject : function (options) {
17219            var formDataObj = guideBridge._getFormDataObj();
17220            var resultObject = new GuideResultObject();
17221            resultObject.data = formDataObj;
17222            // using typeof for built in types
17223            if (options && typeof options.success === 'function') {
17224                options.success(resultObject);
17225            }
17226        },
17227
17228        /**
17229         * returns string representation of form data xml or json
17230         * @param {object} options input to the getData API
17231         * @param {function} [options.success] callback which receives the result of the API
17232         * in case of success.
17233         * @method
17234         * @memberof GuideBridge
17235         * @since 6.5
17236         * @instance
17237         */
17238        getFormDataString : function (options) {
17239            var formDataObj = guideBridge._getFormDataObj();
17240            var resultObject = new GuideResultObject();
17241            resultObject.data = formDataObj.data;
17242            if (options && typeof options.success === 'function') {
17243                options.success(resultObject);
17244            }
17245        },
17246
17247
17248        /**
17249         * Imports form data from a given string, which can be either JSON or XML format.
17250         * This is useful for initializing a form with pre-filled data received as a string.
17251         *
17252         * @param {Object} options - The options for importing data.
17253         * @param {string} options.data - The string representation of form data (XML or JSON).
17254         * @method
17255         * @memberof GuideBridge
17256         * @since Forms As A Cloud Service
17257         * @instance
17258         * @example
17259         * guideBridge.importData({ data: jsonString }); // For JSON data
17260         * guideBridge.importData({ data: xmlString });  // For XML data
17261         */
17262        importData : function (options) {
17263            // todo: add support for attachments and custom context later
17264            var prefillData = {
17265                data: options.data,
17266                isMergedJson: false
17267                // customContext: {}
17268                // fileAttachmentMap: {}
17269                // fileAttachmentWrappers:
17270                // attachments: '[]'
17271            };
17272            guidelib.model.mergeData(prefillData, guideBridge._guide, guideBridge._guide.runtime.guideContext);
17273        },
17274
17275        /**
17276         * @summary Hides all the submit buttons present in the Adaptive Form
17277         *
17278         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17279         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors|errors} property.
17280         * @memberof GuideBridge
17281         * @instance
17282         * @since 6.0
17283         */
17284        hideSubmitButtons : function () {
17285            return this._hideElements("guideButton", "submit");
17286        },
17287
17288        /**
17289         * @returns {string} Current Locale of the Form
17290         * @method
17291         * @memberof GuideBridge
17292         * @since Forms As A Cloud Service
17293         * @instance
17294         */
17295        getFormLocale : function() {
17296            return this._readRuntimeLocale();
17297        },
17298
17299        /**
17300         * @returns {string} ID of the Form
17301         * @method
17302         * @memberof GuideBridge
17303         * @since Forms As A Cloud Service
17304         * @instance
17305         */
17306        getFormId : function() {
17307            var guidePath = guideBridge._guide.jsonModel["jcr:path"];
17308            return btoa(guidePath);
17309        },
17310
17311        /**
17312         * Gets the Document of Record. If options is not passed or if success function is not defined,
17313         * then the default behaviour is to download the Document of Record PDF in user's system.
17314         * @param {object} options options to control the behaviour after Document of Record (DOR) is retrieved
17315         * @param {function} [options.success] callback which receives the result of the API
17316         * {@link GuideResultObject#errors|errors} property as false.
17317         * @param {function} [options.error] callback for error handling
17318         * {@link GuideResultObject#errors|errors} property as true.
17319         * @method
17320         * @memberof GuideBridge
17321         * @since Forms As A Cloud Service
17322         * @instance
17323         * @example <caption>Getting the Document of Record</caption>
17324         * guideBridge.getDocumentOfRecord({
17325         *   success: function (guideResultObject) {},
17326         *   error: function (guideResultObject) {}
17327         * })
17328         */
17329        getDocumentOfRecord : function(options) {
17330            var self = this;
17331            var formName = self._getFormName(self.getGuidePath());
17332            if (!options) {
17333                options = {};
17334            }
17335            if (!_.isFunction(options.success)) {
17336                options.success = function (guideResultObject) {
17337                    if (guideResultObject.completed && guideResultObject.data) {
17338                        var blob = new Blob([guideResultObject.data], {type: 'application/pdf'});
17339                        var downloadUrl = URL.createObjectURL(blob);
17340                        var a = document.createElement("a");
17341                        a.setAttribute('href', downloadUrl);
17342                        a.setAttribute('download', formName);
17343                        a.setAttribute('style', 'display:none');
17344                        document.body.appendChild(a);
17345                        a.click();
17346                    }
17347                }
17348            }
17349            if (!_.isFunction(options.error)) {
17350                options.error = function(guideResultObject) {
17351                    console.error(guideResultObject.data);
17352                }
17353            }
17354            function _getDocumentOfRecord(formData) {
17355                var formId = self.getFormId();
17356                var locale = self.getFormLocale();
17357                var dorGenerationURL = self._getUrl("/adobe/forms/af/dor/" + formId + "?locale=" + locale);
17358                $.ajax({
17359                    url : dorGenerationURL,
17360                    type : "POST",
17361                    processData : false,
17362                    cache : false,
17363                    contentType : false,
17364                    data : formData,
17365                    xhrFields:{
17366                        responseType: 'blob'
17367                    },
17368                    success : function(blob) {
17369                        var guideResultObject = new GuideResultObject();
17370                        guideResultObject.data = blob;
17371                        guideResultObject.completed = true;
17372                        options.success(guideResultObject);
17373                    },
17374                    error : function (exception) {
17375                        var guideResultObject = new GuideResultObject();
17376                        guideResultObject.data = exception;
17377                        guideResultObject.completed = false;
17378                        options.error(guideResultObject);
17379                    }
17380                });
17381            };
17382
17383            self.getFormDataString({
17384                success: function(result) {
17385                    var attachedFilesList = self._getFileAttachmentsList();
17386                    var fileNameDomMap = self._juiceOutNameAndFileDomMap(attachedFilesList);
17387                    var dataForm = new FormData();
17388                    var fileAttachmentPromise = self._appendFileAttachmentsToFormData(dataForm, fileNameDomMap, attachedFilesList);
17389                    fileAttachmentPromise.then(function (dataForm) {
17390                        dataForm.append('data', result.data);
17391                        _getDocumentOfRecord(dataForm);
17392                    }).catch(function (e) {
17393                        console.error(e);
17394                    });
17395                }
17396            })
17397        },
17398
17399        /**
17400         * This API is designed to evaluate the expression entered by the author.
17401         * This API is given only to enable Auto Save meta information use case.
17402         * @returns value obtained after executing the expression.
17403         * @method
17404         * @private
17405         * @memberof GuideBridge
17406         * @deprecated since 6.3 this API is deprecated
17407         */
17408        _evaluateExpression : function (expression) {
17409            if (this._guide) {
17410                var compiledExpression = this._guide._compileExpression(expression, null);
17411                return compiledExpression.apply(this._guide);
17412            }
17413        },
17414
17415        /**
17416         * Adaptive Form can be configured to save draft automatically. This property indicates whether Adaptive Form is
17417         * configured to save draft automatically or not.
17418         *
17419         * Enabling auto save doesn't mean that AF will create the draft when the Form is loaded. Based on the result of
17420         * **Auto save start expression** the draft will be created. Once the expression returns true, drafts will be
17421         * saved at regular interval or at specific events as configured.
17422         *
17423         * @summary Whether autoSave is enabled for this Adaptive Form or not
17424         * @returns {boolean} true if auto save is enabled otherwise false.
17425         * @method
17426         * @memberof GuideBridge
17427         * @instance
17428         * @since 6.1 FP1
17429         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Saving an adaptive Form}
17430         */
17431        getAutoSaveEnabledStatus : function () {
17432            var _isAutoSaveEnable = false;
17433            // check if form is loaded or not, if loaded then check for auto save
17434            if (this.isConnected()) {
17435                _isAutoSaveEnable = this._guide.enableAutoSave;
17436            }
17437            return _isAutoSaveEnable;
17438        },
17439
17440        /**
17441         * This API indicates that auto save is enabled and draft is being saved at the configured location.
17442         * @summary Whether Adaptive Form data is being saved as draft or not.
17443         * @returns {Boolean} whether autoSave has started.
17444         * @method
17445         * @memberof GuideBridge
17446         * @instance
17447         * @since 6.1 FP1
17448         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Saving an adaptive Form}
17449         **/
17450        hasAutoSaveStarted : function () {
17451            return this._guide && this._guide.enableAutoSave && this._guide.autoSaveStart;
17452        },
17453
17454        /**
17455         * @summary the autoSaveinfo that is stored at the guideContainer.
17456         * @returns {object}
17456 object contains the additional meta information stored along with form data
17457         * @method
17458         * @memberof GuideBridge
17459         * @instance
17460         * @since 6.1 FP1
17461         * @deprecated since 6.3
17462         */
17463        getAutoSaveInfo : function () {
17464            return this._guide.autoSaveInfo;
17465        },
17466
17467        /**
17468         * The API is used to provide extra information to be saved in Final data XML. It can also be used to retrieve
17469         * that information.
17470         *
17471         * If _value_ is null then the value of the _property_ is returned
17472         * @summary store or retrieve submission related information
17473         * @param {string} property name of the property against which to save the value or retrieve the value of
17474         * property
17475         * @param {string} [value] value to save.
17476         * @returns {*} old value of the property
17477         * @method
17478         * @since 6.1 FP1
17479         * @memberof GuideBridge
17480         * @instance
17481         * @deprecated since 6.3
17482         */
17483        afSubmissionInfo : function (property, value) {
17484            var afSubmissionInfo = guideBridge._guide.runtime.guideContext.afSubmissionInfo || {};
17485            if (_.isUndefined(value)) {
17486                return afSubmissionInfo[property];
17487            } else {
17488                var oldValue = afSubmissionInfo[property];
17489                afSubmissionInfo[property] = value;
17490                guideBridge._guide.runtime.guideContext.afSubmissionInfo = afSubmissionInfo;
17491                return oldValue;
17492            }
17493        },
17494
17495        /**
17496         * @summary this API returns the globalMetaInfo stored in global context (in globalMetaInfo tab).
17497         * @returns {object}
17498         * @method
17499         * @memberof GuideBridge
17500         * @instance
17501         * @deprecated since 6.3
17502         */
17503        getGlobalMetaInfo : function () {
17504            return this._guide.globalMetaInfo;
17505        },
17506
17507        /**
17508         * @summary this API returns the metadata configured for submission. Value depends on the selection of metadata
17509         * type, local or global.
17510         * @returns {Object}
17511         * @method
17512         * @since 6.1 FP1
17513         * @memberof GuideBridge
17514         * @instance
17515         * @deprecated since 6.3
17516         */
17517        getSubmissionMetadataInfo : function () {
17518            if (this._guide.submissionMetaInfo && this._guide.submissionMetaInfo.metadataselector === LOCAL_METADATA_SELECTOR) {
17519                // In order to maintain backward compatibility, this piece of code will always be here.
17520                // For the cases where metadata selection is being configured for submit actions
17521                return getOrElse(this._guide, "submissionMetaInfo.metadata", null);
17522            } else {
17523                //From 6.2 onwards, we are asking author to provide metadata only at one place, which is global to whole form
17524                // In case, metadataselector's value is "global" or not configured at all, this block will get executed
17525                return getOrElse(this._guide, "globalMetaInfo.metadata", null);
17526            }
17527        },
17528
17529        /**
17530         * The API enables auto save in Adaptive Form
17531         * @summary  enable auto save in Adaptive Form.
17532         * @param value {boolean} true to enable auto save otherwise false.
17533         * @method
17534         * @memberof GuideBridge
17535         * @instance
17536         * @since 6.1 FP1
17537         * @see {@link GuideBridge#getAutoSaveEnabledStatus|getAutoSaveEnabledStatus}
17538         * @see {@link https://helpx.adobe.com/aem-forms/6-1/auto-save-an-adaptive-form.html|Auto Save an Adaptive Form}
17539         */
17540        setEnabledAutoSave : function (value) {
17541            this._guide.enableAutoSave = value;
17542        },
17543
17544        /**
17545         * @summary Hides all the file attachment listing buttons present in the Adaptive Form
17546         *
17547         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17548         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17549         * @memberof GuideBridge
17550         * @instance
17551         * @since 6.0
17552         */
17553        hideFileAttachmentListingButtons : function () {
17554            return this._hideElements("guideListFileAttachmentButton");
17555        },
17556
17557        /**
17558         * @todo: Function can change as per usecase, it can behave as a wrapper
17559         * where it can use the configuration provided through registerConfig and invoke any callback if required
17560         *
17561         * @returns {boolean} boolean indicating whether Adaptive Form is offline
17562         * @private
17563         */
17564        isOffline : function () {
17565            return checkAFOffline;
17566        },
17567
17568        /**
17569         * function to set the status of Adaptive Form (online or offline)
17570         * @type {boolean}
17571         * @private
17572         */
17573        setIsOffline : function (value) {
17574            checkAFOffline = value;
17575        },
17576
17577        /**
17578         * @summary Hide all the File Attachment component present in the Adaptive Form
17579         *
17580         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17581         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17582         * @memberof GuideBridge
17583         * @instance
17584         * @since 6.0
17585         */
17586        hideFileAttachments : function () {
17587            return this._hideElements("guideFileUpload");
17588        },
17589
17590        /**
17591         * @summary Hides the global toolbar of the Adaptive Form.
17592         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17593         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17594         * @memberof GuideBridge
17595         * @instance
17596         * @since 6.0
17597         */
17598        hideGlobalToolbar : function () {
17599            var resultObject = new GuideResultObject(),
17600                $toolbar;
17601
17602            // If guide dom not initialized, return
17603            if (!this._checkGuide(resultObject)) {
17604                return resultObject;
17605            }
17606
17607            if (guideBridge._guide.toolbar) {
17608                $toolbar = this._getGuideDomElement(guideBridge._guide.toolbar.somExpression);
17609                if ($toolbar && $toolbar.length > 0) {
17610                    $toolbar.hide();
17611                }
17612            }
17613
17614            resultObject.completed = true;
17615            return resultObject;
17616        },
17617
17618        /*
17619         *
17620         * This API is designed to return all the toolbar buttons present in the Adaptive Form(except submit, save, reset and file attachment listing)
17621         *
17622         * @returns {GuideResultObject} data contains an array of all the tool bar buttons available(except submit, save, reset and file attachment listing)
17623         * Each element of data property is an object holding model and html property.
17624         * The html string does not contain any script tags, this is to avoid crosss site scripting attacks
17625         */
17626        /*
17627         getToolbarButtons : function(){
17628         var resultObject = new GuideResultObject(),
17629         resultData = [],
17630         $elem = null;
17631         // If guide dom not initialized, return
17632         if (!this._checkGuide(resultObject)) {
17633         return resultObject;
17634         }
17635         resultObject.completed = true;
17636         this.visit(function(node){
17637         // Check if this node is a guide button and if it resides inside a guideToolBar
17638         if(node.className === "guideButton" && node.parent.className === "guideToolbar"){
17639         if(node.type !== "submit" && node.type !== "save" && node.type !== "fileattachmentlisting" && node.type !== "next" && node.type !=="prev") {
17640         $elem =  this._getGuideDomElement(node.somExpression);
17641         // Remove the script tag from the $html, we don't support execution of Adaptive Form Scripts in parent or other domain
17642         // This is to avoid cross site scripting attacks
17643         $elem.find("script").remove();
17644         resultData.push({
17645         "model" : node,
17646         "html"  : $elem.html()
17647         });
17648         }
17649         }
17650         });
17651         resultObject.data = resultData;
17652         return resultObject;
17653         }, */
17654
17655        /**
17656         * @summary Hides all the save buttons present in the Adaptive Form
17657         *
17658         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17659         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17660         * @memberof GuideBridge
17661         * @instance
17662         * @since 6.0
17663         */
17664        hideSaveButtons : function () {
17665            return this._hideElements("guideButton", "save");
17666        },
17667
17668        /**
17669         * @summary Hides all the reset buttons present in the Adaptive Form
17670         *
17671         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17672         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17673         * @memberof GuideBridge
17674         * @instance
17675         * @since 6.3
17676         */
17677        hideResetButtons : function () {
17678            return this._hideElements("guideButton", "reset");
17679        },
17680
17681        /**
17682         * The API can be used to retrieve the value of a specific property for a list of AF components. If the property
17683         * doesn't exists for a component then the corresponding value in the resulting array will be null.
17684         *
17685         * The {@link GuideResultObject#data|data} element of the return object will be an array containing the values
17686         * of the _property_ for each component in the list of components
17687         *
17688         * The API fails if the Form is not initiailzed
17689         *
17690         * **_Note:_** If a somExpression provided doesn't points to a valid {@link GuideNode} null is returned for
17691         * that element and an error message is added in the returned object
17692         * @summary returns the value of a specific property for a set of Adaptive Form Components
17693         *
17694         * @param {object}
17694 options input object containing the propertyName and the list of components
17695         * @param {string} options.propertyName name of the property whose value has to be returned
17696         * @param {string[]} options.somExpression list of somExpression of the components for which the value is to be
17697         * returned.
17698         *
17699         * @returns {GuideResultObject} The {@link GuideResultObject#data|data} member of the object contains the property
17700         * values
17701         * @method
17702         * @memberof GuideBridge
17703         * @since 6.0
17704         * @instance
17705         * @deprecated since 6.3
17706         * @see GuideNode#somExpression
17707         * @example
17708         * var result = guideBridge.getElementProperty({
17709         *    propertyName: "value",
17710         *   somExpression: ["somExpression1", "somExpression2"]
17711         * });
17712         * if (result.errors) {
17713         *      console.log("some som expressions were invalid");
17714         *      var err = result.getNextMessage();
17715         *     while(err != null) {
17716         *          //err.somExpression will point to the invalid somExpression in the Field.
17717         *          console.log(err.message);
17718         *     }
17719         * }
17720         * for(var i = 0; i< result.data.length; i++) {
17721         *      console.log(result.data[i]);
17722         * }
17723         */
17724        getElementProperty : function (options) {
17725            var somExpressions = options.somExpressions;
17726            var propertyName = options.propertyName;
17727            var resultObject = new GuideResultObject();
17728            if (!this._checkGuide(resultObject)) {
17729                return resultObject;
17730            }
17731            resultObject.data = [];
17732            for (var i = 0; i < somExpressions.length; i++) {
17733                var element = this.resolveNode(somExpressions[i]);
17734                if (element == null) {
17735                    resultObject.addMessage(0, "No element " + somExpressions[i] + " exists", somExpressions[i]);
17736                    resultObject.data.push(null);
17737                } else {
17738                    resultObject.completed = true;
17739                    resultObject.data.push(element[propertyName]);
17740                }
17741            }
17742            return resultObject;
17743        },
17744
17745        _getGuideDomElement : function (somExpression, option) {
17746            if (this._guideView) {
17747                return this._guideView._getGuideDomElement(somExpression, option);
17748            } else {
17749                return null;
17750            }
17751        },
17752
17753        /**
17754         * File Attachment object
17755         * @typedef {object} GuideBridge~FileAttachementObject
17756         * @property {string} name name of the uploaded File
17757         * @property {string} path path of the uploaded File
17758         * @memberof GuideBridge
17759         * @since 6.0
17760         */
17761        /**
17762         * Success callback that is called from {@link GuideBridge#getFileAttachmentsInfo} with the list of File
17763         * Attachments
17764         * @callback GuideBridge~FileAttachmentInfoHandler
17765         * @param {GuideBridge~FileAttachementObject[]} fileAttachementList list of file attachement objects uploaded
17766         * in the Form
17767         */
17768        /**
17769         * The API provides a list containing File Names and File URLS for the Files Attached by the user using the
17770         * File Attachment component. The API is a asynchronous API and takes success handler which is called with
17771         * the list of File Names and URLs.
17772         *
17773         * @param {object} options Object containing the callback which will be invoked with the result of this API
17774         * @param {function} options.success success callback which will be invoked. The signature of the callback should
17775         * match the signature of {@link GuideBridge~FileAttachmentInfoHandler|FileAttachmentInfoHandler}
17776         * @param {object} [options.context] _this_ parameter in the success handler will point to this object
17777         *
17778         * @example  <caption>Example usage of the getFileAttachmentsInfo API</caption>
17779         * guideBridge.getFileAttachmentsInfo({
17780         *        success:function(list) {
17781         *             for(var i = 0; i< list.length; i++) {
17782         *                  console.log(list[i].name + " "+ list[i].path);
17783         *             }
17784         *        }
17785         * });
17786         * @method
17787         * @memberof GuideBridge
17788         * @since 6.0
17789         * @deprecated since Forms As a Cloud Service
17790         * @instance
17791         */
17792        getFileAttachmentsInfo : function (options) {
17793            console.error("getFileAttachmentsInfo API is not supported on Forms As a Cloud Service");
17794            options.success.call(options.context, []);
17795        },
17796
17797        /**
17798         * Syntax - argObject : {"options" : options to be passed to the callback,
17799         *                   "fileAttachmentsList" : fileAttachmentsList,
17800         *                    "fileUploadPath" :fileUploadPath
17801         *                     "callback" :callback, "errorCallback" :errorCallback}
17802         * @param {object}
17802 argObject Input object containing the callbacks that will be invoked
17803         * to provide the result of the API
17804         * @private
17805         * @memberof GuideBridge
17806         * @since 6.0
17807         */
17808        _getGuideAttachments : function (argObject) {
17809            var fileDoms = [],
17810                fileNames = [],
17811                fileUrl = null,
17812                didSubmit = false,
17813                contextRoot = this._getContextRoot(),
17814                options = argObject.options,
17815                fileAttachmentsList = argObject.fileAttachmentsList,
17816                fileUploadPath = argObject.fileUploadPath,
17817                callback = argObject.callback,
17818                errorCallback = argObject.errorCallback,
17819                fileNameDomMap;
17820
17821            // In the case of draft, url comes with context root. Need to remove it so that correct
17822            // value gets stored in model
17823            if (contextRoot) {
17824                if (fileUploadPath.indexOf(contextRoot) === 0) {
17825                    fileUploadPath = fileUploadPath.substring(contextRoot.length);
17826                }
17827            }
17828            // File attachment list is an array containing the list of file attachments
17829            // We need to fetch the fileNameDomMap even when there's no fileAttachmentsList as there can be
17830            // lazy loaded file attachment models as well.
17831            fileNameDomMap = this._juiceOutNameAndFileDomMap(fileAttachmentsList);
17832            fileDoms = fileNameDomMap.fileDom;
17833            fileNames = fileNameDomMap.fileName;
17834            if (fileDoms.length > 0) {
17835                // since there can be a dom element which is null, in case of draft reload, get the first
17836                // non null file dom
17837                var firstNonNullFileDom = _.indexOf(fileDoms, _.find(fileDoms, function (item) {
17838                    return item !== null && !_.isString(item);
17839                }));
17840                // fileUploadPath doesn't contain the context path and hence we need to to pass the baseURL
17841                // FileUploader takes a _getUrl option which is baseUrl/contextPath
17842                if (firstNonNullFileDom !== -1 && fileUploadPath) {
17843                    var uploaderPluginName = guideBridge.userConfig.uploaderPluginName || "adobeFileUploader";
17844                    fileUrl = fileDoms[firstNonNullFileDom][uploaderPluginName]("uploadFile", {
17845                        'fileName' : fileNames,
17846                        'fileDom' : fileDoms,
17847                        'fileUploadPath' : fileUploadPath,
17848                        'multiple' : true,
17849                        _getUrl : guideBridge._getUrl("")
17850                    });
17851
17852                    // The file url returned by file upload widget can contain context root.
17853                    // Remove it so that correct value gets stored in model.
17854                    if (contextRoot) {
17855                        if (fileUrl.indexOf(contextRoot) === 0) {
17856                            fileUrl = fileUrl.substring(contextRoot.length);
17857                        }
17858                    }
17859
17860                    fileDoms[firstNonNullFileDom].one("adobeFileUploader.multipleFileUploaded",
17861                        $.proxy(callback, {
17862                            "attachments" : fileNames,
17863                            "fileUrl" : fileUrl,
17864                            "fileAttachmentsList" : fileAttachmentsList,
17865                            "options" : options
17866                        })
17867                    );
17868                    if (errorCallback) {
17869                        fileDoms[firstNonNullFileDom].one("adobeFileUploader.fileUploadFailed",
17870                                            $.proxy(errorCallback, {
17871                                                "attachments" : fileNames,
17872                                                "fileUrl" : fileUrl,
17873                                                "fileAttachmentsList" : fileAttachmentsList,
17874                                                "options" : options
17875                                            })
17876                                        );
17877                    }
17878                    didSubmit = true;
17879                }
17880                // if fileUrl is not yet set, default it to fileUploadPath
17881                if (fileUrl === null && fileUploadPath) {
17882                    fileUrl = fileUploadPath;
17883                }
17884            }
17885            if (!didSubmit) {
17886                // if there are no files attached, still call the callback to submit the json contents
17887                // if there is only one file attachment component with no files, in this case else is 
17887important
17888                callback.apply({
17889                    "attachments" : fileNames,
17890                    "fileUrl" : fileUrl,
17891                    "fileAttachmentsList" : fileAttachmentsList,
17892                    "options" : options
17893                });
17894            }
17895        },
17896        /**
17897         * Iterates over all the components in the Adaptive Form and invokes its {@link GuideNode#visit|visit} method
17898         * passing the _callback_ to the API.
17899         *
17900         * @summary Traverse all the components in the Adaptive Form and invoke callback function for each of the
17901         * component
17902         * @param {function} callback Function to be called for every Adaptive Form Component present
17903         * in the Form. The signature of the callback matches the signature of
17904         * {@link GuideNode~VisitorCallback|VisitorCallback}
17905         * @param {object} [context=window] _this_ object in the callback will point to this object
17906         *
17907         * @example <caption>Creating a list of all components having name <i>testName</i></caption>
17908         * var myList = []
17909         * guideBridge.visit(function(cmp) {
17910         *     if(cmp.name === "testName") {
17911         *          myList.push[cmp];
17912         *     }
17913         * }};
17914         * @method
17915         * @memberof GuideBridge
17916         * @since 6.0
17917         * @instance
17918         */
17919        visit : function (callback, context) {
17920            this._guide.visit(callback, context || window);
17921        },
17922
17923        /**
17924         *
17925         * Hides the elements of the specified class name.
17926         * In case of guideButton, it checks for type too, if no type is specified in "guideButton", then that button
17927         * cannot be made hidden
17928         *
17929         * @param className String representing the classname of the node
17930         * @param type [optional] type will be used only if the classname is "guideButton"
17931         * @private
17932         */
17933        _hideElements : function (className, type) {
17934            var resultObject = new GuideResultObject();
17935            // If guide dom not initialized, return
17936            if (!this._checkGuide(resultObject)) {
17937                return resultObject;
17938            }
17939            resultObject.completed = true;
17940            this.visit(function (node) {
17941                // if the class name is guide button only the use the type
17942                if (node.className === "guideButton") {
17943                    if (node.type === type) {
17944                        node.visible = false;
17945                    }
17946                } else {
17947                    // else just compare the classname and hide it
17948                    if (node.className === className) {
17949                        node.visible = false;
17950                    }
17951                }
17952            });
17953            return resultObject;
17954        },
17955
17956        /**
17957         * In Adaptive Form there is a summary component to show the summary of submission. This API hides the parent
17958         * panel of the summary component. If the component is not present inside the Form, this operation doesn't do
17959         * anything
17960         * @summary Hides the panel that contains the summary component.
17961         *
17962         * @returns {GuideResultObject} the data property of GuideResultObject would be undefined. The API will fail if
17963         * the Form is not initialized which would be indicated by the {@link GuideResultObject#errors} property.
17964         * @memberof GuideBridge
17965         * @instance
17966         * @since 6.0
17967         */
17968        hideSummaryPanel : function () {
17969            var resultObject = new GuideResultObject();
17970            // If guide dom not initialized, return
17971            if (!this._checkGuide(resultObject)) {
17972                return resultObject;
17973            }
17974            resultObject.completed = true;
17975            this.visit(function (node) {
17976                if (node.className === "guideNode" && node.jsonModel['sling:resourceType'] === "fd/afaddon/components/summary") {
17977                    node.panel.visible = false;
17978                }
17979            });
17980            return resultObject;
17981        },
17982
17983        _getFileAttachmentsList : function () {
17984            var fileAttachmentsList = [];
17985            this.visit(function (node) {
17986                if (node.className === "guideFileUpload") {
17987                    fileAttachmentsList.push(node);
17988                }
17989            });
17990            return fileAttachmentsList;
17991        },
17992
17993        /**
17994         * @summary the captchaData which will be submitted to server for validation purposes.
17995         * @param captchaModel
17996         * @returns {object}
17996 object contains the captchaData which includes captcha service provider name, its SOM exp and
17997         * data coming from OOTB/third-party captcha widget.
17998         * @method
17999         * @memberof GuideBridge
18000         * @instance
18001         * @since 6.3
18002         */
18003        _getCaptchaData : function (captchaModel) {
18004            if (captchaModel) {
18005                return {
18006                    serviceType : captchaModel.captchaService,
18007                    somExpression : captchaModel.somExpression,
18008                    validationMessage : captchaModel.validateExpMessage,
18009                    mandatoryMessage : captchaModel.mandatoryMessage,
18010                    data : captchaModel.value
18011                };
18012            }
18013            return {};
18014        },
18015
18016        /**
18017         * This function returns the additional action Field information that is required during submit.
18018         *
18019         * @returns {object} object having the action Field information.
18020         * @memberof GuideBridge
18021         */
18022        _getAdditionalSubmitInfo : function () {
18023            var additionalSubmitInfo = {},
18024                actionFieldDiv = $("#actionField");
18025            var thankYouPage = this._getThankYouPageFromConfig();
18026            if (typeof thankYouPage === "string") {
18027                document.getElementById(":redirect").value = thankYouPage;
18028            }
18029            var actionFields = actionFieldDiv.find('input')
18030                .each(function () {
18031                    additionalSubmitInfo[$(this).attr("name")] = $(this).val();
18032                    if ($(this).attr("name") == "_guideValueMap" && $(this).val() == "yes") {
18033                        var guideKeyValue = {};
18034                        window.guideBridge._guide._collectValues(guideKeyValue);
18035                        additionalSubmitInfo['_guideValuesMap'] = JSON.stringify(guideKeyValue);
18036                    }
18037                });
18038            return additionalSubmitInfo;
18039        },
18040
18041        /**
18042         * Gets the guideDom based on whether reducedJSON option is true or not.
18043         * If reducedJSON is true, only the white-listed properties are included.
18044         *
18045         * @returns {object} guideDom
18046         * @memberof GuideBridge
18047         */
18048
18049        _getGuideDom : function (options) {
18050            var guideDom;
18051            if (options.reducedJSON) {
18052                guideDom = guideBridge._guide._getReducedJSON();
18053            } else {
18054                guideDom = guideBridge._guide.jsonModel;
18055            }
18056            return guideDom;
18057        },
18058
18059        /**
18060         * Creates the guideState and the liveXml.
18061         *
18062         * @param options {object} options should contain a GuideResultObject [{obj:"<GuideResultObject type>"}]
18063         * @memberof GuideBridge
18064         * Steps performed by the function -
18065         * 1) creates the xfaState
18066         * 2) creates the guideState that consists of guideDom, guideContext and additionalSubmitInfo
18067         * 3) creates guideLiveData
18068         * 4) adds xfaState and guideLiveData to the guideState
18069         *
18070         * @private
18071         */
18072        _createGuideStateAndLiveXml : function (options) {
18073            var obj = new GuideResultObject();
18074            // add the guideResultObject to options so that it can be passed to the success handler
18075            options.obj = obj;
18076
18077            if (!this._checkGuide(obj)) {
18078                return;
18079            }
18080
18081            var saveXfaXml = function (xfaResultObj) {
18082                if (!xfaResultObj.errors && xfaResultObj.completed) {
18083                    xfaState.currentContext = {'data' : xfaResultObj.data};
18084                }
18085            };
18086
18087            obj.data = {};
18088            var xfaState = null;
18089            if (this._isXfaGuide() && this._isValidXFAGuide()) {
18090                var xfaResultObject = null;
18091                if (options.reducedJSON) {
18092                    //If reduceJson is asked, then xfaState should also be reduced by passing the diff and bSubmit flag to true
18093                    xfaResultObject = window.formBridge.getFormState(true, true);
18094                } else {
18095                    xfaResultObject = window.formBridge.getFormState();
18096                }
18097                if (xfaResultObject.errors) {
18098                    guideBridge._guide.logger().log("Error in getting Xfa State:" + JSON.stringify(xfaResultObject.getNextMessage()));
18099                    alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-001"]));
18100                }
18101                xfaState = xfaResultObject.data;
18102            }
18103
18104            var guideDom = guideBridge._getGuideDom(options);
18105
18106            //adding additionalSubmitInfo in the guideState.
18107            //additionalSubmitInfo contains the information about action fields.
18108            var additionalSubmitInfo = guideBridge._getAdditionalSubmitInfo();
18109            //set the updated file attachment map in the customPropertyMap
18110            guideBridge.customContextProperty("fileAttachmentMap", JSON.stringify(this.getFileAttachmentMap()));
18111            var guideState = {
18112                guideDom : guideDom,
18113                //save renderContext in guide state to enable deferred submit even if guide is not open
18114                guideContext : guideBridge._guide.runtime.guideContext,
18115                additionalSubmitInfo : additionalSubmitInfo
18116            };
18117
18118            if (guideBridge._guide.allLazyChildren.length > 0) {
18119                guideBridge._guide.internal.liveDataUtils.updateLiveData();
18120                var listOfDirtyPanels = guideBridge._guide.internal.GuideDirtyMarkerAndVisitor.flatten
18120DirtyPanelMapToCSV();
18121                if (listOfDirtyPanels.length > 0) {
18122                    this.afSubmissionInfo("afDraft", listOfDirtyPanels);
18123                }
18124                // save live xml & xfa state as xml for restoration of lazy model on 'restore'
18125                guideState.guideLiveData = guideBridge._guide.internal.liveDataUtils.getLiveDataStr();
18126                if (this._isXfaGuide() && this._isValidXFAGuide()) {
18127                    formBridge.getDataXML({"success" : saveXfaXml}); // currently xfa restore relies on formBridge.getDataXML being sync
18128                }
18129            }
18130            obj.data.guideState = guideState;
18131            if (xfaState) {
18132                obj.data.guideState.xfaState = xfaState;
18133            }
18134
18135        },
18136
18137        _updateAFSubmissionInfo : function (guide) {
18138            if (guideBridge.isGuideLoaded(true) && !guide) {
18139                var previousFocusSom = this._guideView._previousFocusItemSom;
18140                var previousItemModel = guideBridge.resolveNode(this._guideView._previousFocusItemSom);
18141                if (getOrElse(previousItemModel, "parent.className", undefined) === "guideToolbar") {
18142                    previousFocusSom = previousItemModel.parent.parent.somExpression;
18143                }
18144                this.afSubmissionInfo("lastFocusItem", this._guideView.getSomOnNavigableAncestor(previousFocusSom));
18145            }
18146            var newGuide = guide ? guide : guideBridge._guide;
18147            this.afSubmissionInfo("excludeFromDoR", newGuide._getExcludeFromDorMap());
18148            // send state override on in cases when we have dor
18149            var stateOverrides = {};
18150            if (newGuide.dorType && "none" !== newGuide.dorType) {
18151                stateOverrides = newGuide._getStateOverrideMap();
18152            }
18153            this.afSubmissionInfo("stateOverrides", stateOverrides);
18154            // Add signers to af submission info
18155            this.afSubmissionInfo("signers", newGuide._getSigners());
18156
18157        },
18158
18159        /**
18160         * Adaptive Form stores its state in the form of JSON. The Files attached in the component are uploaded
18161         * onto the server and their paths are returned in the JSON state except in certain conditions mentioned below.
18162         * The API is an asynchronous call which calls the success and error handlers with the data.
18163         *
18164         * In the below mentioned scenarios the file will not be uploaded
18165         * * User doesn't have **write permissions** on the _fileUploadPath_ provided
18166         * * The _fileUploadPath_ property doesn't point to a node of type _**sling:Folder**_
18167         *
18168         * @summary Retrieve the current state of Adaptive Form as json string
18169         * @param {object} options Input object containing the callbacks that will be invoked
18170         * to provide the result of the API
18171         * @param {function} [options.success] callback which receives the result of the API
18172         * in case of success.
18173         * {@link GuideResultObject#errors|errors} property as false.
18174         * @param {function} [options.error] callback which receives the result of the API in
18175         * case of failure.
18176         * {@link GuideResultObject#errors|errors} property as true.
18177         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18178         * object
18179         * @param {string} [options.fileUploadPath] controls whether the files in the File Attachment component have to be
18180         * uploaded or not. If _fileUploadPath_ is non null, only then file gets uploaded and the model's value is
18181         * updated with the file url
18182         *
18183         * @method
18184         * @memberof GuideBridge
18185         * @since 6.0
18186         * @instance
18187         */
18188        getGuideState : function (options) {
18189
18190            // walk through the model to get the list of file attachment components
18191            var fileAttachmentsList = this._getFileAttachmentsList();
18192            guideBridge._updateAFSubmissionInfo();
18193
18194            if (guideBridge.isGuideLoaded(true)) {
18195                this.customContextProperty("lastFocusItem", this._guideView.getSomOnNavigableAncestor(this._guideView._previousFocusItemSom));
18196            }
18197
18198            // Walk through the list of file Attachment components
18199            // and update the value of every item
18200            // Get the list of file Attachments
18201            if (options.fileUploadPath) {
18202                var optionArgument = {"options" : options,
18203                                       "fileAttachmentsList" : fileAttachmentsList,
18204                                       "fileUploadPath" : options.fileUploadPath,
18205                                        "callback" : window.guideBridge._collectFileUrls,
18206                                        "errorCallback" : window.guideBridge._fileUploadFailed};
18207
18208                this._getGuideAttachments(optionArgument);
18209            } else {
18210                this._createGuideStateAndLiveXml(options);
18211                if (options.success) {
18212                    options.success.call(options.context, options.obj);
18213                }
18214            }
18215
18216        },
18217
18218        /**
18219         * Validates the Adaptive Form or it's specific panel and return the validation status. The API also moves
18220         * focus to first invalid element
18221         * @summary validate the entire Form or a component in Adaptive Form
18222         * @param  {Field~ValidationError[]} errorList Input must be an empty array. The array will be filled with list
18223         * of Adaptive Form Components that failed validation.
18224         * @param  {string}
18224 [somExpression] SOM Expression of the Guide Node for which validation should be triggered.
18225         * If not provided, it would validate the entire Adaptive Form
18226         * @param {boolean} [setFocus=true] If true, set focus to the first invalid element.
18227         * @returns {boolean} true if the component/form was valid, false otherwise
18228         * @method
18229         * @memberof GuideBridge
18230         * @since 6.0
18231         * @instance
18232         * @see Field#validate
18233         * @see Panel#validate
18234         */
18235        validate : function (errorList, somExpression, setFocus, guide) {
18236            // guide parameter is not to be documented and it is meant for internal use only
18237            var guideNode = null,
18238                isFocusEnabled = _.isUndefined(setFocus) ? true : setFocus,
18239                ec = guidelib.util.ErrorConstants,
18240                validationContext,
18241                afContainer = guide ? guide : this._guide; // done, to keep this thread safe
18242            //  get Json of all the dirty , non visited (templateJson missing from cache)
18243            if (afContainer.allLazyChildren.length > 0) {
18244                afContainer.guideLazyUtil.putDirtyToTemplateCacheIfMissing(afContainer);
18245            }
18246            if (somExpression) {
18247                guideNode = this.resolveNode(somExpression);
18248                // how to know if the panel is navigable from the model. We do not bring the nonNavigable property ?
18249                if (guideNode instanceof guidelib.model.GuidePanel) {
18250                    validationContext = ec.CONTEXT_NAVIGATION;
18251                }
18252            } else {
18253                guideNode = afContainer;
18254                validationContext = ec.CONTEXT_SUBMISSION;
18255            }
18256            this.setValidationContext(validationContext);
18257            var status = false;
18258            if (!errorList) {
18259                errorList = [];
18260            }
18261            status = guideNode.validate(errorList);
18262
18263            try {
18264                // there can be errors in the user script, hence handling the exception gracefully, and resetting the global error state properly
18265                this._guide._triggerOnBridge("validationComplete", this._guide, status, "", errorList);
18266                if (!status && isFocusEnabled) {
18267                    var errorSom = errorList[0]["som"];
18268
18269                    guideBridge._guide.on(guidelib.event.GuideModelEvent.LAZY_LOADED, function () {
18270                        var errorField = guideBridge.resolveNode(errorSom);
18271                        if (errorField) {
18272                            errorField.validate();
18273                        }
18274                    }, {});
18275
18276                    this.setFocus(errorSom);
18277
18278                    guideBridge._guide.off(guidelib.event.GuideModelEvent.LAZY_LOADED);
18279                }
18280
18281            } catch (exception) {
18282                this._guide.logger().log(exception);
18283            } finally {
18284                // since the errors have been published reset the state back to normal
18285                //guidelib.runtime.errorManager.setGlobalError(false);
18286                this.unsetValidationContext(validationContext);
18287                return status;
18288            }
18289
18290        },
18291
18292        // todo: submit behaviour should make sure that if the value of file upload
18293        /**
18294         * Adaptive Form can be restore in three ways
18295         * * by passing the JSON data obtained from {@link GuideBridge#getGuideState}. This can be done by setting
18296         * _**data**_ property .
18297         * * by passing a URL pointing to a resource that returns JSON/XML data that should be used. This can be done by setting
18298         * _**dataRef**_ property. The data can be obtained by calling the
18299         * {@link GuideBridge#getData|getData} API.
18300         * * by passing a URL pointing to a resource that returns JSON data obtained from {@link GuideBridge#getGuideState}.
18301         * This can be done by setting _**guideStatePathRef**_ property .
18302         *
18303         * When restoring from dataRef, only values and other properties, that are dependant on value, are restored. For
18304         * example, If a Field was hidden based on the click of a Button then
18305         * when restoring from data XML/JSON the Field will not remain hidden.
18306         *
18307         * **NOTE:** The _data_, _dataRef_ and _guideStatePathRef_ must not be null simultaneously and only one property
18308         * must be specified. Specifying more than one can lead to undesired results.
18309         * @summary restore/prepopulate the state of Adaptive Form from an earlier saved state
18310         * @param {object}
18310 options object containing the callbacks to be invoked on
18311         * success/failure and data from where to restore the object.
18312         * @param {function} [options.success] callback which receives the result of the API
18313         * in case of success
18314         * {@link GuideResultObject#errors|errors} property as false.
18315         * @param {function} [options.error] callback which receives the result of the API in
18316         * case of failure.
18317         * {@link GuideResultObject#errors|errors} property as true.
18318         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18319         * object.
18320         * @param {object} [options.data] It must be the value of the {@link GuideResultObject#data|data} property passed to
18321         * the _success_ handler of {@link GuideBridge#getGuideState|getGuideState} API.
18322         * @param {string} [options.dataRef] URL pointing to the data XML/JSON.
18323         * @param {string} [options.guideStatePathRef] URL pointing to the JSON state of Adaptive Form.
18324         *
18325         * @method
18326         * @memberof GuideBridge
18327         * @since 6.0
18328         * @instance
18329         * @example <caption>Restoring from JSON data</caption>
18330         * var jsonData;
18331         * guideBridge.getGuideState({
18332         *      success : function (guideResultObj) {
18333         *          jsonData = guideResultObj.data;
18334         *      },
18335         *      error : function (guideResultObj) {
18336         *          // log error
18337         *      }
18338         * });
18339         *
18340         * // after some time or on click of a button or reloading the page
18341         * guideBridge.restoreGuideState({
18342         *      guideState : jsonData.guideState,
18343         *      error : function (guideResultObject) {
18344         *          // log the errors
18345         *      }
18346         * })
18347         *
18348         * @example <caption>Restoring from data XML/JSON</caption>
18349         * guideBridge.getData({
18350         *      success : function (guideResultObj) {
18351         *          var data = guideResultObj.data;
18352         *          //post the data to a server that saves it at say http://abc.com/my/data.xml
18353         *          //or http://abc.com/my/data.json
18354         *      },
18355         *      error : function (guideResultObj) {
18356         *          // log the errors
18357         *      }
18358         * });
18359         *
18360         * // after some time or on click of a button or reloading the page
18361         * guideBridge.restoreGuideState({
18362         *      dataRef : "http://abc.com/my/data.xml",
18363         *      error : function (guideResultObject) {
18364         *          // log the errors
18365         *      }
18366         * })
18367         *
18368         * @example <caption>Restoring from URL to a JSON</caption>
18369         * guideBridge.getGuideState({
18370         *      success : function (guideResultObj) {
18371         *          var json = guideResultObj.data;
18372         *          //post the JSON to a server that saves it at say http://abc.com/my/data.json
18373         *      },
18374         *      error : function (guideResultObj) {
18375         *          // log the errors
18376         *      }
18377         * });
18378         *
18379         * // after some time or on click of a button or reloading the page
18380         * guideBridge.restoreGuideState({
18381         *      guideStatePathRef : "http://abc.com/my/data.json",
18382         *      error : function (guideResultObject) {
18383         *          // log the errors
18384         *      }
18385         * })
18386         **/
18387        restoreGuideState : function (options) {
18388            var parameters,
18389                path;
18390            if (options && options.dataRef) {
18391                parameters = {"dataRef" : options.dataRef};
18392            } else if (options && options.guideStatePathRef) {
18393                parameters = {"guideStatePathRef" : options.guideStatePathRef};
18394            }
18395            // if parameters have DataRef or guideStatePathRef, a recursive call is made to restoreGuideState.
18396            if (parameters) {
18397                path = window.guideBridge.getGuidePath();
18398                path = path + ".guidejson";
18399                $.ajax({
18400                    url : path,
18401                    type : "GET",
18402                    async : false,
18403                    cache : false,
18404                    data : parameters,
18405                    success : function (response) {
18406                        //case where section information exist in guideState
18407                        if (response.guideState && response.guideState.guideContext
18408                            && response.guideState.guideContext.customPropertyMap
18409                            && response.guideState.guideContext.customPropertyMap.sections
18410                            && response.guideState.guideContext.customPropertyMap.sections.length > 0) {
18411                            // todo: add safe check for string vs array
18412                            window.guideBridge.customContextProperty.sections = response.guideState.guideContext.customPropertyMap.sections;
18413                        }
18414                        //passing the options again, but with DataRef or guideStatePathRef removed from it.
18415                        window.guideBridge.restoreGuideState(_.extend(
18416                            {},
18417                            options,
18418                            {
18419                                guideState : response.guideState,
18420                                dataRef : undefined,
18421                                guideStatePathRef : undefined
18422                            }
18423                        ));
18424                    },
18425                    error : function (response) {
18426                        window.guideBridge._guide.logger().log("Error: " + response);
18427                    }
18428                });
18429                return;
18430            }
18431
18432            /*
18433             * We have to merge the runtime guideContext with the guideContext passed in the guideState
18434             * so that no custom properties that were set in the guideState.guideContext are ignored.
18435             */
18436            guidelib.__runtime__.guideContext = guidelib.__runtime__.guideContext || {};
18437            if (guideBridge.isGuideLoaded()) {
18438                guideBridge._guide.runtime.guideContext = guideBridge._guide.runtime.guideContext || {};
18439            }
18440            var gc = getOrElse(options, "guideState.guideContext", undefined);
18441            if (!_.isUndefined(options.guideState.guideContext)) {
18442                /* Runtime custom property map is set by external application and hence, shallow copy will set the value
18443                 * as set externally. If no value was set, the guideState custom property map keys stay.
18444                 */
18445                _.extend(gc.customPropertyMap, guidelib.__runtime__.guideContext.customPropertyMap);
18446                if (guideBridge.isGuideLoaded()) {
18447                    _.extend(gc.customPropertyMap, guideBridge._guide.runtime.guideContext.customPropertyMap);
18448                }
18449            }
18450            // not setting at guidelib runtime, but honoring if anyone has set customPropertyMap
18451            // through guidelib.runtime.guideContext directly
18452            if (guideBridge.isGuideLoaded()) {
18453                _.extend(guideBridge._guide.runtime.guideContext, gc);
18454            }
18455
18456            if (!this._guide) {
18457                this.storage = {};
18458                this.storage.guideState = options.guideState;
18459                //NOCHECKMARX - This is error callback to be provided by the user of this API.
18460                this.storage.error = options.error;
18461                this.storage.success = options.success;
18462                this.storage.context = options.context;
18463            } else {
18464                this._playGuideJson(options);
18465                // Trigger the event
18466                // If guide has restore state, call sync guide node to html
18467                // Case 1: If this is called before view gets initialized, there would be no listener present, hence nothing would happen
18468                // Case 2: If it is called after view gets initialized(using restore guide state in mobile workspace), then the model would sync to view
18469                // using this event
18470                // If view is initialized, which means a listener would to MODEL_REFRESH would be set, hence just trigger the event for execution
18471                if (this._guideView) {
18472                    this._guide._triggerEvent(guidelib.event.GuideModelEvent.MODEL_REFRESH, "jsonModel", null, null);
18473                }
18474            }
18475
18476        },
18477
18478        /**
18479         * Adaptive Form can set data in three ways:
18480         * * by passing the JSON data obtained from {@link GuideBridge#getGuideState}. This can be done by setting
18481         * _**data**_ property .
18482         * * by passing a URL pointing to a resource that returns data JSON/XML that should be used. This can be done by setting
18483         * _**dataRef**_ property. The data can be obtained by calling the
18484         * {@link GuideBridge#getData|getData} API.
18485         * * by passing a URL pointing to a resource that returns JSON data obtained from {@link GuideBridge#getGuideState}.
18486         * This can be done by setting _**guideStatePathRef**_ property .
18487         *
18488         * When setting data from dataRef, only values and other properties, that are dependant on value, are set. For
18489         * example, If a Field was hidden based on the click of a Button in the data passed then
18490         * when setting data from XML/JSON the Field will not remain hidden.
18491         *
18492         * **NOTE:** The _data_, _dataRef_ and _guideStatePathRef_ must not be null simultaneously and only one property
18493         * must be specified. Specifying more than one can lead to undesired results.
18494         * @summary Populate the Adaptive Form from the data.
18495         * @param {object}
18495 options object containing the callbacks to be invoked on
18496         * success/failure and data from where to restore the object.
18497         * @param {function} [options.success] callback which receives the result of the API
18498         * in case of success
18499         * {@link GuideResultObject#errors|errors} property as false.
18500         * @param {function} [options.error] callback which receives the result of the API in
18501         * case of failure.
18502         * {@link GuideResultObject#errors|errors} property as true.
18503         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
18504         * object.
18505         * @param {object} [options.data] It must be the value of the {@link GuideResultObject#data|data} property passed to
18506         * the _success_ handler of {@link GuideBridge#getGuideState|getGuideState} API.
18507         * @param {string} [options.dataRef] URL pointing to the data JSON/XML.
18508         * @param {string} [options.guideStatePathRef] URL pointing to the JSON state of Adaptive Form.
18509         *
18510         * @method
18511         * @memberof GuideBridge
18512         * @since 6.3
18513         * @instance
18514         * @example <caption>Setting data from JSON data</caption>
18515         * var jsonData;
18516         * guideBridge.getGuideState({
18517         *      success : function (guideResultObj) {
18518         *          jsonData = guideResultObj.data;
18519         *      },
18520         *      error : function (guideResultObj) {
18521         *       // log the errors
18522         *      }
18523         * });
18524         *
18525         * guideBridge.setData({
18526         *      guideState : jsonData,
18527         *      error : function (guideResultObject) {
18528         *          // log the errors
18529         *      }
18530         * })
18531         *
18532         * @example <caption>Setting data from XML/JSON</caption>
18533         * guideBridge.getData({
18534         *      success : function (guideResultObj) {
18535         *          var data = guideResultObj.data;
18536         *          //post the XML/JSON to a server that saves it at say http://abc.com/my/data.xml
18537         *          //or http://abc.com/my/data.json
18538         *      },
18539         *      error : function (guideResultObj) {
18540         *          // log the errors
18541         *      }
18542         * });
18543         *
18544         * guideBridge.setData({
18545         *      dataRef : "http://abc.com/my/data.xml",
18546         *      error : function (guideResultObject) {
18547         *          // log the errors
18548         *      }
18549         * })
18550         *
18551         * @example <caption>Setting data from URL to a JSON</caption>
18552         * guideBridge.getGuideState({
18553         *      success : function (guideResultObj) {
18554         *          var json = guideResultObj.data;
18555         *          //post the JSON to a server that saves it at say http://abc.com/my/data.json
18556         *      },
18557         *      error : function (guideResultObj) {
18558         *          // log the errors
18559         *      }
18560         * });
18561         *
18562         * guideBridge.setData({
18563         *      guideStatePathRef : "http://abc.com/my/data.json",
18564         *      error : function (guideResultObject) {
18565         *          // log the errors
18566         *      }
18567         * })
18568         **/
18569        setData : function (options) {
18570            guideBridge.restoreGuideState(options);
18571        },
18572
18573        /*
18574         * @private
18575         */
18576        _getStorage : function () {
18577            var storage = null;
18578            if (this.storage) {
18579                // Get the storage
18580                storage = this.storage;
18581                this.storage = null;
18582            }
18583            return storage;
18584        },
18585
18586        getGuideContext : function () {
18587            var obj = new GuideResultObject();
18588            obj.data = jQuery.extend(true, {}, (this._guide ? this._guide.runtime.guideContext : null));
18589            return obj;
18590        },
18591
18592        _getContextRoot : function () {
18593            return this.userConfig["contextPath"];
18594        },
18595
18596        _getEnableFocusOnFirstField : function () {
18597            var renderConfig = this.userConfig.renderConfig || {},
18598                enableFocusOnFirstField = renderConfig.enableFocusOnFirstField === undefined ? true : renderConfig.enableFocusOnFirstField,
18599                // convert "true"/"false" strings to boolean too
18600                enableFocusOnFirstFieldAsBoolean = enableFocusOnFirstField === 'true' || (enableFocusOnFirstField === 'false' ? false : enableFocusOnFirstField);
18601            // default value is true
18602            return enableFocusOnFirstFieldAsBoolean;
18603        },
18604
18605        _updateAjaxUrl : function (baseUrl) {
18606            if (this.hostName === "server") {
18607                $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
18608                    // 'Rebase' the URL if required.
18609                    var thisUrl = options.url;
18610                    if ((thisUrl.lastIndexOf('http://', 0) !== 0) && (thisUrl.lastIndexOf('https://', 0) !== 0)) {
18611                        // thisUrl is relative.
18612                        // thisUrl may or may not begin with slash
18613                        // encoding taken care by the ajax call
18614                        if (thisUrl.indexOf("/") === 0) {
18615                            // if begins with slash
18616                            thisUrl = baseUrl + thisUrl;
18617                        } else {
18618                            thisUrl = baseUrl + "/" + thisUrl;
18619                        }
18620                        options.url = thisUrl;
18621                    }
18622                });
18623
18624                // Native XHR Wrapper
18625                var originalOpen = XMLHttpRequest.prototype.open;
18626                XMLHttpRequest.prototype.open = function(method, url) {
18627                    if ((url.lastIndexOf('http://', 0) !== 0) && (url.lastIndexOf('https://', 0) !== 0)) {
18628                        // url is relative
18629                        if (url.indexOf("/") === 0) {
18630                            url = baseUrl + url;
18631                        } else {
18632                            url = baseUrl + "/" + url;
18633                        }
18634                    }
18635                    originalOpen.apply(this, arguments);
18636                };
18637            }
18638        },
18639
18640        _getUrl : function (url) {
18641            var baseUrl = this.userConfig["baseUrl"],
18642                contextPath = this.userConfig["contextPath"];
18643            if (baseUrl) {
18644                return baseUrl + url;
18645            } else if (contextPath && contextPath !== "/" && url.indexOf(contextPath) !== 0 && (url.length === 0 || url.indexOf("/") === 0)) {
18646                //if url does not have contextPath and starts with /, pre-pend contextPath
18647                // Also url.length check because I need to pass "" to getUrl and get context path
18648                return contextPath + url;
18649            }
18650            return url;
18651        },
18652
18653        _getGuidePathUrl : function (urlSuffix, guidePath) {
18654            // guidePath here refers to the path got from json state of guide
18655            // we use this path, if there is no guidePath set in guidelib.runtime.guideContext, cases where guide is not initialized but
18656            // guideBridge is present
18657            var path = guidePath || this.getGuidePath(),
18658                url = path + (urlSuffix || "");
18659            return this._getUrl(url);
18660        },
18661
18662        /**
18663         * @summary Returns the path which refers to the location of
18664         * the content resource of adaptive form container
18665         * @returns {String} Path to the content resource of the adaptive form container
18666         * @method
18667         * @memberof GuideBridge
18668         * @since 6.5
18669         * @instance
18670         */
18671        getGuidePath : function () {
18672            var guideContext = this.getGuideContext().data;
18673            if (guideContext && guideContext.hasOwnProperty("guidePath")) {
18674                return guideContext["guidePath"];
18675            }
18676            return null;
18677        },
18678
18679        /**
18680         * @summary Given a somExpression, return the {@link GuideNode} having the same somExpression.
18681         * @param {string} somExpression somExpression of the Adaptive Form component
18682         * @returns {GuideNode} GuideNode matching the som expression or null if not found
18683         * @method
18684         * @memberof GuideBridge
18685         * @since 6.0
18686         * @instance
18687         * @see GuideNode#somExpression
18688         */
18689        resolveNode : function (somExpression) {
18690            return this._guide.resolveNode(somExpression);
18691        },
18692        /*
18693         * Internal API. Should be used carefully.
18694         */
18695        _resolveId : function (id) {
18696            var node = this._guide._modelTemplateCacheStore.getModel(id);
18697            return node;
18698        },
18699
18700        /**
18701         * Helper method for accesibility announcements
18702         * Is part of the fix for FORMS-7071 (CQ-4276669)
18703         */
18704        _ariaLiveAnnouncement : function (text) {
18705            var ariaLiveElement = $("#ariaLiveElement");
18706            setTimeout(function() {
18707                $(ariaLiveElement).text(text);
18708                return (setTimeout(function() {
18709                    $(ariaLiveElement).text("");
18710                }, 2000))
18711            }, 500);
18712        },
18713
18714        /**
18715         * Invokes {@link Field#resetData}
18715 API for all the Fields inside the Form to reset their values to default
18716         * @summary Reset the values of all the Fields to their default values.
18717         *
18718         * @method
18719         * @memberof GuideBridge
18720         * @instance
18721         * @since 6.0
18722         */
18723        reset : function () {
18724            if (window.xfalib && window.xfalib.runtime && window.xfalib.runtime.xfa) {
18725                var xfa = window.xfalib.runtime.xfa;
18726                xfa.host.resetData();
18727            }
18728            this._guide.resetData();
18729
18730            if (this._guide.internal.liveDataUtils.isLiveDataInitialized()) {
18731                this._guide.internal.liveDataUtils.updateLiveData();
18732            }
18733
18734            var guideDirtyMarkerAndVisitor = this._guide.internal.GuideDirtyMarkerAndVisitor;
18735            guideDirtyMarkerAndVisitor.visitMap = guidelib.model.util.CommonUtils.createMap(this._guide.allLazyChildren, 0);
18736
18737            this._ariaLiveAnnouncement(guidelib.i18n.strings["formHasBeenReset"]);
18738        },
18739
18740        _getPreviousFocus : function () {
18741            return this._guideView._previousFocusItemSom;
18742        },
18743
18744        /**
18745         * Returns the somExpression of the current {@link Panel} or current {@link Field} in Focus. The API can also
18746         * be used to get the somExpression of the Navigable Panel that contains the current Element in Focus.
18747         *
18748         * @summary return the somExpression of the {@link Panel} or {@link Field} that is currently in focus
18749         * @param {object} options configuration to be passed to the API to get the desired result
18750         * @param {?string} [options.focusOption] Currently the following value of this option are supported
18751         * * `navigablePanel`: if one wants to get the somExpression of the Navigable Panel
18752         * @returns {string} somExpression of Adaptive Form component representing the field or panel.
18753         * @method
18754         * @memberof GuideBridge
18755         * @instance
18756         * @since 6.0
18757         * @see {GuideNode#somExpression}
18758         * @example
18759         * guideBridge.getFocus({"focusOption": "navigablePanel"})
18760         */
18761        getFocus : function (options) {
18762            var focusOption;
18763            if (_.isUndefined(options)) {
18764                return this._guideView.currentFocusItemSom;
18765            }
18766            if ((focusOption = getOrElse(options, "focusOption", null)) === "navigablePanel") {
18767                return this._guideView._lastFocussedPanelForNonActionFields;
18768            }
18769            this._guide.logger().log("Invalid Focus option.", focusOption);
18770        },
18771
18772        /**
18773         * The API is equivalent to calling
18774         * `guideBridge.setFocus(options.somExpression, options.focusOption, options.runCompletionScript)`
18775         * @summary An alternate signature to the {@link GuideBridge#setFocus|setFocus} API
18776         * @method setFocus
18777         * @memberof GuideBridge
18778         * @instance
18779         * @since 6.1 FP1
18780         * @param {object} options options passed to the API
18781         * @param {string} options.somExpression somExpression to set the focus to
18782         * @param {string} options.focusOption item inside the Panel to focus to
18783         * @param {string} options.runCompletionScript whether to run the completion script or not.
18784         * @return {boolean} true if the focus was set successfully otherwise false.
18785         */
18786
18787        /**
18788         * In Adaptive Form one can focus a Field/Panel. Setting focus on a Panel means setting focus to its first
18789         * child. This can be controlled using the _focusOption_ provided in this API.
18790         *
18791         * The API provides two mechanism to focus a Field/Panel.
18792         * * **Direct** : By providing the somExpression of the Field/Panel. If the somExpression of Panel is provided,
18793         * then based on the focusOption one of its child (or their child) is set to Focus
18794         * * **Indirect** : By providing an item's relative position inside a Panel, first or last item inside of a
18795         * Panel, sibling of current focussed Item of a Panel, etc. If the item is a Panel then the First Item of
18796         * that Panel (if that is again a Panel, this process continues until a Field is found) is activated.
18797         *
18798         * The first way is trivial, by providing the _somExpression_ of a {@link Field} to the API, the focus will be
18799         * set to the Field.
18800         *
18801         * If that Field is inside a Panel that is not currently open because of tabbed/wizard navigation, then that tab
18802         * would be opened and focus would be set to the Field/Panel.
18803         *
18804         * The API can also execute the
18805         * [completion expression](https://helpx.adobe.com/aem-forms/6-1/adaptive-form-expressions.html#main-pars_header_8)
18806         * of the current Panel and only if the expression returns true set focus to the required element.
18807         *
18808         * **Note:**
18809         * * If _focusOption_ is either of nextItemDeep or prevItemDeep then _somExpression_ parameter must not be
18810         * passed. Otherwise the API will throw an exception
18811         * * If _somExpression_ points to a {@link Field} and _focusOption_ is not _nextItemDeep_ or _prevItemDeep_ then
18812         * _focusOption_ is ignored.
18813         *
18814         * @summary Sets focus to a {@link Field} or {@link Panel}
18815         * @param {?string} somExpression SOM Expression of the Adaptive Form Field or Panel which has to be activated.
18816         * @param {string} [focusOption=firstItem] The option provides the mechanism to focus onto an sibling of the
18817         * current active item.
18818         * * **_firstItem_** - Focuses to the first focusable item of the Panel whose _SOM Expression_ is provided
18819         * * **_lastItem_** - Focuses to the last focusable item of the Panel whose _SOM Expression_ is provided
18820         *
18821         * If either the _firstItem_ or _lastItem_ is a Panel, then the _firstItem_ of that Panel (until a Field is
18822         * found) is set to Focus.
18823         *
18824         * * **_nextItem_** - Next sibling component of the current active Item of the Panel whose _somExpression_ is
18825         * provided. It is equivalent to the result of `panel.navigationContext.nextItem` API.
18826         * * **prevItem** - Previous sibling component of the current active Item of the Panel show _somExpression_ is
18827         * provided. It is equivalent to the result of `panel.navigationContext.prevItem` API.
18828         *
18829         * * **_nextItemDeep_** - Focus is set to the next Navigable Panel of root Panel in DFS Order
18830         * * **_prevItemDeep_** - Focus is set to the next Navigable Panel of root Panel in DFS Order
18831         * @param {boolean} [runCompletionScript=false] indicating whether to execute the completion expression or not.
18832         * @returns {boolean} true if the focus was set to requested field successfully otherwise false
18833         * @method
18834         * @memberof GuideBridge
18835         * @since 6.0
18836         * @instance
18837         * @example
18838         * setFocus(somExpression); // Focus is set to the specified somExpression.
18839         * setFocus(this.panel.somExpression,'nextItem',true); // Focus is set to next item in the Panel.
18840         * setFocus(null,'nextItemDeep',true); // Focus is set to next navigable Panel in rootPanel
18841         */
18842        setFocus : function (somExpression, focusOption, runCompletionScript) {
18843            var options,
18844                focusDone,
18845                originalSkipFieldFocus;
18846            if (_.isObject(somExpression)) {
18847                options = somExpression;
18848            } else {
18849                options = {
18850                    somExpression : somExpression,
18851                    focusOption : focusOption,
18852                    runCompletionScript : runCompletionScript
18853                };
18854            }
18855            try {
18856                originalSkipFieldFocus = this._guideView.skipFieldFocus;
18857                /**
18858                 * Setting of this._guideView.skipFieldFocus was added for issue LC-3911361
18859                 * Here we set a skipFieldFocus property for gudeContainerView, which prevents
18860                 * actual 'input' / widget focus. This was done to prevent opening of keyboard or dropdown spinner
18861                 * or date picker.. in case of swipe and use of deep navigators in mobile view of Adaptive Form.
18862                 *
18863                 * when user validates Adaptive Form, skipFieldFocus is set to  options.skipFieldFocus based on somExpression
18864                 * which has default value of'undefined' else the skipFieldFocus set to the negated value of global variable
18865                 * enableFocusOnFirstField to enable/disable focus on first field of Adaptive Form.
18866                */
18867                var fallbackSkipFieldFocus = !this._guide.enableFocusOnFirstField;
18868                if (!fallbackSkipFieldFocus) {
18869                    fallbackSkipFieldFocus = !guideBridge._getEnableFocusOnFirstField();
18870                }
18871                this._guideView.skipFieldFocus = options.somExpression ? options.skipFieldFocus : fallbackSkipFieldFocus;
18872                focusDone = this._guideView.setFocus(options);
18873            } finally {
18874                this._guideView.skipFieldFocus = originalSkipFieldFocus; //moving back to original state
18875            }
18876            //TODO: need a more common place to do that.
18877            if (!this._guide._currentContext) {
18878                this._guide.runPendingExpressions();
18879            }
18880            return focusDone;
18881        },
18882
18883        /**
18884         * Loads the lazy fragment specified by somExpression
18885         * @param {string} somExpression somexpression of the lazy loaded fragment
18886         * @param {object} options options to control the behaviour of loadLazyFragment API.
18887         * @param {object} [options.async] options to control if the fragment is to be loaded lazily
18888         * @param {function} [options.error] callback which receives the result of the API in
18889         * case of failure.
18890         * @method
18891         * @memberof GuideBridge
18892         * @since 6.4
18893         * @instance
18894         * @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
18895         * would load both</caption>
18896         * guideBridge.loadLazyFragment("x[0].y[0].z[0]");
18897         *
18898         */
18899        loadLazyFragment : function (somExpression, options) {
18900            options = options || {};
18901            if (!_.isUndefined(somExpression)) {
18902                var relativeSom = guidelib.util.GuideUtil.relativeSom(this._guide.rootPanel.somExpression, somExpression);
18903                if (relativeSom) {
18904                    var somTokens = relativeSom.split(".");
18905                    var currItem = this._guide.rootPanel;
18906                    _.each(somTokens, function (qName, index) {
18907                        if (currItem != null) {
18908                            var arr = currItem._findChildren(qName, false);
18909                            if (arr.length > 0) {
18910                                var node = arr[0];
18911                                if (node && node._lazyReference && !node._itemsLoaded) {
18912                                    this._guide.internal.liveDataUtils.updateLiveData();
18913                                    if (options.async) {
18914                                        var successFunc = (function () {
18915                                            return function (complete) {
18916                                                if (options.success) { // Check if success callback exists
18917                                                    options.success.call(this, {lazyLoadingComplete: complete});
18918                                                }
18919                                            }
18920                                        }(index === somTokens.length - 1))
18921                                    }
18922                                    node._loadLazyFragment(options);
18923                                }
18924                                currItem = options.async === true ? null : node;
18925                            } else {
18926                                currItem = null;
18927                            }
18928                        }
18929                    }, this);
18930                }
18931            }
18932        },
18933
18934        /*
18935         * Get the download link of signed document set by signing service.
18936         * @return: url from where the signed document can be accessed, empty in case its not set by signing service.
18937         */
18938        getSignedDocDownloadLink : function () {
18939            var url = "";
18940            if (!_.isUndefined(FD)
18941                && !_.isUndefined(FD.AFaddon)
18942                && !_.isUndefined(FD.AFaddon.Signing)
18943                && !_.isUndefined(FD.AFaddon.Signing.signedDocDownloadLink)) {
18944                url = FD.AFaddon.Signing.signedDocDownloadLink;
18945            }
18946            return url;
18947        },
18948
18949        /*
18950         If true is passed to the function then it checks for model and view both,
18951         if false or no parameter is passed, then it checks the model only.
18952         */
18953        isGuideLoaded : function (complete) {
18954            if (complete) {
18955                return !_.isEmpty(window.guideBridge._guide && window.guideBridge._guideView);
18956            }
18957            return !_.isEmpty(window.guideBridge._guide);
18958        },
18959
18960        _doInternalSubmit : function (options) {
18961            if (options.excludeFormState) {
18962                var submissionInfo = options.guideState.data.guideState.guideContext.afSubmissionInfo;
18963                if (submissionInfo && submissionInfo.hasOwnProperty('lastFocusItem')) {
18964                    submissionInfo.lastFocusItem = undefined;
18965                }
18966            }
18967            // Make a clone of options so that original options are not modified.
18968            // Remove additionalSubmitInfo from the guideState so that no extra information
18969            // is sent to the server.
18970            var clonedGuideState = JSON.parse(JSON.stringify(options.guideState));
18971            if (!_.isEmpty(clonedGuideState.data.guideState.additionalSubmitInfo)) {
18972                clonedGuideState.data.guideState.additionalSubmitInfo = {};
18973            }
18974            var guideState = clonedGuideState,
18975                strContent = this.getMultipartData({
18976                    guideState : JSON.stringify(guideState.data),
18977                    dorData : options.dorData || false,
18978                    _charset_ : "UTF-8"
18979                }),
18980            // check if guide state is present, if yes get guide path from guide state
18981            // Specifically written for mobile workspace to getDataXML from current json state
18982                guidePath = ((guideState && guideState.data) ? guideState.data.guideState.guideContext.guidePath : null);
18983
18984            $.ajax({
18985                url : this._getGuidePathUrl(".af.internalsubmit.jsp", guidePath),
18986                type : "POST",
18987                async : options.async || false,
18988                contentType : "multipart/form-data; charset=UTF-8; boundary=" + strContent[0],
18989                data : strContent[1],
18990                success : options.success,
18991                error : options.error
18992            });
18993        },
18994
18995        _submitInternal : function (options) {
18996            var self = this;
18997            options = options || {};
18998            if (!options.guideState) {
18999                this.getGuideState({
19000                    "diff" : "diff",
19001                    "fileUploadPath" : options.fileUploadPath,
19002                    "success" : function (guideState) {
19003                        self._doInternalSubmit({
19004                            guideState : guideState,
19005                            success : options.success,
19006                            error : options.error,
19007                            async : options.async,
19008                            excludeFormState : options.excludeFormState,
19009                            dorData : options.dorData
19010                        });
19011                    },
19012                    "error" : options.error,
19013                    reducedJSON : true
19014                });
19015            } else {
19016                this._doInternalSubmit({
19017                    guideState : options.guideState,
19018                    success : options.success,
19019                    error : options.error,
19020                    async : options.async,
19021                    excludeFormState : options.excludeFormState,
19022                    dorData : options.dorData
19023                });
19024 
19024           }
19025        },
19026
19027        getMultipartData : function (data) {
19028            //Start multipart formatting
19029            var initBoundary = this.randomString();
19030            var strBoundary = "--" + initBoundary;
19031            var strMultipartBody = "";
19032            var strCRLF = "\r\n";
19033
19034            //Create multipart for each element of the form
19035            for (var key in data) {
19036                if (data.hasOwnProperty(key)) {
19037                    var value = _.isObject(data[key]) ? JSON.stringify(data[key]) : data[key];
19038                    strMultipartBody +=
19039                        strBoundary +
19040                        strCRLF +
19041                        "Content-Disposition: form-data; name=\"" + key + "\"" +
19042                        strCRLF +
19043                        strCRLF +
19044                        value +
19045                        strCRLF;
19046                }
19047            }
19048            //End the body by delimiting it
19049            strMultipartBody += strBoundary + "--" + strCRLF;
19050            //Return boundary without -- and the multipart content
19051            return [initBoundary, strMultipartBody];
19052        },
19053
19054        randomString : function () {
19055            var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
19056            var string_length = 8;
19057            var randomstring = '';
19058            for (var i = 0; i < string_length; i++) {
19059                var rnum = Math.floor(Math.random() * chars.length);
19060                randomstring += chars.substring(rnum, rnum + 1);
19061            }
19062            return randomstring;
19063        },
19064
19065        /*
19066         * Get the file Attachment map that contains a mapping of som expression vs path when files have been uploaded
19067         * and som expression vs name when the files have not yet been uploaded .
19068         * @return: map of som expression and paths.
19069         * @private
19070         */
19071        getFileAttachmentMap : function () {
19072            var fileAttachmentMap = {},
19073                fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
19074            for (var i = 0; i < fileAttachmentsList.length; i++) {
19075                var node = fileAttachmentsList[i];
19076                if (!_.isEmpty(node.fileAttachment.value)) {
19077                    fileAttachmentMap[node.somExpression] = node.fileAttachment.value;
19078                }
19079            }
19080
19081            var lazyAttachmentMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap();
19082            _.each(lazyAttachmentMap, function (mapObject, key) {
19083                fileAttachmentMap[key] = mapObject.value;
19084            });
19085            return fileAttachmentMap;
19086        },
19087
19088        /*
19089         * sets the value of the file attachment component based on the map that is passed.
19090         * @private
19091         */
19092        putFileAttachmentMap : function (fileAttachmentMap) {
19093            _.each(fileAttachmentMap, function (value, som) {
19094                var node = guideBridge.resolveNode(som);
19095                node.fileAttachment.value = value;
19096            });
19097        },
19098
19099        _appendFileAttachmentsToFormData : function (dataForm, fileNameDomMap, fileAttachmentsList) {
19100            var fileNamesIndex,
19101                fileDoms = fileNameDomMap.fileDom,
19102                fileNames = fileNameDomMap.fileName,
19103                faPromise = {},
19104                rejectedFileNames = [],
19105                isIOS = guidelib.util.GuideUtil._isIOS(),
19106                createUnorderedList = function (list, bulletChar) {
19107                    var result = "";
19108                    for (var i = 0; i < list.length; ++i) {
19109                        result += bulletChar + " " + list[i] + "\n";
19110                    }
19111                    return "\n" + result;
19112                },
19113                throwException = function (fileNames) {
19114                    if (fileNames && fileNames.length > 0) {
19115                        throw guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-024"], [createUnorderedList(fileNames, "•")]);
19116                    }
19117                };
19118            for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
19119                // multiple files inside one filedom element & draft save case is handled.
19120                var currentFileNames = fileNames[fileNamesIndex].split("\n");
19121                for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
19122                    if (currentFileNames[fileIndex] && _.isString(fileDoms[fileNamesIndex])) {
19123                        //handle draft save scenario when fileDoms[fileNamesIndex] is string(URL) & currentFileNames[fileIndex] is a url
19124                        dataForm.append("_guideFileAttachment." + guideBridge._getRelativeFilePath(currentFileNames[fileIndex]), fileDoms[fileNamesIndex]);
19125                    }
19126                }
19127            }
19128            dataForm.append("_guideAttachments", fileNames.toString());
19129            if (isIOS) {
19130                var allFAPromises = [];
19131                _.each(fileAttachmentsList, function (fileAttachmentModel, index) {
19132                    var fileAttachmentWrapperPromises = fileAttachmentModel._fileAttachmentWrapperIOS;
19133                    if (fileAttachmentWrapperPromises) {
19134                        allFAPromises.push.apply(allFAPromises, fileAttachmentWrapperPromises);
19135                    }
19136                });
19137                faPromise = Promise.allSettled(allFAPromises).then(function (results) {
19138                    for (var pIndex = 0; pIndex < results.length; pIndex++) {
19139                        // if status rejected, fail submission
19140                        if (results[pIndex].status === "rejected") {
19141                            rejectedFileNames.push(results[pIndex].reason);
19142                        } else {
19143                            var resultValue = results[pIndex].value;
19144                            var completeNameOfFile = resultValue.formElementName + "/" + resultValue.name;
19145                            dataForm.append(completeNameOfFile, resultValue.dataURLtoBlob(), resultValue.name);
19146                        }
19147                    }
19148                    // to fail this promise, throw an exception here
19149                    throwException(rejectedFileNames);
19150                    return dataForm;
19151                });
19152            } else {
19153                var allFileAccessPromise = [];
19154                for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
19155                    // multiple files inside one filedom element & draft save case is handled.
19156                    var currentFileNames = fileNames[fileNamesIndex].split("\n");
19157                    for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
19158                        // in case of IOS, file binary is from file object, we use the in-memory data
19159                        if (fileDoms[fileNamesIndex] && !_.isString(fileDoms[fileNamesIndex]) && fileDoms[fileNamesIndex].length > 0) {
19160                            // promise is not supported in IE11
19161                            // for IE11, we don't read file bytes
19162                            if (window.Promise) {
19163                                var fileAccessPromise = guidelib.util.GuideUtil._checkIfFileIsAccessible(currentFileNames[fileIndex], fileDoms[fileNamesIndex][0].files[fileIndex]);
19164                                allFileAccessPromise.push(fileAccessPromise);
19165                            } else {
19166                                // append each file of input file element to formdata
19167                                dataForm.append(currentFileNames[fileIndex], fileDoms[fileNamesIndex][0].files[fileIndex]);
19168                            }
19169
19170                        }
19171                    }
19172                }
19173                // promise is not supported in IE11
19174                if (window.Promise) {
19175                    faPromise = Promise.allSettled(allFileAccessPromise).then(function (results) {
19176                        for (var pIndex = 0; pIndex < results.length; pIndex++) {
19177                            // if status rejected, fail submission
19178                            if (results[pIndex].status === "rejected") {
19179                                rejectedFileNames.push(results[pIndex].reason);
19180                            } else {
19181                                var resultValue = results[pIndex].value;
19182                                dataForm.append(resultValue.fileName, resultValue.file);
19183                            }
19184                        }
19185                        throwException(rejectedFileNames);
19186                        return dataForm;
19187                    });
19188                } else {
19189                    faPromise = $.Deferred().resolve(dataForm);
19190                }
19191            }
19192            return faPromise;
19193        },
19194
19195        doAjaxSubmitWithFileAttachment : function (actionUrl, submitData, options, fileAttachmentsList) {
19196            var _options = options || {},
19197                self = this,
19198                dataForm = new FormData(),
19199                fileNameDomMap = this._juiceOutNameAndFileDomMap(fileAttachmentsList),
19200                faPromise = this._appendFileAttachmentsToFormData(dataForm, fileNameDomMap, fileAttachmentsList);
19201
19202            var _submitForm = function () {
19203                    $.ajax({
19204                        url : actionUrl,
19205                        type : "POST",
19206                        processData : false,
19207                        cache : false,
19208                        contentType : false,
19209                        dataType : 'json',
19210                        data : dataForm,
19211                        success : function (data) {
19212                            self.doAjaxSubmitSuccess(data, _options);
19213                        },
19214                        error : function (data) {
19215                            self.doAjaxSubmitError(data, _options);
19216                        }
19217                    });
19218                };
19219            faPromise.then(function (dataForm) {
19220                    $.each(submitData, function (key, val) {
19221                        if (typeof val == "object") {
19222                            val = JSON.stringify(val);
19223                        }
19224                        dataForm.append(key, val);
19225                    });
19226                    _submitForm();
19227                })
19228                .catch(function (e) {
19229                    // handle errors here
19230                    console.error(e);
19231                    if (typeof e === "string") {
19232                        guideBridge._handleSubmitError("", e);
19233                    } else {
19234                        guideBridge._handleSubmitError({
19235                            "status" : 400
19236                        });
19237                    }
19238
19239                });
19240        },
19241
19242        doAjaxSubmit : function (actionUrl, submitData, options) {
19243            var _options = options || {},
19244            self = this,
19245            asyncSubmit = _options.async !== false,
19246            strContent = this.getMultipartData(submitData);
19247            $.ajax({
19248                url : actionUrl,
19249                type : "POST",
19250                traditional : true,
19251                async : asyncSubmit,
19252                contentType : "multipart/form-data; charset=UTF-8; boundary=" + strContent[0],
19253                data : strContent[1],
19254                success : function (data) {
19255                    self.doAjaxSubmitSuccess(data, _options);
19256                },
19257                error : function (data) {
19258                    self.doAjaxSubmitError(data, _options);
19259                }
19260            });
19261        },
19262
19263        KEY_AF_SUCCESS_PAYLOAD : "afSuccessPayload",
19264        KEY_AF_SUCCESS_DOCUMENT_OF_RECORD : "afSuccessDocumentOfRecord",
19265
19266        doAjaxSubmitSuccess : function (data, options) {
19267            var guideResultObject = new GuideResultObject();
19268            guideResultObject.data = data;
19269            guideResultObject.completed = true;
19270            // remove the submitting message too after success of ajax submit
19271            guideBridge._showGuideLoading(false);
19272            if (_.isFunction(options.success)) {
19273                options.success.call(options.context, guideResultObject);
19274            } else {
19275                if (data.hasOwnProperty("signingURL")) {
19276                    // Adobe sign : FormFiller enabled case.
19277                    window.location.href = data.signingURL;
19278                } else {
19279                    var payload = {};
19280                    if (data.hasOwnProperty(guideBridge.KEY_AF_SUCCESS_PAYLOAD)) {
19281                        try {
19282                            payload = JSON.parse(data[guideBridge.KEY_AF_SUCCESS_PAYLOAD]);
19283                            payload.data = this._guide.internal.afdata;
19284                            if(data.hasOwnProperty(guideBridge.KEY_AF_SUCCESS_DOCUMENT_OF_RECORD)) {
19285                                payload.dorUri = data[guideBridge.KEY_AF_SUCCESS_DOCUMENT_OF_RECORD];
19286                            }
19287                            var schemaType = this._guide.runtime.guideContext.schemaType;
19288                            if (!schemaType) {
19289                                //TODO define a constant for schema Type.
19290                                schemaType = "xmlschema";
19291                            }
19292                            payload.contentType = schemaType;
19293                        } catch (e) {
19294                            guideBridge._guide.logger().log("Error while parsing AF Success Payload: " + e);
19295                        }
19296                    }
19297                    guideBridge._guide.executeExpression("submitSuccess", payload); // Executing Rule Editor code for submit success.
19298                    if (data.agreementId && guideBridge._guide._isFirstSignerFormFiller()) {
19299                        guidelib.util.GuideUtil.redirectWithDelay(data.afSuccessRedirectUrl, 3000);
19300                    }
19301                }
19302            }
19303        },
19304
19305        doAjaxSubmitError : function (data, options) {
19306            var guideResultObject = new GuideResultObject();
19307            guideResultObject.data = data;
19308            guideResultObject.completed = false;
19309            guideResultObject.addMessage(2, "Error in Async Submit", "");
19310            guideBridge._showGuideLoading(false);
19311            if (_.isFunction(options.error)) {
19312                options.error.call(options.context, guideResultObject);
19313            } else {
19314                var errorPayload = {};
19315                try {
19316                    errorPayload = JSON.parse(data.responseText);
19317                } catch (e) {
19318                    guideBridge._guide.logger().log("Error while parsing errorPayload." + e);
19319                }
19320                guideBridge._guide.executeExpression("submitError", errorPayload); //Executing Rule Editor code for submitError
19321            }
19322        },
19323
19324        handleUpload : function () {
19325            self = this.self;
19326            this.submitData['_guideAttachments'] = this.attachments.toString();
19327            _.each(this.attachments, function (att) {
19328                this.submitData["_guideFileAttachment." + att] = this.submitData['fileUrl'] + "/" + att;
19329            }, this);
19330            delete this.submitData['fileUrl'];
19331            self.doAjaxSubmit(this.actionUrl, this.submitData, this.options);
19332        },
19333
19334        _handleSubmitError : function (data, message) {
19335            // case: show message if it exists, for example, there could be client side errors during submit
19336            if (message) {
19337                alert(message);
19338            } else {
19339                // based on http status show error, these errors are based on server side http response codes
19340                var status = Number(data.status);
19341                switch (status) {
19342                    case 502:
19343                        alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-003"]));
19344                        break;
19345                    case 400:
19346                        alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-022"]));
19347                        break;
19348                    default:
19349                        alert(guidelib.util.GuideUtil.getLocalizedMessage("AF", guidelib.i18n.LogMessages["AEM-AF-901-004"]));
19350                        break;
19351                }
19352            }
19353            guideBridge._showGuideLoading(false);
19354        },
19355
19356        updateSubmitData : function (fileAttachmentsList, submitData, fileList) {
19357            var fileCount = 0,
19358                attachments = [],
19359                name;
19360            if (fileList.length === 0 && fileAttachmentsList.length > 0) {
19361                _.each(fileAttachmentsList, function (fileUploadComponentId, index) {
19362                    var currentCount = 0;
19363                    var componentInModel = window.guideBridge._resolveId(fileUploadComponentId);
19364                    var fileNameList = componentInModel["fileAttachment"].value;
19365                    if (fileNameList) {
19366                        var fileNames = fileNameList.split("\n");
19367                        _.each(fileNames, function (fileUrl, index) {
19368                            name = componentInModel.name + "/" + fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
19369                            if (name) {
19370                                attachments[fileCount++] = name;
19371                                submitData["_guideFileAttachment." + name] = fileUrl;
19372                            }
19373                        }, this);
19374                    }
19375                }, this);
19376                submitData['_guideAttachments'] = attachments;
19377            } else if (fileList.length > 0) {
19378                _.each(fileList, function (file, index) {
19379                    name = guideBridge._getRelativeFilePath(file);
19380                    attachments[fileCount++] = name;
19381                    submitData["_guideFileAttachment." + name] = file;
19382                }, this);
19383                submitData['_guideAttachments'] = attachments;
19384            }
19385        },
19386
19387        _collectFileUrls : function (event) {
19388            var list = [],
19389                fileUploadError = false;
19390
19391            // Populate list to have path of all the uploaded files. The file Attachment component whose model was
19392            // loaded would have their fileNames first followed by the list of file names of unloaded file upload components.
19393            _.each(this.attachments, function (attachment) {
19394                _.each(attachment.split("\n"), function (att) {
19395                    // check if att is a url and hence push it directly to list
19396                    if (_.isString(att) && att.match(/\//g).length > 1) {
19397                        list.push(att);
19398                    } else {
19399                        list.push(this.fileUrl + "/" + att);
19400                    }
19401                }, this);
19402            }, this);
19403
19404            var options = {
19405                fileUrlList : list,
19406                fileUploadModelsList : this.fileAttachmentsList,
19407                lazyAttachmentMap : guideBridge._guide.internal.liveDataUtils._getLazyAttachmentMap()
19408            };
19409            guidelib.util.GuideUtil._updateFileModelsAndLazyMap(options);
19410
19411            var submitOptions = this.options.ajaxSubmitObject;
19412            if (submitOptions && submitOptions.ajaxSubmitDataHandler) {
19413                submitOptions.ajaxSubmitDataHandler.call(this.options.context, submitOptions.fileAttachmentsList, submitOptions.submitData, list);
19414                window.guideBridge.doAjaxSubmit(submitOptions.actionUrl, submitOptions.submitData, this.options);
19415            } else if (this.options.success) {
19416                //create the guideState now as the model has been updated with the latest values.
19417                //do this only during getGuideState and not on ajax submit
19418                guideBridge._createGuideStateAndLiveXml(this.options);
19419                this.options.success.call(this.options.context, this.options.obj);
19420            }
19421
19422        },
19423
19424        _fileUploadFailed : function (event) {
19425            $.proxy(guideBridge._handleSubmitError({
19426                        "status" : "500"
19427                    }), guideBridge);
19428        },
19429
19430        // This function extracts the form name from the guideContainerPath.
19431        _getFormName : function (guidePath) {
19432            var formName = "";
19433            if (guidePath) {
19434                var index = guidePath.indexOf("/jcr:content/guideContainer");
19435                guidePath = guidePath.substring(0, index);
19436                formName = guidePath.substring(guidePath.lastIndexOf("/") + 1);
19437            }
19438            return formName;
19439        },
19440
19441        /**
19442         * returns the form element to be used for submission in case of non-ajax
19443         * submit.
19444         * The function looks in the submitConfig for a form and if not present,
19445         * creates a new form
19446         * @returns {object} jQuery object for form element
19447         * @private
19448         */
19449        _getFormForSubmission : function () {
19450            var submitConfig = this.userConfig.submitConfig || {},
19451                form = submitConfig.form || $("<form method='post' enctype='multipart/form-data'></form>").appendTo($("body"));
19452            return $(form);
19453        },
19454
19455        _getThankYouPageFromConfig : function () {
19456            var submitConfig = this.userConfig.submitConfig || {};
19457            return submitConfig.thankyouPage;
19458        },
19459
19460        /**
19461         * This function prepare the guideValueMap and returns it.
19462         * @returns A map consisting of name and value for all the unbound components
19463         * @private
19464         */
19465        _prepareGuideValueMap : function () {
19466            var guideValueMap = {}, visitedMap = {};
19467            this.visit(function (node) {
19468                if (!node.bindRef && !visitedMap[node.somExpression]) {
19469                    if (node instanceof guidelib.model.Field && node.value) {
19470                        visitedMap[node.somExpression] = true;
19471                        guideValueMap[node.getAttribute("name")] = node.value;
19472                    } else if (node instanceof guidelib.model.GuideCompositeField) {
19473                        var obj = guideValueMap[node.getAttribute("name")] = {};
19474                        _.each(node.items, function (childNode, index) {
19475                            visitedMap[childNode.somExpression] = true;
19476                            if (childNode.value) {
19477                                obj[childNode.getAttribute("name")] = childNode.value;
19478                            }
19479                        }, this);
19480                    }
19481                }
19482            });
19483            return guideValueMap;
19484        },
19485
19486        _showGuideLoading : function (flag, msg) {
19487            if(!flag){
19488                if(_focusedSubmitButtonModel){
19489                    _focusedSubmitButtonModel.enabled = true;
19490                    _focusedSubmitButtonModel = null;
19491                }
19492            }
19493            var util = guidelib.util.GuideUtil;
19494            if (util) {
19495                util.showGuideLoading(flag);
19496                if (msg !== undefined) {
19497                    util.showMessages(msg);
19498                } else {
19499                    util.removeAllMessages();
19500                }
19501            }
19502        },
19503
19504        _submitAfterValidation : function (options, submitSuccess, submitError) {
19505            var self = this;
19506            if (guidelib.util.GuideUtil) {
19507                var msg = guidelib.i18n.strings.submittingForm;
19508                if (options && options.submissionSelector === 'agreement') {
19509                    msg = guidelib.i18n.strings.generatingSignAgreement;
19510                }
19511                guidelib.util.GuideUtil.showMessages(msg);
19512            }
19513            // Trigger submitStart before calling internal submit.
19514            if (guideBridge.isGuideLoaded() && self._guide._triggerOnBridge) {
19515                self._guide._triggerOnBridge("submitStart", "", "", "", "");
19516            }
19517            var excludeFormState = true;
19518            if (options && options.hasOwnProperty("excludeFormState")) {
19519                excludeFormState = options.excludeFormState;
19520            }
19521            try {
19522                var guideState = getOrElse(options, "guideState", null);
19523                if (guideState || guideBridge.isGuideLoaded()) {
19524                    var twoStepSubmission = getOrElse(options, "twoStepSubmission", false);
19525                    if (guideState || self._guide.xdpRef || twoStepSubmission) {
19526                        self._submitInternal({
19527                            guideState : guideState,
19528                            success : function () {
19529                                try {
19530                                    submitSuccess.apply(self, arguments);
19531                                } catch (e) {
19532                                    self._handleInternalSubmitError(submitError, self, arguments);
19533                                }
19534                            },
19535                            error : function () {
19536                                self._handleInternalSubmitError(submitError, self, arguments);
19537                            },
19538                            async : true,
19539                            excludeFormState : excludeFormState
19540                        });
19541                    } else {
19542                        self.getFormDataString({
19543                            success : function () {
19544                                try {
19545                                    submitSuccess.apply(self, arguments);
19546                                } catch (e) {
19547                                    self._handleInternalSubmitError(submitError, self, arguments);
19548                                }
19549                            }
19550                        });
19551                    }
19552                } else {
19553                    console.error("Form Submission failed as the form doesn't exist on the page");
19554                }
19555            } catch (e) {
19556                self._showGuideLoading(false);
19557                if (console && console.error) {
19558                    console.error(e);
19559                }
19560            }
19561        },
19562
19563        _handleCaptchaTimeout : function () {
19564            window.alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-025"]));
19565            window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
19566            guideBridge._showGuideLoading(false);
19567            return;
19568        },
19569
19570        /**
19571         * Validate and submits the data of the Adaptive Form to the pre-configured submit action.
19572         *
19573         * The success handler provided in the argument is executed only if the Adaptive Form is configured to use AJAX
19574         * for submission using {@link GuideBridge#registerConfig|registerConfig} API
19575         * @summary submits the Adaptive Form
19576         * @param {object} options options to control the behaviour of submit API.
19577         * @param {string} [options.submissionSelector] url selector governs the submission behaviour at server
19578         * Default value is "submit", other options are "agreement", "signSubmit"
19579         * @param {function} [options.success] callback which receives the result of the API
19580         * in case of success.
19581         * {@link GuideResultObject#errors|errors} property as false.
19582         * @param {function} [options.error] callback which receives the result of the API in
19583         * case of failure.
19584         * {@link GuideResultObject#errors|errors} property as true.
19585         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
19586         * object
19587         * @param {boolean} [options.validate=true] whether to validate the form before submission or not
19588         * @method
19589         * @memberof GuideBridge
19590         * @since 6.0
19591         * @instance
19592         * @example <caption>Submitting the form without validation</caption>
19593         * guideBridge.submit({
19594         *    validate: false,
19595         *    error : function (guideResultObject) {//log message}
19596         * });
19597         * @example <caption>Submitting the form and showing a success message</caption>
19598         * guideBridge.registerConfig("submitConfig" : {"useAjax" : true});
19599         * guideBridge.submit({
19600         *   validate: false,
19601         *   error : function (guideResultObject) {//log message}
19602         *   success : function (guideResultObject) {alert("data submitted successfully")
19603         * });
19604         */
19605
19606        submit : function (options) {
19607            // Disabling the submit button
19608            var focusedElementSOM = guideBridge.getFocus();
19609            if(focusedElementSOM){
19610                _focusedSubmitButtonModel = guideBridge.resolveNode(focusedElementSOM);
19611                _focusedSubmitButtonModel.enabled = false;
19612            }
19613            _isAutoSaveEnabled = window.guideBridge.getAutoSaveEnabledStatus();
19614            //Disable auto save till submission is not completed
19615            if (_isAutoSaveEnabled) {
19616                window.guideBridge.setEnabledAutoSave(false);
19617            }
19618            var self = this;
19619            var guideContextFromOptions,
19620                runtimeGuideContext = getOrElse(this._guide, "runtime.guideContext", {});
19621            if (getOrElse(options, "guideState", "")) {
19622                guideContextFromOptions = options.guideState.data.guideState.guideContext;
19623            }
19624            var localGuideContext = guideContextFromOptions || runtimeGuideContext;
19625            // to submit guideContainerForm  which will be stopped so that autocomplete values can be remembered
19626            $(".guideContainerFormSubmitButton").click();
19627
19628            window.guideBridge._populateBindRefToSomMap();
19629
19630            function submitError(data) {
19631                self._ariaLiveAnnouncement(guidelib.i18n.strings["formSubmitFail"]);
19632                if (options && options.error) {
19633                    options.error.call(options.context || this, data);
19634                } else {
19635                    $.proxy(guideBridge._handleSubmitError(data), guideBridge);
19636                }
19637            }
19638
19639            function submitSuccess(result) {
19640                var isAjaxSubmit = false;
19641
19642                if (options) {
19643                    isAjaxSubmit = options.success ? true : false;
19644                }
19645                options = options || {};
19646                options.success = options.success || (self.userConfig.submitConfig || {}).submitSuccessHandler;
19647                isAjaxSubmit = isAjaxSubmit || (self.userConfig.submitConfig || {useAjax : false}).useAjax || guideBridge._guide.enableAsyncSubmission;
19648                var submitData = {};
19649
19650                if (this.isGuideLoaded()) {
19651                    var guideCaptchaList = [];
19652                    this.visit(function (node) {
19653                        if (node.className === "guideCaptcha") {
19654                            guideCaptchaList.push(node);
19655                        }
19656                    });
19657                    var captchaModel = guideCaptchaList[0];
19658                    if (captchaModel) {
19659                        var captchaData = window.guideBridge._getCaptchaData(captchaModel);
19660                        submitData['captchaData'] = captchaData;
19661                    }
19662                }
19663
19664                // check if guide state is present, if yes get guide path from guide state
19665                var guidePath = getOrElse(options, "guideState.data.guideState.guideContext.guidePath", ""),
19666                    guideContainerPath = guidePath || window.guideBridge.getGuidePath(),
19667                    aemFormComponentPath = this.userConfig.submitConfig ? this.userConfig.submitConfig.aemFormComponentPath : "",
19668                    submissionSelector = options.submissionSelector || "submit",
19669                    actionUrl = window.guideBridge._getGuidePathUrl(".af." + submissionSelector + ".jsp", guideContainerPath);
19670
19671                submitData['guideContainerPath'] = guideContainerPath;
19672                submitData['aemFormComponentPath'] = aemFormComponentPath;
19673                submitData['_asyncSubmit'] = isAjaxSubmit;
19674                submitData['_charset_'] = "UTF-8";
19675                var customPropMap = localGuideContext.customPropertyMap || {};
19676                // need to remove lastFocusItem from being sent as a different property
19677                // as it being sent in xml and with afSubmissionInfo as well.
19678                var whiteListedProperties = ["lastFocusItem"];
19679                for (var prop in customPropMap) {
19680                    if (customPropMap.hasOwnProperty(prop) && whiteListedProperties.indexOf(prop) < 0) {
19681                        submitData[prop] = customPropMap[prop];
19682                    }
19683                }
19684                // todo: Have to remove the excludeFromDor map from the submission info, is this required ?
19685                if (this.isGuideLoaded()) {
19686                    submitData['afSubmissionInfo'] = this._guide.runtime.guideContext.afSubmissionInfo || {};
19687                }
19688                var resultJson = result,
19689                    guideJson,
19690                    data,
19691                    fileAttachmentsList,
19692                    attachments = [],
19693                    fileCount = 0;
19694                if (resultJson.hasOwnProperty("guideValue")) {
19695                    guideJson = resultJson.guideValue;
19696                } else if (!_.isUndefined(options.guideValueMap)) {
19697                    guideJson = options.guideValueMap;
19698                } else {
19699                    // todo: why is this required in client ?
19700                    guideJson = window.guideBridge._prepareGuideValueMap();
19701                }
19702                if (resultJson.hasOwnProperty("data")) {
19703                    data = resultJson["data"];
19704                }
19705
19706                if (resultJson.hasOwnProperty("fileAttachmentsList")) {
19707                    fileAttachmentsList = resultJson["fileAttachmentsList"];
19708                }
19709
19710                for (var key in guideJson) {
19711                    if (guideJson.hasOwnProperty(key)) {
19712                        submitData[key] = guideJson[key];
19713                    }
19714                }
19715
19716                if (data) {
19717                    submitData['jcr:data'] = data;
19718                    submitData['jcr:data@TypeHint'] = "Binary";
19719                    if (self.isGuideLoaded()) {
19720                        self._guide.internal.afdata = data;
19721                    }
19722                }
19723                if (!_.isUndefined(options.fileAttachmentMap)) {
19724                    submitData.fileAttachmentMap = options.fileAttachmentMap;
19725                } else {
19726                    //send the fileAttachmentMap through submit data to restore submission attachments for read only viewing
19727                    submitData.fileAttachmentMap = JSON.stringify(guideBridge._getFileAttachmentMapForSubmit());
19728                }
19729                // read the additional information from the guideState if it is passed in options
19730                // otherwise get the additional information from the DOM
19731                var additionalSubmitInfo = {};
19732                if (options.guideState && options.guideState.data.guideState.additionalSubmitInfo) {
19733                    additionalSubmitInfo = options.guideState.data.guideState.additionalSubmitInfo;
19734                } else {
19735                    additionalSubmitInfo = guideBridge._getAdditionalSubmitInfo();
19736                }
19737                // append additionalSubmitInfo to the submitData
19738                $.extend(true, submitData, additionalSubmitInfo);
19739
19740                if (isAjaxSubmit && isAjaxSubmit === true) {
19741                    // 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.
19742                    // we just update the submitData with the attachment information
19743                    if (options.fileAttachmentMap) {
19744                        var attachmentMap = JSON.parse(options.fileAttachmentMap);
19745                        var keys = _.keys(attachmentMap);
19746                        for (var i = 0; i < keys.length; i++) {
19747                            if (attachmentMap[keys[i]]) {
19748                                var fileNames = attachmentMap[keys[i]].split("\n");
19749                                for (var j = 0; j < fileNames.length; j++) {
19750                                    var name = guideBridge._getRelativeFilePath(fileNames[j]);
19751                                    attachments[fileCount++] = name;
19752                                    submitData["_guideFileAttachment." + name] = fileNames[j];
19753                                }
19754                            }
19755                        }
19756                        submitData['_guideAttachments'] = attachments;
19757                        self.doAjaxSubmit(actionUrl, submitData, options);
19758                    } else {
19759                        var attachedFilesList = [];
19760                        var currentCount = 0;
19761                        // need to check if the guide is loaded, as it is not available for mobile workspace app use case
19762                        if (guideBridge.isGuideLoaded()) {
19763                            attachedFilesList = window.guideBridge._getFileAttachmentsList();
19764                        }
19765                        _.each(attachedFilesList, function (object) {
19766                            var fileNameList = object["fileAttachment"].value;
19767                            if (fileNameList) {
19768                                currentCount++;
19769                            }
19770                        });
19771                        // If a file has been attached and isAjaxSubmit is true, then a UUID is generated and
19772                        // the files are uploaded at temp storage path.
19773                        // The submit data is updated with the attached files and then
19774                        // doAjaxSubmit is called.
19775                        if (currentCount > 0) {
19776                            self.doAjaxSubmitWithFileAttachment(actionUrl, submitData, options, attachedFilesList);
19777                        } else {
19778                            self.doAjaxSubmit(actionUrl, submitData, options);
19779                        }
19780                    }
19781                } else {
19782                    var $form = self._getFormForSubmission();
19783                    $form.attr('action', actionUrl);
19784                    $form.attr('data-name', 'afSubmissionForm');
19785                    for (var fields in submitData) {
19786                        if (submitData.hasOwnProperty(fields)) {
19787                            var value = submitData[fields];
19788                            $("<input>").attr("type", "hidden")
19789                                .attr("name", fields)
19790                                .val(_.isObject(value) ? JSON.stringify(value) : value)
19791                                .appendTo($form);
19792                        }
19793                    }
19794                    /*
19795                     * This means we did not do any preprocessing
19796                     * for file attachments so fileAttachment list won't be present
19797                     * so posting DOM for the files.
19798                     * */
19799                    var attachmentNameDomMap = guideBridge._getFileNameFileDomMap(),
19800                        fileNameList = [],
19801                        _guideAttachments = "";
19802                    // A string containing the names of all the files that are attached is stored in the variable _guideAttachments.
19803                    // For all the files that have been uploaded already and don't have a dom element are
19804                    // added to $form with prefix "_guideFileAttachment."
19805                    if (attachmentNameDomMap && attachmentNameDomMap.fileDom) {
19806                        fileNameList = attachmentNameDomMap.fileName;
19807                        _.each(attachmentNameDomMap.fileDom, function (file, index) {
19808                            if (!_.isString(file)) {
19809                                file.attr("name", fileNameList[index].split["\n"])
19810                                    .attr("class", "hidden")
19811                                    .appendTo($form);
19812                                _guideAttachments += fileNameList[index] + ",";
19813                            } else {
19814                                if (fileNameList[index]) {
19815                                    var name = guideBridge._getRelativeFilePath(fileNameList[index]);
19816                                    $("<input>").attr("type", "hidden")
19817                                        .attr("name", "_guideFileAttachment." + name)
19818                                        .attr("value", file)
19819                                        .appendTo($form);
19820                                    _guideAttachments += name + ",";
19821                                }
19822                            }
19823                        });
19824                    }
19825                    $("<input>").attr("type", "hidden")
19826                        .attr("name", "_guideAttachments")
19827                        .attr("value", _guideAttachments)
19828                        .appendTo($form);
19829
19830                    $form.submit();
19831                }
19832            }
19833
19834            self._showGuideLoading(true, guidelib.i18n.strings.val
19834idatingForm);
19835            // since validate is synchronous call, putting this in timeout
19836            // so that html changes can be display
19837            setTimeout(function () {
19838                // update the snapshot just before validating
19839                // so that we get true state of play before loading panels
19840                if (guideBridge.isGuideLoaded() && guideBridge._guide.allLazyChildren && guideBridge._guide.allLazyChildren.length > 0) {
19841                    self._guide.internal.liveDataUtils.updateLiveData();
19842                }
19843                var isValid = false;
19844                try {
19845                    isValid = self._performConditionalValidation(options);
19846                } catch (e) {
19847                    isValid = false;
19848                } finally {
19849                    self._showGuideLoading(true);
19850                }
19851                if (isValid) {
19852                    /* Handle Invisible Recaptcha on form submission */
19853                    var recaptchaInvisibleElement = FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) ?
19854                        $("#captchaInvisible") : $("#recaptchaInvisible");
19855                    if (recaptchaInvisibleElement != undefined && recaptchaInvisibleElement.attr("af-recaptcha-execute") == "") {
19856                        recaptchaInvisibleElement.trigger({
19857                            type: "recaptchaExecution",
19858                            submitParameters: {
19859                                options: options,
19860                                success: submitSuccess,
19861                                error: submitError
19862                            },
19863                            triggerPostSubmission: true
19864                        });
19865                        return;
19866                    }
19867                    guideBridge._submitAfterValidation(options, submitSuccess, submitError);
19868                } else {
19869                    window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
19870                    self._showGuideLoading(false);
19871                    return;
19872                }
19873            }, 1);
19874        },
19875
19876        /**
19877         * Save draft of the current adaptive form loaded
19878         * @param saveBtnConfig {object} Optional parameter for providing
19879         * @param options {object} Optional parameter options can consist of following -
19880         *  <ul>
19881         *     <li> success: {function}  Handler executed in case when the draft is successfully saved</li>
19882         *     <li> error: {function}  Handler  executed in case of draft failure</li>
19883         *     <li> context {object}  The context with which the success or error handler needs to be executed</li>
19884         * </ul>
19885         *
19886         */
19887        handleDraftSave : function (saveBtnConfig, custom_options) {
19888            custom_options = $.extend({
19889                success : $.noop,
19890                error : $.noop,
19891                context : this
19892            }, custom_options);
19893            // isAutoSaveTriggered is not a documented property.
19894            //handleDraftSave method is also called via auto save component,where we pass this value as true.
19895            // This flag is just set to understand if the call is triggered by auto save strategy or not
19896            custom_options.isAutoSaveTriggered = custom_options.isAutoSaveTriggered || false;
19897
19898            var options = {
19899                success : function (result) {
19900                    var draftId = result.data.draftId;
19901                    window.guideBridge.customContextProperty("draftId", draftId);
19902                    /** if (!isAutoSaveTriggered) {
19903                         $(".__FP_Saved_Message").show();
19904                         $(".__FP_Saved_Message").fadeOut(1600, "linear");
19905                     }**/
19906
19907                    window.guideBridge.trigger(
19908                        "saveCompleted",
19909                        window.guidelib.event.GuideModelEvent.createEvent("saveCompleted")
19910                    );
19911                    var payload = {};
19912                    payload.draftId = draftId;
19913                    payload.isAutoSaveTriggered = custom_options.isAutoSaveTriggered;
19914                    guideBridge._guide.executeExpression("saveSuccess", payload); // Executing Rule Editor code for save success.
19915                    // window.guideBridge._defaultSaveSuccessHandler();
19916                    custom_options.success.call(custom_options.context);
19917                },
19918                error : function (result) {
19919                    if (!custom_options.isAutoSaveTriggered) {
19920                        if (result.status == "503") {
19921                            alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-008"]));
19922                        } else {
19923                            alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-009"]));
19924                        }
19925                    }
19926                    var errorPayload = {};
19927                    errorPayload.result = result;
19928                    errorPayload.isAutoSaveTriggered = custom_options.isAutoSaveTriggered;
19929                    guideBridge._guide.executeExpression("saveError", errorPayload); //Executing Rule Editor code for saveError
19930                    custom_options.error.call(custom_options.context);
19931                }
19932            };
19933            var guidePath = window.guideBridge.getGuidePath();
19934            var draftId = window.guideBridge.customContextProperty("draftId") || "";
19935
19936            var contextPath = window.guideBridge._getUrl(guidePath);
19937            var self = this;
19938            guideBridge.getFormDataObject({
19939                "success" : function (resultObj) {
19940                    window.guideBridge.trigger(
19941                        "saveStarted",
19942                        window.guidelib.event.GuideModelEvent.createEvent("saveStarted")
19943                    );
19944                    var afFormData,
19945                        htmlFormData;
19946                    afFormData = resultObj.data;
19947                    htmlFormData = afFormData.toHTMLFormData();
19948                    htmlFormData.append('draftId', draftId);
19949                    self._doAjaxSubmitWithHTMLFormData(contextPath + ".af.save.jsp", htmlFormData, options);
19950                }
19951            });
19952        },
19953
19954        /**
19955         * @private
19956         */
19957        _doAjaxSubmitWithHTMLFormData : function (actionURL, htmlFormData, options) {
19958            var self = this;
19959            $.ajax({
19960                url : actionURL,
19961                type : "POST",
19962                processData : false,
19963                cache : false,
19964                contentType : false,
19965                dataType : 'json',
19966                data : htmlFormData,
19967                success : function (data) {
19968                    self.doAjaxSubmitSuccess(data, options);
19969                },
19970                error : function (data) {
19971                    self.doAjaxSubmitError(data, options);
19972                }
19973            });
19974        },
19975
19976        /**
19977         * @private
19978         */
19979        _handleInternalSubmitError : function (submitError, selfVar, args
19979) {
19980            try {
19981                submitError.apply(selfVar, args);
19982            } catch (e) {
19983                //ignoring the error
19984            } finally {
19985                guideBridge._showGuideLoading(false);
19986
19987            }
19988        },
19989        /**
19990         * @private
19991         */
19992        _getFileAttachmentMapForSubmit : function () {
19993            var fileAttachmentMap = {},
19994                fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
19995            for (var i = 0; i < fileAttachmentsList.length; i++) {
19996                var node = fileAttachmentsList[i];
19997                if (!_.isUndefined(node.value) && node.value.length > 0) {
19998                    var attachmentList = node.value.split("\n");
19999                    for (var j = 0; j < attachmentList.length; j++) {
20000                        attachmentList[j] = node.name + "/" + attachmentList[j];
20001                    }
20002                    fileAttachmentMap[node.somExpression] = attachmentList.join('\n');
20003                }
20004            }
20005
20006            var lazyAttachmentMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap();
20007            _.each(lazyAttachmentMap, function (mapObject, key) {
20008                var attachmentList = mapObject.value.split("\n");
20009                for (var j = 0; j < attachmentList.length; j++) {
20010                    attachmentList[j] = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + attachmentList[j];
20011                }
20012                fileAttachmentMap[key] = attachmentList.join('\n');
20013            });
20014            return fileAttachmentMap;
20015        },
20016
20017        ERROR_CAUSED_BY : {
20018            CAPTCHA_VALIDATION : "CAPTCHA_VALIDATION",
20019            SERVER_SIDE_VALIDATION : "SERVER_SIDE_VALIDATION",
20020            FORM_SUBMISSION : "FORM_SUBMISSION",
20021            AGREEMENT_CREATION : "AGREEMENT_CREATION",
20022            SERVICE_INVOCATION_FAILURE: "SERVICE_INVOCATION_FAILURE"
20023        },
20024
20025        /**
20026         * This API displays validation error messages at the field level corresponding to the input errorJson object
20027         * @summary Displays validation error messages at field level
20028         * @memberof GuideBridge
20029         * @instance
20030         * @param {object} 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)
20031         * @see {@link https://helpx.adobe.com/experience-manager/6-5/forms/using/custom-validation-message-adaptive-forms.html%7CCustom validation message in adaptive form}
20032         */
20033        handleServerValidationError : function (errorJson) {
20034            var self = this;
20035            if (errorJson) {
20036                var errors = errorJson.errors;
20037                if (errors && errors.length > 0) {
20038                    var firstFocusableSom;
20039                    _.each(errors, function (object, i) {
20040                        var errMsg;
20041                        if (object.errorMessages) {
20042                            errMsg = object.errorMessages.join("\n");
20043                        } else {
20044                            errMsg = object.errorMessage;
20045                        }
20046                        var som = (object.somExpression) ? object.somExpression : self._guide._bindRefMap[object.bindRef];
20047                        var node = self.resolveNode(som);
20048
20049                        if (node) {
20050                            if (!firstFocusableSom) {
20051                                firstFocusableSom = som;
20052                            }
20053                            node.markAsInvalid(errMsg);
20054                        }
20055                    });
20056                    // set focus to first invalid node
20057                    if (firstFocusableSom) {
20058                        self.setFocus(firstFocusableSom);
20059                    }
20060                }
20061            }
20062        },
20063
20064        /* Handle the server side validation failure in case of submission fails.
20065         * This function handles Captcha validation as well as server side validation.
20066         * @private
20067         */
20068        _handleServerValidationError : function (errorJson) {
20069            var self = this;
20070            window.guideBridge.setEnabledAutoSave(_isAutoSaveEnabled);
20071            if (errorJson) {
20072                if (errorJson.errorCausedBy && errorJson.errorCausedBy === this.ERROR_CAUSED_BY.CAPTCHA_VALIDATION) {
20073                    var errors = errorJson.errors,
20074                        firstFocusableSom = errors[0].somExpression;
20075                    _.each(errors, function (object, i) {
20076                        var somExpression = object.somExpression,
20077                            errorMessage = object.errorMessage,
20078                            guideCaptcha;
20079                        /*Setting focus to load captcha's view.
20080                         This is required when panel's children get loaded later.
20081                         Setting focus ensures that view is loaded properly so that model can throw
20082                         'guide.errorChanged' event and view can listen the same.
20083                         */
20084                        self.setFocus(somExpression);
20085                        guideCaptcha = self.resolveNode(somExpression);
20086                        if (guideCaptcha) {
20087                            guideCaptcha.showCaptchaError(errorMessage);
20088                        }
20089                    });
20090                    //Setting focus to the first captcha element.
20091                    self.setFocus(firstFocusableSom);
20092                } else if (errorJson.errorCausedBy && errorJson.errorCausedBy === this.ERROR_CAUSED_BY.FORM_SUBMISSION
20093                    || errorJson.errorCausedBy === this.ERROR_CAUSED_BY.AGREEMENT_CREATION) {
20094                    if (errorJson.errors && errorJson.errors.length > 0) {
20095                        window.guideBridge.handleServerValidationError(errorJson);
20096                    } else {
20097                        var statusCode = errorJson.originCode ? Number(errorJson.originCode) : 500,
20098                            errorMessage = statusCode === 400 ? (errorJson.errorMessage ? errorJson.errorMessage : "") : "";
20099                        // show the message returned by server only if if the HTTP status code is 400
20100                        // this is done so that users could act upon the error and re-submit the form
20101                        $.proxy(guideBridge._handleSubmitError({
20102                            "status" : statusCode
20103                        }, errorMessage), guideBridge);
20104                    }
20105                } else {
20106                    //Everything else is "SERVER_SIDE_VALIDATION". Calling this as it was being called.
20107                    window.guideBridge.handleServerValidationError(errorJson);
20108                }
20109            }
20110        },
20111
20112        /*
20113         * Populates bindRefToSomMap.
20114         * This function is called during submission and during unloading of a lazy fragment
20115         * @param {node} is equal to the lazy loaded fragment model if this is called during lazy fragment unloading
20116         * @private
20117         */
20118        _populateBindRefToSomMap : function (node) {
20119
20120            /*
20121             * While populating bindRefToSomMap we basically check if any panel is repeatable panel.
20122             * If a panel is repeatable, in that node and its descendant nodes we replace the bindRef
20123             * by corresponding json-pointer in the map.
20124             * parameter {jsonp} refers to the json-pointer of the parent node. It is valid if
20125             * some ancestor of current node in the hierarchy was a repeatable panel
20126             */
20127            var bindRefToSomMapper = function (node, map, jsonp) {
20128                var path, bindref;
20129                if (node.bindRef) {
20130                    if (node.repeatable) { // current node is a repeatable panel
20131                        if (jsonp) { // some ancestor panel in the hierarchy was a repeatable panel
20132                            path = jsonp + "/" + node.bindRef.split("/").slice(-1)[0] + "/" + node.index;
20133                            bindref = path;
20134                        } else { // current node is the first repeatable panel in the hierarchy
20135                            path = node.bindRef + "/" + node.index;
20136                            bindref = path;
20137                        }
20138                    } else {
20139                        if (jsonp) { // some panel in the upper level was a repeatable panel
20140                            path = jsonp + "/" + node.bindRef.split("/").slice(-1)[0];
20141                            bindref = path;
20142                        } else { // no repeatable panel till now
20143                            bindref = node.bindRef;
20144                        }
20145                    }
20146                    map[bindref] = node.somExpression;
20147                }
20148
20149                if (node._children) {
20150                    node._children.forEach(function (element) {
20151                        bindRefToSomMapper(element, map, path);
20152                    });
20153                }
20154            };
20155            var jsonp;
20156
20157            // since we support lazy-loading for a fragment upto only two level deep, the immediate parent panel
20158            // of a lazy-loaded fragment can atmost be a repeatable panel. so we only check the repeatability for the parent
20159            if (node && node.parent && node.parent.repeatable && node.parent.bindRef) {
20160                jsonp = node.parent.bindRef + "/" + node.parent.index;
20161            }
20162
20163            if (!node) {
20164                node = window.guideBridge._guide;
20165            }
20166
20167            if (window.guideBridge.isGuideLoaded()) {
20168                if (!window.guideBridge._guide._bindRefMap) {
20169                    window.guideBridge._guide._bindRefMap = {};
20170                }
20171                bindRefToSomMapper(node, window.guideBridge._guide._bindRefMap, jsonp);
20172            }
20173        },
20174
20175        SELECTOR_FORM_CONTAINER : "#guideContainerForm",
20176
20177        THANK_YOU_OPTION : {
20178            PAGE : "page",
20179            MESSAGE : "message"
20180        },
20181
20182        addDorDownloadLink: function (thankYouContent, dorUri, isSubmisionId) {
20183            if(isSubmisionId) {
20184                var guidePath = window.guideBridge.getGuidePath();
20185            	var contextPath = window.guideBridge._getUrl(guidePath);
20186                dorUri = contextPath + ".af.dor.pdf?submissionId="+dorUri;
20187            }
20188            var dorVariable = "$%7BAF_DocumentOfRecord%7D";
20189            if (thankYouContent && thankYouContent.indexOf(dorVariable) !== -1) {
20190                var tempElement = document.createElement("div");
20191                tempElement.innerHTML = thankYouContent;
20192                var anchorTags = tempElement.querySelectorAll("a");
20193                for (var i=0; i<anchorTags.length; i++) {
20194                    var tag = anchorTags.item(i);
20195                    if(tag.getAttribute("href") == dorVariable) {
20196                        tag.setAttribute("href", dorUri);
20197                        tag.setAttribute("download", tag.getAttribute("title"));
20198                        thankYouContent = tempElement.innerHTML;
20199                    }
20200                }
20201            }
20202            return thankYouContent;
20203        },
20204        /*
20205         *  default Submit Success Handler.
20206         *  This function handles the Thank You Page/Message
20207         */
20208        _defaultSubmitSuccessHandler : function (successPayload) {
20209            if (successPayload) {
20210                if (successPayload.thankYouOption === this.THANK_YOU_OPTION.MESSAGE) {
20211                    if ( FD.isToggleEnabled("FT_CQ-4325048") || FD.isToggleEnabled("FT_CQ-4340778")) {
20212                        successPayload.thankYouContent = this.addDorDownloadLink(successPayload.thankYouContent, successPayload.dorUri, FD.isToggleEnabled("FT_CQ-4340778"));
20213                    }
20214                    var tyMessage = $("<div class='tyMessage'>" + successPayload.thankYouContent + "</div>");
20215                    $(this.SELECTOR_FORM_CONTAINER).replaceWith(tyMessage);
20216                    tyMessage.attr({'tabindex': '-1',
20217                                   'role': 'alertdialog'});
20218                    tyMessage.focus();
20219                } else if (successPayload.thankYouOption === this.THANK_YOU_OPTION.PAGE) {
20220                    window.location.href = encodeURI(successPayload.thankYouContent);
20221                }
20222            }
20223        },
20224
20225        _defaultSaveSuccessHandler : function (successPayload) {
20226            alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings["formSavedMessage"]));
20227        },
20228
20229        _defaultSaveErrorHandler : function () {
20230            alert(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings["formSaveError"]));
20231        },
20232
20233        // This function gets the relative path of the file.
20234        // Suppose the component Name is attachment and the file name is a.jpg,
20235        // then it will return "attachment/a.jpg" as the path
20236        _getRelativeFilePath : function (fileName) {
20237            var relPath = fileName;
20238            if (fileName.indexOf("/") !== -1) {
20239                var splitPath = fileName.split("/");
20240                if (splitPath.length > 2) {
20241                    relPath = splitPath[splitPath.length - 2] + "/" + splitPath[splitPath.length - 1];
20242                }
20243            }
20244            return relPath;
20245        },
20246
20247        // We do not need to validate if options.validate = false.
20248        // This function makes sure that validations are not performed when validate flag is false.
20249        // Validation is performed in all the other cases.
20250        _performConditionalValidation : function (options) {
20251            if (getOrElse(options, "validate", true)) {
20252                return guideBridge.validate(null, null, true, false);
20253            }
20254            return true;
20255        },
20256
20257        /**
20258         * This API returns the HTML content of another Adaptive Form and optionally load the Form inside an HTML
20259         * element
20260         *
20261         * The {@link GuideResultObject#data|data} property of the result passed to success handler will contain the HTML of
20262         * the Form
20263         * @summary load an Adaptive Form given its path
20264         * @param {object} options object to pass to the API
20265         * @param {function} [options.success] callback which receives the result of the API
20266         * in case of success.
20267         * {@link GuideResultObject#errors|errors} property as false.
20268         * @param {function} [options.error] callback which receives the result of the API in
20269         * case of failure.
20270         * {@link GuideResultObject#errors|errors} property as true.
20271         * @param {object} [options.context] _this_ object inside the _success_ and _error_ callback will point to this
20272         * object
20273         * @param {string} options.path Path of the Adaptive Form whose HTML is required. If sever is running at a
20274         * context path, this parameter must have the context path
20275         * @param {string} [options.dataRef] URL of the resource that returns the XML. The protocol of the URL must
20276         * match the supported URL protocols
20277         * @param {string} [options.containerSelector] jquery Selector of the HTML element where to insert the HTML
20278         * of the form.
20279         * @method
20280         * @memberof GuideBridge
20281         * @since 6.1 FP1
20282         * @instance
20283         * @example
20284         * guideBridge.loadAdaptiveForm({
20285         *      success : function (guideResultObj) {console.log("html is " + guideResultObj.data)},
20286         *      error : function (guideResultObj) { //log errors},
20287         *      dataRef : "http://url/of/the/dataRef",
20288         *      path : "/contextpath/content/dam/formsanddocuments/form1"
20289         * })
20290         * @see {@link https://api.jquery.com/category/selectors/|jQuery selectors}
20291         * @see <a href="#guidebridge-api-usage" >GuideBridge API Usage</a>
20292         */
20293        loadAdaptiveForm : function (options) {
20294            if (options && options.path) {
20295                // Let's covert the adaptive form asset path or af path
20296                // @todo: add notion of channel type in the options to load adaptive form
20297                var path = options.path.replace(FM_DAM_ROOT, FM_AF_ROOT);
20298                path += "/jcr:content/guideContainer.html";
20299                $.ajax({
20300                    url : path,
20301                    type : "GET",
20302                    data : {
20303                        // lets set the wcmmode to disabled
20304                        wcmmode : "disabled",
20305                        // Set the data reference
20306                        "dataRef" : options.dataRef
20307                    },
20308                    async : false,
20309                    success : function (data) {
20310                        // Get the container selector and do a replaceWith HTML
20311                        // not using jquery since jquery create a separate array objects for script, link etc
20312                        if (options.containerSelector) {
20313                            //NOCHECKMARX - data is coming from serverside preventing Reflective XSS All Clients.
20314                            $(options.containerSelector).html(data);
20315                        }
20316                        var guideResultObject = new GuideResultObject();
20317                        // data would here be html
20318                        guideResultObject.data = data;
20319                        guideResultObject.completed = true;
20320                        if (options.success && _.isFunction(options.success)) {
20321                            options.success.call(options.context, guideResultObject);
20322                        }
20323                    },
20324                    error : function (data) {
20325                        var guideResultObject = new GuideResultObject();
20326                        // data is an object containing xhr request, status and error
20327                        guideResultObject.data = data;
20328                        guideResultObject.completed = false;
20329                        guideResultObject.addMessage(2, "Error in getting HTML of Adaptive Form: " + options.path, "");
20330                        if (options.error && _.isFunction(options.error)) {
20331                            options.error.call(options.context, guideResultObject);
20332                        }
20333                    }
20334                });
20335            } else {
20336                if (typeof(console) !== "undefined") {
20337                    console.log("Path of Adaptive Form not specified to loadAdaptiveForm API");
20338                }
20339            }
20340        },
20341
20342        /**
20343         * Unloads the Form loaded using the {@link GuideBridge#loadAdaptiveForm|loadAdaptiveForm} API
20344         * @summary Unloads an adaptive Form from the browser, removing all the existing event listeners, data, html.
20345         * @param containerSelector jQuery Selector of the container, which contains the HTML of the Adaptive Form
20346         * @method
20347         * @memberof GuideBridge
20348         * @since 6.1 FP1
20349         * @instance
20350         * @see {@link https://api.jquery.com/category/selectors/|jQuery selectors}
20351         */
20352        unloadAdaptiveForm : function (containerSelector) {
20353            guidelib.util.GuideUtil._unloadAdaptiveForm(containerSelector);
20354        },
20355
20356        /**
20357         * Disables all the fields and global toolbar
20358         * @private
20359         */
20360        _disableForm : function () {
20361            var rootPanel = guideBridge.resolveNode("guide[0].guide1[0].guideRootPanel[0]"),
20362                globalToolbar = guideBridge.resolveNode("guide[0].guide1[0].toolbar[0]");
20363
20364            // The following API disables the loaded fields
20365            rootPanel.disableAllFields();
20366            // The following API disables the form toolbar
20367            if (globalToolbar) {
20368                globalToolbar.disableAllFields();
20369            }
20370        },
20371
20372        /**
20373         * @summary Disables the adaptive form, i.e. it disables all the fields and buttons, including toolbar's button
20374         * @method
20375         * @memberof GuideBridge
20376         * @since 6.3
20377         */
20378        disableForm : function () {
20379            guideBridge._disableForm();
20380            //Listening on guideBridge for "elementLazyLoaded" event to disable lazily loaded fields
20381            guideBridge.on("elementLazyLoaded", guideBridge._disableForm);
20382        },
20383
20384        _playGuideJson : function (options) {
20385            this._guide.setGuideState(guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_PROGRESS);
20386            /*
20387             * no need to check here since merged json will not have xfaState if
20388             * xdp is invalid
20389             */
20390            if (this._isXfaGuide() && options.guideState.xfaState && options.guideState.xfaState.xfaDom) {
20391                var that = this;
20392                window.formBridge.restoreFormState({
20393                    formState : options.guideState.xfaState,
20394                    context : this,
20395                    //NOCHECKMARX - This is error callback to be provided by the user of this API.
20396                    error : options.error || defaultErrorHandler,
20397                    success : function () {
20398                        that._playNonXfaJson(options);
20399                    }
20400                });
20401            } else {
20402                this._playNonXfaJson(options);
20403            }
20404        },
20405
20406        _playNonXfaJson : function (options) {
20407            // try to  get xml-s from restore state 1st as they will be more relevant than the prefill state
20408            var xmlStr = getOrElse(options, "guideState.guideLiveData", null)
20409                    || getOrElse(options, "guideState.guidePrefillXml", null),
20410                xfaXmlStr = getOrElse(options, "guideState.xfaState.currentContext.data", null)
20411                    || JSON.parse(getOrElse(options, "guideState.xfaState.xfaRenderContext", "{}")).data,
20412                jsonStr = getOrElse(options, "guideState.guidePrefillJson", null);
20413            if (xmlStr || xfaXmlStr) {
20414                this._guide.internal.liveDataUtils.initLiveData(xmlStr, xfaXmlStr,
20415                    _.isString(this._guide.xdpRef), _.isString(this._guide.xsdRef),
20416                    this._guide.getAttribute("xsdRootElement"));
20417                this._guide.internal.liveModel.prefillCrossFragFields(this._guide);
20418                this._guide.internal.liveDataUtils.dropXfaXml();
20419            } else if (jsonStr) {
20420                this._guide.internal.liveDataUtils.initLiveData(jsonStr, this._guide.runtime.guideContext);
20421            } else {
20422                this._guide.internal.liveDataUtils.initLiveData(null, null,
20423                    _.isString(this._guide.xdpRef), _.isString(this._guide.xsdRef),
20424                    this._guide.getAttribute("xsdRootElement"));
20425            }
20426
20427            // If the restore state is not stored in local storage,then use it from the json passed from the server
20428            if (options.guideState.guideDom) {
20429                this._guide.playJson(options.guideState.guideDom, options.attachments);
20430            }
20431            if (options.guideState.unboundDataMap && options.guideState.unboundDataMap.data) {
20432                this.visit(function (node) {
20433                    if ((node instanceof guidelib.model.Field || node instanceof guidelib.model.GuideCompositeField)
20434                        && !node.getAttribute("bindRef") && options.guideState.unboundDataMap.data[node.name]) {
20435                        var nodeValue = options.guideState.unboundDataMap.data[node.name];
20436                        //If the xml had empty tag, an empty object will come in the map, so set to null.
20437                        if (_.isObject(nodeValue) && _.isEmpty(nodeValue)) {
20438                            node._setGuideValue(null);
20439                        } else {
20440                            node._setGuideValue(nodeValue);
20441                        }
20442
20443                        if (node.className === "guideRadioButton") {
20444                            node.prevOnItem = node.getSelectedIndex(node.jsonModel._value);
20445                        }
20446                    }
20447                });
20448            }
20449            this._guide.setGuideState(guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_COMPLETE);
20450            this._guide.prepare();
20451
20452            if (options.success) {
20453                options.success.call(this);
20454            }
20455        },
20456
20457        _postExternalMessage : function (message) {
20458            if (this.userConfig["postExternalMessageConfig"] && _.isFunction(this.userConfig["postExternalMessageConfig"]["postExternalHandler"])) {
20459                var externalHandler = this.userConfig["postExternalMessageConfig"]["postExternalHandler"];
20460                externalHandler(message);
20461            }
20462        },
20463
20464        _isXfaGuide : function () {
20465            if (this._guide.xdpRef) {
20466                return true;
20467            } else {
20468                return false;
20469            }
20470        },
20471        _readRuntimeLocale : function (runtimeLocale) {
20472            return this.customContextProperty("runtimeLocale", runtimeLocale);
20473
20474        },
20475
20476        /*
20477         * checks whether xdp present in Adaptive Form is valid or not
20478         * This is verified by checking the xdpRef property in guideContext
20479         */
20480        _isValidXFAGuide : function () {
20481            return !_.isUndefined(this._guide.runtime.guideContext.xdpRef);
20482        },
20483
20484        _isEditDesignMode : function () {
20485            if (window.CQ && window.CQ.WCM && (window.CQ.WCM.isEditMode() || window.CQ.WCM.isDesignMode())) {
20486                return true;
20487            } else {
20488                return false;
20489            }
20490        },
20491
20492        /**
20493         * @private
20494         */
20495        _getUUID : function () {
20496            if (this._formInstanceUUID) {
20497                return this._formInstanceUUID;
20498            }
20499            //Generate the UUID for the form instance on client side
20500            this._formInstanceUUID = guideBridge._produceUUID();
20501            return this._formInstanceUUID;
20502        },
20503
20504        /**
20505         * This will produce new UUID
20506         * @returns {string}
20507         * @private
20508         */
20509        _produceUUID : function () {
20510            var uuid = $('div.guideContainerWrapperNode').data("tmproot"),
20511                uuidSuffix = Math.floor((Math.random() * 10000) + 1),
20512                uuidCurrentTime = new Date().getTime();
20513            return uuid + "_" + uuidCurrentTime + uuidSuffix;
20514        },
20515
20516        /**
20517         * Signature of the callback for the GuideBridgeEvent Listener. It must be passed as handler in the
20518         * {@link GuideBridge#on|on} API.
20519         * @callback GuideBridge~GuideBridgeEventCallback
20520         * @param {jQuery.Event} event jQuery Event Object with target property being the instance of GuideBridge
20521         * @param {Object} payload Payload containing extra information in the API
20522         * @see {@link http://api.jquery.com/category/events/event-object/|jQuery.Event}
20523         * @since 6.0
20524         */
20525        /**
20526         * The API can be used to add an event listener for events triggered by GuideBridge object
20527         *
20528         * @summary add a listener on a GuideBridge Event.
20529         * @param eventName {string} name of the event for which listener has to be added. It must be one of the
20530         * following events
20531         * * bridgeInitializeComplete
20532         * * elementEnableChanged
20533         * * elementFocusChanged
20534         * * elementHelpShown
20535         * * elementLazyLoaded
20536         * * elementNavigationChanged
20537         * * elementValidationStatusChanged
20538         * * elementValueChanged
20539         * * elementVisibleChanged:
20540         * * guideAutoSaveStart
20541         * * submitStart
20542         * * validationComplete
20543         * @param {function} handler callback to be invoked whenever the event is triggered. The signature of the
20544         * callback is {@link GuideBridge~GuideBridgeEventCallback|GuideBridgeEventCallback}
20545         * @param {object} [context] The _this_ object in the _handler_ will point to _context_
20546         *
20547         * @method on
20548         * @memberof GuideBridge
20549         * @instance
20550         * @since 6.0
20551         */
20552        on : function (eventName, handler, context) {
20553            this._$target.on(eventName, handler, context);
20554        },
20555
20556        /**
20557         * Unregister the event registered using the {@link GuideBridge#on|on} function
20558         *
20559         * @param eventName {string} name of the event to un-register.
20560         * @param [selector] {string} selector which should match the one originally passed to guideBridge's on() while registering handlers
20561         * @param [handler] {function} handler which needs to un-registered. If not provided all the event listeners
20562         * will be unregistered
20563         *
20564         * @method off
20565         * @memberof GuideBridge
20566         * @instance
20567         * @since 6.0
20568         */
20569
20570        off : function (eventName, selector, handler) {
20571            this._$target.off(eventName, selector, handler);
20572        },
20573
20574        /**
20575         * Internal API
20576         * @param extraParamerts
20577         * @param eventName
20578         * @private
20579         */
20580        trigger : function (eventName, extraParamerts) {
20581            this._$target.trigger(eventName, extraParamerts);
20582        },
20583
20584        /**
20585         * If the name of the file attachments have to be made unique then the
20586         * vaule of this function would be true else false
20587         * @returns {*}
20588         * @private
20589         */
20590        _makeFileNameUnique : function () {
20591            if (this._guide && this._guide.runtime && this._guide.runtime.guideContext) {
20592                return this._guide.runtime.guideContext.makeFileNameUnique;
20593            }
20594        },
20595        /*this function is used to mince out
20596         * file attachmenemts name and dom in case of
20597         * anonymous user
20598         * */
20599        _getFileNameFileDomMap : function () {
20600            var fileAttachmentsList = this._getFileAttachmentsList();
20601            return this._juiceOutNameAndFileDomMap(fileAttachmentsList);
20602        },
20603
20604        /**
20605         * Returns a list of file attachment wrapper object represeting all file binaries
20606         * @returns reference of {@link guidelib.model.FileAttachmentWrapper}
20607         * @method
20608         * @memberof GuideBridge
20609         * @since FaaCS
20610         * @instance
20611         */
20612        getFileAttachmentWrapper : function () {
20613            var fileNameDomBindRefMap = this._getFileNameFileDomMap(),
20614                attachments = [],
20615                fileDoms = fileNameDomBindRefMap.fileDom,
20616                fileNames = fileNameDomBindRefMap.fileName,
20617                bindRefs = fileNameDomBindRefMap.fileBindRef,
20618                contentTypes = fileNameDomBindRefMap.fileContentType,
20619                _getFileName = function (fileName, componentName) {
20620                    // if file name contains component name
20621                    if (fileName.indexOf(componentName) !== -1) {
20622                        return fileName.replace(componentName + "/", "");
20623                    } else if (fileName.indexOf("/") !== -1) {
20624                        // if file name is a URL
20625                        return fileName.substring(fileName.lastIndexOf('/') + 1);
20626                    }
20627                };
20628
20629            var fileNamesIndex;
20630            for (fileNamesIndex = 0; fileNamesIndex < fileNames.length; fileNamesIndex++) {
20631                // multiple files inside one filedom element & draft save case is handled.
20632                var currentFileNames = fileNames[fileNamesIndex].split("\n");
20633                for (var fileIndex = 0; fileIndex < currentFileNames.length; fileIndex++) {
20634                    if (fileDoms[fileNamesIndex] && !_.isString(fileDoms[fileNamesIndex]) && fileDoms[fileNamesIndex].length > 0) {
20635                        // append each file of input file element
20636                        attachments.push(new guidelib.model.FileAttachmentWrapper({
20637                            name : _getFileName(currentFileNames[fileIndex], bindRefs[fileNamesIndex]),
20638                            data : fileDoms[fileNamesIndex][0].files[fileIndex],
20639                            contentType : fileDoms[fileNamesIndex][0].files[fileIndex].type,
20640                            bindRef : bindRefs[fileNamesIndex]
20641                        }));
20642                    } else if (currentFileNames[fileIndex]) {
20643                        //handle draft save scenario when fileDoms[fileNamesIndex] is null & currentFileNames[fileIndex] is a url
20644                        attachments.push(new guidelib.model.FileAttachmentWrapper({
20645                            name : _getFileName(guideBridge._getRelativeFilePath(currentFileNames[fileIndex]), bindRefs[fileNamesIndex]),
20646                            data : fileDoms[fileNamesIndex],
20647                            contentType : contentTypes[fileNamesIndex],
20648                            bindRef : bindRefs[fileNamesIndex]
20649                        }));
20650
20651                    }
20652                }
20653            }
20654            return attachments;
20655        },
20656
20657        /**
20658         * Returns the file attachment name and dom (input type=file) element
20659         * The returned object contains a list of file Doms and a list of corresponding file Names.
20660         * If the file is already uploaded, then the file DOM is null and file Name contains the URL.
20661         * @param fileAttachmentsList object list of file attachment models
20662         * @returns {{fileName: Array, fileDom: Array}}
20663         * @private
20664         */
20665        _juiceOutNameAndFileDomMap : function (fileAttachmentsList) {
20666            var fileDoms = [],
20667                fullFileNames = [],
20668                fullContentTypes = [],
20669                fileBindRefs = [],
20670                fileContentTypes = [],
20671                fileCount = 0,
20672                loadedFileDoms = [],
20673                loadedBindRefs = [],
20674                loadedContentTypes = [],
20675                loadedFileNames = [];
20676
20677            _.each(fileAttachmentsList, function (fileAttachmentModel, index) {
20678                var fileName = fileAttachmentModel._getFileAttachmentNames(),
20679                    fileAttachmentModelValue = fileAttachmentModel.value,
20680                    effectiveBindRef = fileAttachmentModel._getEffectiveBindRef(),
20681                    fileNameList = fileName; // even in case of makeFileNameUnique context set, fileName has the correct unique value
20682                if (fileNameList) {
20683                    var fileNames = fileNameList.split("\n");
20684                    var fileList = $.extend(true, [], fileAttachmentModel.fileList);
20685                    var fileNamesIndex = 0;
20686
20687                    _.each(fileList, function (inputFileDOM, currIndex) {
20688                        var fileNamesOfFileDom = null;
20689
20690                        // case: if there is a file dom
20691                        if (!_.isString(inputFileDOM)) {
20692                            _.each(inputFileDOM[0].files, function (file) {
20693                                var fileName = fileNames[fileNamesIndex++];
20694                                if (fileName) {
20695                                    if (fileNamesOfFileDom) {
20696                                        fileNamesOfFileDom += "\n" + fileAttachmentModel.name + "/" + fileName;
20697                                    } else {
20698                                        fileNamesOfFileDom = fileAttachmentModel.name + "/" + fileName;
20699                                    }
20700                                }
20701                            });
20702                            if (fileNamesOfFileDom != null) {
20703                                // Check if the value exist in the file, this is done because in IE9 and IE10 the list
20704                                // will have an extra empty dom
20705                                if ($(inputFileDOM).val().length > 0) {
20706                                    $(inputFileDOM).attr('name', fileNamesOfFileDom);
20707                                    loadedFileNames[fileCount] = fileNamesOfFileDom;
20708                                    loadedBindRefs[fileCount] = effectiveBindRef;
20709                                    // since the api is internal, we are not setting this
20710                                    loadedContentTypes[fileCount] = null; // we don't set "\n" separated content type here
20711                                    loadedFileDoms[fileCount++] = $(inputFileDOM);
20712                                }
20713                            }
20714                        } else {
20715                            // these values are nothing but field present as part of guidelib.model.FileAttachmentWrapper
20716                            // @note: to minimize the refactoring, not reusing the same model
20717                            // since there is no file dom in case of draft reload, make it null
20718                            loadedFileNames[fileCount] = fileAttachmentModel.name + "/" + fileNames[currIndex];
20719                            loadedBindRefs[fileCount] = effectiveBindRef;  // we add effective bindRef here
20720                            loadedContentTypes[fileCount] = fileAttachmentModel._getContentType(fileList[currIndex]);  // we add effective bindRef here
20721                            loadedFileDoms[fileCount++] = fileList[currIndex]; // we add the file URL in fileDom
20722                            fileNamesIndex++;
20723                        }
20724                    }, this);
20725
20726                }
20727            }, this);
20728
20729            // create the dom and name map for lazy file upload components as well
20730            var lazyFileMap = this._guide.internal.liveDataUtils._getLazyAttachmentMap(),
20731                lazyFileDom = [],
20732                lazyFileBindRef = [],
20733                lazyFileContentType = [],
20734                lazyFileName = [];
20735            _.each(lazyFileMap, function (mapObject, key) {
20736                var fileList = mapObject.fileList;
20737                var fileUploadValue = mapObject.value.split("\n");
20738                var fileUploadBindRef = mapObject.bindRef;
20739                var fileNames = mapObject.fileNames.split("\n");
20740                var fileNamesIndex = 0;
20741                _.each(fileList, function (value) {
20742                    if (!_.isString(value)) {
20743                        var fileNamesOfFileDom = null;
20744                        _.each(value[0].files, function (file) {
20745                            var fileName = fileUploadValue[fileNamesIndex++];
20746                            if (fileName) {
20747                                var fullName = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + fileName;
20748                                if (fileNamesOfFileDom) {
20749                                    fileNamesOfFileDom += "\n" + fullName;
20750                                } else {
20751                                    fileNamesOfFileDom = fullName;
20752                                }
20753                            }
20754                        });
20755
20756                        lazyFileDom.push(value);
20757                        lazyFileName.push(fileNamesOfFileDom);
20758                    } else {
20759                        var fullName = guidelib.util.GuideUtil.guideSomToComponentName(key) + "/" + fileNames[fileNamesIndex];
20760                        lazyFileDom.push(value);
20761                        lazyFileName.push(fullName);
20762                        fileNamesIndex++;
20763                    }
20764                    lazyFileBindRef.push(fileUploadBindRef);
20765                    lazyFileContentType.push(null); // todo: check if this use-case would ever hit
20766                });
20767            });
20768
20769            // concatenate the arrays for loaded and unloaded file doms and names
20770            fileDoms = loadedFileDoms.concat(lazyFileDom);
20771            fullFileNames = loadedFileNames.concat(lazyFileName);
20772            fileBindRefs = loadedBindRefs.concat(lazyFileBindRef);
20773            fileContentTypes = loadedContentTypes.concat(lazyFileContentType);
20774
20775            return {
20776                "fileName" : fullFileNames,
20777                "fileDom" : fileDoms,
20778                "fileBindRef" : fileBindRefs,
20779                "fileContentType" : fileContentTypes
20780            };
20781        },
20782
20783        setValidationContext : function (context) {
20784            var ec = guidelib.util.ErrorConstants;
20785            if (typeof ec[context] === "number") {
20786                var nContext = ec[context];
20787                if (nValidationContext < nContext) {
20788                    nValidationContext = nContext;
20789                    sValidationContext = context;
20790                }
20791            }
20792        },
20793
20794        unsetValidationContext : function (context) {
20795            if (context === sValidationContext) {
20796                nValidationContext = 0;
20797                sValidationContext = "";
20798            }
20799        },
20800
20801        getValidationContext : function () {
20802            return sValidationContext;
20803        },
20804
20805        /**
20806         * @summary Enable/Disable the swipe gesture for navigation on touch devices.
20807         * @param swiptLeft boolean flag to enable(true)/disable(false) the swipe left gesture to perform next item navigation
20808         * @param swipeRight boolean flag to enable(true)/disable(false) the swipe right gesture to perform previous item navigation
20809         * @method
20810         * @memberof GuideBridge
20811         * @instance
20812         * @since 6.3
20813         */
20814        enableSwipeGesture : function (swiptLeft, swipeRight) {
20815            $guideWrapperNode = $('.guideContainerWrapperNode');
20816            $guideWrapperNode.off('swipeleft', window.guideBridge._performItemDeepNavigationNext);
20817            $guideWrapperNode.off('swiperight', window.guideBridge._performItemDeepNavigationPrevious);
20818            if (swiptLeft) {
20819                $guideWrapperNode.on('swipeleft', window.guideBridge._performItemDeepNavigationNext);
20820            }
20821            if (swipeRight) {
20822                $guideWrapperNode.on('swiperight', window.guideBridge._performItemDeepNavigationPrevious);
20823            }
20824        },
20825
20826        /**
20827         * Enable the next item navigation (deep) using swipe left gesture
20828         * @private
20829         */
20830        _performItemDeepNavigationNext : function () {
20831            window.guideBridge.setFocus({
20832                somExpression : null,
20833                focusOption : 'nextItemDeep',
20834                runCompletionScript : true,
20835                skipFieldFocus : true
20836            });
20837        },
20838
20839        /**
20840         * Enable the previous item navigation (deep) using swipe right gesture
20841         * @private
20842         */
20843        _performItemDeepNavigationPrevious : function () {
20844            window.guideBridge.setFocus({
20845                somExpression : null,
20846                focusOption : 'prevItemDeep',
20847                runCompletionScript : true,
20848                skipFieldFocus : true
20849            });
20850        },
20851
20852        /**
20853         * Update the model popup that appears at click of file attachment listing button
20854         * This function is currently run of the clickExp of fileAttachmentListingButton
20855         * @param node
20856         * @private
20857         */
20858        _updateFileListing : function (node) {
20859            var somExpression = node.somExpression,
20860                viewOfListingButton = guideBridge._guideView.getView(somExpression);
20861            viewOfListingButton._clearFileListing();
20862            guideBridge.visit($.proxy(viewOfListingButton._updateFileListing, viewOfListingButton));
20863
20864        },
20865
20866        registerPanelProvider : function (panelProvider) {
20867            var resultObj = new GuideResultObject();
20868            if (this.panelProvider == null) {
20869                resultObj.data = panelProvider;
20870                this.panelProvider = panelProvider;
20871                return resultObj;
20872            }
20873            resultObj.addMessage(2, "registrationError: PanelProvider already registered", "");
20874            return resultObj;
20875        }
20876    });
20877
20878    window.guideBridge = new GuideBridge();
20879    window.guideBridge._$target = $(window.guideBridge);
20880    window.guideBridge.on("af.invisibleMandatoryRecaptchaInitialization", function (event, data) {
20881        var model = data.jsonModel.target.jsonModel;
20882        var formContainerSelector = FD.isToggleEnabled("FT_FORMS-11858") ? guidelib.util.GuideUtil.GUIDE_CONTAINER_FORM_CLASS : ".guideContainer,.aemformcontainer";
20883        if(FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)) {
20884            $(formContainerSelector).append('<div id="captchaInvisible"></div>');
20885            var captchaInvisibleElement = $("#captchaInvisible"), captchaElement = $("[data-captchaservice]");
20886
20887            captchaInvisibleElement.attr({
20888                "modelId" : model.id || model.templateId,
20889                "af-recaptcha-execute" : "",
20890                "data-locale" : captchaElement.attr("data-locale")
20891            });
20892
20893            if (model.captchaService === 'turnstile') {
20894                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.CaptchaUtil.captchaExecution);
20895                var turnstileParameters = {
20896                    'sitekey' : model.siteKey,
20897                    'theme' : model.theme || 'light',
20898                    'size' : model.size,
20899                    'language' : captchaElement.attr('data-locale'),
20900                    'execution' : 'execute'
20901                };
20902                guidelib.util.CaptchaUtil.renderCaptcha(captchaInvisibleElement, model,
20903                    model.clientJsUrl, 'cf-turnstile-response', turnstileParameters);
20904            } else if (model.captchaService === 'hcaptcha') {
20905                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.CaptchaUtil.captchaExecution);
20906                var hcaptchaParameters = {
20907                    'sitekey' : model.siteKey,
20908                    'theme' : model.theme || 'light',
20909                    'size' : model.size,
20910                };
20911                guidelib.util.CaptchaUtil.renderCaptcha(captchaInvisibleElement, model,
20912                    model.clientJsUrl, 'h-captcha-response', hcaptchaParameters);
20913            } else {
20914                captchaInvisibleElement.attr({
20915                    "data-externaldomain" : captchaElement.attr("data-externaldomain")
20916                });
20917                captchaInvisibleElement.on("recaptchaExecution", guidelib.util.RecaptchaUtil.recaptchaExecution);
20918                guidelib.util.RecaptchaUtil.renderRecaptcha(captchaInvisibleElement, model);
20919            }
20920        } else {
20921            $(formContainerSelector).append('<div id="recaptchaInvisible"></div>');
20922            var recaptchaInvisibleElement = $("#recaptchaInvisible"), captchaElement = $("[data-captchaservice]");
20923
20924            recaptchaInvisibleElement.attr({
20925                "modelId" : model.id || model.templateId,
20926                "af-recaptcha-execute" : "",
20927                "data-externaldomain" : captchaElement.attr("data-externaldomain"),
20928                "data-locale" : captchaElement.attr("data-locale")
20929            });
20930            recaptchaInvisibleElement.on("recaptchaExecution", guidelib.util.RecaptchaUtil.recaptchaExecution);
20931            guidelib.util.RecaptchaUtil.renderRecaptcha(recaptchaInvisibleElement, model);
20932        }
20933    });
20934
20935    try {
20936        var evnt = document.createEvent("CustomEvent");
20937        evnt.initCustomEvent("bridgeInitializeStart", true, true, {"guideBridge" : window.guideBridge});
20938        window.dispatchEvent(evnt);
20939    } catch (exception) {
20940        // written for env rhino to execute(for server side validation)
20941        // todo: once env rhino implements CustomEvent and initCustomEvent remove this
20942        // this._guide.logger().log(exception);
20943    }
20944
20945    if (!window.guideBridge.userConfig["postExternalMessageConfig"]) {
20946        if (window !== window.parent) {
20947            try {
20948                window.parent.document.getElementById(window.name);
20949                //We are here means no cross domain issue. So if user has not defined custom postExternalMessageConfig and
20950                // then we'll create one which would just send event on parent.
20951                window.guideBridge.registerConfig("postExternalMessageConfig", {
20952                    "postExternalHandler" : function (message) {
20953                        try {
20954                            var tmpEvent = document.createEvent("CustomEvent");
20955                            tmpEvent.initCustomEvent(message.name, true, true, message.data);
20956                            window.parent.dispatchEvent(tmpEvent);
20957                        } catch (exception) {
20958                            // written for env rhino to execute
20959                            //this._guide.logger().log(exception);
20960                        }
20961                    }
20962                });
20963            } catch (e) {
20964                //ignore the error
20965            }
20966        }
20967    }
20968
20969    window.guideBridge._postExternalMessage({
20970        name : "bridgeInitializeStart",
20971        data : {
20972            "guideBridge" : window.guideBridge
20973        }
20974    });
20975})($, _);
20976
20977/**
20978 * @package guidelib.model.DataNode
20979 * @version 0.0.1
20980 */
20981
20982(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
20983
20984    var LiveDataUtils = guidelib.model.LiveDataUtils = xfalib.ut.Class.extend({
20985
20986        constants : {
20987            SKELETON_XML : '<afData><afUnboundData><data/></afUnboundData><afBoundData><data xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/"/></afBoundData></afData>',
20988            SKELETON_JSON : '{"afData":{"afUnboundData":{"data":{}},"afBoundData":{"data":{}}}}',
20989            UNBOUND_SKELETON : '<unBound></unBound>',
20990            UNBOUND_JSON_SKELETON : '{"afUnboundData":{}}',
20991            INDEXED_XPATH_PAT : new RegExp(/\/[^\/]+\[\d+\]/),
20992            INDEXED_XPATH_PAT_JSON : new RegExp(/\/[^\/]+\/\d+/),
20993            XFA_DATA_NODE_ATTR_NAME : "xfa:dataNode",
20994            XFA_DATA_NODE_ATTR_VALUE : "dataGroup",
20995            UNKNOWN_XSD_ROOT_ELEMENT : "?",
20996            AF_ROOT_TAG : "afData",
20997            BOUND_TAG : "afBoundData",
20998            UNBOUND_TAG : "afUnboundData",
20999            XFA_TAG : "xfa",
21000            DATA_TAG : "data",
21001            BOUND_DATA_XPATH : "afBoundData/data",
21002            UNBOUND_DATA_XPATH : "afUnboundData/data",
21003            AF_DRAFT_TAG : "afSubmissionInfo/afDraft"
21004        },
21005
21006        initialize : function () {
21007            LiveDataUtils._super.initialize.call(this);
21008            this._boundDataRoot = null;
21009            this._unboundDataRoot = null;
21010            this._xfaDataRoot = null;
21011            this._fetchingClientSideData = false; // this state indicates that we are fetching client side data, its not use-case to fetch lazy data
21012            this.lazyAttachmentMap = {};
21013            this.attachments = [];
21014        },
21015
21016        /**
21017         * This function updates the lazy attachment Map from
21018         * the map passed
21019         * @param fileAttachmentMap
21020         * @private
21021         */
21022        _updateLazyAttachmentMap : function(fileAttachmentMap) {
21023            _.each(fileAttachmentMap, function (value, key) {
21024                this.lazyAttachmentMap[key] = {};
21025                this.lazyAttachmentMap[key].fileList = value.split("\n");
21026                this.lazyAttachmentMap[key].value = value;
21027            }, this);
21028        },
21029
21030        /**
21031         * This function updates the lazy attachment Map from the model.
21032         * It gets the value and fileList from the model and updates the map.
21033         * If the fileUpload component is not in a lazy panel then it removes
21034         * its entry form the map(if the entry is already there).
21035         * @param model
21036         * @private
21037         */
21038        _updateLazyAttachmentMapFromModel : function (model) {
21039            // add the component in the map only when its in a lazy panel
21040            // add the entry in map only when its not not empty
21041            if (model.parent._selfOrAncestorIsLazyReference && model.value && model.fileList && !this._fetchingClientSideData) {
21042                this.lazyAttachmentMap[model.somExpression] = {
21043                    value : model.value,
21044                    fileList : model.fileList,
21045                    bindRef : model._getEffectiveBindRef(),
21046                    fileNames : model._getFileAttachmentNames()
21047                };
21048            } else {
21049                if (this.lazyAttachmentMap[model.somExpression]) {
21050                    delete this.lazyAttachmentMap[model.somExpression];
21051                }
21052            }
21053        },
21054
21055        /**
21056         * This function returns the value in the lazy attachment map for the model.
21057         * It removes the entry from the map as well. This is required so that the map gets
21058         * updated with the new values when the panel unloads.
21059         * @param model
21060         * @returns {*}
21061         * @private
21062         */
21063        _getAttachmentDataForModel : function (model) {
21064            var effectiveBindRef = model._getEffectiveBindRef();
21065            if (model.somExpression && !_.isEmpty(this.lazyAttachmentMap)) {
21066                var data = this.lazyAttachmentMap[model.somExpression];
21067                delete this.lazyAttachmentMap[model.somExpression];
21068                return data;
21069            }
21070            if (effectiveBindRef && !_.isEmpty(this.attachments)) {
21071                var data = model._getCurrentFileAttachmentWrapper(this.attachments);
21072                return data;
21073            }
21074        },
21075
21076        _getLazyAttachmentMap : function () {
21077            return this.lazyAttachmentMap;
21078        },
21079
21080        dropXfaXml : function () {
21081            this._xfaDataRoot = null;
21082        },
21083
21084        // only called from test framework
21085        destroy : function () {
21086            this._liveDataDoc = null;
21087            this._boundDataRoot = null;
21088            this._unboundDataRoot = null;
21089            this._xfaDataRoot = null;
21090        },
21091
21092        initLiveData : function (prefillDataStr, xfaPrefillDataStr, isXdp, isXsd, xsdRootElement, attachments) {
21093            this.attachments = attachments;
21094        },
21095
21096        isLiveDataInitialized : function () {
21097        },
21098
21099        getLiveDataStr : function () {
21100        },
21101
21102        getLiveDataDoc : function () {
21103            return this._liveDataDoc;
21104        },
21105
21106        _isNonNaked : function () {
21107        },
21108
21109        _getNameAndIndex : function (xpathPart) {
21110        },
21111
21112        isIndexedPath : function (xpath) {
21113        },
21114
21115        _createElements : function (contextNode, xpathParts) {
21116        },
21117
21118        _createRepeatedElements : function (contextNode, xpathParts) {
21119        },
21120
21121        _createChildElement : function (parentElement, elemName) {
21122        },
21123
21124        _createAttributeNode : function (parentElement, attrName) {
21125        },
21126
21127        getContextNode : function (schemaPath, dataSection, createMissingNodes, lastNodeValue) {
21128        },
21129
21130        addIndexToPath : function (path, index) {
21131        },
21132
21133        _getElement : function (node, xpath, options) {},
21134
21135        hasChildNodes : function (node) {
21136        },
21137
21138        /**
21139         * Removes a child node from its parent
21140         * @param parentNode {Node} Parent Node from which to remove the child node
21141         * @param targetNode {String} Node name of the child to remove
21142         * @param index Index of the child node to remove
21143         */
21144        removeChild : function (parentNode, targetNodeName, index) {
21145        },
21146
21147        insertNode : function (parentNode, childNodeName, index) {
21148        },
21149
21150        _getDataContext : function (model, bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
21151            var bindRef = model.bindRef,
21152                liveDataUtils = this,
21153                xmlSec,
21154                indexedXpath;
21155
21156            if (model._isXfaNode()) {
21157                xmlSec = liveDataUtils.constants.XFA_TAG;
21158                indexedXpath = xfalib.ut.XMLUtils.dataSom2xpath(model.dataSom);
21159            } else if (_.isEmpty(bindRef)) {
21160                xmlSec = liveDataUtils.constants.UNBOUND_TAG;
21161                indexedXpath = unBound_indexedXpathSoFar + '/' + model.getAttribute("name").replace(/\s+/g, '');
21162                // use attr 'name' here, as schema might have an elem called 'name'
21163            } else {
21164                xmlSec = liveDataUtils.constants.BOUND_TAG;
21165
21166                var xpathMatch = liveDataUtils.getMatchingXpathHierarchy(bou
21166nd_indexedXpathSoFar, bindRef);
21167                if (xpathMatch.isCrossHierarchy) {
21168                    indexedXpath = bindRef;
21169                } else {
21170                    indexedXpath = bound_indexedXpathSoFar;
21171                    if (!_.isEmpty(xpathMatch.suffixParts)) {
21172                        indexedXpath += '/' + xpathMatch.suffixParts.join('/');
21173                    }
21174                }
21175            }
21176
21177            return {
21178                'xmlSec' : xmlSec,
21179                'indexedXpath' : indexedXpath
21180            };
21181        },
21182
21183        /**
21184         * return true if both xpath parts have same element name and indices
21185         * absence of index in the templateName is ignored
21186         * @param indexedName
21187         * @param templateName
21188         * @returns {boolean}
21189         * @private
21190         * @memberof LiveDataUtils
21191         */
21192        _cmpXpathParts : function (indexedName, templateName) {
21193          },
21194
21195        /**
21196         * get a partition of the matching xpath part hierarchy
21197         * the matching parts have same element names and agreeable indices
21198         * @param parentXpath
21199         * @param currentXpath
21200         * @returns {{prefixParts: Array, suffixParts: (*|Array.<T>|list), isCrossHierarchy: boolean}}
21201         * @memberof LiveDataUtils
21202         */
21203        getMatchingXpathHierarchy : function (parentXpath, currentXpath) {
21204            var isCrossHierarchy = false,
21205                prefixParts = [],
21206                suffixParts = this._sanitizedXpathParts(currentXpath);
21207
21208            _.find(this._sanitizedXpathParts(parentXpath), function (parentPart) {
21209                if (this._cmpXpathParts(parentPart, suffixParts[0])) {
21210                    prefixParts.push(parentPart);
21211                    suffixParts.shift();
21212                } else {
21213                    isCrossHierarchy = true;
21214                    return true;
21215                }
21216            }, this);
21217
21218            return {
21219                'prefixParts' : prefixParts,
21220                'suffixParts' : suffixParts,
21221                'isCrossHierarchy' : isCrossHierarchy
21222            };
21223        },
21224
21225        _getXpathContext : function (targetPanel) {
21226            var boundXpath = '',
21227                unBoundXpath = '',
21228                ancestors = [],
21229                panel = targetPanel.parent;
21230
21231            while (panel instanceof guidelib.model.GuidePanel) {
21232                if (panel._preserveLazyValue()) {
21233                    ancestors.unshift(panel);
21234                }
21235                panel = panel.parent;
21236            }
21237
21238            _.each(ancestors, function (ancestor) {
21239                var xmlContext = ancestor._syncModelAndData(boundXpath, unBoundXpath);
21240                boundXpath = xmlContext.bound;
21241                unBoundXpath = xmlContext.unBound;
21242            });
21243
21244            return {
21245                'bound' : boundXpath,
21246                'unBound' : unBoundXpath
21247            };
21248        },
21249
21250        _applyOnLiveData : function (action, targetPanel) {
21251            if (_.isString(targetPanel)) {
21252                targetPanel = guideBridge.resolveNode(targetPanel);
21253            }
21254
21255            if (targetPanel instanceof guidelib.model.GuidePanel) {
21256                var indexedXpathsFromRoot = targetPanel._guide().internal.liveDataUtils._getXpathContext(targetPanel);
21257                targetPanel[action](indexedXpathsFromRoot.bound, indexedXpathsFromRoot.unBound);
21258            } else {
21259                guideBridge._guide.rootPanel[action]('', '');
21260            }
21261        },
21262
21263        /**
21264         * will capture the currently loaded model hierarchy in a xml doc to be referred to later by lazily loaded panels
21265         * @private
21266         * @memberof LiveDataUtils
21267         */
21268        updateLiveData : function (targetPanel, fetchingClientSideData) {
21269            this._fetchingClientSideData = !_.isUndefined(fetchingClientSideData);
21270            this._applyOnLiveData('_updateLiveData', targetPanel);
21271            this._fetchingClientSideData = false;
21272        },
21273
21274        /**
21275         * will replay the model hierarchy from the live xml, for the supplied panel
21276         * @param targetPanel
21277         * @private
21278         * @memberof LiveDataUtils
21279         */
21280        playLiveData : function (targetPanel) {
21281            this._applyOnLiveData('_playLiveData', targetPanel);
21282        },
21283
21284        getListOfDirtyPanels : function (dataString) {
21285            return [];
21286        },
21287
21288        addDataNodeInfo : function (contextNode) {
21289        },
21290
21291        /**
21292         * Set the value of the node referred by xpath in the bounded/unbounded
21293         * section as specified by section. This optionally creates the data nodes
21294         * if they are not present
21295         * @param xpath
21296         * @param section
21297         * @param createMissingNodes
21298         * @param value
21299         */
21300        setDataValue : function (xpath, section, createMissingNodes, value) {
21301        },
21302
21303        /**
21304         * Set the rich text(html) value of the node referred by xpath in the bounded/unbounded
21305         * section as specified by section. This optionally creates the data nodes
21306         * if they are not present
21307         * @param xpath
21308         * @param xmlSection
21309         * @param createMissingNodes
21310         * @param value
21311         */
21312        setRichTextValue : function (xpath, xmlSection, createMissingNodes, value) {
21313            this.setDataValue(xpath, xmlSection, createMissingNodes, value);
21314        },
21315
21316        /**
21317         * Returns the value of the node referred by xpath in the bounded/unbounded
21318         * section as specified by section. It returns undefined if the node doesn't
21319         * exist
21320         * @param xpath
21321         * @param section
21322         */
21323        getDataValue : function (xpath, section) {
21324        },
21325
21326        _convertModelIndexToDataIndex : function (index) {
21327        },
21328
21329        getParentRef : function (path) {
21330        },
21331
21332        /**
21333         * returns the parent data node for the context specified by dataNodeContext
21334         * @param dataNodeContext {object} containing xpath and section
21335         * @param createIfMissing
21336         * @returns {*}
21337         * @param parentNodeValue
21338         */
21339        getParentDataNode : function (dataNodeContext, createIfMissing, parentNodeValue) {
21340            var parentRef = this.getParentRef(dataNodeContext.indexedXpath),
21341                parentNode;
21342            if (_.isEmpty(parentRef)) {
21343                parentNode = this.getContextNode("", dataNodeContext.xmlSec, false);
21344            } else {
21345                parentNode = this.getContextNode(parentRef, dataNodeContext.xmlSec, createIfMissing, parentNodeValue);
21346            }
21347            return parentNode;
21348        },
21349
21350
21351        /**
21352         * Insert submission Info in the data
21353         * @param submissionInfo {object} object containing the properties to be added as submission info in data
21354         */
21355        insertSubmissionInfo : function (submissionInfo) {
21356
21357        }
21358
21359    });
21360
21361}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
21362
21363/**
21364 * @package guidelib.model.DataNode
21365 * @version 0.0.1
21366 */
21367
21368(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
21369    var getOrElse = xfalib.ut.XfaUtil.prototype.getOrElse;
21370
21371    var LiveJsonUtils = guidelib.model.LiveJsonUtils = guidelib.model.LiveDataUtils.extend({
21372
21373        initialize : function () {
21374            LiveJsonUtils._super.initialize.call(this);
21375            this._liveDataDoc = null;
21376        },
21377
21378        initLiveData : function (prefillDataStr, guideContext) {
21379            LiveJsonUtils._super.initLiveData.apply(this, arguments);
21380            prefillDataStr = prefillDataStr || getOrElse(guideContext, "guidePrefillJson", null);
21381
21382            if (_.isString(prefillDataStr) && prefillDataStr.length > 0) {
21383                var prefillDataDoc = JSON.parse(prefillDataStr);
21384
21385                if (this._isNonNaked(prefillDataDoc)) {
21386                    // non naked json, assuming full hierarchy afdata/afbounddata/data
21387                    this._liveDataDoc = prefillDataDoc;
21388                    this._boundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.BOUND_DATA_XPATH);
21389                    this._unboundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.UNBOUND_DATA_XPATH);
21390
21391                } else {
21392                    // naked json start from prefill data root
21393                    this._boundDataRoot = prefillDataDoc;
21394                    this._unboundDataRoot = JSON.parse(this.constants.UNBOUND_JSON_SKELETON)[this.constants.UNBOUND_TAG];  // need this for unbound data fill across lazy
21395                    this._liveDataDoc = prefillDataDoc;
21396                }
21397            } else {
21398                // init default skeleton for no prefill cases
21399                this._liveDataDoc = JSON.parse(this.constants.SKELETON_JSON);
21400                this._boundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.BOUND_DATA_XPATH);
21401                this._unboundDataRoot = this._getElement(this._liveDataDoc.afData, this.constants.UNBOUND_DATA_XPATH);
21402            }
21403            if (this._boundDataRoot == null && this._isNonNaked(prefillDataDoc)) {
21404                this._liveDataDoc.afData.afBoundData = this._liveDataDoc.afData.afBoundData || {};
21405                this._liveDataDoc.afData.afBoundData.data = this._liveDataDoc.afData.afBoundData.data || {};
21406                this._boundDataRoot = this._liveDataDoc.afData.afBoundData.data;
21407            }
21408        },
21409
21410        /*
21411         * This API gets the element w.r.t to the node.
21412         * Eg - path is a/b/c, then it converts the path to a.b.c and then searches for c.
21413         */
21414        _getElement : function (node, path, options) {
21415            if (!(node instanceof Object)) {
21416                return null;
21417            }
21418
21419            if (_.isEmpty(path) || !_.isString(path)) {
21420                return node;
21421            }
21422            options = options || {};
21423            var index = options.index;
21424            var convertedPath = path.split('/').join('.');
21425            if (!(_.isUndefined(index) || _.isNull(index))) {
21426                convertedPath = convertedPath + "." + index;
21427            }
21428            return getOrElse(node, convertedPath, null);
21429        },
21430
21431        /**
21432         * This function checks if the data contains naked or non naked json
21433         * @returns {boolean} returns true if there exists a afData node inside data
21434         * @private
21435         * @memberof LiveJsonUtils
21436         * @param prefillData
21437         */
21438        _isNonNaked : function (prefillData) {
21439            prefillData = prefillData || this.getLiveDataDoc();
21440            if (prefillData) {
21441                return prefillData.hasOwnProperty("afData");
21442            } else {
21443                return false;
21444            }
21445        },
21446
21447        isLiveDataInitialized : function () {
21448            return (this.getLiveDataDoc() instanceof Object);
21449        },
21450
21451        getLiveDataStr : function () {
21452            if (this.isLiveDataInitialized()) {
21453                return JSON.stringify(this.getLiveDataDoc());
21454            } else {
21455                return '';
21456            }
21457        },
21458
21459        /*
21460         * This API will remove the spaces,"\" from the path.
21461         * It will return an array after splitting the path.
21462         * Eg - for a/0/b/c, it will return ["a/0","b","c"]
21463         */
21464        _sanitizedXpathParts : function (path) {
21465            var pathParts = (path || '').replace(/^\//, '').replace(/\s+/g, '');
21466            pathParts = this._splitForIndex(pathParts);
21467
21468            return _.filter(pathParts, function (xpathPart) {
21469                return this._getNameAndIndex(xpathPart) !== null;
21470            }, this);
21471        },
21472
21473        _splitForIndex : function (path) {
21474            var pathArray = [];
21475            var pathParts = path.split('/');
21476            for (var i = 0; i < pathParts.length; i++) {
21477                var str = pathParts[i];
21478                if ((i + 1) < pathParts.length && !isNaN(pathParts[i + 1]) && !_.isEmpty(pathParts[i + 1])) {
21479                    str = str + "/" + pathParts[i + 1];
21480                    i = i + 1;
21481                }
21482                pathArray.push(str);
21483            }
21484            return pathArray;
21485        },
21486
21487        /**
21488         * Returns the index associated with the pathPart.
21489         * Eg - if pathPart is 'a/1', then it returns {name : a, index : 1}
21490         * @param pathPart
21491         * @returns {*}
21492         * @private
21493         */
21494        _getNameAndIndex : function (pathPart) {
21495            if (pathPart) {
21496                var elName = pathPart.match(/^([^\s\/]+)(?:\/(\d+))?$/);  // match the whole string
21497                if (elName !== null) {
21498                    return {
21499                        name : elName[1],
21500                        index : elName[2] ? parseInt(elName[2]) : -1
21501                        // -1 index for depicting non repeatable element
21502                    };
21503                }
21504            }
21505            return null;
21506        },
21507
21508        _cmpXpathParts : function (indexedName, templateName) {
21509            if (indexedName && templateName) {
21510                var match1 = this._getNameAndIndex(indexedName),
21511                    match2 = this._getNameAndIndex(templateName);
21512                return !_.isEmpty(match1 && match2)
21513                    && match1.name === match2.name
21514                    && (match2.index === -1 || match1.index === match2.index);
21515            }
21516            return false;
21517        },
21518
21519        /**
21520         * This function gets or creates the node if its not there. The node can be any valid JSON Value
21521         * null, string, object, array, number, boolean.
21522         * @param schemaPath
21523         * @param dataSection
21524         * @param createMissingNodes
21525         * @param lastNodeValue
21526         * @returns {*}
21527         */
21528        getContextNode : function (schemaPath, dataSection, createMissingNodes, lastNodeValue) {
21529            var contextNode,
21530                baseContextNode,
21531                basePath = "",
21532                pathParts = this._sanitizedXpathParts(schemaPath);
21533            if (dataSection == this.constants.BOUND_TAG) {
21534                baseContextNode = this._boundDataRoot;
21535                if (this._isNonNaked(this._liveDataDoc)) {
21536                    basePath = "afData/" + this.constants.BOUND_DATA_XPATH + "/";
21537                }
21538            } else if (dataSection === this.constants.UNBOUND_TAG) {
21539                baseContextNode = this._unboundDataRoot;
21540                if (this._isNonNaked(this._liveDataDoc)) {
21541                    basePath = "afData/" + this.constants.UNBOUND_DATA_XPATH + "/";
21542                }
21543            }
21544            if (!_.isEmpty(pathParts)) {
21545                var path = (basePath + pathParts.join('/'));
21546
21547                // return baseContextNode for naked json. path can be "" only for naked json.
21548                if (path == "" && !this._isNonNaked(this._liveDataDoc)) {
21549                    return baseContextNode;
21550                }
21551
21552                contextNode = this._getElement(this._liveDataDoc, path);
21553                if (!contextNode && createMissingNodes) {
21554                    contextNode = this._createElements(baseContextNode, pathParts, lastNodeValue);
21555                }
21556            } else {
21557                contextNode = baseContextNode;
21558            }
21559            return contextNode;
21560        },
21561
21562        /**
21563         * This function creates the node at the path.
21564         *
21565         * @param contextNode
21566         * @param pathParts
21567         * @returns {*}
21568         * @private
21569         * @param lastNodeValue
21570         */
21571        _createElements : function (contextNode, pathParts, lastNodeValue) {
21572            if (!(contextNode instanceof Object)) {
21573                return null;
21574            }
21575
21576            if (_.isEmpty(pathParts)) {
21577                return contextNode;
21578            }
21579
21580            // recurse and create one level of tags at a time
21581            contextNode = this._createRepeatedElements(contextNode, pathParts, lastNodeValue);
21582            return contextNode;
21583        },
21584
21585        // it will always return the parent node after checking the last token
21586        _createRepeatedElements : function (contextNode, pathParts, lastNodeValue) {
21587            var childContextNode = contextNode,
21588                xpathPart = this._getNameAndIndex(pathParts[0]),
21589                elemName = xpathPart.name,
21590                index = xpathPart.index || 0,
21591                i,
21592                isLastToken = (pathParts.length == 1),
21593                elementNode = contextNode[elemName];
21594            // -1 signifies non repeating element
21595            if (index === -1) {
21596                if (elementNode == null) {
21597                    childContextNode = this._createChildElement(contextNode, elemName, isLastToken, lastNodeValue);
21598                } else {
21599                    childContextNode = elementNode;
21600                }
21601                // if its the last token, then stop recursion here and return the created node
21602                if (isLastToken) {
21603                    return childContextNode;
21604                }
21605            } else {
21606                if (elementNode != null) {
21607                    var numOfChildren = elementNode.length;
21608                    if (numOfChildren < index + 1) {
21609                        // create immediate 'extra' children
21610                        for (i = numOfChildren; i < index + 1; ++i) {
21611                            childContextNode = {};
21612                            contextNode[elemName].push(childContextNode);
21613                        }
21614                    } else {
21615                        childContextNode = elementNode[index];
21616                    }
21617                } else {
21618                    contextNode[elemName] = [];
21619                    for (i = 0; i < index + 1; ++i) {
21620                        childContextNode = {};
21621                        contextNode[elemName].push(childContextNode);
21622                    }
21623                }
21624            }
21625            // recursively create descendants
21626            return this._createElements(childContextNode, pathParts.slice(1), lastNodeValue);
21627        },
21628
21629        _createChildElement : function (parentElement, elemName, isLastToken, nodeValue) {
21630            if (parentElement instanceof Object) {
21631                if (isLastToken) {
21632                    parentElement[elemName] = nodeValue;
21633                } else {
21634                    parentElement[elemName] = {};
21635                }
21636                return parentElement[elemName];
21637            }
21638        },
21639
21640        isIndexedPath : function (xpath) {
21641            return (xpath || "").match(this.constants.INDEXED_XPATH_PAT_JSON) !== null;
21642        },
21643
21644        /**
21645         * This function sets the value of the field in the live data document.
21646         * @param xpath
21647         * @param xmlSection
21648         * @private
21649         * @param createMissingNodes
21650         * @param value
21651         */
21652        setDataValue : function (xpath, xmlSection, createMissingNodes, value) {
21653            var lastSlash = xpath.lastIndexOf("/"),
21654                parentPath = xpath.substring(0, lastSlash),
21655                name = xpath.substring(lastSlash + 1),
21656                parent = this.getContextNode(parentPath, xmlSection, createMissingNodes, {});
21657            if (parent instanceof Object) {
21658                if (createMissingNodes || parent.hasOwnProperty(name)) {
21659                    parent[name] = value;
21660                }
21661            }
21662        },
21663
21664        /**
21665         * This function sets the value in the model from the live data document.
21666         * @param node
21667         * @param field
21668         * @private
21669         */
21670        getDataValue : function (xpath, xmlSection) {
21671            var lastSlash = xpath.lastIndexOf("/"),
21672                parentPath = xpath.substring(0, lastSlash),
21673                name = xpath.substring(lastSlash + 1),
21674                parent = this.getContextNode(parentPath, xmlSection, false);
21675            if (parent instanceof Object) {
21676                return parent[name] === undefined ? null : parent[name];
21677            }
21678            return null;
21679        },
21680
21681        getRichTextValue : function (xpath, xmlSection) {
21682            return this.getDataValue(xpath, xmlSection);
21683        },
21684
21685        addIndexToPath : function (path, index) {
21686            if (path.match(/\/\d+$/) === null) { // only add repeat index if it doesn't already end in one
21687                path += '/' + (index);
21688            } else {
21689                this.logger().debug("AF", "Tried to add index to already indexed JSON path :" + path);
21690            }
21691            return path;
21692        },
21693
21694        hasChildNodes : function (node) {
21695            return !_.isEmpty(node);
21696        },
21697
21698        removeChild : function (parentNode, targetNodeName, index) {
21699            parentNode[targetNodeName].splice(index, 1);
21700        },
21701
21702        insertNode : function (parentNode, childNodeName, index) {
21703            if (parentNode[childNodeName] == null) {
21704                parentNode[childNodeName] = [];
21705            }
21706            for (var i = 0; i < index; i++) {
21707                if (parentNode[childNodeName][i] == null) {
21708                    parentNode[childNodeName][i] = {};
21709                }
21710            }
21711            parentNode[childNodeName].splice(index, 0, {});
21712            return parentNode[childNodeName][index];
21713        },
21714
21715        getDataInstances : function (dataContext, dataNodeName) {
21716            return this.getContextNode(dataContext.indexedXpath, dataContext.xmlSec);
21717        },
21718
21719        _convertModelIndexToDataIndex : function (index) {
21720            if (index < 0) {
21721                return 0;
21722            }
21723            return index;
21724        },
21725
21726        getParentRef : function (path) {
21727            return path.replace(/\/[^\/]+(?:\/\d+)?$/, "");
21728        },
21729
21730        insertSubmissionInfo : function (submissionInfo, rootNode) {
21731            if (this._isNonNaked()) {
21732                var node = rootNode,
21733                    self = this,
21734                    finalValue, insert, keyNode;
21735                if (node == null) {
21736                    node = this._liveDataDoc.afData.afSubmissionInfo;
21737                }
21738                if (node == null && this._liveDataDoc.afData.afSubmissionInfo == null) {
21739                    node = {};
21740                    this._liveDataDoc.afData.afSubmissionInfo = node;
21741                }
21742                _.each(submissionInfo, function (value, key) {
21743                    if (value instanceof Array) {
21744                        // we only support string items in json array
21745                        finalValue = [];
21746                        insert = true;
21747                        _.each(value, function (arrItem, index) {
21748                            if (typeof arrItem === "string") {
21749                                finalValue.push(arrItem);
21750                            } else {
21751                                //ignore this. we currently do not support anything other than string
21752                            }
21753                        });
21754                        if (insert) {
21755                            node[key] = finalValue.join(',');
21756                        }
21757                    } else if (typeof (value) === "object" && value != null) {
21758                        keyNode = node[key];
21759                        if (keyNode == null) {
21760                            keyNode = {};
21761                            node[key] = keyNode;
21762                        }
21763                        self.insertSubmissionInfo(value, keyNode);
21764                    } else {
21765                        node[key] = value;
21766                    }
21767                });
21768            }
21769        }
21770
21771    });
21772
21773}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
21774
21775/**
21776 * @package guidelib.model.DataNode
21777 * @version 0.0.1
21778 */
21779
21780(function ($, _, guideBridge, guidelib, formBridge, xfalib) {
21781    var isXdp, isXsd, isNone;
21782
21783    var LiveXmlUtils = guidelib.model.LiveXmlUtils = guidelib.model.LiveDataUtils.extend({
21784
21785        initialize : function () {
21786            LiveXmlUtils._super.initialize.call(this);
21787
21788            if (_.isUndefined(document.evaluate)) {
21789                wgxpath.install();
21790            }
21791            this._liveDataDoc = null;
21792        },
21793
21794        initLiveData : function (prefillXmlStr, xfaPrefillXmlStr, isXdp, isXsd, xsdRootElement) {
21795            LiveXmlUtils._super.initLiveData.apply(this, arguments);
21796            isXdp = isXdp || false;
21797            isXsd = isXsd || false;
21798            isNone = !(isXdp || isXsd);
21799            this.xsdRootElement = xsdRootElement;
21800            // init default skeleton for no pefill cases
21801            this._liveDataDoc = $.parseXML(this.constants.SKELETON_XML);
21802            this._boundDataRoot = this._getElement(this._liveDataDoc.documentElement, this.constants.BOUND_DATA_XPATH);
21803            this._unboundDataRoot = this._getElement(this._liveDataDoc.documentElement, this.constants.UNBOUND_DATA_XPATH);
21804
21805            if (_.isString(prefillXmlStr) && prefillXmlStr.length > 0) {
21806                var prefillXmlDoc = $.parseXML(prefillXmlStr);
21807
21808                // find data root
21809                if (this._isNonNaked(prefillXmlDoc)) {
21810                    // non naked xml, assuming full hierarchy afdata/afbounddata/data
21811
21812                    var prefillBoundDataRoot,
21813                        prefillUnBoundDataRoot,
21814                        newDataNode;
21815
21816                    if (!isXdp) { //capture bound data from prefill, for both none(may contain bound form/frag) and xsd
21817                        prefillBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.BOUND_DATA_XPATH);
21818                        if (null == prefillBoundDataRoot) {
21819                            prefillBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.BOUND_TAG +
21820                                                                        "/" + guideBridge._guide.jsonModel.xsdRootElement);
21821                        }
21822                        if (prefillBoundDataRoot) {
21823                            newDataNode = this._liveDataDoc.importNode(prefillBoundDataRoot, true);
21824                            this._boundDataRoot.parentNode.replaceChild(newDataNode, this._boundDataRoot);
21825                            this._boundDataRoot = newDataNode;
21826                        }
21827                    }
21828
21829                    prefillUnBoundDataRoot = this._getElement(prefillXmlDoc.documentElement, this.constants.UNBOUND_DATA_XPATH);
21830                    if (prefillUnBoundDataRoot) {
21831                        newDataNode = this._liveDataDoc.importNode(prefillUnBoundDataRoot, true);
21832                        this._unboundDataRoot.parentNode.replaceChild(newDataNode, this._unboundDataRoot);
21833                        this._unboundDataRoot = newDataNode;
21834                    }
21835
21836                } else {
21837                    // naked xml start from prefill data root
21838
21839                    if (isNone) {
21840                        this._unboundDataRoot = prefillXmlDoc.documentElement;
21841                        this._boundDataRoot = null;
21842                    } else {
21843                        if (isXsd) {
21844                            this._boundDataRoot = prefillXmlDoc.documentElement;
21845                        }
21846
21847                        var unBoundXmlDoc = $.parseXML(this.constants.UNBOUND_SKELETON);
21848                        this._unboundDataRoot = unBoundXmlDoc.documentElement;  // need this for unbound data fill across lazy
21849                    }
21850                    this._liveDataDoc = prefillXmlDoc;
21851                }
21852            }
21853
21854            if (isXdp) { // don't need the bound data sec, model is always loaded & server will fill during submission
21855                if (_.isString(xfaPrefillXmlStr) && xfaPrefillXmlStr.length > 0) {
21856                    this._xfaDataRoot = xfalib.ut.XMLUtils.getXFARootFormElementFromXML($.parseXML(xfaPrefillXmlStr));
21857                }
21858                this._boundDataRoot.parentNode.parentNode.removeChild(this._boundDataRoot.parentNode);
21859                this._boundDataRoot = null;
21860            }
21861        },
21862
21863        isLiveDataInitialized : function () {
21864            return (this.getLiveDataDoc() instanceof Node);
21865        },
21866
21867        getLiveDataStr : function () {
21868            if (this.isLiveDataInitialized()) {
21869                return (new XMLSerializer()).serializeToString(this.getLiveDataDoc());
21870            } else {
21871                return '';
21872            }
21873        },
21874
21875        _ignoreXpathRoot : function (xpathRoot) {
21876            return this.xsdRootElement === this.cons
21876tants.UNKNOWN_XSD_ROOT_ELEMENT
21877                || this.xsdRootElement === xpathRoot;
21878        },
21879
21880        /**
21881         * will return the apt node, in the AF xml, based on the xml context passed in.
21882         * Will create nodes if it doesn't exist and createMissingNodes is passed as true
21883         * @param schemaPath
21884         * @param dataSection
21885         * @param createMissingNodes
21886         * @returns {*}
21887         * @memberof LiveXmlUtils
21888         */
21889        getContextNode : function (schemaPath, dataSection, createMissingNodes) {
21890            var contextNode,
21891                baseContextNode,
21892                xpathParts = this._sanitizedXpathParts(schemaPath);
21893            if (dataSection === this.constants.BOUND_TAG) {
21894                baseContextNode = this._boundDataRoot;
21895            } else if (dataSection === this.constants.UNBOUND_TAG) {
21896                baseContextNode = this._unboundDataRoot;
21897            } else if (dataSection === this.constants.XFA_TAG) {
21898                baseContextNode = this._xfaDataRoot;
21899            }
21900            if (!_.isEmpty(xpathParts)) {
21901                if (dataSection === this.constants.BOUND_TAG) {
21902                    if (this._ignoreXpathRoot(xpathParts[0])) {
21903                        xpathParts = xpathParts.slice(1);   // discard xsd schema root
21904                        if (xpathParts.length === 0) {
21905                            return baseContextNode;
21906                        }
21907                    }
21908                }
21909
21910                contextNode = this._getElement(baseContextNode, xpathParts.join('/'));
21911
21912                if (!contextNode && createMissingNodes) {
21913                    contextNode = this._createElements(baseContextNode, xpathParts);
21914                }
21915            } else if (_.isEmpty(schemaPath)) {
21916                contextNode = baseContextNode;
21917            }
21918            return contextNode;
21919        },
21920
21921        addIndexToPath : function (path, index) {
21922            if (path.match(/\[\d+\]$/) === null) { // only add repeat index if it doesn't already end in one
21923                path += '[' + (index + 1) + ']'; // indices in xpath 1 based}
21924            } else {
21925                this.logger().debug("AF", "Tried to add index to already indexed xpath :" + path);
21926            }
21927            return path;
21928        },
21929
21930        getDataInstances : function (dataContext, dataNodeName) {
21931            var node = this.getContextNode(dataContext.indexedXpath, dataContext.xmlSec);
21932            if (node != null) {
21933                return _.filter(node.parentNode.childNodes, function (child) {
21934                    return (child instanceof Element) && child.nodeName === dataNodeName;
21935                }, this);
21936            }
21937            return null;
21938        },
21939
21940        _findLastDataNode : function (parentContextNode, dataNodeName) {
21941            var xmlUtils = xfalib.ut.XMLUtils,
21942                iterator = xmlUtils.evaluateXPath(dataNodeName, parentContextNode, null, null, null),
21943                result = xmlUtils.iteratorToArray(iterator);
21944            if (result.length > 0) {
21945                return result[result.length - 1];
21946            }
21947            return null;
21948        },
21949
21950        hasChildNodes : function (node) {
21951            return node.hasChildNodes();
21952        },
21953
21954        removeChild : function (parentNode, targetNodeName, index) {
21955            var childNode = this._getElement(parentNode, targetNodeName + "[" + (index + 1) + "]", null);
21956            if (childNode) {
21957                parentNode.removeChild(childNode);
21958            }
21959        },
21960
21961        insertNode : function (parentNode, childNodeName, index) {
21962            var childNode = this._getElement(parentNode, childNodeName + "[" + (index + 1) + "]", null),
21963                node = parentNode.ownerDocument.createElement(childNodeName);
21964            if (childNode) {
21965                parentNode.insertBefore(node, childNode);
21966            } else {
21967                var lastNode = this._findLastDataNode(parentNode, childNodeName);
21968                if (lastNode && lastNode.nextSibling) {
21969                    parentNode.insertBefore(node, lastNode.nextSibling);
21970                } else if (lastNode && !lastNode.nextSibling) {
21971                    // for the case when the last node is there but there is no next sibling.
21972                    // we don't need to create all the nodes for this scenario.
21973                    parentNode.appendChild(node);
21974                } else {
21975                    // we need to create all the nodes till the count reaches the index.
21976                    for (var i = 0; i <= index; i++) {
21977                        var newNode = parentNode.ownerDocument.createElement(childNodeName);
21978                        parentNode.appendChild(newNode);
21979                    }
21980                }
21981            }
21982            return node;
21983        },
21984
21985        /**
21986         * Form an xpath part returns the index as well as the tagName.
21987         * Index returned is 0 if not present
21988         * @param xpathName
21989         * @returns {*}
21990         * @private
21991         * @memberof LiveXmlUtils
21992         */
21993        _getNameAndIndex : function (xpathPart) {
21994            if (xpathPart) {
21995                var elName = xpathPart.match(/^([^[\s\/]+)(?:\[(\d+)\])?$/);  // match the whole string
21996                if (elName !== null) {
21997                    return {
21998                        name : elName[1],
21999                        index : elName[2] ? parseInt(elName[2]) : 0
22000                    };
22001                }
22002            }
22003            return null;
22004        },
22005
22006        _cmpXpathParts : function (indexedName, templateName) {
22007            if (indexedName && templateName) {
22008                var match1 = this._getNameAndIndex(indexedName),
22009                    match2 = this._getNameAndIndex(templateName);
22010                return !_.isEmpty(match1 && match2)
22011                    && match1.name === match2.name
22012                    && (match2.index === 0 || match1.index === match2.index);
22013            }
22014            return false;
22015        },
22016
22017        /**
22018         * Will split an xpath string into an array containing one xml element/node per part
22019         * This expects only the simple xpath syntax allowed in bindRefs of xsd bound fields
22020         * of the form /a/b/c/@d
22021         * @param xpath
22022         * @returns {*|Array.<T>|list}
22023         * @private
22024         * @memberof LiveXmlUtils
22025         */
22026        _sanitizedXpathParts : function (xpath) {
22027            var xpathParts = (xpath || '').replace(/^\//, '').replace(/\s+/g, '').split('/');
22028
22029            if (_.last(xpathParts) === "text()") { // ignore "/text()" appended to bindRef for SimpleType schema element
22030                xpathParts.splice(-1, 1); // drop last element
22031            }
22032
22033            return _.filter(xpathParts, function (xpathPart) {
22034                return this._getNameAndIndex(xpathPart) !== null;
22035            }, this);
22036        },
22037
22038        /**
22039         * returns true if the xpath uses indices
22040         * @param xpath
22041         * @returns {boolean}
22042         * @memberof LiveXmlUtils
22043         */
22044        isIndexedPath : function (xpath) {
22045            return (xpath || "").match(this.constants.INDEXED_XPATH_PAT) !== null;
22046        },
22047
22048        _createElements : function (contextNode, xpathParts) {
22049            if (!(contextNode instanceof Node)) {
22050                return null;
22051            }
22052
22053            if (_.isEmpty(xpathParts)) {
22054                return contextNode;
22055            }
22056
22057            if (xpathParts[0][0] === '@') { // xpath parts having '@' as 1st char must be and attr
22058                var attrName = xpathParts[0].slice(1);
22059                // in bindrefs attributes are the last xpath part, so no need to recurse
22060                contextNode = this._createAttributeNode(contextNode, attrName);
22061            } else {
22062                // recurse and create one level of tags at a time
22063                contextNode = this._createRepeatedElements(contextNode, xpathParts);
22064            }
22065
22066            return contextNode;
22067        },
22068
22069        /**
22070         * This will update the xml with the required tags,
22071         * and return the context node matching the xpath query.
22072         * Further if xml has lesser number of tags than the index in each part,
22073         * it'll fill those gaps with empty tags.
22074         * @param contextNode node beneath which tags are to be created
22075         * @param xpathParts
22076         * @returns {*}
22077         * @private
22078         * @memberof LiveXmlUtils
22079         */
22080        _createRepeatedElements : function (contextNode, xpathParts) {
22081            var childContextNode = contextNode,
22082                xpathPart = this._getNameAndIndex(xpathParts[0]),
22083                elemName = xpathPart.name,
22084                index = xpathPart.index || 1,
22085                i,
22086                children = _.filter(contextNode.childNodes, function (child) {
22087                    return (child instanceof Element) && child.nodeName === elemName;
22088                });
22089
22090            if (children.length < index) {
22091                // create immediate 'extra' children
22092                for (i = children.length; i < index; ++i) {
22093                    childContextNode = this._createChildElement(contextNode, elemName);
22094                }
22095            } else {
22096                childContextNode = children[index - 1]; // indices are 1 based in xml
22097            }
22098            // recursively create descendants
22099            return this._createElements(childContextNode, xpathParts.slice(1));
22100        },
22101
22102        _createChildElement : function (parentElement, elemName) {
22103            if (parentElement instanceof Element) {
22104                var childElem = parentElement.ownerDocument.createElement(elemName);
22105                parentElement.appendChild(childElem);
22106                return childElem;
22107            }
22108        },
22109
22110        _createAttributeNode : function (parentElement, attrName) {
22111            if (parentElement instanceof Element) {
22112                var attrNode = parentElement.ownerDocument.createAttribute(attrName);
22113                parentElement.setAttributeNode(attrNode);
22114                return attrNode;
22115            }
22116        },
22117
22118        /**
22119         * finds xml node/element based on current context node and xpath
22120         * @param node
22121         * @param xpath
22122         * @param options
22123         * @returns {*}
22124         * @private
22125         * @memberof LiveXmlUtils
22126         */
22127        _getElement : function (node, xpath, options) {
22128            if (!(node instanceof Node)) {
22129                return null;
22130            }
22131
22132            if (_.isEmpty(xpath) || !_.isString(xpath)) {
22133                return node;
22134            }
22135            options = options || {};
22136            var nsResolver = options.nsResolver;
22137            var index = options.index;
22138            // in IE singleNodeValue maybe null for attribute queries,
22139            // so find parent element of attribute, and then explicitly check for attribute node's presence
22140
22141            var xpathParts = xpath.split('/@'),
22142                checkAttr = false,
22143                attributeName;
22144
22145            if (xpathParts.length > 2) { // more than 1 attr unsupported
22146                xfalib.ut.XfaUtil.prototype.getLogger().error("BindRefs must be Xpaths ending in atmost one attribute"); // TODO localize
22147                return null;
22148            } else if (xpathParts.length === 2) {
22149                xpath = xpathParts[0]; // find parent el and seek attribute there
22150                attributeName = xpathParts[1]; // attr can only be in the last part
22151                checkAttr = true;
22152            }
22153            if (!(_.isUndefined(index) || _.isNull(index))) {
22154                xpath = xpath + "[" + index + "]";
22155            }
22156            if (!window.XPathResult) {
22157                document.evaluate = undefined;
22158                wgxpath.install(window, true);
22159            }
22160            var result = xfalib.ut.XMLUtils.evaluateXPath(xpath, node, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null),
22161                el;
22162
22163            if (result && result.resultType === XPathResult.FIRST_ORDERED_NODE_TYPE) {
22164                el = result.singleNodeValue;
22165                if (el instanceof Node) {
22166                    if (!checkAttr) {
22167                        return el;
22168                    } else if (el.hasAttribute(attributeName)) {
22169                        el = el.getAttributeNode(attributeName);
22170                        if (el instanceof Node) {
22171                            return el;
22172                        }
22173                    }
22174                }
22175            }
22176        },
22177
22178        /**
22179         * This function checks if the document was naked or non naked xml
22180         * @param doc
22181         * @returns {boolean} returns true if there exists a afData node inside data false otherwise
22182         * @private
22183         * @memberof LiveXmlUtils
22184         */
22185        _isNonNaked : function (doc) {
22186            doc = doc || this.getLiveDataDoc();
22187            if (doc) {
22188                return doc.documentElement.tagName === this.constants.AF_ROOT_TAG;
22189            } else {
22190                return false;
22191            }
22192        },
22193
22194        /**
22195         * Returns list of panels touched by the end user before saving the draft
22196         * @param dataString
22197         */
22198        getListOfDirtyPanels : function (dataString) {
22199            if (dataString == null || dataString === "") {
22200                return [];
22201            }
22202            var livePrefillXmlDoc = $.parseXML(dataString),
22203                draftDoc = this._getElement(livePrefillXmlDoc.documentElement, this.constants.AF_DRAFT_TAG);
22204            if (_.isUndefined(draftDoc) || draftDoc.childNodes.length === 0) {
22205                return [];
22206            }
22207            var draftStr = draftDoc.firstChild.textContent.replace(/\"/g, ""),
22208                retVal = [];
22209            // not using filter here explicitly, due to ES4 syntax
22210            if (draftStr) {
22211                retVal = draftStr.split(",");
22212            }
22213            return retVal;
22214        },
22215
22216        /**
22217         * This function sets the rich text value of the field in the live data.
22218         * @param xpath
22219         * @param xmlSection
22220         * @param createMissingNodes
22221         * @param value
22222         * @private
22223         */
22224        setRichTextValue : function (xpath, xmlSection, createMissingNodes, value) {
22225            var node = this.getContextNode(xpath, xmlSection, createMissingNodes);
22226            if (node instanceof Node) {
22227                var richTextNode = $.parseXML(value);
22228                // clear the text content before appending child
22229                node.textContent = "";
22230                node.appendChild(richTextNode.documentElement);
22231            }
22232        },
22233
22234        setDataValue : function (xpath, xmlSection, createMissingNodes, value) {
22235            var node = this.getContextNode(xpath, xmlSection, createMissingNodes);
22236            if (node instanceof Node) {
22237                node.textContent = value;
22238            }
22239        },
22240
22241        getDataValue : function (xpath, xmlSection) {
22242            var node = this.getContextNode(xpath, xmlSection, false);
22243            if (node instanceof Node) {
22244                return node.textContent || null;
22245            }
22246            return undefined;
22247        },
22248
22249        getRichTextValue : function (xpath, xmlSection) {
22250            var node = this.getContextNode(xpath, xmlSection, false);
22251            if (node instanceof Node) {
22252                return node.innerHTML.trim();
22253            }
22254            return undefined;
22255        },
22256
22257        _convertModelIndexToDataIndex : function (index) {
22258            if (index < 0) {
22259                return 1;
22260            }
22261            return index + 1;
22262        },
22263
22264        getParentRef : function (path) {
22265            return path.substring(0, path.lastIndexOf("/"));
22266        },
22267
22268        insertSubmissionInfo : function (submissionInfo, rootNode) {
22269            if (this._isNonNaked()) {
22270                var xmlutils = xfalib.ut.XMLUtils,
22271                    node = rootNode === undefined
22272                        ? xmlutils.findOrCreateElement("afSubmissionInfo", this._liveDataDoc.documentElement)
22273                        : rootNode,
22274                    self = this;
22275                _.each(submissionInfo, function (value, key) {
22276                    var keyNode;
22277                    if (value instanceof Array) {
22278                        // we only support string items in json array
22279                        var finalValue = [], insert = true;
22280                        _.each(value, function (arrItem, index) {
22281                            if (typeof arrItem === "string") {
22282                                finalValue.push(arrItem);
22283                            } else if (arrItem instanceof Object && arrItem != null) {
22284                                insert = false;
22285                                var el = node.ownerDocument.createElement(key);
22286                                node.appendChild(el);
22287                                self.insertSubmissionInfo(arrItem, el);
22288                            }
22289                        });
22290                        if (insert) {
22291                            keyNode = xmlutils.findOrCreateElement(key, node);
22292                            keyNode.textContent = finalValue.join(',');
22293                            node.appendChild(keyNode);
22294                        }
22295                    } else if (typeof (value) === "object" && value != null) {
22296                        keyNode = xmlutils.findOrCreateElement(key, node);
22297                        self.insertSubmissionInfo(value, keyNode);
22298                        node.appendChild(keyNode);
22299                    } else {
22300                        keyNode = xmlutils.findOrCreateElement(key, node);
22301                        keyNode.textContent = value;
22302                        node.appendChild(keyNode);
22303                    }
22304                });
22305            }
22306        }
22307    });
22308
22309}($, _, window.guideBridge, window.guidelib, window.formBridge, window.xfalib));
22310
22311/*
22312 * ***********************************************************************
22313 * ADOBE CONFIDENTIAL
22314 * __________________
22315 *
22316 * Copyright 2015 Adobe Systems Incorporated
22317 * All Rights Reserved.
22318 *
22319 * NOTICE:  All information contained herein is, and remains
22320 * the property of Adobe Systems Incorporated and its suppliers,
22321 * if any.  The intellectual and technical concepts contained
22322 * herein are proprietary to Adobe Systems Incorporated and its
22323 * suppliers and may be covered by U.S. and Foreign Patents,
22324 * patents in process, and are protected by trade secret or copyright law.
22325 * Dissemination of this information or reproduction of this material
22326 * is strictly forbidden unless prior written permission is obtained
22327 * from Adobe Systems Incorporated.
22328 * ***********************************************************************
22329 */
22330
22331/**
22332 * @package guidelib.model.LiveModel
22333 * @version 0.0.1
22334 */
22335
22336(function ($, _, guideBridge, guidelib) {
22337    var LiveModel = guidelib.model.LiveModel = xfalib.ut.Class.extend({
22338        initialize : function () {
22339            LiveModel._super.initialize.call(this);
22340            this._crossFragmentFields = {}; // 2 level map: name => { bindRef => abstract model }
22341            this._dataNodes = {};
22342        },
22343
22344        // only called from test framework
22345        destroy : function () {
22346            this._crossFragmentFields = {};
22347            this._dataNodes = {};
22348        },
22349
22350        getCrossFragmentFields : function () {
22351            return this._crossFragmentFields;
22352        },
22353
22354        add : function (key, model) {
22355            if (key) {
22356                var dn = this._dataNodes[key] || new guidelib.model.DataNode();
22357                dn.addField(model);
22358                this._dataNodes[key] = dn;
22359            }
22360        },
22361
22362        isLive : function (key) {
22363            return _.isString(key) && _.has(this._dataNodes, key);
22364        },
22365
22366        remove : function (key, model) {
22367            if (this.isLive(key)) {
22368                var dn = this._dataNodes[key];
22369                dn.removeField(model);
22370            }
22371        },
22372
22373        getAllFieldModels : function (keys) {
22374            return _.flatten(_.map(keys, function (key) {
22375                var result,
22376                    dataNode = this._dataNodes[key];
22377                if (dataNode) {
22378                    result = dataNode.getFieldModels();
22379                }
22380                return result;
22381            }, this));
22382        },
22383
22384        getAllAbstractFieldModels : function (keys) {
22385            return _.flatten(_.map(keys, function (key) {
22386                return this._dataNodes[key].getAbstractFieldModels();
22387            }, this));
22388        },
22389
22390        resetData : function () {
22391            // all loaded models in data nodes dataNodes will be reset by the respective fields
22392            // just need to reset the abstract cross frag fields
22393            _.each(this._crossFragmentFields, function (fields) {
22394                _.each(fields, function (abstractField) {
22395                    abstractField.resetData();
22396                });
22397            });
22398        },
22399
22400        createDataNodes : function (duplicateBindRefs) {
22401            _.each(duplicateBindRefs, function (bindRef) {
22402                this.add(bindRef);
22403            }, this);
22404        },
22405
22406        createCrossFragFields : function (crossFragFields, guide) {
22407            _.each(crossFragFields, function (field) {
22408                var effectiveBindRef = field.bindRef || field.name,
22409                    value = field._value || null,// default value, keep null because js is quirky with operations on undefined
22410                    absModel = new guidelib.model.AbstractField({
22411                        'name' : field.name,
22412                        'className' : field.guideNodeClass,
22413                        'bindRef' : field.bindRef,
22414                        'dataSom' : field.dataSom,
22415                        'afDataSom' : field.afDataSom,
22416                        'jsonModel' : {
22417                            '_value' : value,
22418                            "{default}" : value
22419                        },
22420                        '_guideContainer' : guide
22421                    });
22422
22423                if (_.isEmpty(this._crossFragmentFields[field.name])) {
22424                    this._crossFragmentFields[field.name] = {};
22425                }
22426                this._crossFragmentFields[field.name][effectiveBindRef] = absMo
22426del;
22427
22428                this.add(effectiveBindRef, absModel); // unbound globals with same name linked together
22429
22430            }, this);
22431        },
22432
22433        prefillCrossFragFields : function (guide) {
22434            var dataUtils = guide.internal.liveDataUtils;
22435            if (dataUtils.isLiveDataInitialized()) {
22436                _.each(this._crossFragmentFields, function (fields, name) {
22437                    _.each(fields, function (absModel, bindRef) {
22438                        var dataContext = dataUtils._getDataContext(absModel, '', '');
22439                        // fill value from prefill data or saved lazy live data
22440                        absModel.value = dataUtils.getDataValue(dataContext.indexedXpath, dataContext.xmlSec);
22441                    }, this);
22442                }, this);
22443            }
22444        }
22445    });
22446}($, _, window.guideBridge, window.guidelib));
22447
22448/**
22449 * @package guidelib.model.FormData
22450 * @version 0.0.1
22451 */
22452
22453(function ($, _, guidelib) {
22454
22455    /**
22456     * JavaScript class to represent form data
22457     * @class FormData
22458     * @since Forms As A Cloud service (FaaCS)
22459     */
22460    var AfFormData = guidelib.model.FormData = xfalib.ut.Class.extend({
22461
22462        initialize : function () {
22463            AfFormData._super.initialize.call(this);
22464        },
22465
22466        toJsObject : function() {
22467            return {
22468                "data" : this.data,
22469                "contentType" : this.contentType,
22470                "attachments" : this.attachments
22471            }
22472        },
22473
22474        /**
22475         * This returns the html form data representation of adaptive form data. This could be used to submit the adaptive form data to
22476         * external end point from the client. The HTML form data contains the following the key / value pairs:
22477         * 1. data -> contains form data represented as string
22478         * 2. contentType -> contains content type of form data (it would be application/xml or application/json)
22479         * 2. fileAttachments -> list of blobs containing the file (in case of fileUrl's the type of blob would be application/json)
22480         * 3. fileAttachmentBindRefs -> list of string containing file bindRef's, this has one to one mapping with fileAttachments
22481         * @returns {*}
22482         */
22483        toHTMLFormData : function() {
22484            // using native formData class
22485            var formData = new FormData();
22486            // appending data of adaptive form in data key
22487            // data could be JSON or XML
22488            if (this.contentType) {
22489                formData.append("contentType", this.contentType);
22490            }
22491            formData.append("data", this.data);
22492            for (var index = 0; index < this.attachments.length; index++) {
22493                var fileAttachmentWrapper = this.attachments[index];
22494                // 2nd parameter should be of blob type, hence adding an explicit check here
22495                // we could have created dataURL for all the files in the client, but this would cause the browser
22496                // to slow down since it would serialize the binary, hence following the below approach
22497                if (fileAttachmentWrapper.isFile()) {
22498                    formData.append("fileAttachments", fileAttachmentWrapper.data, fileAttachmentWrapper.name);
22499                } else {
22500                    // blob is supported on all major browsers
22501                    var urlBlob = new Blob([
22502                        JSON.stringify({
22503                            "data" : fileAttachmentWrapper.data,
22504                            "name" : fileAttachmentWrapper.name,
22505                            "contentType" : fileAttachmentWrapper.contentType
22506                        })
22507                    ], { type: 'application/json' });
22508                    formData.append("fileAttachments", urlBlob);
22509                }
22510                formData.append("fileAttachmentBindRefs", fileAttachmentWrapper.bindRef);
22511            }
22512            return formData;
22513        }
22514    });
22515
22516    AfFormData.defineProps({
22517        /**
22518         * Actual form data (could be JSON or xml)
22519         */
22520        data : {
22521            get : function () {
22522                return this.options.data;
22523            }
22524        },
22525
22526        /**
22527         * List of {FileAttachmentWrapper} {@link FileAttachmentWrapper}
22528         */
22529        attachments : {
22530            get : function () {
22531                return this.options.attachments;
22532            }
22533        },
22534
22535        /**
22536         * Content type of form data (it could be application/xml or application/json)
22537         */
22538        contentType : {
22539            get : function () {
22540                return this.options.contentType;
22541            }
22542        }
22543    });
22544
22545
22546}($, _, window.guidelib));
22547
22548/**
22549 * @package guidelib.model.FileAttachmentWrapper
22550 * @version 0.0.1
22551 */
22552
22553(function ($, _, guidelib) {
22554
22555    /**
22556     * JavaScript class to represent the each file data present in the form.
22557     * Data could be URI (URI could be a file URL or dataURL)
22558     * @class FileAttachmentWrapper
22559     * @since Forms As A Cloud service (FaaCS)
22560     */
22561    var FileAttachmentWrapper = guidelib.model.FileAttachmentWrapper = xfalib.ut.Class.extend({
22562
22563        initialize : function () {
22564            FileAttachmentWrapper._super.initialize.call(this);
22565        },
22566
22567        /**
22568         * Converts file attachment wrapper to a javascript object
22569         * @returns {{name: *, contentType: *, bindRef: *, data: *}}
22570         */
22571        toJsObject : function () {
22572            return {
22573                name : this.name,
22574                contentType : this.contentType,
22575                bindRef : this.bindRef,
22576                data : this.data
22577            }
22578        },
22579
22580        /**
22581         * Checks if the file data is native JS File object
22582         * @returns {boolean}
22583         */
22584        isFile : function() {
22585            return this.data instanceof File;
22586        },
22587
22588
22589        /**
22590         * Returns blob for the data URL present in data
22591         * @returns {*}
22592         */
22593        dataURLtoBlob : function() {
22594            var dataurl = this.data, // data should be a data url
22595                arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
22596                bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
22597            while(n--){
22598                u8arr[n] = bstr.charCodeAt(n);
22599            }
22600            return new Blob([u8arr], {type: mime});
22601        }
22602    });
22603
22604    FileAttachmentWrapper.defineProps({
22605        /**
22606         * Actual name of the file associated with data
22607         */
22608        name : {
22609            get : function () {
22610                return this.options.name;
22611            }
22612        },
22613
22614        /**
22615         * Content type of file
22616         */
22617        contentType : {
22618            get : function () {
22619                return this.options.contentType;
22620            }
22621        },
22622
22623        /**
22624         * This would be effective bindRef meaning bindRef in case of data model or component name in case of unbound data
22625         */
22626        bindRef : {
22627            get : function () {
22628                return this.options.bindRef;
22629            }
22630        },
22631
22632        /**
22633         * This would represent the name of the form element to which the file binary is associated.
22634         * In case of unbound form, bindRef and component name would be the same
22635         */
22636        formElementName : {
22637            get : function () {
22638                return this.options.formElementName || this.options.bindRef;
22639            }
22640        },
22641
22642        /**
22643         * Data could be URI (URI could be file URL or dataURL) or native JavaScript File object
22644         */
22645        data : {
22646            get : function () {
22647                return this.options.data;
22648            }
22649        }
22650    });
22651
22652
22653}($, _, window.guidelib));
22654
22655/*************************************************************************
22656 *
22657 * ADOBE CONFIDENTIAL
22658 * __________________
22659 *
22660 *  Copyright 2014 Adobe Systems Incorporated
22661 *  All Rights Reserved.
22662 *
22663 * NOTICE:  All information contained herein is, and remains
22664 * the property of Adobe Systems Incorporated and its suppliers,
22665 * if any.  The intellectual and technical concepts contained
22666 * herein are proprietary to Adobe Systems Incorporated and its
22667 * suppliers and may be covered by U.S. and Foreign Patents,
22668 * patents in process, and are protected by trade secret or copyright law.
22669 * Dissemination of this information or reproduction of this material
22670 * is strictly forbidden unless prior written permission is obtained
22671 * from Adobe Systems Incorporated.
22672 **************************************************************************/
22673
22674
22675(function (_, $) {
22676    "use strict";
22677
22678    
22679    var isBrowserIE = xfalib.ut.XfaUtil.prototype.detectIE();
22680
22681    var _defaults = {
22682        'showLink' : false,
22683        'scrollMode' : 'vertical',
22684        textAreaClass : ".guide-tnc-content",
22685        checkBoxClass : ".guide-tnc-checkbox",
22686        checkBoxDisableClass : ".guide-tnc-checkbox-disabled",
22687        checkBoxReviewedClass : ".guide-tnc-checkbox-reviewed",
22688        linkClass     : ".guide-tnc-link",
22689        documentVisitedClass : ".guide-tnc-document-visited",
22690        documentUnVisitedClass : ".guide-tnc-document-unvisited"
22691    };
22692
22693    var _reviewStatusMap = {
22694        REVIEWED : "reviewed",
22695        UNREVIEWD : "unreviewed",
22696        AGREE : "agree"
22697    };
22698
22699    var AfTnc = function (element, options) {
22700        this.options = options;
22701        this.$element = $(element);
22702
22703        
22704        this.enters = this.leaves = 0;
22705        this.inside = false;
22706
22707        
22708        this.reviewdoc = this.status = _reviewStatusMap.UNREVIEWD;
22709
22710        
22711        this.$elementCheckBox = this.$element.find(this.options.checkBoxClass || _defaults.checkBoxClass);
22712        
22713        this.$elementTextArea = $(this.textArea());
22714        
22715        this.$elementLink =  $(this.link());
22716
22717        this.isTextContentVisible = false;
22718
22719        if (this.options.showLink) {
22720            
22721            this.$elementLink.find('a').click($.proxy(this.handleReviewStatusChange, this));
22722        } else {
22723            var setCheckBoxState = function () {
22724                if (this.hasScrollBar(this.$elementTextArea.parent().get(0))) {
22725                    
22726                    
22727                    this.$elementTextArea.parent().scroll($.proxy(this.handleReviewStatusChange, this));
22728                } else {
22729                    
22730                    if (this.$elementTextArea.css('display') !== 'none') {
22731                        this.status = _reviewStatusMap.REVIEWED;
22732                        this.isTextContentVisible = true;
22733                        
22734                        if (!this.options.showAsPopUp) {
22735                            this.enableCheckBox();
22736                        }
22737                        this.reviewDoc = this.$elementTextArea.text();
22738                    }
22739                }
22740            };
22741            
22742            
22743            if (document.readyState === "complete") { 
22744                setCheckBoxState.call(this);          
22745            } else {
22746                
22747                
22748                $($.proxy(setCheckBoxState, this));
22749            }
22750        }
22751
22752        
22753        if (this.options.showAsPopUp) {
22754            var unvisitedClass = this.options.documentUnVisitedClass || _defaults.documentUnVisitedClass,
22755                visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
22756            var _self = this,
22757                dialogId = this.$elementCheckBox.find('a')
22758                .keydown(function (e) {
22759                    if (e.keyCode === 13 || e.which == 13 || e.charCode === 32) {
22760                        $(this).click();
22761                        return false;
22762                    }
22763                })
22764                .click(function (event) {
22765                    if ($(this).hasClass(unvisitedClass.substring(1))) {
22766                        $(this).toggleClass(visitedClass.substring(1) + " " + unvisitedClass.substring(1));
22767                    }
22768                    
22769                    
22770                    if (isBrowserIE || _self.isTextContentVisible) {
22771                        _self.enableCheckBox();
22772                    }
22773                }).attr("href");
22774            
22775            $(dialogId).on('hidden.bs.modal', function (e) {
22776                _self.$elementCheckBox.find('input').focus();
22777            });
22778        } else {
22779            
22780            this._updateScreenReaderText();
22781        }
22782
22783        
22784        this.$elementCheckBox.find('input').change($.proxy(this.handleCheckBoxChange, this));
22785    };
22786
22787    AfTnc.prototype = {
22788
22789        clear : function () {
22790            this.$element.val('');
22791        },
22792
22793        destroy : function () {
22794            this.$element.val('');
22795            this.$element.empty();
22796        },
22797
22798        _updateScreenReaderText : function () {
22799            if (!this.options.showAsPopUp) {
22800                var _self = this;
22801                
22802                this.$element.find(".guide-tnc-sr-only").each(function (i, obj) {
22803                    $(this).html(_self.options.screenReaderText);
22804                });
22805            }
22806        },
22807
22808        _restoreClickState : function (value) {
22809            if (this.options.showLink) {
22810                var arr = value.split("\n"),
22811                    linkState = [];
22812                
22813                _.each(arr, function (linkText, index) {
22814                    
22815                    linkState.push(_.last(linkText.split('=')));
22816                });
22817                var unvisitedClass = this.options.documentUnVisitedClass || _defaults.documentUnVisitedClass,
22818                    visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
22819                this.$elementLink.find('a').each(function (index) {
22820                    $(this).data("clicked", linkState[index]);
22821                    if (linkState[index] === "1") {
22822                        $(this).addClass(visitedClass.substring(1));
22823                    } else {
22824                        $(this).addClass(unvisitedClass.substring(1));
22825                    }
22826                });
22827            }
22828        },
22829
22830        value : function (value) {
22831            if (value) {
22832                
22833                if (this.options.showLink) {
22834                    this._restoreClickState(value);
22835                }
22836                this.reviewDoc = value;
22837            } else {
22838                return this.reviewDoc;
22839            }
22840
22841        },
22842
22843        reviewStatus : function (value) {
22844            var val = this.getClickState();
22845            if (!_.isUndefined(value)) {
22846                if (value == "true") {
22847                    this.enableCheckBox();
22848                    this.$elementCheckBox.find('input').attr("checked", "checked");
22849                    this.$elementCheckBox.find('input').prop("checked", true);
22850                } else if (value == null || value == "false") {
22851                    
22852                    this.$elementCheckBox.find('input').removeAttr("checked");
22853                    this.$elementCheckBox.find('input').removeProp("checked");
22854                }
22855                this.approvalStatus = value;
22856            } else {
22857                if (this.status == _reviewStatusMap.REVIEWED || this.status == _reviewStatusMap.UNREVIEWD) {
22858                    return null;
22859                } else if (this.status == _reviewStatusMap.AGREE) {
22860                    return true;
22861                }
22862            }
22863        },
22864
22865        clickStatus : function (value) {
22866            if (value) {
22867                if (value === _reviewStatusMap.REVIEWED) {
22868                    var arr = this.getClickState();
22869                    if (_.isArray(arr) && arr.length > 0) {
22870                        arr = arr.join("\n");
22871                        this._restoreClickState(arr);
22872                    }
22873                    this.enableCheckBox();
22874                }
22875                this.status = value;
22876            } else {
22877                return this.status;
22878            }
22879        },
22880
22881        showLink : function (value) {
22882            if (value !== undefined) {
22883                this.options.showLink = value;
22884            } else {
22885                return this.options.showLink;
22886            }
22887        },
22888
22889        access : function (value) {
22890            this.accessOption = value;
22891            if (value == "readOnly") {
22892                this.disableCheckBox();
22893                if (this.options.showLink) {
22894                    this.$elementLink.find('a').each(function (index, elem) {
22895                        $(elem).css('pointer-events', 'none');
22896                        
22897                        $(elem).attr('disabled', 'disabled');
22898                    });
22899                }
22900            } else if (value == "open") {
22901                
22902                
22903                if ((this.status == _reviewStatusMap.REVIEWED || this.status == _reviewStatusMap.AGREE) && !this.options.showAsPopUp) {
22904                    this.enableCheckBox();
22905                }
22906                if (this.options.showLink) {
22907                    this.$element.find('a').each(function (index, elem) {
22908                        $(elem).css('pointer-events', '');
22909                        $(elem).removeAttr('disabled');
22910                    });
22911                }
22912            }
22913        },
22914
22915        link : function () {
22916            return this.$element.find(this.options.linkClass || _defaults.linkClass);
22917        },
22918
22919        textArea : function () {
22920            return this.$element.find(this.options.textAreaClass || _defaults.textAreaClass);
22921        },
22922
22923        getClickState : function () {
22924            if (this.options.showLink) {
22925                var arr = [];
22926                this.$elementLink.find('a').each(function (index) {
22927                    arr.push({
22928                        'displayText' : $(this).text(),
22929                        'linkText' : $(this).attr('href'),
22930                        'clicked' : $(this).data("clicked")
22931                    });
22932                });
22933                return arr;
22934            }
22935        },
22936
22937        enableCheckBox : function () {
22938            if (this.accessOption !== "readOnly") {
22939                this.$elementCheckBox.find('input').removeAttr("disabled");
22940                this.$elementCheckBox.removeClass(this.options.checkBoxDisableClass.substring(1));
22941            }
22942        },
22943
22944        disableCheckBox : function () {
22945            this.$elementCheckBox.find('input').attr('disabled', 'disabled');
22946            this.$elementCheckBox.addClass(this.options.checkBoxDisableClass.substring(1));
22947        },
22948
22949        handleReviewStatusChange : function (event) {
22950            var arr = [],
22951                visitedClass = this.options.documentVisitedClass || _defaults.documentVisitedClass;
22952            if (this.options.showLink) {
22953                this.status = _reviewStatusMap.REVIEWED;
22954                
22955                $(event.target).data("clicked", 1);
22956                $(event.target).addClass(visitedClass.substring(1));
22957                this.linkStateMap = this.getClickState();
22958                _.each(this.linkStateMap, function (element, index) {
22959                    if (!element.clicked) {
22960                        this.status = _reviewStatusMap.UNREVIEWD;
22961                    }
22962                    
22963                    arr.push(element.displayText + "=" + element.linkText + "=" + (_.isUndefined(element.clicked) ? "0" : "1"));
22964                }, this);
22965                if (arr.length > 0) {
22966                    this.reviewDoc = arr.join("\n");
22967                }
22968
22969                if (this.status == _reviewStatusMap.REVIEWED) {
22970                    this.enableCheckBox();
22971                }
22972
22973                
22974                this.$element.trigger('reviewComplete.tnc');
22975
22976            } else {
22977                
22978                var position = this.getScroll(this.$elementTextArea.parent().get(0)),
22979                    xy = position[this.options.scrollMode == 'vertical' ? 'y' : 'x'];
22980                var isScrolledToEnd = this.getScrollSize(this.$elementTextArea.parent().get(0)).y <=  (this.getSize(this.$elementTextArea.parent().get(0)).y + xy);
22981                
22982                this.reviewDoc = this.$elementTextArea.text();
22983
22984                
22985                if (isScrolledToEnd) {
22986                    
22987                    if (!this.inside) {
22988                        
22989                        this.inside = true;
22990                        this.enters++;
22991                        
22992                        this.status = _reviewStatusMap.REVIEWED;
22993                        if (!this.approvalStatus) {
22994                            this.enableCheckBox();
22995                            
22996                            this.$element.trigger('reviewComplete.tnc', [position,this.enters,event]);
22997                        }
22998                    }
22999                }
23000                
23001                else if (this.inside) {
23002                    this.inside = false;
23003                    this.leaves++;
23004
23005                }
23006            }
23007
23008        },
23009
23010        handleCheckBoxChange : function (event) {
23011            if ($(event.target).is(':checked')) {
23012                this.status = _reviewStatusMap.AGREE;
23013                this.$elementCheckBox.addClass(this.options.checkBoxReviewedClass.substring(1));
23014            } else {
23015                this.status = _reviewStatusMap.UNREVIEWD;
23016                this.$elementCheckBox.removeClass(this.options.checkBoxReviewedClass.substring(1));
23017            }
23018            this.$element.trigger('checkboxStateChange.tnc');
23019        },
23020
23021        getScrollSize : function (elem) {
23022            return {x : elem.scrollWidth, y : elem.scrollHeight};
23023        },
23024
23025        getScroll : function (elem) {
23026            return {x : elem.scrollLeft, y : elem.scrollTop};
23027        },
23028
23029        getSize : function (elem) {
23030            return {x : elem.offsetWidth, y : elem.offsetHeight};
23031        },
23032
23033        hasScrollBar : function (container) {
23034            
23035            if (isBrowserIE) {
23036                
23037                return ((container.scrollHeight - 2) > container.clientHeight) || ((container.scrollWidth - 2) > container.clientWidth);
23038            } else {
23039                return container.scrollHeight > container.clientHeight || container.scrollWidth > container.clientWidth;
23040            }
23041        }
23042    };
23043
23044    $.fn.afTnc = function (option, value) {
23045        var get = '',
23046            element = this.each(function () {
23047
23048                var $this = $(this),
23049                    data = $this.data('AfTnc'),
23050                    options = $.extend({}, _defaults, typeof option === 'object' && option);
23051
23052                
23053                if (!data) {
23054                    $this.data('AfTnc', (data = new AfTnc(this, options)));
23055                }
23056
23057                
23058                if (typeof option === 'string') {
23059                    get = data[option](value);
23060                }
23061            });
23062
23063        if (typeof get !== undefined) {
23064            return get;
23065        } else {
23066            return element;
23067        }
23068    };
23069
23070})(_, $);
23071(function ($) {
23072    var xfaUtil = xfalib.ut.XfaUtil.prototype;
23073    $.widget("xfaWidget.tnc", $.xfaWidget.abstractWidget, {
23074
23075        _widgetName : "tnc",
23076        _superPrototype : $.xfaWidget.abstractWidget.prototype,
23077        getOptionsMap : function () {
23078            var parentOptionsMap = this._superPrototype.getOptionsMap.apply(this, arguments),
23079                newMap = $.extend({}, parentOptionsMap, $.extend({}, this.options, {
23080                    "value" : function (value) {
23081                        this.$userControl.afTnc("value", value);
23082                    },
23083                    "reviewStatus" : function (value) {
23084                        this.$userControl.afTnc("reviewStatus", value);
23085                    },
23086
23087                    "clickStatus" : function (value) {
23088                        this.$userControl.afTnc("clickStatus", value);
23089                    },
23090                    
23091                    "access" : function (value) {
23092                        this.$userControl.afTnc("access", value);
23093                    }
23094                }));
23095            return newMap;
23096        },
23097
23098        _getReviewStatus : function () {
23099            return $(this.element).afTnc("reviewStatus");
23100        },
23101
23102        _getClickStatus : function () {
23103            return $(this.element).afTnc("clickStatus");
23104        },
23105
23106        getEventMap : function () {
23107            var parentEventMap = this._superPrototype.getEventMap.apply(this, arguments),
23108                newMap = $.extend({}, parentEventMap,
23109                    {
23110                        "change" : null,
23111                        "reviewComplete.tnc" : xfaUtil.XFA_CHANGE_EVENT,
23112                        "checkboxStateChange.tnc" : xfaUtil.XFA_CHANGE_EVENT
23113                    });
23114            return newMap;
23115        },
23116        render : function () {
23117            this._superPrototype.render.apply(this, arguments);
23118            $(this.element).afTnc(this.getOptionsMap());
23119            return $(this.element);
23120        },
23121        showDisplayValue : function () {
23122            
23123        },
23124        showValue : function () {
23125            
23126        },
23127        getCommitValue : function () {
23128            this.options.reviewStatus = this._getReviewStatus();
23129            this.options.clickStatus = this._getClickStatus();
23130            return $(this.element).afTnc("value");
23131        }
23132    });
23133})($);
23134
23135(function (_, guidelib) {
23136    var orderGetAttribute = {
23137        "Guide" : "XFA",
23138        "XFA" : "Guide"
23139    },
23140    
23141    newlyAddedProperties = ["enabled", "visible"];
23142    
23143    var GuideNode = guidelib.model.GuideNode = xfalib.ut.EventClass.extend({
23144        msClassName : "guideNode",
23145        guideUtil : guidelib.util.GuideUtil,
23146
23147        initialize : function () {
23148            
23149            
23150            this.className = this.jsonModel.guideNodeClass || this.msClassName;
23151            this.parent = null;
23152            this._isItem = false;
23153            this._index = 0;
23154        },
23155
23156        _postInitialize : function () {
23157            
23158        },
23159
23160        _triggerOnBridge : function (eventName, target, property, oldVal, newVal) {
23161            if (window.guideBridge) {
23162                window.guideBridge.trigger(eventName,
23163                    guidelib.event.GuideModelEvent.createEvent(eventName, target, property,
23164                                                           oldVal, newVal));
23165            }
23166        },
23167
23168        _getEffectiveBindRef : function() {
23169            return this.bindRef || this.getAttribute("name");
23170        },
23171
23172        validate : function (errorList) {
23173
23174        },
23175
23176        
23177        
23178        _getXFAOptionStringFromGuideItems : function (guideItems) {
23179            var optionsStr = "", indexOfSeparator = 0;
23180            if (!_.isEmpty(guideItems) && !_.isArray(guideItems)) {
23181                guideItems = [guideItems];
23182            }
23183            _.each(guideItems, function (item, index, list) {
23184                if(item.indexOf(",") > -1){
23185                    item = item.replace(/,/g, "\\,");
23186                }
23187                indexOfSeparator = item.indexOf('=');
23188                
23189                
23190                if (indexOfSeparator > -1) {
23191                    optionsStr += item.substring(indexOfSeparator + 1) + "," + item.substring(0, indexOfSeparator);
23192                } else {
23193                    optionsStr += item + "," + item;
23194                }
23195                if (index < guideItems.length - 1) {
23196                    optionsStr += ",";
23197                }
23198            });
23199            return optionsStr;
23200        },
23201
23202        _compareXFAItemsWithGuideItems : function (xfaItems, guideItems) {
23203            var match = true;
23204            if (xfaItems.length !== guideItems.length) {
23205                match = false;
23206            }
23207            if (match) {
23208                var bndNode = this.bindNode;
23209                _.each(guideItems, function (item, index, list) {
23210                    if (item.indexOf('=') > -1) {
23211                        if ((bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index)) == item) {
23212                            match = false;
23213                        }
23214                    } else {
23215                        if ((bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index)) == (item + "=" + item)) {
23216                            match = false;
23217                        }
23218                    }
23219                });
23220            }
23221            return match;
23222        },
23223
23224        
23225        syncXFAProps : function () {
23226            if (this.bindNode) {
23227                _.each(this._guide()._guideSchema.getAttributes(this.className),
23228                    function (attr, attrName) {
23229                        var xfaProp = attr.xfaProp,
23230                            propChain = (xfaProp || "").split("."),
23231                            xfaAttr = propChain.length > 0 ? propChain[propChain.length - 1]
23232                                                           : undefined;
23233                        
23234                        
23235                        
23236                        
23237                        
23238                        
23239                        if (!xfaAttr || (newlyAddedProperties.indexOf(attrName) != -1 && _.isUndefined(this.jsonModel[attrName]))) {
23240                            return;
23241                        }
23242                        var objChain = propChain.splice(0, propChain.length - 1),
23243                            obj = _.reduce(objChain,
23244                                function (obj, prop) {
23245                                    if (_.isObject(obj)) {
23246                                        return obj[prop];
23247                                    }
23248                                    return undefined;
23249                                }, this.bindNode),
23250                            val = this.getGuideProp(attrName, attr),
23251                            convertor = this._guide()._guideSchema.getConvertor(attrName),
23252                            cVal = convertor ? convertor.guideToXfa.apply(this, [val]) : val,
23253                            xfaVal;
23254                        try {
23255                            if (obj) {
23256                                xfaVal = obj[xfaAttr];
23257                                if (cVal !== undefined) {
23258                                    if (xfaAttr === "items") {
23259                                        var match = this._compareXFAItemsWithGuideItems(obj, cVal);
23260                                        var SET_ITEMS_INSERT_MODE_PAIR = 2;
23261                                        if (!match) {
23262                                            var optionsStr = this._getXFAOptionStringFromGuideItems(cVal);
23263                                            if (optionsStr !== "") {
23264                                                obj.setItems(optionsStr, SET_ITEMS_INSERT_MODE_PAIR);
23265                                            } else {
23266                                                obj.clearItems();
23267                                            }
23268                                        }
23269                                    } else if (cVal !== xfaVal) {
23270                                        obj[xfaAttr] = cVal;
23271                                    }
23272                                }
23273                            }
23274                        } catch (e) {
23275                            this.logger().error("AF", "setting {0}(guide {1}) for {2} is not supported in xfa",
23276                                [xfaProp, attrName, this.bindNode.somExpression]);
23277                            if (e.stack) {
23278                                this.logger().error("AF", e.stack);
23279                            }
23280                        }
23281                    }, this);
23282            }
23283        },
23284
23285        
23286        prepare : function () {
23287
23288        },
23289
23290        
23291        nakedChildReferences : function (nIndex, obj) {
23292            return;
23293        },
23294
23295        
23296        getNaked : function (nIndex, container, scope) {
23297            var nodeName = this.getAttribute("name"),
23298                oldReference = container._private["_" + nodeName + "_"],
23299                canOverride = (container._isOverriden && !container._isOverriden["_" + nodeName + "_"]),
23300                isGlobalFieldRef = this.isGlobal && (container === guidelib.__runtime__ || container === this._guide().runtime) 
23301                    && (container[nodeName] instanceof guidelib.model.AbstractField);
23302
23303            if ((scope && scope._nameArray[nodeName] === 1) || (nIndex === this.index)) {
23304                if (oldReference === null || oldReference === undefined || canOverride || isGlobalFieldRef) {
23305                    guidelib.util.GuideUtil._createGetterSetter(container, nodeName, this);
23306                    if (canOverride === true) {
23307                        container._isOverriden["_" + nodeName + "_"] = true;
23308                    }
23309                }
23310            }
23311        },
23312
23313        _getReducedJSON : function () {
23314            var whitelistedProperties = ["name", "templateId", "_value", "guideNodeClass"],
23315                reducedJsonObject = {};
23316            guidelib.model.util.CommonUtils.returnMinimalJSON(whitelistedProperties, reducedJsonObject, this);
23317            return reducedJsonObject;
23318        },
23319
23320        _getNakedThis : function () {
23321            return this;
23322        },
23323
23324        _xfa : function () {
23325            if (window.xfalib) {
23326                return window.xfalib.runtime.xfa;
23327            }
23328            return null;
23329        },
23330
23331        _guide : function () {
23332            return this.options._guideContainer;
23333        },
23334
23335        
23336        playJson : function (pJsonModel) {
23337
23338        },
23339
23340        
23341        
23342        visit : function (callback, context) {
23343            callback.apply(context, [this]);
23344        },
23345
23346        _collectValues : function (keyValue) {
23347
23348        },
23349
23350        _setParentAccess : function (value) {
23351            
23352        },
23353
23354        _unloadModel : function () {
23355            this.trigger(guidelib.event.GuideModelEvent.OBJECT_DESTROYED,
23356                guidelib.event.GuideModelEvent.createEvent(
23357                    guidelib.event.GuideModelEvent.OBJECT_DESTROYED,
23358                    this,
23359                    "destroy",
23360                    null,
23361                    this
23362                )
23363            );
23364            this._guide()._modelTemplateCacheStore.removeModel(this.id);
23365            this.off();
23366
23367            if (_.isObject(guidelib.__runtime__[this.name]) && (guidelib.__runtime__[this.name] === this || guidelib.__runtime__[this.name].somExpression === this.somExpression)) {
23368                guidelib.__runtime__[this.name] = undefined;
23369                if (_.isObject(guidelib.__runtime__._private['_' + this.name + '_'])) {
23370                    guidelib.__runtime__._private['_' + this.name + '_'] = undefined;
23371                }
23372            }
23373
23374            if (_.isObject(this._guide().runtime[this.name]) && (this._guide().runtime[this.name] === this || this._guide().runtime[this.name].somExpression === this.somExpression)) {
23375                this._guide().runtime[this.name] = undefined;
23376                if (_.isObject(this._guide().runtime._private['_' + this.name + '_'])) {
23377                    this._guide().runtime._private['_' + this.name + '_'] = undefined;
23378                }
23379            }
23380        },
23381
23382        _triggerEvent : function (event, propName, prevText, newText) {
23383            this.trigger(event,
23384                guidelib.event.GuideModelEvent.createEvent(event, this, propName,
23385                                                           prevText, newText));
23386        },
23387
23388        
23389        dispatchEvent : function (eventName, payload) {
23390            this._triggerEvent(eventName, payload);
23391            if(this.parent !== null){
23392                this.parent.dispatchEvent(eventName, payload);
23393            }
23394        },
23395
23396        
23397        setAttribute : function (value, attrName) {
23398            if (this.jsonModel[attrName] !== value) { 
23399                var oldValue = this.jsonModel[attrName];
23400                this.jsonModel[attrName] = value;
23401                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, attrName, oldValue, value);
23402            }
23403        },
23404
23405        _getSomExpression : function () {
23406            if (this.parent == null) {
23407                return "guide[0]." + this._escapeQualifiedName();
23408            } else {
23409                return this.parent.somExpression + "." + this._escapeQualifiedName();
23410            }
23411        },
23412
23413        _escapeQualifiedName : function () {
23414            var name = this.getAttribute("name");
23415            var index = this._index;
23416            var qname = name + "[" + index + "]";
23417            return qname.replace(/\./, "\\.");
23418        },
23419
23420        
23421        getGuideProp : function (attrName, attr) {
23422            var val = this.getOrElse(this.jsonModel, attrName, attr["default"]);
23423            if (val === undefined) {
23424                return undefined;
23425            }
23426            return guidelib.model.GuideSchema.prototype.getTypedValue(attr.type, val);
23427            
23428        },
23429
23430        
23431        getXFAProp : function (attrName, attr) {
23432            var xfaName = attr.xfaProp,
23433                convertor = guidelib.model.GuideSchema.prototype.getConvertor(attrName),
23434                val;
23435            if (this.bindNode && xfaName !== undefined) {
23436                val = this.bindNode.getOrElse(this.bindNode, xfaName, undefined);
23437                if (convertor) {
23438                    val = convertor.xfaToGuide.apply(this, [val]);
23439                }
23440                if (val !== undefined) {
23441                    return val;
23442                }
23443            }
23444            return undefined;
23445        },
23446
23447        
23448        getAttribute : function (attrName) {
23449            var attr = guidelib.model.GuideSchema.prototype.getAttributeProps(this.className, attrName),
23450                priority = attr.priority || (attr.xfaProp !== undefined ? "XFA" : "Guide"), 
23451                                                  
23452                val = this["get" + priority + "Prop"].apply(this, [attrName, attr]); 
23453            
23454            if (val === undefined) {
23455                
23456                val = this["get" + orderGetAttribute[priority] + "Prop"].apply(this, [attrName, attr]);
23457            }
23458            return val;
23459        },
23460
23461        
23462        resetData : function () {
23463
23464        }
23465    });
23466
23467    GuideNode.defineProps({
23468
23469        
23470        "name" : {
23471            get : function () {
23472                return (this.getAttribute("name") || "").replace(/\s+/g, '');
23473            }
23474        },
23475
23476        "templateId" : {
23477            get : function () {
23478                return this.getAttribute("templateId");
23479            }
23480        },
23481
23482        
23483        "id" : {
23484            get : function () {
23485                return this.getAttribute("id") || this.templateId;
23486            }
23487        },
23488
23489        
23490        somExpression : {
23491            get : function () {
23492                return this._getSomExpression();
23493            }
23494        },
23495
23496        
23497        "title" : {
23498            get : function () {
23499                return this.getAttribute("jcr:title");
23500            }
23501        },
23502
23503        
23504        "nonLocalizedTitle" : {
23505            get : function () {
23506                return this.getAttribute("nonLocalizedTitle");
23507            }
23508        },
23509
23510        
23511        panel : {
23512            get : function () {
23513                return this.parent.panel;
23514            }
23515        },
23516
23517        viewVisited : {
23518            get : function () {
23519                return this.getAttribute("viewVisited");
23520            },
23521            set : function (visit) {
23522                this.setAttribute(visit, "viewVisited");
23523            }
23524        },
23525
23526        
23527        index : {
23528            get : function () {
23529                return this._index;
23530            }
23531        },
23532
23533        
23534        visible : {
23535            get : function () {
23536                return true;
23537            },
23538            set : function (value) {
23539                
23540            }
23541        },
23542
23543        
23544        enabled : {
23545            get : function () {
23546                return true;
23547            },
23548            set : function (value) {
23549                
23550            }
23551        },
23552
23553        
23554        cssClassName : {
23555            get : function () {
23556                return this.getAttribute("css");
23557            }
23558        },
23559
23560        enableLayoutOptimization : {
23561            get : function () {
23562                return false;
23563            }
23564        },
23565
23566        jcrPath : {
23567            get : function () {
23568                return this.jsonModel["jcr:path"];
23569            }
23570        },
23571
23572        
23573        targetVersion : {
23574            get : function () {
23575                return this.getAttribute("fd:targetVersion");
23576            }
23577        }
23578    });
23579}(_, guidelib));
23580(function (_, guidelib, $) {
23581    var Verify = guidelib.model.Verify = guidelib.model.GuideNode.extend({
23582        msClassName : "verify",
23583
23584        initialize : function () {
23585            Verify._super.initialize.call(this);
23586            this.validationStatus = true;
23587        },
23588
23589        validate : function (errorList) {
23590            
23591
23592            var iframeFormBridge = null, validationStatus = true;
23593
23594            if (this.jsonModel.interactive !== undefined && this.jsonModel.interactive === "true") {
23595                
23596                
23597                
23598                
23599                
23600                if (guideBridge.hostName === "client") {
23601                    iframeFormBridge = $('#verifiable_form').get(0).contentWindow.formBridge;
23602                }
23603                
23604                
23605                if (iframeFormBridge !== undefined && iframeFormBridge !== null) {
23606                    validationStatus = iframeFormBridge.validateForm();
23607                    if (!validationStatus) {
23608                        errorList.push({som : this.somExpression, errorText : "XFA validation errors."});
23609                    }
23610                    this.validationStatus = validationStatus;
23611                }
23612            }
23613
23614            return validationStatus;
23615        }
23616    });
23617    Verify.defineProps({
23618        forceElementFocusChange : {
23619            get : function () {
23620                return true;
23621            }
23622        }
23623    });
23624})(_, guidelib, $);
23625(function (_, guidelib) {
23626    var Esign = guidelib.model.Esign = guidelib.model.GuideNode.extend({
23627        msClassName : "esign",
23628
23629        initialize : function () {
23630            Esign._super.initialize.call(this);
23631            this.validationStatus = true;
23632        },
23633
23634        validate : function (errorList) {
23635            
23636            
23637            var validationStatus =  true;
23638            if (!_.isUndefined(FD) &&
23639                !_.isUndefined(FD.AFaddon) &&
23640                FD.AFaddon.Signing) {
23641                validationStatus = FD.AFaddon.Signing.isDocumentSigned(this.jsonModel.signingService);
23642                if (!validationStatus) {
23643                    errorList.push({som : this.somExpression, errorText : "Signing not complete."});
23644                }
23645            }
23646            this.validationStatus = validationStatus;
23647            return validationStatus;
23648        }
23649    });
23650    Esign.defineProps({
23651        forceElementFocusChange : {
23652            get : function () {
23653                return true;
23654            }
23655        }
23656    });
23657})(_, guidelib);
23658(function (_, xfalib, guidelib) {
23659    
23660    var expressionContent = "with(this) {" +
23661                        "\n\t with(guidelib.__runtime__) {" +
23662                        "\n\t with(this._guide().runtime) {" +
23663                        "\n\t\t var _guide_result = this[${affectedProp}] = eval(\"${expression}\");" +
23664                        "\n\t\t return _guide_result ;" +
23665                        "\n\t }" +
23666                        "\n}};",
23667        scriptContent = "with(this) {" +
23668                        "\n\t with(guidelib.__runtime__) {" +
23669                        "\n\t with(this._guide().runtime) {" +
23670                        "\n\t var result = eval(\"${expression}\");" +
23671                        "\n\t\t return result; " +
23672                        "\n\t }" +
23673                        "\n}}";
23674    
23675    var Scriptable = guidelib.model.Scriptable = guidelib.model.GuideNode.extend({
23676        msClassName : "scriptable",
23677
23678        initialize : function () {
23679            Scriptable._super.initialize.call(this);
23680            
23681            this.className = this.jsonModel.guideNodeClass || this.msClassName;
23682            this._compiledExpressions = {};
23683            this._compiledScripts = {};
23684            this.mActiveEvents = [];
23685            this.dependants = [];
23686            
23687            if (this.initScript) {
23688                this._isInitScriptExecuted = false;
23689            }
23690            this._collectExpressions();
23691        },
23692
23693        _postInitialize : function () {
23694            
23695            if (this._isXfaNode()) {
23696                this.bindNode = this.options.bindNode || this._getBindNode();
23697                if (this.bindNode) {
23698                    this.bindNode.on(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
23699                }
23700            }
23701            
23702            this._parentAccess = this.getOrElse(this, "parent.enabled", true);
23703        },
23704
23705        _unloadModel : function () {
23706            if (this._isXfaNode && this._isXfaNode()) {
23707                if (this.bindNode) {
23708                    this.bindNode.off(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
23709                }
23710            }
23711
23712            Scriptable._super._unloadModel.call(this);
23713        },
23714
23715        _collectExpressions : function () {
23716            if (this.visibleExp) {
23717                this._compiledExpressions["visibleExp"] = this._compileExpression(this.visibleExp, "visible");
23718            }
23719            if (this.enabledExp) {
23720                this._compiledExpressions["enabledExp"] = this._compileExpression(this.enabledExp, "enabled");
23721            }
23722            
23723            if (this.initScript) {
23724                this._compiledScripts.initScript = this._compileExpression(this.initScript, null);
23725            }
23726        },
23727
23728        _compileExpression : function (expression, affectedProp) {
23729            if (expression) {
23730                try {
23731                    
23732                    var content = affectedProp ? expressionContent.replace(/\${affectedProp}/g, '"' + affectedProp + '"')
23733                                                                  .replace(/\${expression}/g, expression.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/(?:\r\n|\r|\n)/g, " "))
23734                                               : scriptContent.replace(/\${expression}/g,
23735                                                                        expression.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/(?:\r\n|\r|\n)/g, " "));
23736
23737                    return new Function(content);
23738                } catch (exception) {
23739                    this.logger().error("AF", "Error in compiling expression:" + expression);
23740                }
23741            }
23742            return null;
23743        },
23744
23745        _isXfaNode : function () {
23746            return (this._xfa() && this.getOrElse(this, "jsonModel.bindRef", "").indexOf("xfa[0].form[0].") === 0);
23747        },
23748
23749        _xfa : function () {
23750            return this.getOrElse(window, "xfalib.runtime.xfa", null);
23751        },
23752
23753        prepare : function () {
23754            Scriptable._super.prepare.apply(this);
23755            
23756            
23757            
23758            
23759            
23760            if (this.initScript && !this._isInitScriptExecuted) {
23761                this.executeExpression("initScript");
23762                this._isInitScriptExecuted = true;
23763            }
23764            var expressionTypes = _.keys(this._compiledExpressions);
23765            this._guide().queueExpressions(this, expressionTypes);
23766        },
23767
23768        
23769        handleEvent : function (evnt) {
23770            if (evnt instanceof xfalib.script.XfaModelEvent) {  
23771                switch (evnt.name) {
23772                    case xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED:
23773                        this._handleXfaModelChanged(evnt);
23774                        break;
23775                    default:
23776                    
23777                }
23778            } else if (evnt instanceof guidelib.event.GuideModelEvent) {
23779                this.handleGuideEvent(evnt);
23780            }
23781        },
23782
23783        handleGuideEvent : function (evnt) {
23784        },
23785
23786        
23787        executeExpression : function (eventName, detail) {
23788            var guideContainerNode = this._guide();
23789            if (this._isXfaNode() && this.bindNode instanceof xfalib.script.EventContainerNode) {
23790                if (guidelib.util.GuideUtil.xfaExprMap[eventName] !== null) {
23791                    this.bindNode.execEvent(guidelib.util.GuideUtil.xfaExprMap[eventName] || eventName, detail);
23792                }
23793            }
23794            if (_.isUndefined(this._compiledExpressions[eventName]) && _.isUndefined(this._compiledScripts[eventName])) {
23795                if (!guideContainerNode._currentContext) {
23796                    guideContainerNode.runPendingExpressions();
23797                } else {
23798                    this.logger().log("AF", "executeExpression called withing from another executeExpression. Should NEVER happen ");
23799                }
23800                return true;
23801            }
23802
23803            if (this.mActiveEvents[eventName]) {
23804                return;
23805            }
23806            this.mActiveEvents[eventName] = true;
23807            var managedExp = this._compiledExpressions[eventName] ? true : false,
23808                oldContext = guideContainerNode._currentContext;
23809            
23810            guideContainerNode._currentContext = {contextNode: this, expression: eventName, managedExp: managedExp};
23811            this._setExpressionContext(this, this.index);
23812            var $event = {
23813                name: eventName,
23814                target: this,
23815                data: detail
23816            };
23817            guideContainerNode.runtime.$event = $event;
23818            var expResult = this._expressionHandler(eventName);
23819            this.mActiveEvents[eventName] = false;
23820            
23821            
23822            guideContainerNode._currentContext = oldContext;
23823            if (oldContext && oldContext.contextNode) {
23824                oldContext.contextNode._setExpressionContext(oldContext.contextNode, oldContext.contextNode.index);
23825            }
23826            guideContainerNode.runtime.$event = null;
23827            guideContainerNode.runPendingExpressions();
23828            return expResult;
23829        },
23830
23831        _setExpressionContext : function (startNode, currentIndex) {
23832            
23833            var currentSom = this.somExpression;
23834            function somCommonPrefixLen(field) {
23835                return guidelib.util.GuideUtil.commonPrefixLen(currentSom, field.somExpression);
23836            }
23837
23838            if (this._guide().internal.liveModel) {
23839                _.each(this._guide().internal.liveModel.getCrossFragmentFields(), function (fields, name) {
23840                    var loadedFields,
23841                        nearestField;
23842
23843                    
23844                    loadedFields = this._guide().internal.liveModel.getAllFieldModels(_.keys(fields));
23845
23846                    
23847                    if (!_.isEmpty(loadedFields)) {
23848                        nearestField = _.max(loadedFields, somCommonPrefixLen);
23849                    }
23850
23851                    
23852                    
23853
23854                    
23855                    guidelib.util.GuideUtil._createGetterSetter(guidelib.__runtime__, name, nearestField || fields[_.keys(fields)[0]]);
23856                    guidelib.util.GuideUtil._createGetterSetter(this._guide().runtime, name, nearestField || fields[_.keys(fields)[0]]);
23857                }, this);
23858            }
23859
23860            
23861            this._guide().runtime._isOverriden = {};
23862            guidelib.__runtime__._isOverriden = {};
23863            while (startNode) {
23864                
23865                startNode.nakedChildReferences(currentIndex, guidelib.__runtime__);
23866                startNode.nakedChildReferences(currentIndex, this._guide().runtime);
23867                currentIndex = startNode.index;
23868                startNode = startNode.parent;
23869            }
23870        },
23871
23872        _expressionHandler : function (expressionName) {
23873            var expFn, returnValue;
23874            if (this._compiledExpressions[expressionName]) {
23875                expFn = this._compiledExpressions[expressionName];
23876                try {
23877                    returnValue = expFn.apply(this);
23878                } catch (exception) {
23879                    
23880                    this.logger().error("AF", "Error in compiling expression:" + this.name + ":" + expressionName + ":" + exception.stack);
23881                }
23882            } else if (this._compiledScripts[expressionName]) {
23883                expFn = this._compiledScripts[expressionName];
23884                try {
23885                    return expFn.apply(this);
23886                } catch (scriptException) {
23887                    
23888                    this.logger().error("AF", "Error in compiling expression:" + this.name + ":" + expressionName + ":" + scriptException.stack);
23889                }
23890            }
23891            return returnValue;
23892        },
23893
23894        _handleXfaModelChanged : function (event) {
23895            if (event._property == "presence") {
23896                
23897                var newText = !(event.newText != "visible");
23898                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "visible", event.prevText, newText);
23899            } else if (event._property == "access") {
23900                this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
23901                    guidelib.event.GuideModelEvent.createEvent(
23902                        guidelib.event.GuideModelEvent.MODEL_CHANGED,
23903                        this,
23904                        "enabled",
23905                        event.prevText == "open",
23906                        event.newText == "open"
23907                    )
23908                );
23909            }
23910        },
23911
23912        _getScreenReaderText : function (index) {
23913            var screenReaderText, assistPriority = this._getAssistPriority();
23914            if (assistPriority == "custom") {
23915                screenReaderText = this._getCustomAssist(index) || this._getToolTip(index) || this._getCaption(index) || this._getName(index);
23916            } else if (assistPriority == "shortDescription") {
23917                screenReaderText = this._getToolTip(index) || this._getCaption(index) || this._getName(index);
23918            } else if (assistPriority == "label") {
23919                screenReaderText = this._getCaption(index) || this._getName(index);
23920            } else if (assistPriority == "name") {
23921                screenReaderText = this._getName(index);
23922            }
23923            return screenReaderText;
23924        },
23925
23926        _getAssistPriority : function () {
23927            
23928            return this.getAttribute("assistPriority") || "custom";
23929        },
23930
23931        _getCustomAssist : function () {
23932            var customAssist;
23933            if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
23934                customAssist = this.bindNode.assist.speak.value;
23935            } else if (this.jsonModel.custom) {
23936                customAssist = this.jsonModel.custom;
23937            }
23938            return customAssist;
23939        },
23940
23941        _getToolTip : function () {
23942            return this.shortDescription;
23943        },
23944
23945        _getCaption : function () {
23946            return this.getAttribute("jcr:title");
23947        },
23948
23949        _getName : function (index) {
23950            return this.getAttribute("name");
23951        },
23952
23953        _getBindNode : function () {
23954            var bindRef = this.getAttribute("bindRef");
23955            if (!bindRef) {
23956                return null;
23957            }
23958            var bindNode = null;
23959            var bindParent = this.parent ? this.parent._bindParent() : null;
23960            if (bindParent) {
23961                var bindParentRef = bindParent.getAttribute("bindRef");
23962                if (bindRef.substring(0, bindParentRef.length) == bindParentRef) {
23963                    
23964                    
23965                    var relativeBindRef = bindRef.substring(bindParentRef.length + 1); 
23966                    bindNode = bindParent.bindNode.resolveNode(relativeBindRef);
23967                }
23968            }
23969            if (!bindNode && this._isXfaNode()) {
23970                bindNode = this._xfa().resolveNode(bindRef);
23971            }
23972            return bindNode;
23973        },
23974
23975        _bindParent : function () {
23976            if (this.bindNode) {
23977                return this;
23978            } else if (this.parent) {
23979                return this.parent._bindParent();
23980            }
23981            return null;
23982        },
23983
23984        
23985        _getEnabled : function () {
23986            if (this.bindNode) {
23987                return this.bindNode.access == "open";
23988            } else {
23989                return this.getAttribute("enabled") && this._parentAccess;
23990            }
23991        },
23992
23993        
23994        _setEnabled : function (value) {
23995            if (!this.bindNode) {
23996                if (this.getAttribute("enabled") !== value) {
23997                    var oldEnabled = this.getAttribute("enabled");
23998                    this.setAttribute(value, "enabled");
23999                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
24000                        guidelib.event.GuideModelEvent.createEvent(
24001                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
24002                            this,
24003                            "enabled",
24004                            oldEnabled,
24005                            this.jsonModel.enabled
24006                        )
24007                    );
24008                    this._triggerOnBridge("elementEnableChanged", this, "enablement", oldEnabled, this.jsonModel.enabled);
24009                }
24010
24011            } else {
24012                var convertor = this._guide()._guideSchema.getConvertor("enabled");
24013                if (convertor) {
24014                    this.bindNode.access =  convertor.guideToXfa.apply(this, [value]);
24015                }
24016            }
24017        },
24018
24019        
24020        _setParentAccess : function (value) {
24021            var oldValue = this._parentAccess;
24022            this._parentAccess = value;
24023            this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
24024                guidelib.event.GuideModelEvent.createEvent(
24025                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
24026                    this,
24027                    "enabled",
24028                    oldValue,
24029                    this.enabled
24030                )
24031            );
24032        },
24033
24034        
24035        _addStateOverride : function (key, values) {
24036            if (key !== null && _.isString(key) && values !== null) {
24037                var somExpr = this.somExpression;
24038                somExpr = somExpr.substring(this._guide().somExpression.length + 1);
24039                this.jsonModel.stateOverrides = this.jsonModel.stateOverrides || {"somExpr" : somExpr};
24040                this.jsonModel.stateOverrides[key] = values;
24041                this._guide()._addToStateOverrideMap(this.id + this.name, this.jsonModel.stateOverrides);
24042            }
24043        }
24044    });
24045
24046    Scriptable.defineProps({
24047        
24048        shortDescription : {
24049            get : function () {
24050               return this.getAttribute("shortDescription");
24051           }
24052        },
24053
24054        
24055        longDescription : {
24056            get : function () {
24057                return this.getAttribute("longDescription");
24058            }
24059        },
24060
24061        visibleExp : {
24062            get : function () {
24063                return this.getAttribute("visibleExp");
24064            }
24065        },
24066
24067        initScript : {
24068            get : function () {
24069                return this.jsonModel.initScript;
24070            }
24071        },
24072
24073        enabledExp : {
24074            get : function () {
24075                return this.getAttribute("enabledExp");
24076            }
24077        },
24078
24079        
24080        visible : {
24081            get : function () {
24082                return this.getAttribute("visible");
24083            },
24084
24085            set : function (value) {
24086                if (!this.bindNode) {
24087                    if (this.getAttribute("visible") !== value) {
24088                        var oldVisible = this.getAttribute("visible"),
24089                            dorExclusionFlag;
24090                        this.setAttribute(value, "visible");
24091                        
24092                        
24093                        if (this.getAttribute("dorExclusion") !== null) {
24094                            if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true") 
24095                                || (this._guide().print
24096                                && this._guide().print["excludeFromDoRIfHidden"] === "true")) {
24097                                dorExclusionFlag = !value;
24098                                
24099                                
24100                                this.dorExclusion = dorExclusionFlag;
24101                            }
24102                        }
24103                        this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
24104                            guidelib.event.GuideModelEvent.createEvent(
24105                                guidelib.event.GuideModelEvent.MODEL_CHANGED,
24106                                this,
24107                                "visible",
24108                                oldVisible,
24109                                this.jsonModel.visible
24110                            )
24111                        );
24112                        this._triggerOnBridge("elementVisibleChanged", this, "visible", oldVisible, this.jsonModel.visible);
24113
24114                    }
24115                } else {
24116                    if (value == true) {
24117                        this.bindNode.presence = "visible";
24118                    } else {
24119                        this.bindNode.presence = "hidden";
24120                    }
24121                }
24122            }
24123        },
24124
24125        
24126        dorExclusion : {
24127            get : function () {
24128                
24129                if (this.jsonModel.dorExclusion != null) {
24130                    if (_.isString(this.jsonModel.dorExclusion)) {
24131                        
24132                        return this.jsonModel.dorExclusion === "true";
24133                    } else {
24134                        return this.jsonModel.dorExclusion;
24135                    }
24136                }
24137                
24138                else if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true") 
24139                    || (this._guide().print
24140                    && this._guide().print["excludeFromDoRIfHidden"] === "true")) {
24141                    return !this.visible;
24142                } else {
24143                    
24144                    return false;
24145                }
24146            },
24147
24148            set : function (value) {
24149                
24150                
24151                
24152                var somExpr = this.somExpression;
24153                somExpr = somExpr.substring(this._guide().somExpression.length + 1);
24154                this._guide()._addToExcludeFromDorMap(somExpr, value);
24155                this.jsonModel.dorExclusion = value;
24156            }
24157        },
24158
24159        
24160        stateOverrides : {
24161            get : function () {
24162                return this.jsonModel.stateOverrides;
24163            }
24164        },
24165
24166        
24167        enabled : {
24168            get : function () {
24169                return this._getEnabled();
24170            },
24171
24172            set : function (value) {
24173                
24174                this._setEnabled(!!value);
24175            }
24176        },
24177
24178        
24179        bindRef : {
24180            get : function () {
24181                return (this.getAttribute("bindRef") || "").replace(/\s+/g, '');
24182            }
24183        },
24184
24185        
24186        isXsd : {
24187            
24188            get : function () {
24189                return _.isString(guideBridge._guide.xsdRef) && !_.isEmpty(this.bindRef) && this.bindRef[0] === '/';
24190            }
24191        }
24192    });
24193})(_, window.xfalib, guidelib);
24194(function (_, guidelib) {
24195    var GuideImage = guidelib.model.GuideImage = guidelib.model.Scriptable.extend({
24196        msClassName : "guideImage"
24197    });
24198
24199    GuideImage.defineProps({
24200        value : {
24201            get : function () {
24202                if (this.bindNode) {
24203                    return this.bindNode.rawValue;
24204                } else {
24205                    return null;
24206                }
24207            }
24208        }
24209    });
24210})(_, guidelib);
24211(function (_, guidelib) {
24212    var GuideAdModule = guidelib.model.GuideAdModule = guidelib.model.Scriptable.extend({
24213        msClassName : "guideAdModule",
24214
24215        initialize : function () {
24216            GuideAdModule._super.initialize.call(this);
24217            this.jsonModel["{default}"] = this.getOrElse(this.jsonModel, "{default}", this.jsonModel._value);
24218            this.layoutConfigs = [];
24219            
24220            if (typeof this.jsonModel.layoutConfig === "string") {
24221                this.layoutConfigs.push(JSON.parse(this.jsonModel.layoutConfig));
24222            } else {
24223                _.each(this.jsonModel.layoutConfig, function (layoutConfig) {
24224                    this.layoutConfigs.push(JSON.parse(layoutConfig));
24225                }, this);
24226            }
24227        },
24228
24229        _getTypedValue : function (value) {
24230            if (_.isUndefined(value) || value === null || value === "") {
24231                return null;
24232            }
24233            return value + "";
24234        },
24235
24236        playJson : function (pJsonModel) {
24237            var olval = this.jsonModel._value;
24238            this.jsonModel._value = pJsonModel._value;
24239            this._triggerOnBridge("elementValueChanged", this, "value", olval, this.jsonModel._value);
24240        }
24241    });
24242
24243    GuideAdModule.defineProps({
24244        
24245        value : {
24246            get : function () {
24247                return this._getTypedValue(this.jsonModel._value);
24248            },
24249            set : function (newValue) {
24250                var oldValue = this._getTypedValue(this.jsonModel._value),
24251                    newTypedValue = this._getTypedValue(newValue);
24252                
24253                if (newTypedValue !== undefined && (newTypedValue !== oldValue)) {
24254                    if (this.jsonModel._value !== newValue) {
24255                        this.jsonModel._value = newTypedValue || "";
24256                    }
24257                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
24258                }
24259            }
24260        }
24261    });
24262}(_, guidelib));
24263(function (_, $) {
24264
24265    var Responsive = {
24266        breakpoints : [],
24267        controlRowDefaults : {}
24268    },
24269    isPad = navigator.userAgent.match(/iPad/i) !== null,
24270    isIphone = (navigator.userAgent.match(/iPhone/i) !== null) || (navigator.userAgent.match(/iPod/i) !== null),
24271    isIphoneOrIpad = isPad || isIphone;
24272    
24273    Responsive.breakpoints = [
24274        {
24275            name : 'desktop',
24276            width : Infinity
24277        },
24278        {
24279            name : 'tablet-landscape',
24280            width : 1024
24281        },
24282        {
24283            name : 'tablet-potrait',
24284            width : 768
24285        },
24286        {
24287            name : 'mobile-landscape',
24288            width : 480
24289        },
24290        {
24291            name : 'mobile-potrait',
24292            width : 320
24293        }
24294    ];
24295
24296    
24297    Responsive.controlRowDefaults = {
24298        
24299        breakpoints : Responsive.breakpoints,
24300
24301        
24302        controlRowDetails : {
24303            renderer : function (tablePlugin, row) {
24304                var cells = null;
24305                if (tablePlugin.options.bControlRowHiddenCells) {
24306                    cells = row.$tableRowElement.find("td:hidden");
24307                } else {
24308                    cells = row.$tableRowElement.find("td");
24309                    
24310                    if (tablePlugin.options.bDisableControlRowCells) {
24311                        
24312                        row.$tableRowElement.find("input, select, textarea, button").attr("disabled", "disabled");
24313                    }
24314                }
24315                var data = cells.map(function (index, cell) {
24316                    var $cell = $(cell),
24317                        header = tablePlugin.header($cell),
24318                        $clickedTableRow = row.$tableRowElement,
24319                        cellIdx = null,
24320                        cellData = null;
24321                    cellIdx = {
24322                        
24323                        row : $clickedTableRow.index(),
24324                        column : $cell.index()
24325                    };
24326
24327                    cellData = tablePlugin._getCellData(cellIdx);
24328                    return $("<li></li>").attr("data-rtp-index", cellIdx.column).addClass("clearfix").append(
24329                        $("<div></div>").addClass("rtp-title").text($.trim(header.text()))
24330                    ).append(
24331                        $("<div></div>").addClass("rtp-data").append(cellData)
24332                    );
24333                });
24334
24335                return $('<ul data-rtp-index="' + row.index + '"></ul>').append(data.get());
24336            },
24337
24338            target : 0,
24339
24340            type : 'inline'
24341        }
24342    };
24343    
24344    var ResponsiveTablePlugin = function (element, options) {
24345        this.options = options;
24346        this.$element = $(element);
24347        this.columns = [];
24348    };
24349
24350    
24351    var TableColumn = function ($tableElement, colIdx, bIsResize) {
24352        var $colHeaderElement = $tableElement.find("th").eq(colIdx);
24353        
24354        this.minWidth =  (bIsResize ? (parseInt($colHeaderElement.css("min-width"), 10)) : $colHeaderElement.outerWidth());
24355        this.header = $colHeaderElement;
24356        this.colIndex = colIdx;
24357        this.$tableElement = $tableElement;
24358    };
24359
24360    
24361    TableColumn.prototype = {
24362        
24363        cells : function () {
24364            
24365            var headerValue = this.header.attr("id");
24366            return this.$tableElement.find("tr td").filter(function () {
24367                var id = $(this).attr("headers");
24368                if (id) {
24369                    if (id.indexOf(headerValue) > -1) {
24370                        return $(this);
24371                    }
24372                }
24373            });
24374        },
24375        
24376        visible : function (bFlag) {
24377            var cells = this.cells();
24378            this.isVisible = bFlag;
24379            if (bFlag ===  true) {
24380                cells.show();
24381                this.header.show();
24382            } else {
24383                this.header.hide();
24384                
24385                var headers = this.header.prevAll().filter(":visible"),
24386                    headerLen = headers.length;
24387                
24388                $.each(cells, function () {
24389                    if (!$(this).data("shown")) {
24390                        $(this).hide();
24391                    }
24392                    var colSpan = $(this).data("colspan") || $(this).attr("colspan");
24393                    
24394                    if (colSpan > 1) {
24395                        var totalColSpan = 0;
24396                        $(this).prevAll().each(function () {
24397                            totalColSpan += (+($(this).data("colspan") || $(this).attr("colspan")));
24398                        });
24399                        
24400                        if (totalColSpan == 0) {
24401                            $(this).show();
24402                            $(this).data("shown", true);
24403                            
24404                            if ($(this).data("colspan") == null) {
24405                                $(this).data("colspan", $(this).attr("colspan"));
24406                            }
24407                            $(this).attr("colspan", headerLen);
24408                        }
24409                        
24410                        else if (totalColSpan < headerLen) {
24411                            $(this).show();
24412                            $(this).data("shown", true);
24413                            if ($(this).data("colspan") == null) {
24414                                $(this).data("colspan", $(this).attr("colspan"));
24415                            }
24416                            $(this).attr("colspan", (headerLen - totalColSpan));
24417                        }
24418                    }
24419                });
24420            }
24421        }
24422    };
24423
24424    
24425    var TableRow = function ($tableRowElement) {
24426        this.$tableRowElement = $tableRowElement;
24427        this.index = $tableRowElement.index();
24428        
24429        this.child = {
24430            $element : null,
24431            isShown : false
24432        };
24433        $tableRowElement.data("tableRow", this);
24434    };
24435
24436    TableRow.prototype = {
24437
24438        updateChild : function (info, colSpan) {
24439            
24440            if (this.child.$element && this.child.$element.length > 0) {
24441                this.child.$element.empty();
24442                this.child.$element.append($("<td></td>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).attr("colspan", colSpan).append($(info)));
24443            } else if (this.$tableRowElement.next(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).length > 0) {
24444                this.child.$element = this.$tableRowElement.next();
24445                this.child.$element.append($("<td></td>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).attr("colspan", colSpan).append($(info)));
24446            } else {
24447                
24448                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)));
24449                
24450                this.$tableRowElement.after(this.child.$element);
24451            }
24452
24453        },
24454
24455        showChild : function () {
24456            
24457            this.child.$element.get(0).style.display = "";
24458            this.child.isShown = true;
24459        },
24460
24461        hideChild : function () {
24462            this.child.$element.hide();
24463            this.child.isShown = false;
24464        }
24465    };
24466
24467    ResponsiveTablePlugin.prototype = {
24468        
24469        _getCellData : function (index) {
24470            
24471            var tableRow = this.$element.find("tbody tr").eq(index.row),
24472                tableCell =   tableRow.find("td").eq(index.column);
24473            
24474            if (this.options.viewCallback) {
24475                
24476                var id = tableCell.find(ResponsiveTablePlugin.prototype.defaults.GUIDE_ID_SELECTOR).attr("id");
24477                
24478                return this.options.viewCallback(id);
24479            } else {
24480                return tableCell.html();
24481            }
24482        },
24483
24484        
24485        header : function (cell) {
24486            
24487            
24488            var id = cell.attr("headers").split(" ")[0];
24489            
24490            return this.$element.find("#" + id);
24491        },
24492
24493        initializeColumns : function (bIsResize) {
24494            var columns = [];
24495            
24496            
24497            
24498            this.colLength = this.$element.find("th").length;
24499            for (var colIdx = 0; colIdx < this.colLength; colIdx++) {
24500                
24501                
24502                columns.push(new TableColumn(this.$element, colIdx, bIsResize));
24503            }
24504            return columns;
24505        },
24506
24507        
24508        _initializeColumnWidth : function () {
24509            
24510            
24511            
24512            var display = this._getColumnsVisibility(),
24513                
24514                visibleColumns = _.filter(display, function (item) {
24515                    return item == true;
24516                }).length,
24517                $allTableHeaders = this.$element.find("th"),
24518                $tableHeader = null,
24519                width = null,
24520                sum = 0;
24521            if (!this.options.bAutoWidth) {
24522                
24523                
24524                for (var i = 0; i < visibleColumns; i++) {
24525                    sum += parseInt(this.options.aWidth[i], 10);
24526                }
24527            } else {
24528                sum = visibleColumns;
24529            }
24530
24531            if (display.length == this.colLength) {
24532                for (var i = 0; i < visibleColumns; i++) {
24533                    if (this.options.aWidth) {
24534                        
24535                        width = ((Math.floor((this.options.aWidth[i] * 100) / sum)) + "%");
24536                    } else {
24537                        width = ((Math.floor((1 * 100) / sum)) + "%");
24538                    }
24539                    $tableHeader = $allTableHeaders.eq(i);
24540                    
24541                    
24542                    $tableHeader[0].style.width = width;
24543                }
24544            }
24545        },
24546
24547        _constructor : function () {
24548            var that = this;
24549            
24550            this.controlRow = $.extend(true, {}, Responsive.controlRowDefaults);
24551            this.columns = this.initializeColumns();
24552            
24553            $(window).on("resize orientationchange", function (event) {
24554                that._initializeColumnVisibility(event);
24555            });
24556
24557            
24558            
24559            this.controlRow.breakpoints.sort(function (a, b) {
24560                return a.width < b.width ? 1 :
24561                    a.width > b.width ? -1 : 0;
24562            });
24563            this._initializeColumnVisibility();
24564            
24565            this._controlRowInitialization();
24566        },
24567
24568        _initializeColumnVisibility : function (event) {
24569            var that = this;
24570            
24571            if (event) {
24572                
24573                
24574                this.$element.find("td").each(function () {
24575                    $(this).removeData("shown");
24576                    
24577                    if ($(this).data("colspan") != null) {
24578                        
24579                        $(this).attr("colspan", $(this).data("colspan"));
24580                    }
24581                });
24582                
24583                
24584                
24585                this.columns = this.initializeColumns(event);
24586            }
24587            
24588            
24589            
24590            
24591            this._initializeColumnWidth();
24592            this.display = this._resize();
24593            
24594            
24595            this.$element.find("tbody tr:not(.child)").each(function () {
24596                if ($(this).next(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).length == 0) {
24597                    $(this).after($("<tr></tr>").addClass(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_CLASS).hide());
24598                }
24599            });
24600
24601            
24602            var details = this.controlRow.controlRowDetails;
24603            
24604            if (details.type) {
24605                
24606                this._controlRowVisibility(event);
24607                
24608                
24609                this.$element.on(ResponsiveTablePlugin.prototype.defaults.EVENT_COLUMN_VISIBILITY, function () {
24610                    that._controlRowVisibility();
24611                });
24612
24613                this.$element.addClass('rtp-' + details.type);
24614            }
24615            
24616            if (this.options.fixTableControls) {
24617                
24618                
24619                
24620                if (_.isUndefined(event) || event.type === "orientationchange" || (event.type === "resize" && !isIphoneOrIpad)) {
24621                    
24622                    this.options.fixTableControls(event);
24623                }
24624            }
24625        },
24626
24627        
24628        _fixControlRows : function () {
24629            this.$element.find(ResponsiveTablePlugin.prototype.defaults.CONTROL_ROW_SELECTOR).remove();
24630        },
24631
24632        
24633        isColumnHidden : function () {
24634            return this.bColumnHidden || false;
24635        },
24636
24637        
24638        _rearrangeTableRuntimeControls : function (lastVisibleColumn, event) {
24639            
24640            
24641            var $runtimeAddControls = this.$element.find(".guideTableRuntimeControls .guideTableRuntimeAddControl"),
24642                runtimeControlIndex = 0,
24643                that = this,
24644                index = null;
24645            $runtimeAddControls.each(function () {
24646                
24647                if ($(this).is(":visible")) {
24648                    runtimeControlIndex = $(this).closest("td").index();
24649                    return false;
24650                }
24651            });
24652            
24653            if ((runtimeControlIndex <= lastVisibleColumn)) {
24654                
24655                
24656                $runtimeAddControls.each(function () {
24657                    
24658                    
24659                    var $runtimeControl = $(this).closest(".guideTableRuntimeControls"),
24660                        $runtimeControlTableRow = $(this).closest("tr");
24661                    if ($runtimeControl.hasClass("guideTableRuntimeRightControls")) {
24662                        
24663                        $runtimeControl.appendTo($runtimeControlTableRow.find("td").eq(lastVisibleColumn));
24664                        if (runtimeControlIndex !== lastVisibleColumn) {
24665                            var $component = $runtimeControl.prev();
24666                            $component.css("display", "block");
24667                            $component.css("float", "none");
24668                        }
24669                    }
24670
24671                });
24672            }
24673        },
24674
24675        
24676        _controlRowVisibility : function (event) {
24677            var that = this,
24678                
24679                hiddenColumns = _.filter(this.columns, function (element) {
24680                    return (element.isVisible) !== true;
24681                }),
24682                lastVisibleColumn = this.columns.length - hiddenColumns.length;
24683            
24684            
24685            this._rearrangeTableRuntimeControls(lastVisibleColumn - 1, event);
24686            
24687            if (hiddenColumns && hiddenColumns.length > 0) {
24688                
24689                this.$element.addClass('collapsed');
24690                
24691            this.bColumnHidden = true;            } else {
24692                
24693                this.$element.removeClass('collapsed');
24694                
24695                this.bColumnHidden = false;
24696            }
24697        },
24698
24699        
24700        _controlRowInitialization : function () {
24701            var that    = this;
24702            var details = this.controlRow.controlRowDetails;
24703
24704            
24705            if (details.type === 'inline') {
24706                
24707                details.target = ("." +  (this.options.tableRuntimeEditControlClass || "tableRuntimeEditControl"));
24708            }
24709
24710            
24711            
24712            
24713            var target   = details.target;
24714            var selector = typeof target === 'string' ? target : 'td';
24715
24716            
24717            this.$element.on('click keypress', selector, function (e) {
24718                
24719                
24720                if ((e.type == "keypress" && e.keyCode == 13) || e.type == "click") {
24721                    
24722                    if (!that.$element.hasClass('collapsed')) {
24723                        return;
24724                    }
24725                    
24726                    var $row = $(this).closest('tr'),
24727                        rowData = $row.data("tableRow"),
24728                        row = rowData;
24729                    
24730                    
24731                    
24732                    if (row == null || row.child.$element.parent().length === 0) {
24733                        row = new TableRow($row);
24734                        $row.data("tableRow", row);
24735                    }
24736                    if (row.child.isShown) {
24737                        row.hideChild();
24738                        row.$tableRowElement.removeClass('parent');
24739                    } else {
24740                        var info = that.controlRow.controlRowDetails.renderer(that, row);
24741                        row.updateChild(info, that.colLength);
24742                        row.showChild();
24743                        row.$tableRowElement.addClass('parent');
24744                        
24745                        row.child.$element.find("input, select, textarea, button").eq(0).focus();
24746                    }
24747                }
24748            });
24749        },
24750
24751        
24752        _resize : function () {
24753            var width = $(window).width();
24754            var breakpoints = this.controlRow.breakpoints;
24755            var breakpoint = breakpoints[0].name;
24756
24757            
24758            for (var i = breakpoints.length - 1 ; i >= 0 ; i--) {
24759                if (width <= breakpoints[i].width) {
24760                    breakpoint = breakpoints[i].name;
24761                    break;
24762                }
24763            }
24764
24765            
24766            var display = this._getColumnsVisibility(breakpoint);
24767
24768            _.each(this.columns, function (item, index) {
24769                item.visible(display[index]);
24770            });
24771
24772            return display;
24773        },
24774
24775        
24776        _getColumnsVisibility : function (breakpoint) {
24777            var columns = this.columns,
24778                i,
24779                len = this.$element.find("th"),
24780                display = [];
24781
24782            
24783            var widthAvailable = this.$element.parent().outerWidth();
24784            var usedWidth = widthAvailable;
24785
24786            
24787            
24788            display = _.map(columns, function (item) {
24789                usedWidth -= item.minWidth;
24790                return ((usedWidth < 0) ? false : true);
24791            });
24792
24793            
24794            display[0] = true;
24795            return display;
24796        }
24797
24798    };
24799
24800    $.fn.responsiveTablePlugin = function (option, value) {
24801        var get = '',
24802            element = this.each(function () {
24803                
24804                if ($(this).is('table') === true) {
24805                    var $this = $(this),
24806                        data = $this.data('responsiveTablePlugin'),
24807                        options = $.extend({}, ResponsiveTablePlugin.prototype.defaults, typeof option === 'object' && option);
24808
24809                    
24810                    if (!data) {
24811                        $this.data('responsiveTablePlugin', (data = new ResponsiveTablePlugin(this, options)));
24812                        data._constructor();
24813                    }
24814
24815                    
24816                    if (typeof option === 'string') {
24817                        get = data[option](value);
24818                    }
24819                }
24820            });
24821
24822        if (get != "") {
24823            return get;
24824        } else {
24825            return element;
24826        }
24827    };
24828
24829    ResponsiveTablePlugin.prototype.defaults = {
24830        
24831        EVENT_COLUMN_VISIBILITY : "responsiveTablePlugin.columnVisibility",
24832        GUIDE_ID_SELECTOR : "div[data-guide-view-bind]",
24833        CONTROL_ROW_CLASS : "child",
24834        CONTROL_ROW_SELECTOR : "tr.child"
24835    };
24836
24837})(_, $);
24838(function ($, _, guidelib) {
24839
24840    
24841    var getPanelsWithNumericFields = function (panels, fieldName) {
24842            if (_.isUndefined(panels) || panels === null) {
24843                return [];
24844            }
24845            if (!_.isArray(panels)) {
24846                panels = [panels];
24847            }
24848            return _.filter(panels, function (panel) {
24849                return panel instanceof guidelib.model.GuidePanel
24850                    && panel[fieldName] instanceof guidelib.model.GuideNumericBox;
24851            });
24852        },
24853        
24854        sum = function (numPanels, fieldName) {
24855            return _.reduce(numPanels,
24856                function (memo, currentItem) {
24857                    var curValue = parseFloat(currentItem.getOrElse(currentItem, fieldName + ".value", 0));
24858                    if (isNaN(curValue)) {
24859                        curValue = 0;
24860                    }
24861                    return memo + curValue;
24862                }, 0);
24863        };
24864
24865    
24866    guidelib.__runtime__.af.sum = function (panels, fieldName) {
24867        return sum(getPanelsWithNumericFields(panels, fieldName), fieldName);
24868    };
24869
24870    
24871    guidelib.__runtime__.af.avg = function (panels, fieldName) {
24872        var n_panels = getPanelsWithNumericFields(panels, fieldName),
24873            total = sum(n_panels, fieldName);
24874        if (n_panels.length === 0) {
24875            return 0;
24876        }
24877        return total / n_panels.length;
24878    };
24879
24880    
24881    guidelib.__runtime__.af.max = function (panels, fieldName) {
24882        var panel = _.max(getPanelsWithNumericFields(panels, fieldName), function (panel) {
24883            return panel.getOrElse(panel, fieldName + ".value", Number.NEGATIVE_INFINITY);
24884        });
24885        if (panel instanceof guidelib.model.GuidePanel) {
24886            return panel[fieldName];
24887        }
24888        return null;
24889    };
24890
24891    
24892    guidelib.__runtime__.af.min = function (panels, fieldName) {
24893        var panel =  _.min(getPanelsWithNumericFields(panels, fieldName), function (panel) {
24894            return panel.getOrElse(panel, fieldName + ".value", Number.POSITIVE_INFINITY);
24895        });
24896        if (panel instanceof guidelib.model.GuidePanel) {
24897            return panel[fieldName];
24898        }
24899        return null;
24900    };
24901
24902}($, _, guidelib));
24903(function ($, _, guidelib) {
24904
24905    
24906    
24907    guidelib.__runtime__.af.reduce = function (panels, fieldName, iterator, memo, context) {
24908        if (!_.isArray(panels)) {
24909            panels = [panels];
24910        }
24911        return _.reduce(panels, function (memo, panel) {
24912            if (panel instanceof guidelib.model.GuidePanel && !_.isUndefined(panel[fieldName])) {
24913                if (_.isFunction(iterator)) {
24914                    return iterator.apply(context, [memo, panel, panel[fieldName]]);
24915                }
24916            }
24917            return memo;
24918        }, memo);
24919    };
24920
24921    
24922    
24923    guidelib.__runtime__.af.filter = function (panels, fieldName, predicate, context) {
24924        if (!_.isArray(panels)) {
24925            panels = [panels];
24926        }
24927        return _.map(
24928            _.filter(panels, function (panel) {
24929                if (panel instanceof guidelib.model.GuidePanel && !_.isUndefined(panel[fieldName])) {
24930                    if (_.isFunction(predicate)) {
24931                        return predicate.apply(context, [panel, panel[fieldName]]);
24932                    }
24933                    return false;
24934                }
24935            }),
24936            function (panel) {
24937                return panel[fieldName];
24938            }
24939        );
24940    };
24941    
24942    guidelib.__runtime__.af.formatDateToISOString = function (dateObject) {
24943        var day, month, year;
24944        if (!_.isUndefined(dateObject) && _.isObject(dateObject)) {
24945            day = dateObject.getDate().toString();
24946            
24947            month = (dateObject.getMonth() + 1).toString();
24948            year = dateObject.getFullYear().toString();
24949            if (month.length === 1) {
24950                month = "0" + month.toString();
24951            }
24952            
24953            return year + "-" + month + "-" + day;
24954
24955        }
24956    };
24957}($, _, guidelib));
24958(function (_, guidelib) {
24959    
24960    var GuideNavigationContext = guidelib.model.util.GuideNavigationContext = xfalib.ut.Class.extend({
24961        msClassName : "guideNavigationContext",
24962        initialize : function () {
24963            GuideNavigationContext._super.initialize.call(this);
24964            this._currentItem = this.options.currentItem;
24965            this._parentPanel = this.options.parentPanel;
24966            this.guideUtil = guidelib.util.GuideUtil;
24967        },
24968
24969        getQualifiedNamedItem : function (qName) {
24970            var navItems = this._getNavigableItems();
24971            var qItem = _.find(navItems, function (item) {
24972                return (item._escapeQualifiedName() == qName);
24973            }, this);
24974            return qItem;
24975        },
24976
24977        getItemForNav : function (navToken) {
24978            if (navToken == "prevItem" || navToken == "nextItem" || navToken == "firstItem" || navToken == "lastItem") {
24979                return this[navToken];
24980            } else {
24981                return this.getQualifiedNamedItem(navToken);
24982            }
24983        },
24984
24985        
24986        _isNavigableItem : function (item) {
24987            return item.visible;
24988        },
24989
24990        
24991        _isNavigablePanel : function (item) {
24992            if (item && item instanceof guidelib.model.GuidePanel) {
24993                return item.visible && item.isNavigable;
24994            }
24995        },
24996
24997        _getNavigableItems : function () {
24998            var navItems = _.filter(this._parentPanel.items, function (item) {
24999                return this._isNavigableItem(item);
25000            }, this);
25001            return navItems;
25002        },
25003        
25004        _getNavigableDescendant : function (navigableAncestor) {
25005            
25006            
25007            if (navigableAncestor && navigableAncestor != this._parentPanel) {
25008                var currentItem = navigableAncestor.parent._navigationContext.currentItem,
25009                    deepItem = null;
25010                while (currentItem instanceof guidelib.model.GuidePanel) {
25011                    deepItem = currentItem;
25012                    currentItem = currentItem._navigationContext.currentItem;
25013                }
25014                return deepItem;
25015            }
25016            return null;
25017        },
25018
25019        
25020        _getSomOnNavigableAncestor : function (somExpression) {
25021            if (_.isEmpty(somExpression)) {
25022                return null;
25023            }
25024
25025            var index = somExpression.lastIndexOf("."),
25026                parentModel,
25027                parentSom,
25028                isNavigable,
25029                guideModel = this._parentPanel._guide();
25030
25031            if (index !== -1) {
25032                parentSom = somExpression.substring(0, index);
25033                parentModel = guideModel.resolveNode(parentSom);
25034                if (parentModel) {
25035                    isNavigable = this._isNavigablePanel(parentModel);
25036                }
25037                if (isNavigable) {  
25038                    return somExpression;
25039                }
25040                return this._getSomOnNavigableAncestor(parentSom);
25041            }
25042            
25043            return guideModel.rootPanel.somExpression;
25044        },
25045
25046        
25047        _getNavigableAncestor : function (navOrder) {
25048            
25049            
25050            
25051            var guideModel = this._parentPanel._guide(),
25052                navigableAncestorSom = this._getSomOnNavigableAncestor(guideModel._currentNavigablePanelSom),
25053                navigableAncestorItem = guideModel.resolveNode(navigableAncestorSom);
25054            
25055            while (navigableAncestorItem
25056                && navigableAncestorItem != this._parentPanel && !navigableAncestorItem.parent._navigationContext[navOrder]
25057                && this.guideUtil.isChildPartOfContainer(this._parentPanel, navigableAncestorItem)) {
25058                
25059                var navigableParentItemSom = this._getSomOnNavigableAncestor(navigableAncestorItem.parent.somExpression);
25060                navigableAncestorItem = guideModel.resolveNode(navigableParentItemSom);
25061            }
25062            return navigableAncestorItem;
25063        },
25064
25065        _getNakedThis : function () {
25066            return this;
25067        }
25068    });
25069
25070    GuideNavigationContext.defineProps({
25071        
25072        currentItem : {
25073            get : function () {
25074                if (this._currentItem) {
25075                    return this._currentItem;
25076                } else {
25077                    return this.firstItem;
25078                }
25079            },
25080            set : function (value) {
25081                this._currentItem = value;
25082            }
25083        },
25084        
25085        prevItem : {
25086            get : function () {
25087                var navItems = this._getNavigableItems();
25088                var item = this.currentItem;
25089                if (navItems.indexOf(item) > 0) {
25090                    return navItems[navItems.indexOf(item) - 1];
25091                } else {
25092                    return null;
25093                }
25094            }
25095        },
25096        
25097        nextItem : {
25098            get : function () {
25099                var navItems = this._getNavigableItems();
25100                var item = this.currentItem;
25101                if (navItems.indexOf(item) < (navItems.length - 1)) {
25102                    return navItems[navItems.indexOf(item) + 1];
25103                } else {
25104                    return null;
25105                }
25106            }
25107        },
25108        
25109        nextNavigablePanel : {
25110            get : function () {
25111                var navigableAncestor = this._getNavigableAncestor("nextItem"),
25112                
25113                    navigableDescendant = this._getNavigableDescendant(navigableAncestor);
25114                return navigableDescendant;
25115            }
25116        },
25117
25118        
25119        prevNavigablePanel : {
25120            get : function () {
25121                var navigableAncestor = this._getNavigableAncestor("prevItem"),
25122                
25123                    navigableDescendant = this._getNavigableDescendant(navigableAncestor);
25124                return navigableDescendant;
25125            }
25126        },
25127
25128        
25129        firstItem : {
25130            get : function () {
25131                var navItems = this._getNavigableItems();
25132                return navItems[0] || null;
25133            }
25134        },
25135        
25136        lastItem : {
25137            get : function () {
25138                var navItems = this._getNavigableItems();
25139                if (navItems.length) {
25140                    return navItems[navItems.length - 1];
25141                } else {
25142                    return null;
25143                }
25144            }
25145        },
25146        
25147        hasNextItem : {
25148            get : function () {
25149                return this.nextItem != null;
25150            }
25151        },
25152        
25153        hasPrevItem : {
25154            get : function () {
25155                return this.prevItem != null;
25156            }
25157        },
25158
25159        
25160        hasNextNavigablePanel : {
25161            get : function () {
25162                return this.nextNavigablePanel != null;
25163            }
25164        },
25165
25166        
25167        hasPrevNavigablePanel : {
25168            get : function () {
25169                return this.prevNavigablePanel != null;
25170            }
25171        },
25172
25173        
25174        isFirstItem : {
25175            get : function () {
25176                return this.currentItem == this.firstItem;
25177            }
25178        },
25179        
25180        isLastItem : {
25181            get : function () {
25182                return this.currentItem == this.lastItem;
25183            }
25184        }
25185    });
25186
25187})(_, guidelib);
25188(function (_, guidelib) {
25189
25190    
25191    var GuideModelEvent = guidelib.event.GuideModelEvent = xfalib.ut.Class.extend({
25192        msClassName : "guideModelEvent"
25193    });
25194
25195    GuideModelEvent.defineProps({
25196        
25197        "prevText" : {
25198            get : function () {
25199                return this.jsonModel.prevText;
25200            }
25201        },
25202        
25203        "newText" : {
25204            get : function () {
25205                return this.jsonModel.newText;
25206            }
25207        },
25208        
25209        "name" : {
25210            get : function () {
25211                return this.jsonModel.name;
25212            }
25213        },
25214        "keyDown" : {
25215            get : function () {
25216                return this.jsonModel.keyDown;
25217            }
25218        },
25219        "modifier" : {
25220            get : function () {
25221                return this.jsonModel.modifier;
25222            }
25223        },
25224        
25225        "target" : {
25226            get : function () {
25227                return this.jsonModel.target;
25228            }
25229        },
25230        "shift" : {
25231            get : function () {
25232                return this.jsonModel.shift;
25233            }
25234        },
25235        "change" : {
25236            get : function () {
25237                return this.jsonModel.change;
25238            },
25239            set : function (value) {
25240                this.jsonModel.change = value;
25241            }
25242        },
25243        
25244        "_property" : {
25245            get : function () {
25246                return this.jsonModel._property;
25247            }
25248        }
25249    });
25250
25251    GuideModelEvent.createEvent = function (nm, tgt, prop, oldVal, newVal) {
25252        var evnt = {
25253            name : nm,
25254            target : tgt,
25255            _property : prop,
25256            prevText : oldVal,
25257            newText : newVal
25258        };
25259        return new GuideModelEvent({"jsonModel" : evnt});
25260    };
25261
25262    GuideModelEvent.MODEL_REFRESH = "guide.modelRefresh";
25263    GuideModelEvent.CHILD_CHANGED = "guide.childChanged";
25264    GuideModelEvent.MULTIPLE_CHILD_ADDED = "guide.multipleChildAdded";
25265    GuideModelEvent.MODEL_CHANGED = "guide.modelChanged";
25266    GuideModelEvent.VALUE_CHANGED = "guide.valueChanged";
25267    GuideModelEvent.ERROR_CHANGED = "guide.errorChanged";
25268    GuideModelEvent.ERROR_RESET = "guide.errorReset";
25269    GuideModelEvent.VISIBLE_CHANGED = "guide.visibleChanged";
25270    GuideModelEvent.ENABLED_CHANGED = "guide.enabledChanged";
25271    GuideModelEvent.ITEMS_CHANGED   = "guide.itemsChanged";
25272    GuideModelEvent.OBJECT_DESTROYED = "guide.objectDestroyed";
25273    GuideModelEvent.NAVIGATE_SECTION = "guide.navigateSection";
25274    GuideModelEvent.LAZY_LOADED = "guide.lazyLoaded";
25275}(_, guidelib));
25276(function ($, _, guidelib) {
25277    var GuideViewRegistry = guidelib.view.GuideViewRegistry = xfalib.ut.Class.extend({
25278
25279        
25280        _findWidget : function (config, name, className) {
25281            var result = _.find(config, function (widgetName, identifier) {
25282                return name === identifier;
25283            });
25284            if (result === undefined) {
25285                result = _.find(config, function (widgetName, identifier) {
25286                    return className === identifier;
25287                });
25288            }
25289            return result;
25290        },
25291
25292        
25293        _findWidgetNameFromCSS : function (cssClasses) {
25294            var result = null;
25295            if (_.isString(cssClasses)) {
25296                _.find(cssClasses.split(" "),
25297                    function (cssClass, index) {
25298                        var match = cssClass.match(/^widget_([\w\W]+)$/);
25299                        if (match && match.length === 2) {
25300                            result = match[1];
25301                            return true;
25302                        }
25303                        return false;
25304                    });
25305            }
25306            return result;
25307        },
25308
25309        createView : function (element, parentView) {
25310            var $element = $(element);
25311            var options = {
25312                    'element' : $element.get(0),
25313                    'widgetName' : $element.data("guideViewWidget"),
25314                    'parentView' : parentView
25315                };
25316            var guideViewBind = $element.data("guideViewBind");
25317            var model = window.guideBridge._resolveId(guideViewBind);
25318            
25319            
25320            if (model) {
25321                options.model = model;
25322                var clsName = model.className;
25323                var nodeClass = clsName.charAt(0).toUpperCase() + clsName.substr(1) + "View";
25324                var viewClass = guidelib.view[nodeClass],
25325                    widgetConfig = window.guideBridge.userConfig.widgetConfig;
25326                if (model instanceof guidelib.model.Field || model instanceof guidelib.model.GuideCompositeField) {
25327                    options.widgetName = this._findWidgetNameFromCSS(model.cssClassName)
25328                        || this._findWidget(widgetConfig, model.name, model.className);
25329                }
25330                if (!viewClass && model instanceof guidelib.model.GuideContainerNode) {
25331                    viewClass = guidelib.view.GuideContainerView;
25332                }
25333                if (!viewClass && model instanceof guidelib.model.Field) {
25334                    viewClass = guidelib.view.GuideFieldView;
25335                }
25336                if (!viewClass && model instanceof guidelib.model.GuidePanel) {
25337                    viewClass = guidelib.view.GuidePanelView;
25338                }
25339                if (!viewClass && model instanceof guidelib.model.GuideItemsContainer) {
25340                    viewClass = guidelib.view.GuideItemsView;
25341                }
25342                if (!viewClass) {
25343                    viewClass = guidelib.view.GuideBaseView;
25344                }
25345                
25346                var bindView = new viewClass(options);
25347                return bindView;
25348            }
25349        }
25350    });
25351
25352})($, _, guidelib);
25353(function (_, guidelib, xfalib) {
25354    var DataNode = guidelib.model.DataNode = xfalib.ut.Class.extend({
25355        initialize : function () {
25356            this.linkedFields = [];
25357            this.isUpdateInProgress = false;
25358        },
25359
25360        addField : function (model) {
25361            if (!_.isEmpty(model) && !_.contains(this.linkedFields, model)) {
25362                this.linkedFields.push(model);
25363                model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this);
25364            }
25365        },
25366
25367        removeField : function (model) {
25368            if (!_.isEmpty(model)) {
25369                model.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, this);
25370                this.linkedFields = _.without(this.linkedFields, model);
25371            }
25372        },
25373
25374        getFieldModels : function () {
25375            return _.filter(this.linkedFields, function (field) {
25376                return (field instanceof guidelib.model.Field);
25377            });
25378        },
25379
25380        getAbstractFieldModels : function () {
25381            return _.filter(this.linkedFields, function (field) {
25382                return (field instanceof guidelib.model.AbstractField);
25383            });
25384        },
25385
25386        handleEvent : function (event) {
25387            switch (event.name) {
25388            case guidelib.event.GuideModelEvent.VALUE_CHANGED:
25389                if (!_.contains(['guideButton', 'guideTextDraw', 'guideAdobeSignBlock'], event.target.className)) {
25390                    this.updateLinkedFieldsValue(event);
25391                }
25392                break;
25393            default:
25394                event.target.logger().warn("AF", "Unexpected Event type on Data Node", event);
25395            }
25396        },
25397
25398        updateLinkedFieldsValue : function (event) {
25399            if (this.isUpdateInProgress) {
25400                return;
25401            }
25402
25403            this.isUpdateInProgress = true;
25404            var newValue = event.target._getValue();
25405
25406            try {
25407                _.each(this.linkedFields, function (field) {
25408                    if (field !== event.target) {
25409                        field.value = newValue;
25410                    }
25411                }, this);
25412            } catch (ex) {
25413                event.target.logger().error("AF", "Unable to set Linked Field value" + ex);
25414            } finally {
25415                this.isUpdateInProgress = false;
25416            }
25417        }
25418    });
25419
25420}(_, guidelib, xfalib));
25421
25422
25423(function (guidelib, $) {
25424
25425    var VERSION_AEM_61 = "AEM6.1",
25426        VERSION_AEM_62 = "AEM6.2",
25427        VERSION_AEM_63 = "AEM6.3",
25428        VERSION_AEM_65 = "AEM6.5",
25429        flagsStatus = {},
25430        getMinorMajor = function (version) {
25431            var match = version.match(/AEM(\d+)(?:\.(\d+))?/);
25432            if (match == null) {
25433                return null;
25434            }
25435            return {
25436                major : match[1],
25437                minor : match[2] === undefined ? "0" : match[2]
25438            };
25439        },
25440        compareNumbers = function (num1, num2) {
25441            return (num1 - num2);
25442        },
25443        compareVersions = function (version1, version2) {
25444            if (typeof version1 !== "string" || typeof version2 !== "string") {
25445                throw "Comparing Invalid Versions";
25446            }
25447            var v1 = getMinorMajor(version1),
25448                v2 = getMinorMajor(version2);
25449            if (v1 == null || v2 == null) {
25450                throw "Comparing Invalid Versions";
25451            }
25452            var c = compareNumbers(+v1.major, +v2.major);
25453            return c !== 0 ? c : compareNumbers(+v1.minor, +v2.minor);
25454        },
25455        Version = guidelib.util.Version = xfalib.ut.Class.extend({
25456            initialize : function (options) {
25457                flagsStatus = {};
25458                var compat = options.scriptingBehaviourVersion;
25459                if (compat === "None") {
25460                    compat = this.current();
25461                }
25462                this.scriptingBehaviourVersion = compat || VERSION_AEM_65;
25463                var majorMinor = getMinorMajor(this.scriptingBehaviourVersion);
25464                if (majorMinor == null) {
25465                    throw "Invalid Version number";
25466                }
25467                this.major = majorMinor.major;
25468                this.minor = majorMinor.minor;
25469            },
25470
25471            current : function () {
25472                return VERSION_AEM_65;
25473            },
25474
25475            compatibleVersion : function () {
25476                return this.scriptingBehaviourVersion;
25477            },
25478
25479            isPrevious : function (version) {
25480                return compareVersions(this.scriptingBehaviourVersion, version) < 0;
25481            },
25482
25483            isPreviousOrSame : function (version) {
25484                var c = compareVersions(this.scriptingBehaviourVersion, version);
25485                return c < 0 || c == 0;
25486            },
25487
25488            isAfter : function (version) {
25489                return compareVersions(this.scriptingBehaviourVersion, version) > 0;
25490            },
25491
25492            isAfterOrSame : function (version) {
25493                var c = compareVersions(this.scriptingBehaviourVersion, version);
25494                return c > 0 || c == 0;
25495            },
25496
25497            isSame : function (version) {
25498                return compareVersions(this.scriptingBehaviourVersion, version) == 0;
25499            },
25500
25501            isOn : function (flag) {
25502                switch (flag) {
25503                    case this.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE:
25504                        if (flagsStatus[flag] == undefined) {
25505                            flagsStatus[flag] = this.isAfter(this.AEM_61);
25506                        }
25507                        return flagsStatus[flag];
25508                    case this.Flags.RUN_VALUE_COMMMIT_ON_PREFILL:
25509                        if (flagsStatus[flag] == undefined) {
25510                            flagsStatus[flag] = this.isAfter(this.AEM_63);
25511                        }
25512                        return flagsStatus[flag];
25513                }
25514                throw "Invalid Flag";
25515            }
25516        });
25517
25518    Version.prototype.Flags = {};
25519    Object.defineProperties(Version.prototype.Flags, {
25520        RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE : {
25521            value : "manageValueCommit",
25522            writable : false
25523        },
25524        RUN_VALUE_COMMMIT_ON_PREFILL : {
25525            value : "manageValueCommitOnPrefill",
25526            writable : false
25527        }
25528    });
25529    Version.defineProps({
25530        AEM_61 : {
25531            value : VERSION_AEM_61,
25532            writable : false
25533        },
25534
25535        AEM_62 : {
25536            value : VERSION_AEM_62,
25537            writable : false
25538        },
25539
25540        AEM_63 : {
25541            value : VERSION_AEM_63,
25542            writable : false
25543        },
25544
25545        AEM_65 : {
25546            value : VERSION_AEM_65,
25547            writable : false
25548        }
25549    });
25550}(guidelib, $));
25551(function ($, guidelib, _) {
25552    var GuideBaseView = guidelib.view.GuideBaseView = xfalib.ut.Class.extend({
25553        guideUtil : guidelib.util.GuideUtil,
25554        _triggerOnBridge : function (eventName, target, property, oldVal, newVal) {
25555            var evnt = guidelib.event.GuideModelEvent.createEvent(eventName, target,
25556                                                    property, oldVal, newVal);
25557            window.guideBridge.trigger(eventName, evnt);
25558        },
25559
25560        initialize : function () {
25561            GuideBaseView._super.initialize.call(this);
25562            this.$element = $(this.options.element);
25563            this.id = this.$element.attr("id");
25564            this._model = this.options.model;
25565            this.parentView = this.options.parentView;
25566            this.$element.data("guideView", this);
25567            this._$item = null;
25568            this._$itemNav = null;
25569            if (this._model && this._model != null) {
25570                this._model.on(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
25571            }
25572            this._syncPending = true; 
25573            this._visibleHelpElement = "none";
25574            this._polyfills();
25575        },
25576
25577        _polyfills: function () {
25578            var IEpolyfillForObjectDotEntries = function() {
25579                if(!Object.entries) {
25580                    Object.entries = function (obj) {
25581                        var ownProps = Object.keys(obj),
25582                            i = ownProps.length,
25583                            resArray = new Array(i); 
25584                        while (i--)
25585                            resArray[i] = [ownProps[i], obj[ownProps[i]]];
25586
25587                        return resArray;
25588                    };
25589                }
25590            };
25591
25592            var polyfills = [IEpolyfillForObjectDotEntries];
25593
25594            for (var i = 0; i < polyfills.length; ++i) {
25595                polyfills[i](); 
25596            }
25597        },
25598
25599        postInitialize : function () {
25600        },
25601
25602        _unloadView : function () {
25603            
25604            this._model.off(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleModelChanged, this);
25605            
25606            this.$element = null;
25607            this.$widget = null;
25608            this._model = null;
25609            this._$item = null;
25610            this._$itemNav = null;
25611            this.parentView = null;
25612        },
25613
25614        handleVisibleChanged : function (event) {
25615            
25616            
25617            if (!event.newText) {
25618                this.$item.addClass("hidden");
25619                this.$itemNav.addClass("hidden");
25620                if (this.parentView.currentActiveItemView == this) {
25621                    this.parentView.setActive("nextItem");
25622                }
25623            }   else {
25624                
25625                this.$item.removeClass("hidden");
25626                this.$itemNav.removeClass("hidden");
25627            }
25628        },
25629
25630        handleModelChanged : function (event) {
25631            switch (event._property) {
25632                case "viewVisited":
25633                    if (event.newText) {
25634                        this.$item.addClass("stepped");
25635                        this.$itemNav.addClass("stepped");
25636                    }else {
25637                        this.$item.removeClass("stepped");
25638                        this.$itemNav.removeClass("stepped");
25639                    }
25640                    break;
25641
25642                case "visible":
25643                    this.handleVisibleChanged(event);
25644                    break;
25645            }
25646        },
25647
25648        setActive : function (activeItemToken, focus, muteScripts) {
25649            if (focus && (this._model.className === "guideNode" || this._model.forceElementFocusChange)) {
25650                if (this.$element !== null && typeof this.$element.focus === "function" && !this._guideView.skipFieldFocus) {
25651                    
25652                    this.$element.focus();
25653                    
25654                    this._guideView.currentFocusItemSom = this._model.somExpression;
25655                }
25656
25657            }
25658            return true;
25659        },
25660
25661        focusable : function () {
25662            return this._model.visible;
25663        },
25664
25665        _find : function (selector) {
25666            return this._guideView.$element.find(selector);
25667        },
25668
25669        _syncGuideNodeToHtml : function (deepSync) {
25670            this._syncPending = false;
25671            
25672            
25673            this.handleVisibleChanged(guidelib.event.GuideModelEvent.createEvent(
25674                guidelib.event.GuideModelEvent.MODEL_CHANGED,
25675                this,
25676                "visible",
25677                this._model.visible,
25678                this._model.visible
25679            ));
25680        },
25681
25682        _updateIds : function ($el, oldId, newId) {
25683            if (oldId == newId) {
25684                return;
25685            }
25686            
25687            var idSelector = "#" + oldId,
25688                modelBindSelector = this.guideUtil.modelElSelector(oldId),
25689                attrSelector = '[id^="' + oldId + '"]',
25690                longDescriptionSelector = '[data-guide-longDescription^="' + oldId + '"]',
25691                labelSelector = 'label[for^="' + oldId + '"]',
25692                targetIdSelector = "[data-guide-id^='" + oldId + "']",
25693                $elById = $el.find(idSelector).addBack(idSelector),
25694                selectorAttrObject  = {
25695                    "id" : attrSelector ,
25696                    "for" : labelSelector,
25697                    "data-guide-longDescription" : longDescriptionSelector,
25698                    "data-guide-id" : targetIdSelector
25699                };
25700            
25701            
25702            
25703            if ($elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM_CONTAINER) !== undefined) {
25704                $elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM_CONTAINER, newId + guidelib.util.GuideUtil.GUIDE_ITEM_CONTAINER_SUFFIX);
25705            }
25706            
25707            if ($elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM) !== undefined) {
25708                $elById.attr(guidelib.util.GuideUtil.DATA_GUIDE_ITEM, newId + guidelib.util.GuideUtil.GUIDE_ITEM_SUFFIX);
25709            }
25710            $elById.attr("id", newId);
25711            $el.find(modelBindSelector).addBack(modelBindSelector).attr(this.guideUtil.GUIDE_VIEW_BIND_ATTR, newId);
25712            
25713            _.each(_.keys(selectorAttrObject), function (item, index) {
25714                var selector = selectorAttrObject[item];
25715                $el.find(selector).addBack(selector).each(function () {
25716                    
25717                    var $this = $(this),
25718                        prevId = $this.attr(item),
25719                        nextId = newId + prevId.substring(oldId.length);
25720                    $this.attr(item, nextId);
25721                });
25722            }, this);
25723        },
25724
25725        getSiblingItemView : function (siblingType) {
25726            if (this.parentView instanceof guidelib.view.GuidePanel
25726View) {
25727                var siblingItem = this.parentView._model.navigationContext.getItemForNav(siblingType);
25728                if (siblingItem) {
25729                    return this.parentView.getQualifiedNamedView(siblingItem._escapeQualifiedName());
25730                }
25731            }
25732            return null;
25733        }
25734    });
25735
25736    GuideBaseView.defineProps({
25737        _guideView : {
25738            get : function () {
25739                return window.guideBridge._guideView;
25740            }
25741        },
25742
25743        _guide : {
25744            get : function () {
25745                return window.guideBridge._guide;
25746            }
25747        },
25748
25749        $item : {
25750            get : function () {
25751                if (!this._$item || this._$item.length == 0) {
25752                    var itemSelector = this.guideUtil.itemSelector(this._model.id, this._model);
25753                    this._$item = this._find(itemSelector);
25754                    
25755                    
25756                    if (this._$item && this._$item.length == 0) {
25757                        return this.$element;
25758                    }
25759                }
25760                return this._$item;
25761            }
25762        },
25763
25764        $itemNav : {
25765            get : function () {
25766                if (!this._$itemNav) {
25767                    var itemNavSelector = this.guideUtil.itemNavSelector(this._model.id);
25768                    this._$itemNav = this._find(itemNavSelector);
25769                }
25770                return this._$itemNav;
25771            }
25772        },
25773        visibleHelpElement :  {
25774            get : function () {
25775                return this._visibleHelpElement;
25776            },
25777            set : function (helpType) {
25778                this._visibleHelpElement = helpType;
25779            }
25780        },
25781
25782        
25783        isItem : {
25784            get : function () {
25785                return this._model._isItem;
25786            }
25787        },
25788
25789        qualifiedName : {
25790            get : function () {
25791                return this._model._escapeQualifiedName();
25792            }
25793        }
25794
25795    });
25796}($, guidelib, _));
25797(function ($, guidelib, _) {
25798
25799    var xfaUtil = xfalib.ut.XfaUtil.prototype,
25800        GuideFieldView = guidelib.view.GuideFieldView = guidelib.view.GuideBaseView.extend({
25801            _defaultWidgetName : "defaultWidget",
25802
25803            
25804            autofillFieldKeywordToName  : {
25805                "name" : "name",
25806                "given-name" : "fname",
25807                "additional-name" : "mname",
25808                "family-name" : "lname",
25809                "email" : "email",
25810                "street-address" : "address",
25811                "address-line1" : "address",
25812                "address-line2" : "address",
25813                "address-level1" : "state",
25814                "address-level2" : "city",
25815                "postal-code" : "zip",
25816                "country" : "country",
25817                "tel" : "phone",
25818                "cc-name" : "ccname",
25819                "cc-number" : "cardnumber",
25820                "cc-csc" : "cvc",
25821                "cc-exp-month" : "ccmonth",
25822                "cc-exp-year" : "ccyear",
25823                "cc-exp" : "exp-date",
25824                "cc-type" : "card-type"
25825            },
25826
25827            initialize : function () {
25828                GuideFieldView._super.initialize.call(this);
25829                this._initializeWidget();
25830                this._defineModelEvents();
25831                this._markMandatory();
25832                this._updateEmptyStatus();
25833                this.oldValue = null;
25834
25835                if (this._guide.jsonModel.textReplacementMap) {
25836                    var footnoteArr = Object.entries(this._guide.jsonModel.textReplacementMap);
25837                    var tempArray = [];
25838                    for (var i = 0; i < footnoteArr.length; i++) {
25839                        
25840                        
25841                        
25842                        if(!tempArray[footnoteArr[i][1]]){
25843                            tempArray[footnoteArr[i][1]] = footnoteArr[i][0];
25844                        }
25845                        var selector = $("span[data-af-footnote-id=" + "\"" + footnoteArr[i][0] + "\"]");
25846                        for (var j = 0; j < $(selector).length; j++) {
25847                            var supTag = document.createElement("sup");
25848                            var anchorTag = document.createElement("a");
25849                            anchorTag.setAttribute("href", "#" + tempArray[footnoteArr[i][1]] + "_ftn");
25850                            anchorTag.setAttribute("data-footnote-id", tempArray[footnoteArr[i][1]]);
25851                            anchorTag.setAttribute("title", $('#' + tempArray[footnoteArr[i][1]]).text());
25852                            anchorTag.innerHTML = footnoteArr[i][1];
25853                            supTag.appendChild(anchorTag);
25854                            $($(selector)[j]).html(supTag.outerHTML);
25855                        }
25856                    }
25857                }
25858            },
25859
25860            postInitialize : function () {
25861                this._syncGuideNodeToHtml(true);
25862            },
25863
25864            createWidgetOptions : function () {
25865                return {
25866                    name : this._model.getAttribute("autocomplete") ? this.autofillFieldKeywordToName[this._model.getAttribute("autofillFieldKeyword")] : this._model.id + "_jqName",
25867                    value : this._model.value,
25868                    displayValue : this._model.formattedValue,
25869                    commitEvent : this.getCommitEvent(),
25870                    access : this._model.enabled ? "open" : "readOnly",
25871                    screenReaderText : this._model._getScreenReaderText(),
25872                    mandatory : this._model.mandatory
25873                };
25874            },
25875
25876            getCommitEvent : function () {
25877                return xfalib.ut.XfaUtil.prototype.XFA_EXIT_EVENT;
25878            },
25879
25880            getWidgetName : function () {
25881                var widgetName;
25882                if (this.$widget) {
25883                    var $elem = this.$widget.find('[data-af-widgetname]').addBack('[data-af-widgetname]');
25884                    
25885                    if ($elem && $elem.length > 0) {
25886                        widgetName = $elem.attr("data-af-widgetname");
25887                    }
25888                }
25889                if (!widgetName) {
25890                    this.logger().warn("AF", "widget name is not specified for field " + this._model.somExpression +
25891                        ", falling back to other widget");
25892                }
25893                return widgetName || this.options.widgetName || this._defaultWidgetName;
25894            },
25895
25896            _unloadView : function () {
25897                if (this._model) {
25898                    this._model.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
25899                    this._model.off(guidelib.event.GuideModelEvent.ERROR_CHANGED, this.handleErrorChanged, this);
25900                    this._model.off(guidelib.event.GuideModelEvent.ERROR_RESET, this.handleErrorReset, this);
25901                }
25902                
25903                this.jqwidget = null;
25904                GuideFieldView._super._unloadView.apply(this, arguments);
25905            },
25906
25907            _initializeWidget : function () {
25908                if (this.$element.find('div.guideFieldWidget').length) {
25909                    this.$widget = this.$element.find('div.guideFieldWidget');
25910                } else {
25911                    this.$widget = null;
25912                }
25913
25914                
25915                if (this.$widget) {
25916                    $(this.$widget).on(this.getCommitEvent(), $.proxy(this.handleCommit, this))
25917                        .on(xfaUtil.XFA_CLICK_EVENT, $.proxy(this.handleClick, this))
25918                        .on(xfaUtil.XFA_EXIT_EVENT, $.proxy(this.handleFocusOut, this))
25919                        .on(xfaUtil.XFA_ENTER_EVENT, $.proxy(this.handleEnter, this));
25920                }
25921            },
25922
25923            _defineModelEvents : function () {
25924                if (this._model) {
25925                    
25926                    
25927                    this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
25928                    
25929                    this._model.on(guidelib.event.GuideModelEvent.ERROR_CHANGED, this.handleErrorChanged, this);
25930                    this._model.on(guidelib.event.GuideModelEvent.ERROR_RESET, this.handleErrorReset, this);
25931
25932                }
25933            },
25934
25935            _syncGuideNodeToHtml : function (deepSync) {
25936                GuideFieldView._super._syncGuideNodeToHtml.apply(this, arguments);
25937                if (this._model) {
25938                    var propsToSync = {                  
25939                        "visible" : this._model.visible, 
25940                        "jcr:title" : this._model.title
25941                    };
25942                    _.each(propsToSync, function (value, key, list) {
25943                        this.handleModelChanged(guidelib.event.GuideModelEvent.createEvent(
25944                            guidelib.event.GuideModelEvent.MODEL_CHANGED, this, key, value, value
25945                        ));
25946                    }, this);
25947                    this.$element.attr("data-disabled", !this._model.enabled + "");
25948                }
25949                if (this.$widget) {
25950                    var widgetOptions = this.createWidgetOptions();
25951                    if (!this.jqwidget) {
25952                        this.createWidget(this.getWidgetName(), widgetOptions);
25953                    } else {
25954                        this.setWidgetOptions(widgetOptions);
25955                    }
25956                }
25957                
25958                if (this._model.forceErrorShow && this._model._errorText) {
25959                    this.handleErrorChanged({prevText : this._model.validationState, newText : this._model._errorText});
25960                }
25961            },
25962
25963            setWidgetOptions : function (widgetOptions) {
25964                this.jqwidget.option(widgetOptions);
25965
25966            },
25967
25968            
25969            _markMandatory : function (value) {
25970                if (this._model.mandatory && this.$element) {
25971                    this.$element.attr("data-mandatory", "true");
25972                } else {
25973                    this.$element.removeAttr("data-mandatory");
25974                    
25975                    if (this._model._failedTest === this.guideUtil.MANDATORY_TEST) {
25976                        this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
25977                    }
25978                }
25979                if (this.jqwidget) {
25980                    this.setWidgetOptions({
25981                        "mandatory" : value
25982                    });
25983                }
25984            },
25985
25986            
25987            _updateEmptyStatus : function (event) {
25988                var val = event ? event.newText : this._model.value;
25989                if (val == null || typeof val === 'string' && val.length == 0) {
25990                    this.$element.removeClass("af-field-filled").addClass("af-field-empty");
25991                } else {
25992                    this.$element.removeClass("af-field-empty").addClass("af-field-filled");
25993                }
25994            },
25995
25996            handleValueChanged : function (event) {
25997                switch (event._property) {
25998                case "value":
25999                    this.jqwidget.option("value", event.prevText);
26000                    this.jqwidget.option("displayValue", event.newText);
26001                    break;
26002                }
26003                this._updateEmptyStatus(event);
26004            },
26005
26006            handleErrorChanged : function (event) {
26007                var value = event.prevText,
26008                    errorMessage = event.newText;
26009                if (value === true) {
26010                    this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
26011                    this.$element.addClass("validation-success").removeClass("validation-failure");
26012                    this.updateWidgetOption("isValid", true);
26013                } else {
26014                    this._model._guide().runtime.errorManager.markError(errorMessage, this.$element, this._model.somExpression,
26015                        guideBridge.getValidationContext());
26016                    this.$element.addClass("validation-failure").removeClass("validation-success");
26017                    this.updateWidgetOption("isValid", false);
26018                }
26019            },
26020
26021            handleErrorReset : function (event) {
26022                this._model._guide().runtime.errorManager.unMarkError(this.$element, this._model.somExpression);
26023                this.$element.removeClass("validation-failure").removeClass("validation-success");
26024                this.updateWidgetOption("isValid", undefined);
26025            },
26026
26027            handleCommit : function () {
26028                if (this._model.enabled) {
26029                    this.commitValue(this.jqwidget.option("value"));
26030                }
26031            },
26032
26033            handleClick : function (event) {
26034                window.guideBridge.clickedOnWindow = false;
26035            },
26036
26037            handleFocusOut : function (event) {
26038                var gb = window.guideBridge;
26039
26040                if (this.getCommitEvent() !== xfaUtil.XFA_EXIT_EVENT) {
26041                    this._model.executeExpression("exit");
26042                }
26043                if (gb && gb.clickedOnWindow) {
26044                    this._guideView.currentFocusItemSom = null;
26045                }
26046                gb.clickedOnWindow = false;
26047                if (!(this._model.className === 'guideRadioButton'  || this._model.className === 'guideCheckBox' || this._model.className === 'guideButton')) {
26048                    this._triggerOnBridge("elementFocusOut", "", "", "", "");
26049                }
26050                
26051                if ((this.oldValue !== this._model.value) && this._model._errorText) {
26052                    this.handleErrorChanged({prevText : this._model.validationState, newText : this._model._errorText});
26053                }
26054                this.$element.removeClass('guideActiveField');
26055            },
26056
26057            handleModelChanged : function (event) {
26058                switch (event._property) {
26059                    case "enabled":
26060                        
26061                        
26062                        var prop = event.newText ? "open" : "readOnly";
26063                        if (this.jqwidget) {
26064                            this.jqwidget.option("access", prop);
26065                        }
26066                        this.$element.attr("data-disabled", !event.newText + "");
26067                        break;
26068                    case "mandatory":
26069                        
26070                        this._markMandatory(this._model.mandatory);
26071                        break;
26072                    case "validateExpMessage":
26073                        var newText = event.jsonModel.newText;
26074                        this._changeValidationMessage(newText);
26075                        break;
26076                    case "jcr:title":
26077                        
26078                        var newText = event.jsonModel.newText;
26079                        this._changeTitle(newText);
26080                        break;
26081                    default:
26082                        GuideFieldView._super.handleModelChanged.apply(this, arguments);
26083                }
26084            },
26085
26086            
26087            _changeTitle : function (newText) {
26088                var $field = $("#" + this.id),
26089                    $guideFieldLabelDiv = $field.children(".guideFieldLabel"),
26090                    $labelDiv = $guideFieldLabelDiv.children("label");
26091                if ($labelDiv) {
26092                    newText =  DOMPurify.sanitize(newText);
26093                    $labelDiv.html(newText);
26094                }
26095            },
26096
26097            
26098            _changeValidationMessage : function (newText) {
26099                var $fieldNode = $("#" + this.id),
26100                    $errorDiv = $fieldNode.children(".guideFieldError");
26101                $errorDiv.html(newText);
26102            },
26103
26104            
26105            commitValue : function (value) {
26106                this._model.value = value;
26107                var _version = this._model._guide().version;
26108                if (!(_version.isOn(_version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE))) {
26109                    this._model.executeExpression("valueCommitScript");
26110                }
26111                
26112                
26113                if (this.getCommitEvent() === xfaUtil.XFA_CHANGE_EVENT) {
26114                    this._model.executeExpression("change");
26115                } else {
26116                    this._model.executeExpression("exit");
26117                }
26118            },
26119
26120            
26121            tempXfaFixes : function () {
26122                
26123                
26124                
26125                if (this.$element) {
26126                    this.$element.find("input").css("position", "relative");
26127                }
26128                this.handleAccessibility();
26129            },
26130
26131            handleAccessibility : function () {
26132                
26133                if (this._model.mandatory) {
26134                    this.$widget.find("input,textarea,select,button").attr("aria-required", true);
26135                }
26136                if(this._model._getToolTip())  {
26137                    this.$element.find("input,textarea,select,button").attr("aria-labelledby",this._model.id + "_widget" + " " + this._model.id + "_guideFieldShortDescription");
26138                }
26139                if (this._model._getScreenReaderText() === this._model._getToolTip()) {
26140                    this.$element.find("input,textarea,select,button").removeAttr("aria-label");
26141                    this.$element.find("input,textarea,select,button").attr("aria-labelledby",this._model.id + "_guideFieldShortDescription");
26142                }
26143            },
26144
26145            
26146            _getWidgetInitialOptions : function ($widget) {
26147                var $elem = $widget.find('[data-af-widgetname]').addBack('[data-af-widgetname]');
26148                if ($elem.length > 0) {
26149                    this.logger().info("AF", "Getting widget options for " + this._model.somExpression);
26150                    var optionsMap = $elem.data('af-widgetoptions') || {};
26151                    _.each($elem[0].attributes, function (attr) {
26152                        var nm = attr.name.match(/data-af-widgetoption-([^-]+)$/);
26153                        if (nm != null && nm.length > 1) {
26154                            this.logger().info("AF", "adding option " + nm[1] + " with value " + " ");
26155                            optionsMap[nm[1]] = attr.value;
26156                        }
26157                    }, this);
26158                    return optionsMap;
26159                }
26160                return {};
26161            },
26162
26163            _newWidget : function (widgetname, options, $widgetElem) {
26164                var jqwidget = null,
26165                    fixesRequired = widgetname == this._defaultWidget
26165Name;
26166                try {
26167                    
26168                    $widgetElem[widgetname](options);
26169                    
26170                    
26171                    jqwidget = $widgetElem.data(widgetname) || $widgetElem.data('xfaWidget-' + widgetname);
26172                } catch (e) {
26173                    this.logger().error("AF", "widget " + widgetname + " doesn't exists. Falling back to default widget");
26174                    fixesRequired = true;
26175                    jqwidget = $widgetElem[this._defaultWidgetName](options).data('xfaWidget-' + widgetname);
26176                }
26177                
26178                if (fixesRequired) {
26179                    this.tempXfaFixes();
26180                }
26181                return jqwidget;
26182            },
26183
26184            createWidget : function (widgetname, options) {
26185                var initialOptions = this._getWidgetInitialOptions(this.$widget);
26186                var _options = $.extend({}, options, initialOptions);
26187                this.jqwidget = this._newWidget(widgetname, _options, this.$widget);
26188            },
26189
26190            handleEnter : function () {
26191                this._guideView.currentFocusItemSom = this._model.somExpression;
26192                var gb = window.guideBridge;
26193                if (gb) {
26194                    gb.clickedOnWindow = false;
26195                }
26196                if (!(this._model.className === 'guideRadioButton' || this._model.className === 'guideCheckBox' || this._model.className === 'guideButton')) {
26197                    this._triggerOnBridge("elementFocus", "", "", "", "");
26198                }
26199                this.oldValue = this._model.value;
26200                this.$element.addClass('guideActiveField');
26201            },
26202
26203            handleChange : function () {
26204
26205            },
26206
26207            setActive : function (activeItemToken, focus, muteScripts) {
26208                GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
26209                if (focus) {
26210                    
26211                    if (!this._guideView.skipFieldFocus && this.jqwidget && this.jqwidget.focus) {
26212                        this.jqwidget.focus();
26213                        this._guideView.currentFocusItemSom = this._model.somExpression;
26214                    }
26215
26216                }
26217                return true;
26218            },
26219
26220            updateWidgetOption : function (optionName, optionValue) {
26221                
26222                if (this.jqwidget) {
26223                    this.jqwidget.option(optionName, optionValue);
26224                }
26225            }
26226
26227        });
26228}($, guidelib, _));
26229(function ($, guidelib) {
26230    var GuideCaptchaView = guidelib.view.GuideCaptchaView = guidelib.view.GuideFieldView.extend({
26231        
26232        _defaultWidgetName : "afcaptcha",
26233
26234        syncGuideNodeToHtml : true,
26235
26236        initialize : function () {
26237            
26238            if (!FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) || this.options.model.isWidgetRecaptcha) {
26239                if ((this.options.model.captchaEnterprise && !this.options.model.checkBoxkey) ||
26240                    (this.options.model.captchaInvisible && this.options.model.mandatory)) {
26241                    this._model = this.options.model;
26242                    this.syncGuideNodeToHtml = false;
26243                    return;
26244                } else if (this.options.model.captchaInvisible) {
26245                    this.options.element.classList.add("af-hideRecaptchaView");
26246                    this.options.model.captchaValidate = false;
26247                }
26248            } else if ((this.options.model.isWidgetTurnstile || this.options.model.isWidgetHcaptcha) && this.options.model.captchaInvisible) {
26249                this._model = this.options.model;
26250                this.syncGuideNodeToHtml = false;
26251                return;
26252            }
26253            GuideCaptchaView._super.initialize.apply(this, arguments);
26254            if (this._model.captchaWidget) {
26255                
26256                this._defaultWidgetName = this._model.captchaWidget;
26257            }
26258        },
26259
26260        _initializeWidget : function () {
26261            GuideCaptchaView._super._initializeWidget.apply(this, arguments);
26262            if (this.$widget.length > 0) {
26263                this.$widget.on("tokenChange.captcha", $.proxy(this.handleTokenChange, this));
26264            }
26265        },
26266
26267        _syncGuideNodeToHtml : function (deepSync) {
26268            if(!this.syncGuideNodeToHtml)
26269                return;
26270            GuideCaptchaView._super._syncGuideNodeToHtml.call(this, deepSync);
26271        },
26272
26273        handleTokenChange : function (event) {
26274            this._model.value = event.token;
26275        },
26276
26277        createWidgetOptions : function () {
26278            var options = GuideCaptchaView._super.createWidgetOptions.apply(this, arguments);
26279            return $.extend({}, options, {
26280                "captchaConfigData" : this.options.model.jsonModel
26281            });
26282        },
26283
26284        handleErrorChanged : function (event) {
26285                var value = event.prevText,
26286                    errorMessage = event.newText;
26287                if (value === false) {
26288                    this._model._guide().runtime.errorManager.markError(errorMessage, this.$element, this._model.somExpression,
26289                    guideBridge.getValidationContext());
26290                    this.$element.addClass("validation-failure").removeClass("validation-success");
26291                } else {
26292                    this.$element.addClass("validation-success").removeClass("validation-failure");
26293                }
26294            }
26295    });
26296}($, guidelib));
26297(function ($, guidelib, _) {
26298    var xfaUtil = xfalib.ut.XfaUtil.prototype,
26299        GuideCompositeFieldView = guidelib.view.GuideCompositeFieldView = guidelib.view.GuideFieldView.extend({
26300            _defaultWidgetName : "defaultField",
26301
26302            
26303            getModelNameOptionsMap : function () {
26304                return {};
26305            },
26306
26307            initialize : function () {
26308                GuideCompositeFieldView._super.initialize.call(this);
26309                this._defineChildModelEvents();
26310            },
26311
26312            postInitialize : function () {
26313                GuideCompositeFieldView._super.postInitialize.call(this);
26314                var _self = this;
26315                if (this.getModelNameOptionsMap()) {
26316                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
26317                        var childModel = _self._model[modelName];
26318                        if (childModel._errorText) {
26319                            childModel._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
26320                                "validationStatus", childModel.validationState, childModel._errorText);
26321                        }
26322                    });
26323                }
26324            },
26325
26326            _unloadView : function () {
26327                var _self = this;
26328                if (this.getModelNameOptionsMap()) {
26329                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
26330                        var obj = _self._model[modelName];
26331                        
26332                        obj.off(guidelib.event.GuideModelEvent.VALUE_CHANGED, _self.handleValueChanged, _self);
26333                        if (obj.mandatory || obj.validateExp) {
26334                            obj.off(guidelib.event.GuideModelEvent.ERROR_CHANGED, _self.handleErrorChanged, _self);
26335                            obj.off(guidelib.event.GuideModelEvent.ERROR_RESET, _self.handleErrorReset, _self);
26336                        }
26337                    });
26338
26339                }
26340                GuideCompositeFieldView._super._unloadView.call(_self);
26341            },
26342
26343            _defineChildModelEvents : function () {
26344                var _self = this;
26345                if (this.getModelNameOptionsMap()) {
26346                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
26347                        var obj = _self._model[modelName];
26348                        
26349                        obj.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, _self.handleValueChanged, _self);
26350                        
26351                        
26352                        if (obj.mandatory || obj.validateExp) {
26353                            obj.on(guidelib.event.GuideModelEvent.ERROR_CHANGED, _self.handleErrorChanged, _self);
26354                            obj.on(guidelib.event.GuideModelEvent.ERROR_RESET, _self.handleErrorReset, _self);
26355                        }
26356                    });
26357
26358                }
26359            },
26360
26361            handleCommit : function () {
26362                var _self = this;
26363                if (!_.isEmpty(this.getModelNameOptionsMap())) {
26364                    _.each(this.getModelNameOptionsMap(), function (value, modelName) {
26365                        var obj = _self._model[modelName];
26366                        if (!_.isUndefined(obj)) {
26367                            var val = _self.jqwidget.option(value);
26368                            if (_.isArray(val)) {
26369                                val = val.join("\n");
26370                            }
26371                            obj.value = val;
26372                        }
26373                    });
26374                } else {
26375                    this._model.value = this.jqwidget.option("value");
26376                }
26377                this._model.executeExpression("valueCommitScript");
26378                this.execCommitExpression();
26379            },
26380
26381            handleValueChanged : function (event) {
26382                
26383                
26384                switch (event._property) {
26385                    case "value":
26386                        var map = this.getModelNameOptionsMap();
26387                        this.jqwidget.option(map[event.target.name], event.prevText);
26388                        break;
26389                }
26390            },
26391
26392            execCommitExpression : function () {
26393                
26394                if (this.getCommitEvent() == xfaUtil.XFA_CHANGE_EVENT) {
26395                    this._model.executeExpression("change");
26396                } else {
26397                    this._model.executeExpression("exit");
26398                }
26399            }
26400        });
26401}($, guidelib, _));
26402(function ($, guidelib) {
26403    var GuideFileUploadView = guidelib.view.GuideFileUploadView = guidelib.view.GuideCompositeFieldView.extend({
26404        _defaultWidgetName : "fileUpload",
26405
26406        getModelNameOptionsMap : function () {
26407            var map = GuideFileUploadView._super.getModelNameOptionsMap.apply(this, arguments);
26408            return $.extend({}, map, {
26409                "fileAttachment" : "value",
26410                "comment" : "comment"
26411            });
26412        },
26413
26414        createWidgetOptions : function () {
26415            var options = GuideFileUploadView._super.createWidgetOptions.apply(this, arguments),
26416                fileNamesStr = this._model._getFileAttachmentNames(),
26417                fileNamesArr = [];
26418            if (fileNamesStr) {
26419                fileNamesArr = fileNamesStr.split("\n");
26420            }
26421            return $.extend({}, options, {
26422                fileList : this._model.fileList,
26423                buttonText  : this._model.buttonText,
26424                multiSelect : this._model.multiSelection,
26425                fileSizeLimit : this._model.fileSizeLimit,
26426                mimeType : this._model.getOrElse(this._model.jsonModel, "mimeType", ""),
26427                buttonClass : "button.guide-fu-attach-button",
26428                fileItemListClass : "ul.guide-fu-fileItemList",
26429                iframeContainer : "div.guideContainerWrapperNode",
26430                showComment :  this._model.showComment,
26431                value : this._model.fileAttachment.value,
26432                fileNames : fileNamesArr,
26433                comment : this._model.comment.value,
26434                _uuidGenerator : function () { return guideBridge._getUUID.apply(this); }, 
26435                _filePath : "/tmp/fd/af",           
26436                _getUrl : guideBridge._getUrl(""),  
26437                disablePreview : false, 
26438                uploaderPluginName : guideBridge.userConfig.uploaderPluginName || "adobeFileUploader"
26439            });
26440        },
26441
26442        handleCommit : function () {
26443            
26444            
26445            
26446            this._model.fileList = this.jqwidget.option("fileList");
26447            GuideFileUploadView._super.handleCommit.apply(this, arguments);
26448        },
26449
26450        handleModelChanged : function (event) {
26451            switch (event._property) {
26452                case "fileList":
26453                    this.jqwidget.option("fileList", event.prevText);
26454                    break;
26455                default:
26456                    GuideFileUploadView._super.handleModelChanged.apply(this, arguments);
26457                    break;
26458            }
26459        },
26460
26461        handleAccessibility : function () {
26462            
26463            
26464            var isBrowserIE9OrIE10 = ($.browser.msie && ($.browser.version === '9.0' || $.browser.version === '10.0'));
26465            if (isBrowserIE9OrIE10) {
26466                if (this._model.mandatory) {
26467                    this.$widget.attr("aria-required", true);
26468                }
26469                if (this._model._getScreenReaderText() === this._model._getToolTip()) {
26470                    this.$widget.removeAttr("aria-label");
26471                    this.$widget.attr("aria-labelledby", this._model.id + "_guideFieldShortDescription");
26472                }
26473            } else {
26474                GuideFileUploadView._super.handleAccessibility.apply(this, arguments);
26475            }
26476        },
26477
26478        setActive : function (activeItemToken, focus, muteScripts) {
26479            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
26480            if (focus) {
26481                this._guideView.currentFocusItemSom = this._model.somExpression;
26482                this.$element.find("button").focus();
26483            }
26484            return true;
26485        },
26486
26487        
26488        
26489        tempXfaFixes : function () {
26490            
26491            this.handleAccessibility();
26492        },
26493
26494        getCommitEvent : function () {
26495            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
26496        }
26497    });
26498}($, guidelib));
26499(function ($, guidelib) {
26500    var GuideTermsAndConditionsView = guidelib.view.GuideTermsAndConditionsView = guidelib.view.GuideCompositeFieldView.extend({
26501        _defaultWidgetName : "tnc",
26502
26503        getModelNameOptionsMap : function () {
26504            var map = GuideTermsAndConditionsView._super.getModelNameOptionsMap.apply(this, arguments);
26505            return $.extend({}, map, {
26506                "reviewDocument" : "value",
26507                "reviewStatus" : "reviewStatus"
26508            });
26509        },
26510
26511        createWidgetOptions : function () {
26512            var options = GuideTermsAndConditionsView._super.createWidgetOptions.apply(this, arguments);
26513            return $.extend({}, options, {
26514                textAreaClass : ".guide-tnc-content",
26515                checkBoxClass : ".guide-tnc-checkbox",
26516                linkClass     : ".guide-tnc-link",
26517                checkBoxDisableClass : ".guide-tnc-checkbox-disabled",
26518                checkBoxReviewedClass : ".guide-tnc-checkbox-reviewed",
26519                showLink      :  this._model.showLink,
26520                showAsPopUp   :  this._model.showAsPopUp,
26521                value : this._model.reviewDocument.value,
26522                reviewStatus : this._model.reviewStatus.value,
26523                clickStatus  : this._model.clickStatus
26524            });
26525        },
26526
26527        
26528        tempXfaFixes : function () {
26529            
26530            
26531            
26532            if (this.$widget) {
26533                this.$widget.css("position", "relative");
26534            }
26535
26536        },
26537
26538        handleCommit : function (event) {
26539            
26540            this._model.clickStatus = this.jqwidget.option("clickStatus");
26541            
26542            GuideTermsAndConditionsView._super.handleCommit.apply(this, arguments);
26543        },
26544
26545        handleModelChanged : function (event) {
26546            
26547            
26548            switch (event._property) {
26549                case "clickStatus":
26550                    this.jqwidget.option("clickStatus", event.prevText);
26551                    break;
26552                default:
26553                    GuideTermsAndConditionsView._super.handleModelChanged.apply(this, arguments);
26554                    break;
26555            }
26556        },
26557
26558        getCommitEvent : function () {
26559            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
26560        }
26561    });
26562}($, guidelib));
26563(function ($, guidelib) {
26564    var GuideTelephoneView = guidelib.view.GuideTelephoneView = guidelib.view.GuideFieldView.extend({
26565        
26566        _defaultWidgetName : "telephoneWidget",
26567
26568        createWidgetOptions : function () {
26569            var options = GuideTelephoneView._super.createWidgetOptions.apply(this, arguments);
26570            return $.extend({}, options, {
26571                placeholder : this._model.placeholderText
26572            });
26573        }
26574
26575    });
26576}($, guidelib));
26577
26578(function ($, guidelib) {
26579    var GuideTextDrawView = guidelib.view.GuideTextDrawView = guidelib.view.GuideFieldView.extend({
26580        _defaultWidgetName : "abstractWidget",
26581
26582        initialize : function () {
26583            GuideTextDrawView._super.initialize.call(this);
26584            if (this.$element && this.$element.length > 0) {
26585                $(this.$element)
26586                    .on("focus.guideTextDraw", $.proxy(this.handleEnter, this))
26587                    .on("click.guideTextDraw", $.proxy(this.handleClick, this));
26588            }
26589        },
26590
26591        _syncGuideNodeToHtml : function (deepSync) {
26592            GuideTextDrawView._super._syncGuideNodeToHtml.call(this, deepSync);
26593            
26594            
26595            var isFloatingField = this._model._isFloatingField();
26596            var isParentLazy = guidelib.util.GuideUtil._checkIfAncestorIsALazyReference(this);
26597            if (!isParentLazy && this._model.value === this._model.jsonModel._value && this.$element.html() !== this._model.value && !isFloatingField) {
26598                
26599                
26600            } else {
26601                this.handleValueChanged({
26602                    _property : "value",
26603                    newText : this._model.value ? this._model.value : ""
26604                });
26605            }
26606        },
26607
26608        handleValueChanged : function (event) {
26609            switch (event._property) {
26610                case "value":
26611                    this.$element.html(event.newText);
26612                    break;
26613            }
26614        },
26615
26616        setActive : function (activeItemToken, focus, muteScripts) {
26617            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
26618            if (focus && !this._guideView.skipFieldFocus) {
26619                if (this.$element) {
26620                    this.$element.focus();
26621                }
26622                this._guideView.currentFocusItemSom = this._model.somExpression;
26623            }
26624            return true;
26625        }
26626    });
26627}($, guidelib));
26628
26629
26630(function ($, guidelib) {
26631    var GuideAdobeSignBlockView = guidelib.view.GuideAdobeSignBlockView = guidelib.view.GuideTextDrawView.extend({
26632    });
26633}($, guidelib));
26634(function ($, guidelib) {
26635    var GuideButtonView = guidelib.view.GuideButtonView = guidelib.view.GuideFieldView.extend({
26636        _defaultWidgetName : "xfaButton",
26637
26638        handleClick : function (event) {
26639            this._triggerOnBridge("elementButtonClicked", this._model, "click", "", "");
26640            this._model.executeExpression("clickExp");
26641            GuideButtonView._super.handleClick.call(this);
26642        },
26643
26644        _changeTitle : function (newText) {
26645            var $fieldTitleSpan = $("#" + this.id + "_widget");
26646            var $buttonLabel = $fieldTitleSpan.children("[data-guide-button-label]");
26647            newText =  xfalib.ut.XfaUtil.prototype.encodeScriptableTags(newText);
26648            $buttonLabel.html(newText);
26649        },
26650
26651        tempXfaFixes : function () {
26652            
26653            
26654            
26655            if (this.$element) {
26656                this.$element.find("button").css("position", "relative");
26657            }
26658            this.handleAccessibility();
26659        }
26660
26661    });
26662}($, guidelib));
26663(function ($, guidelib, _) {
26664    var fileInputIdCounter = 0;
26665    var GuideListFileAttachmentButtonView = guidelib.view.GuideListFileAttachmentButtonView = guidelib.view.GuideButtonView.extend({
26666        
26667        _clearFileListing : function () {
26668            $('#fileAttachment .modal-list', window.document).children().remove();
26669            _.each(this._fileListViews, function (childView) {
26670                childView._unloadView();
26671            }, this);
26672            this._fileListViews = [];
26673            fileInputIdCounter = 0;
26674        },
26675        _updateFileListing : function (fileAttachmentModel) {
26676            if (fileAttachmentModel.className == "guideFileUpload") {
26677                var $htmlTemplate = this._guideView.$element.find("#" + fileAttachmentModel.id),
26678                    inputFileSelector = "#" + fileAttachmentModel.id + "_widget",
26679                
26680                
26681                
26682                
26683                
26684                    $cloneHtmlTemplate = $htmlTemplate.clone();
26685                
26686                $cloneHtmlTemplate.find(inputFileSelector).attr("id", fileAttachmentModel.id + "_widget" + (++fileInputIdCounter));
26687                this._addSuffixToHelpIds($cloneHtmlTemplate, fileInputIdCounter);
26688                var $fluidDesign = $('<div></div>').addClass("row").append('<div class="col-md-12"></div>');
26689                $('#fileAttachment .modal-list', window.document).append($cloneHtmlTemplate.appendTo($fluidDesign));
26690                var view = guidelib.view.GuideViewRegistry.prototype.createView($cloneHtmlTemplate, this);
26691                this._fileListViews.push(view);
26692                view.postInitialize();
26693
26694            }
26695        },
26696        _addSuffixToHelpIds : function ($html, suffix) {
26697            var $questionMarkElement = $html.find("[data-guide-longDescription]"),
26698                $shortHelpElement;
26699            if ($questionMarkElement.length > 0) {
26700                var idForLongHelp = $questionMarkElement.attr("data-guide-longDescription"),
26701                    $longHelpElement = $(".guideFieldDescription.long", $html);
26702                idForLongHelp = idForLongHelp + suffix;
26703                $longHelpElement.attr("id", idForLongHelp);
26704                $questionMarkElement.attr("data-guide-longDescription", idForLongHelp);
26705            }
26706            
26707
26708        },
26709
26710        
26711        _markFileListing : function () {
26712            if (this.$element) {
26713                this.$element.find("button").attr("data-guide-fileListing", true);
26714            }
26715        },
26716
26717        initialize : function () {
26718            GuideListFileAttachmentButtonView._super.initialize.apply(this, arguments);
26719            this._markFileListing();
26720            
26721            
26722            this._fileListViews = [];
26723        }
26724    });
26725}($, guidelib, _));
26726(function ($, guidelib, _) {
26727    var xfaUtil = xfalib.ut.XfaUtil.prototype,
26728        GuideDropDownListView = guidelib.view.GuideDropDownListView = guidelib.view.GuideFieldView.extend({
26729
26730            _defaultWidgetName : "dropDownList",
26731
26732            initialize : function () {
26733                GuideDropDownListView._super.initialize.apply(this, arguments);
26734                if (this._model.multiSelect) {
26735                    this._defaultWidgetName = "listBox";
26736                }
26737            },
26738
26739            _valueToArray : function (value) {
26740                var valueArray;
26741                if (value !== null && !_.isUndefined(value)) {
26742                    if (_.isString(value)) {
26743                        valueArray = value.split("\n");
26744                    } else if (_.isNumber(value)) {
26745                        valueArray = [value.toString()];
26746                    }
26747                } else {
26748                    valueArray = [null];
26749                }
26750                return valueArray;
26751            },
26752
26753            createWidgetOptions : function () {
26754                var options = GuideDropDownListView._super.createWidgetOptions.apply(this, arguments);
26755                
26756                
26757                return $.extend({}, options, {
26758                    multiSelect : this._model.multiSelect,
26759                    editable : false,
26760                    items : this._model._getOptionsArray("save", "display"),
26761                    value : this._valueToArray(this._model.value),
26762                    placeholder : this._model.placeholderText
26763                });
26764            },
26765
26766            
26767            handleCommit : function () {
26768                var val = this.jqwidget.option("value");
26769                if (_.isArray(val)) {
26770                    val = val.join("\n");
26771                }
26772                
26773                this.commitValue(val);
26774            },
26775
26776            
26777            commitValue : function (value) {
26778                var oldValue = this._model.value;
26779                this._model.value = value;
26780                
26781                
26782                
26783                var _version = this._model._guide().version;
26784                if (!(_version.isOn(_version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE))) {
26785                    this._model.executeExpression("valueCommitScript");
26786                }
26787                if (this.getCommitEvent() === xfaUtil.XFA_CHANGE_EVENT) {
26788                    
26789                    
26790                    
26791                    
26792                    
26793                    this._model.executeExpression("change", {
26794                        "prevText" : oldValue,
26795                        "newText" : this._model.value
26796                    });
26797                } else {
26798                    
26799                    this._model.executeExpression("exit");
26800                }
26801            },
26802
26803            handleValueChanged : function (event) {
26804                this.jqwidget.option("value", this._valueToArray(event.prevText));
26805                this.jqwidget.option("displayValue", this._valueToArray(event.
26805newText));
26806                this._updateEmptyStatus(event);
26807            },
26808
26809            getCommitEvent : function () {
26810                return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
26811            },
26812
26813            handleModelChanged : function (event) {
26814                if (event._property === "addItem") {
26815                    this._handleAddItem(event);
26816                }
26817                if (event._property === "clearItems") {
26818                    this._handleClearItems(event);
26819                }
26820                if (event._property === "deleteItem") {
26821                    this._handleDeleteItem(event);
26822                } else {
26823                    GuideDropDownListView._super.handleModelChanged.apply(this, arguments);
26824                }
26825            },
26826
26827            _handleAddItem : function (event) {
26828                var itemValues = {
26829                    sDisplayVal : event.newText,
26830                    sSaveVal : event.prevText
26831                };
26832                this.jqwidget.addItem(itemValues);
26833            },
26834
26835            _handleClearItems : function (event) {
26836                this.jqwidget.clearItems();
26837            },
26838
26839            _handleDeleteItem : function (event) {
26840                this.jqwidget.deleteItem(event.newText);
26841            },
26842
26843            handleItemsChanged : function (event) {
26844                var items = this._model._getOptionsArray("save", "display");
26845                this.jqwidget.option("items", items);
26846                this.jqwidget.option("value", this._valueToArray(this._model.jsonModel._value));
26847                this.jqwidget.option("displayValue", this._valueToArray(this._model.formattedValue));
26848            },
26849
26850            _defineModelEvents : function () {
26851                GuideDropDownListView._super._defineModelEvents.apply(this, arguments);
26852                if (this._model) {
26853                    
26854                    this._model.on(guidelib.event.GuideModelEvent.ITEMS_CHANGED, this.handleItemsChanged, this);
26855                }
26856            },
26857
26858            
26859            tempXfaFixes : function () {
26860                
26861                
26862                if (this.$element) {
26863                    if (!this._model.multiSelect) {
26864                        this.$element.find("select")
26865                            .css("position", "relative")
26866                            .attr("id", this._model.id + "_widget")
26867                            .attr("aria-describedby", this._model.id + "_widget_desc");
26868                    } else {
26869                        
26870                        if (this._model.height) {
26871                            this.$element.find("ol").css("max-height", "none");
26872                        }
26873                        this.$element.find("ol")
26874                            .css("position", "relative")
26875                            .attr("id", this._model.id + "_widget");
26876                    }
26877                }
26878                this.handleAccessibility();
26879            }
26880        });
26881
26882}($, guidelib, _));
26883(function ($, guidelib, _) {
26884    var GuideCheckBoxView = guidelib.view.GuideCheckBoxView = guidelib.view.GuideFieldView.extend({
26885        _defaultWidgetName : "XfaCheckBox",
26886        initialize : function () {
26887            GuideCheckBoxView._super.initialize.apply(this, arguments);
26888            this._setListenersForLabelClick();
26889            this._setListenersForRadioButtonKeyPress();
26890        },
26891        
26892        _setListenersForLabelClick : function () {
26893            var self = this;
26894            this.$element
26895                .find(".guideWidgetLabel")
26896                .each(function (index, item) {
26897                    $(item).click(
26898                        (function (index) {
26899                            return function () {
26900                                
26901                                if (self._model.enabled) {
26902                                    self.jqwidget[self.getJQWidgetIdentifier(index)].click();
26903                                }
26904                            };
26905                        }(index))
26906                    );
26907                });
26908        },
26909
26910        _setListenersForRadioButtonKeyPress : function () {
26911            var self = this;
26912            this.$element
26913                .find(".guideRadioButtonItem")
26914                .each(function (index, item) {
26915                    $(item).keypress(function (e){
26916                        if(e.keyCode == "13" || e.keyCode == "32"){
26917                            e.preventDefault();
26918                            if (self._model.enabled) {
26919                                self.jqwidget[self.getJQWidgetIdentifier(index)].click();
26920                            }
26921                        }
26922                    });
26923                });
26924        },
26925        _syncGuideNodeToHtml : function (deepSync) {
26926            if (this._model._isStateOverridden("options")) {
26927                this._replaceGroupItemsWithNewOptions(this._model._getOptionsArray(), this._model.getAttribute("alignment"));
26928                
26929                
26930                
26931                
26932                this.jqwidget = null; 
26933
26934            }
26935            GuideCheckBoxView._super._syncGuideNodeToHtml.apply(this, arguments);
26936        },
26937        getJQWidgetIdentifier : function (index) {
26938            return index;
26939        },
26940
26941        createWidgetOptions : function () {
26942            var options = GuideCheckBoxView._super.createWidgetOptions.apply(this, arguments);
26943
26944            return $.extend({}, options, {
26945                states : 2
26946            });
26947        },
26948
26949        getCommitEvent : function () {
26950            return xfalib.ut.XfaUtil.prototype.XFA_CHANGE_EVENT;
26951        },
26952
26953        getStateFromValue : function (value, items) {
26954            if (value === null) {
26955                return 1;
26956            }
26957            var valuesArray = null;
26958            if (value && value.indexOf && value.indexOf("\\,") > -1) {
26959                valuesArray = this.splitOnNonEscapedCommas(value);
26960            } else {
26961                valuesArray = (value + "").split(",");
26962            }
26963            if (valuesArray && valuesArray.indexOf(items[0] + "") !== -1)  {
26964                return 0;
26965            }
26966            return 1;
26967        },
26968
26969        getOnOffValueFromModelValue : function (val, items) {
26970            return items[this.getStateFromValue(val, items)];
26971        },
26972
26973        splitOnNonEscapedCommas : function (string) {
26974            var splitArray = [];
26975            var currentSubstring = '';
26976            var escaped = false;
26977
26978            for (var i = 0; i < string.length; i++) {
26979                var char = string[i];
26980
26981                if (char === ',' && !escaped) {
26982                    splitArray.push(currentSubstring.trim());
26983                    currentSubstring = '';
26984                } else {
26985                    currentSubstring += char;
26986                    escaped = (char === '\\' && !escaped);
26987                }
26988            }
26989            splitArray.push(currentSubstring.trim()); 
26990            return splitArray;
26991        },
26992
26993        handleValueChanged : function (event) {
26994            _.each(this.jqwidget, function (jqwidget) {
26995                var setVal = this.getOnOffValueFromModelValue(event.prevText, this._escapeCommas(jqwidget.option("values")));
26996                setVal = this._unescapeCommas(setVal);
26997                jqwidget.option("value", setVal);
26998                jqwidget.option("displayValue", setVal);
26999            }, this);
27000            this.$widget.find("[checked!=checked]").parents(".guideCheckBoxItem").removeClass('guideItemSelected');
27001            this.$widget.find("[checked=checked]").parents(".guideCheckBoxItem").addClass('guideItemSelected');
27002        },
27003
27004        _escapeCommas : function (items) {
27005            var temp = _.clone(items);
27006            if(temp[0] && temp[0].indexOf && temp[0].indexOf(',') > -1 && temp[0].indexOf('\\,') === -1) {
27007                temp[0] = temp[0].replace(/,/g, "\\,"); 
27008            }
27009            return temp;
27010        },
27011
27012        _unescapeCommas : function (value) {
27013            if(value && value.indexOf && value.indexOf('\\,') > -1) {
27014                value = value.replace(/\\,/g, ','); 
27015            }
27016            return value;
27017        },
27018
27019        handleCommit : function () {
27020            var temp = "";
27021            _.each(this.jqwidget, function (jqwidget, index) {
27022                var items = this._escapeCommas(jqwidget.option("values"));
27023                if (jqwidget.option("state") === 0) {
27024                    
27025                    temp = temp + items[0] + ",";
27026                }
27027            }, this);
27028            temp = temp.substring(0, temp.length - 1);
27029            this.commitValue(this._unescapeCommas(temp));
27030        },
27031
27032        handleEnabledChanged : function (event) {
27033            
27034            if (!this.$element.hasClass("dontSyncEnabled")) {
27035                var prop = event.newText ? "open" : "readOnly";
27036                _.each(this.jqwidget, function (jqwidget) {
27037                    jqwidget.option("access", prop);
27038                });
27039            }
27040
27041            this.$element.attr("data-disabled", !this._model.enabled);
27042        },
27043
27044        handleModelChanged : function (evnt) {
27045            switch (evnt._property) {
27046            case "enabled":
27047                this.handleEnabledChanged(evnt);
27048                break;
27049            default:
27050                GuideCheckBoxView._super.handleModelChanged.apply(this, arguments);
27051            }
27052        },
27053
27054        handleItemsChanged : function (event) {
27055            this._replaceGroupItemsWithNewOptions(this._model._getOptionsArray(), this._model.jsonModel.alignment);
27056            this.createWidget(this.getWidgetName(), this.createWidgetOptions());
27057        },
27058
27059        _getGroupItemIdentifier : function () {
27060            return '.guideCheckBoxGroupItems';
27061        },
27062
27063        _getWidgetType : function () {
27064            return 'checkbox';
27065        },
27066
27067        _getItemName : function () {
27068            return "CheckBoxItem";
27069        },
27070
27071        _getItemSkeleton : function () {
27072            var guideWidgetItemName = "guide" + this._getItemName(); 
27073            var afWidgetItemName = "af" + this._getItemName(); 
27074            return '<div class="' + guideWidgetItemName + ' ' + afWidgetItemName + ' {NAME_PLACEHOLDER} {CSS_PLACEHOLDER}" data-original-title="" title="">\n' +
27075                '            <div class="guideFieldWidget left XfaCheckBox" data-id="{COUNTER_PLACEHOLDER}" data-original-title="" title="">\n' +
27076                '                <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' +
27077                '            </div>\n' +
27078                '            <div class="guideWidgetLabel right">\n' +
27079                '                <label>{LABEL_PLACEHOLDER}</label>\n' +
27080                '            </div>\n' +
27081                '        </div>';
27082        },
27083
27084        _renderGroupItem : function (options) {
27085            var itemSkeleton = this._getItemSkeleton(),
27086                namePlaceHolder = "{NAME_PLACEHOLDER}",
27087                cssPlaceHolder = "{CSS_PLACEHOLDER}",
27088                counterPlaceHolder = "{COUNTER_PLACEHOLDER}" ,
27089                templateIDPlaceHolder = "{TEMPLATE_ID_PLACEHOLDER}",
27090                labelPlaceHolder = "{LABEL_PLACEHOLDER}",
27091                guideUtil = guidelib.util.GuideUtil;
27092            itemSkeleton = guideUtil.replaceAll(itemSkeleton, namePlaceHolder, options.modelName);
27093            itemSkeleton = guideUtil.replaceAll(itemSkeleton, templateIDPlaceHolder, options.modelTemplateId);
27094            itemSkeleton = guideUtil.replaceAll(itemSkeleton, cssPlaceHolder, options.cssValue);
27095            itemSkeleton = guideUtil.replaceAll(itemSkeleton, counterPlaceHolder, options.itemIndex);
27096            itemSkeleton = guideUtil.replaceAll(itemSkeleton, labelPlaceHolder, options.displayValue);
27097            return itemSkeleton;
27098        },
27099
27100        _replaceGroupItemsWithNewOptions : function (items, cssValue) {
27101            var groupItem = this.$element.find(this._getGroupItemIdentifier()),
27102                options = {},
27103                widgetName = this.getWidgetName(),
27104                self = this;
27105
27106            
27107            groupItem.empty();
27108            options.widgetType = this._getWidgetType();
27109            options.modelName = this._model.name;
27110            options.modelTemplateId = this._model.id;
27111
27112            if (this._model.css !== null && !_.isUndefined(this._model.css)) {
27113                cssValue +=  " " + this._model.css;
27114            }
27115            options.cssValue = cssValue;
27116
27117            _.each(items, function (value, index) {
27118                options.itemIndex = index;
27119                options.displayValue = value.displayValue;
27120                options.saveValue = value.saveValue;
27121                groupItem.append(self._renderGroupItem(options));
27122            });
27123            this._initializeWidget();
27124            this._setListenersForLabelClick();
27125        },
27126
27127        _replaceAll : function (stringToReplaceIn, textToReplace, replacementString) {
27128            return stringToReplaceIn.split(textToReplace).join(replacementString);
27129        },
27130
27131        _defineModelEvents : function () {
27132            GuideCheckBoxView._super._defineModelEvents.apply(this, arguments);
27133            if (this._model) {
27134                
27135                this._model.on(guidelib.event.GuideModelEvent.ITEMS_CHANGED, this.handleItemsChanged, this);
27136            }
27137        },
27138
27139        setWidgetOptions : function (options) {
27140            var index = 0;
27141            _.each(this.jqwidget, function (jqwidget, id) {
27142                this._initOrUpdateWidget(id, this._getOptions(options, index++));
27143            }, this);
27144        },
27145
27146        _getOptions : function (options, index) {
27147            var items = this._model.getOnOffValues(index),
27148                val = this.getOnOffValueFromModelValue(this._model.value, items),
27149                optionsCopy = _.extend(options, {
27150                    value : val,
27151                    displayValue : val,
27152                    values : items,
27153                    state : this.getStateFromValue(this._model.value, items),
27154                    screenReaderText : this._model._getScreenReaderText(index)
27155                });
27156            return optionsCopy;
27157        },
27158
27159        _initOrUpdateWidget : function (id, options, widgetname, $widget, initialOptions) {
27160            if (this.jqwidget[id]) {
27161                this.jqwidget[id].option(options);
27162            } else {
27163                var _options = $.extend({}, options, initialOptions);
27164                this.jqwidget[id] = this._newWidget(widgetname, _options, $widget);
27165            }
27166            this.$widget.find("[checked!=checked]").parents(".guideCheckBoxItem").removeClass('guideItemSelected');
27167            this.$widget.find("[checked=checked]").parents(".guideCheckBoxItem").addClass('guideItemSelected');
27168        },
27169
27170        initializeJqWidget : function () {
27171            this.jqwidget = [];
27172        },
27173
27174        createWidget : function (widgetname, options) {
27175            var self = this;
27176            this.initializeJqWidget();
27177            if (this.$widget) {
27178                this.$widget.each(function (index, widget) {
27179                    self._initOrUpdateWidget(self.getJQWidgetIdentifier(index),
27180                        self._getOptions(options, index),
27181                        widgetname,
27182                        $(widget),
27183                        self._getWidgetInitialOptions($(widget)));
27184                });
27185                this.tempXfaFixes();
27186            }
27187        },
27188
27189        setActive : function (activeItemToken, focus, muteScripts) {
27190            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
27191            if (focus && !this._guideView.skipFieldFocus) {
27192                if (this.jqwidget && this.jqwidget[this.getJQWidgetIdentifier(0)]) {
27193                    this.jqwidget[this.getJQWidgetIdentifier(0)].focus();
27194                }
27195                this._guideView.currentFocusItemSom = this._model.somExpression;
27196            }
27197            return true;
27198        },
27199
27200        updateWidgetOption : function (optionName, optionValue) {
27201            _.each(this.jqwidget, function (jqwidget, index) {
27202                if (optionName == "isValid") {
27203                    jqwidget.option(optionName, optionValue);
27204                }
27205            }, this);
27206        },
27207
27208        handleAccessibility : function () {
27209            GuideCheckBoxView._super.handleAccessibility.apply(this, arguments);
27210            this.$element.attr("role", "group");
27211            if (this._model.jsonModel.assistPriority && this._model.jsonModel.custom && this._model.jsonModel.assistPriority === "custom"){
27212                this.$element.attr("aria-label", this._model.jsonModel.custom[0]);
27213            } else {
27214                var $label = this.$element.find(".guideFieldLabel label"),
27215                    label = $label.get(0);
27216                if (label && label.id) {
27217                    this.$element.attr("aria-labelledby", label.id);
27218                }
27219            }
27220        }
27221
27222    });
27223}($, guidelib, window._));
27224
27225(function ($, guidelib, _) {
27226    var GuideRadioButtonView = guidelib.view.GuideRadioButtonView = guidelib.view.GuideCheckBoxView.extend({
27227
27228        _defaultWidgetName : "XfaCheckBox",
27229
27230        _prevOnWidget : null,
27231
27232        _getWidgetType : function () {
27233            return 'radio';
27234        },
27235
27236        _getItemName : function () {
27237            return "RadioButtonItem";
27238        },
27239
27240        _getGroupItemIdentifier : function () {
27241            return '.guideRadioButtonGroupItems';
27242        },
27243
27244        getJQWidgetIdentifier : function (index) {
27245            return this._model.getItemIdentifier(index);
27246        },
27247
27248        handleValueChanged : function (event) {
27249            var somExpression = event.prevText;
27250            if (this.jqwidget[somExpression]) {
27251                this.jqwidget[somExpression].option("value", event.newText);
27252                this.jqwidget[somExpression].option("displayValue", event.newText);
27253                if (event.newText === null) {
27254                    this._prevOnWidget = null;
27255                } else {
27256                    this._prevOnWidget = this.jqwidget[somExpression];
27257                }
27258            }
27259            this.$widget.find("[checked!=checked]").parents(".guideRadioButtonItem").removeClass('guideItemSelected').attr("aria-checked", false);
27260            this.$widget.find("[checked=checked]").parents(".guideRadioButtonItem").addClass('guideItemSelected').attr("aria-checked", true);
27261            this._updateEmptyStatus();
27262        },
27263
27264        handleCommit : function () {
27265            var jqwidgettochange = _.find(this.jqwidget, function (jqwidget) {
27266                    return jqwidget.option("state") === 0 && jqwidget !== this._prevOnWidget;
27267                }, this);
27268            this.commitValue(jqwidgettochange.option("value"));
27269            this._prevOnWidget = jqwidgettochange;
27270        },
27271
27272        _initOrUpdateWidget : function (id, options, widgetname, widget) {
27273            GuideRadioButtonView._super._initOrUpdateWidget.apply(this, arguments);
27274            if (options.state === 0) {
27275                this._prevOnWidget = this.jqwidget[id];
27276            }
27277            this.$widget.find("[checked!=checked]").parents(".guideRadioButtonItem").removeClass('guideItemSelected');
27278            this.$widget.find("[checked=checked]").parents(".guideRadioButtonItem").addClass('guideItemSelected');
27279        },
27280
27281        initializeJqWidget : function () {
27282            this.jqwidget = {};
27283            
27284            
27285            
27286            this.$widget.find("[checked]").removeAttr("checked");
27287            this.$widget.find("[checked=checked]").removeAttr("checked"); 
27288
27289        },
27290
27291        handleAccessibility : function () {
27292            GuideRadioButtonView._super.handleAccessibility.apply(this, arguments);
27293            this.$element.attr("role", "radiogroup");
27294        }
27295    });
27296}($, guidelib, _));
27297(function ($, guidelib, _) {
27298    var GuideSwitchView = guidelib.view.GuideSwitchView = guidelib.view.GuideCheckBoxView.extend({
27299        _defaultWidgetName : "guideSwitch",
27300
27301        createWidgetOptions : function () {
27302            var options = GuideSwitchView._super.createWidgetOptions.apply(this, arguments),
27303                items = this._model.jsonModel.options, checkedLabel, uncheckedLabel;
27304            
27305            if (Array.isArray(items) && items.length > 0) {
27306                checkedLabel = items[0];
27307            } else if (!_.isUndefined(items) && items.length > 0) {
27308                checkedLabel = items;
27309            } else {
27310                checkedLabel = " ";
27311            }
27312            if (Array.isArray(items) && items.length > 1) {
27313                uncheckedLabel = items[1];
27314            } else {
27315                uncheckedLabel = "    ";
27316            }
27317            return $.extend({}, options, {
27318                checkedLabel : checkedLabel.substring(checkedLabel.indexOf("=") + 1),
27319                uncheckedLabel : uncheckedLabel.substring(uncheckedLabel.indexOf("=") + 1)
27320            });
27321        },
27322
27323        handleValueChanged : function (event) {
27324            
27325            var jqwidget = this.jqwidget[0],
27326                jqwidgetOptions = jqwidget.options;
27327            var setVal = this.getOnOffValueFromModelValue(event.prevText, jqwidget.option("values"));
27328            if (jqwidgetOptions.value !== setVal) {
27329                jqwidget.option("value", setVal);
27330                
27331                var userControl = jqwidget.$userControl;
27332                var checked = jqwidgetOptions.value === jqwidgetOptions.values[0];
27333                userControl.prop("checked", checked);
27334                userControl.parent().toggleClass('ui-state-active', checked);
27335                userControl.change();
27336            }
27337        },
27338
27339        handleCommit : function () {
27340            var jqwidget = this.jqwidget[0],
27341                items = jqwidget.option("values"),
27342                state = jqwidget.option("state");
27343            this.commitValue(items[state]);
27344        }
27345    });
27346}($, guidelib, _));
27347
27348(function ($, guidelib) {
27349    var GuideNumericBoxView = guidelib.view.GuideNumericBoxView = guidelib.view.GuideFieldView.extend({
27350        _defaultWidgetName : "numericInput",
27351        createWidgetOptions : function () {
27352            var options = GuideNumericBoxView._super.createWidgetOptions.apply(this, arguments);
27353            return $.extend({}, options, {
27354                dataType : this._model.dataType,
27355                leadDigits : this._model.leadDigits,
27356                fracDigits : this._model.fracDigits,
27357                
27358                zero : guidelib.i18n.numberSymbols.zero,
27359                decimal : guidelib.i18n.numberSymbols.decimal,
27360                commitEvent : this.getCommitEvent(),
27361                placeholder : this._model.placeholderText
27362            });
27363        }
27364    });
27365
27366}($, guidelib));
27367(function ($, guidelib) {
27368    var GuidePasswordBoxView = guidelib.view.GuidePasswordBoxView = guidelib.view.GuideFieldView.extend({
27369        _defaultWidgetName : "defaultWidget",
27370
27371        createWidgetOptions : function () {
27372            var options = GuidePasswordBoxView._super.createWidgetOptions.apply(this, arguments);
27373
27374            return $.extend({}, options, {
27375                 placeholder : this._model.placeholderText
27376             });
27377        }
27378    });
27379}($, guidelib));
27380(function ($, guidelib) {
27381    var GuideDatePickerView = guidelib.view.GuideDatePickerView = guidelib.view.GuideFieldView.extend({
27382        _defaultWidgetName : "dateTimeEdit",
27383
27384        createWidgetOptions : function () {
27385            var options = GuideDatePickerView._super.createWidgetOptions.apply(this, arguments),
27386                useNativeWidget = (this._model.displayPictureClause === null && this._model.editPictureClause == null);
27387
27388            return $.extend({}, options, {
27389                days : guidelib.i18n.calendarSymbols.abbrdayNames,
27390                months : guidelib.i18n.calendarSymbols.monthNames,
27391                zero : guidelib.i18n.numberSymbols.zero,
27392                clearText : xfalib.locale.Strings.clearText,
27393                useNativeWidget : useNativeWidget,
27394                showCalendarIcon : true,
27395                editPattern : this._model.editPictureClause,
27396                placeholder : this._model.placeholderText,
27397                minValidDate : this._model.minimum,
27398                maxValidDate : this._model.maximum,
27399                exclMaxDate :  this._model.exclusiveMaximum,
27400                exclMinDate : this._model.exclusiveMinimum,
27401                allowNonIsoValue : true
27402            });
27403        },
27404
27405        
27406        tempXfaFixes : function () {
27407            GuideDatePickerView._super.tempXfaFixes.apply(this, arguments);
27408            
27409            if (this.$widget) {
27410                this.$widget.children("not:input[type=date]").height("100%"); 
27411            }
27412        },
27413
27414        handleAccessibility : function () {
27415            GuideDatePickerView._super.handleAccessibility.apply(this, arguments);
27416            this.$widget.children("div[tabIndex]").removeAttr("tabIndex");
27417        }
27418    });
27419}($, guidelib));
27420
27421 (function ($, guidelib) {
27422    var GuideFootnotePlaceHolderView = guidelib.view.GuideFootnotePlaceHolderView = guidelib.view.GuideTextDrawView.extend({
27423        _defaultWidgetName : "abstractWidget",
27424
27425        initialize : function () {
27426            GuideFootnotePlaceHolderView._super.initialize.call(this);
27427            var that = this;
27428            $(function () {
27429                that._renderFootnotes();
27430            })
27431            guideBridge.on("elementNavigationChanged", function(event, payload) {
27432                that._renderFootnotes();
27433            })
27434            $(window.document).on('click.guidetab.data-api', '[data-guide-toggle$="accordion-tab"]',
27435                function(e) {
27436                    that._renderFootnotes();
27437                })
27438
27439        },
27440
27441       _renderFootnotes: function () {
27442           
27443           
27444           if(!this.$element.is(":visible")) {
27445               this._model.value = "";
27446               return;
27447           }
27448
27449           var footnoteMap = this._model.footnoteMap;
27450           var footnoteArr = Object.entries(footnoteMap);
27451           if (footnoteArr.length > 0) {
27452               var value = '<div>';
27453               var nodes = new Map();
27454               for (footnoteID in footnoteMap) {
27455                   var selector = "a[data-footnote-id=\"" + footnoteID + "\"]";
27456                   if ($(selector).is(":visible")) {
27457                       var mapKey = $(selector)[0].innerHTML;
27458                       if (!nodes.has(mapKey)) {
27459                           nodes.set(mapKey, footnoteMap[footnoteID]);
27460                       }
27461                   }
27462               };
27463               var tupleArray = [];
27464               nodes.forEach(function(value, key) {
27465                   tupleArray.push([key, value]);
27466               });
27467               tupleArray.sort(function(a, b) {
27468                   return a[0] - b[0];
27469               });
27470               tupleArray.forEach(function(el) {
27471                   value += el[1];
27472               });
27473               value += '</div>';
27474               this._model.value = value;
27475           }
27476       },
27477
27478               setActive: function () {
27479                   this._renderFootnotes();
27480               }
27481    });
27482}($, guidelib));
27483
27484
27485
27486
27487(function ($, guidelib) {
27488    var GuideScribbleView = guidelib.view.GuideScribbleView = guidelib.view.GuideFieldView.extend({
27489        _defaultWidgetName : "ScribbleImageField",
27490
27491        createWidgetOptions : function () {
27492            var options = GuideScribbleView._super.createWidgetOptions.apply(this, arguments);
27493            return $.extend({}, options, {
27494                commitProperty : "src",
27495                geoLocMandatoryOnIpad : "false",
27496                aspectRatio : this._valueOfAspectRatioToBeUsed()
27497            });
27498        },
27499
27500        _valueOfAspectRatioToBeUsed : function () {
27501            var aspectRatio ;
27502            if (this._model.jsonModel.aspectRatio) {
27503                aspectRatio = this._model.jsonModel.aspectRatio;
27504            } else {
27505                
27506                if (!this._presenceOfHeight()) {
27507                    aspectRatio = "6.8888";
27508                }
27509            }
27510            return aspectRatio ;
27511        },
27512
27513        _presenceOfHeight : function () {
27514            return (this._model.jsonModel.hasOwnProperty('height') && this._model.jsonModel.height.toString().length > 0);
27515        },
27516
27517        postInitialize : function () {
27518            GuideScribbleView._super.postInitialize.call(this);
27519            var that = this;
27520            
27521            if (!this._presenceOfHeight()) {
27522                setTimeout(function () {guidelib.util.GuideUtil._computeHeightAndWidthForScribble(that.$widget);}, guidelib.util.GuideUtil.SCRIBBLE_RESIZE_TIME_INTERVAL);
27523                $(window).off("resize", guidelib.util.GuideUtil._resizeScribbleField);
27524                $(window).on("resize", guidelib.util.GuideUtil._resizeScribbleField);
27525            }
27526        },
27527
27528        handleAccessibility : function () {
27529            
27530            if (this._model.mandatory) {
27531                this.$widget.find("img").attr("aria-required", true);
27532            }
27533            if (this._model._getScreenReaderText() === this._model._getToolTip()) {
27534                this.$element.find("img").removeAttr("aria-label");
27535                this.$element.find("img").attr("aria-labelledby", this._model.id + "_guideFieldShortDescription");
27536            } else if (this._model._getAssistPriority() === "none") {
27537                this.$element.find("img").attr("aria-label", " ");
27538            }
27539        },
27540
27541        
27542        tempXfaFixes : function () {
27543            if (this.$widget) {
27544                this.$widget.css("position", "relative").find("img").css("position", "relative");
27545            }
27546            this.handleAccessibility();
27547        }
27548    });
27549}($, guidelib));
27550(function ($, guidelib) {
27551    var GuideTextBoxView = guidelib.view.GuideTextBoxView = guidelib.view.GuideFieldView.extend({
27552        _defaultWidgetName : "textField",
27553
27554        initialize : function () {
27555            GuideTextBoxView._super.initialize.apply(this, arguments);
27556            if (this._model.allowRichText) {
27557                this._defaultWidgetName = "richTextField";
27558            }
27559        },
27560
27561        createWidgetOptions : function () {
27562            var options = GuideTextBoxView._super.createWidgetOptions.apply(this, arguments),
27563                html5Type = this._model.getAttribute("html5Type");
27564            return $.extend({}, options, {
27565                multiLine : this._model.multiLine,
27566                minLength : this._model.allowRichText ? null : this._model.minLength,
27567                length : this._model.allowRichText ? null : this._model.length,
27568                maxChars : this._model.allowRichText ? null : this._model.maxChars,
27569                required : this._model.mandatory,
27570                
27571                html5Type : html5Type ? html5Type : "",
27572                totalLengthMessage : this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalLengthMessage, [this._model.length]),
27573                minimumLengthMessage : this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minimumLengthMessage, [this._model.minLength]),
27574                allowRichText : this._model.allowRichText,
27575                placeholder : this._model.placeholderText
27576            });
27577        },
27578
27579        
27580        
27581        
27582        tempXfaFixes : function () {
27583            if (this._model.jsonModel.multiLine) {
27584                this.$element.find("textarea").css("position", "relative");
27585                this.handleAccessibility();
27586            } else {
27587                GuideTextBoxView._super.tempXfaFixes.apply(this);
27588            }
27589        },
27590
27591        handleAccessibility : function () {
27592            GuideTextBoxView._super.handleAccessibility.apply(this);
27593            if (this._model.jsonModel.multiLine) {
27594                this.$element.find("textarea").attr("aria-multiLine", true);
27595            }
27596        }
27597    });
27598}($, guidelib));
27599(function ($, guidelib) {
27600    var xfaUtil = xfalib.ut.XfaUtil.prototype,
27601        GuideImageView = guidelib.view.GuideImageView = guidelib.view.GuideBaseView.extend({
27602            initialize : function () {
27603                GuideImageView._super.initialize.call(this);
27604                if (this._model.value != null) {
27605                    var srcString = "data:image/*;base64," + this._model.value;
27606                    this.$element.children('img').attr('src', srcString);
27607                }
27608            },
27609
27610            postInitialize : function () {
27611                this._syncGuideNodeToHtml();
27612            },
27613
27614            setActive : function (activeItemToken, focus, muteScripts) {
27615                guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
27616                if (focus && !this._guideView.skipFieldFocus) {
27617                    if (this.$element) {
27618                        this.$element.focus();
27619                    }
27620                    this._guideView.currentFocusItemSom = this._model.somExpression;
27621                }
27622                return true;
27623            }
27624
27625        });
27626}($, guidelib));
27627
27628(function ($, guidelib) {
27629    var GuideChartView = guidelib.view.GuideChartView = guidelib.view.GuideBaseView.extend({
27630
27631        initialize : function () {
27632            GuideChartView._super.initialize.call(this);
27633            var chartView = this;
27634            $(window).on("resize orientationchange", function () {
27635                chartView.renderChart.apply(chartView);
27636            });
27637        },
27638
27639        postInitialize : function () {
27640            this._syncGuideNodeToHtml(true);
27641        },
27642
27643        handleModelChanged : function (event) {
27644            switch (event._property) {
27645                case "data":
27646                case "chartType":
27647                    this.renderChart();
27648                    break;
27649
27650                case "visible":
27651                    this.handleVisibleChanged(event);
27652                    break;
27653            }
27654        },
27655
27656        handleVisibleChanged : function (event) {
27657            
27658            
27659            if (!event.newText) {
27660                
27661                this.$element.addClass("hidden");
27662                if (this.parentView.currentActiveItemView == this) {
27663                    this.parentView.setActive("nextItem");
27664                }
27665            }   else {
27666                
27667                this.$element.removeClass("hidden");
27668            }
27669        },
27670
27671        _generateChart : function () {
27672            var $chartElement = this.$element, chartModel = this._model, isChartVisible, chart;
27673            
27674            var plottedChartSelector = chartModel.jsonModel.isInteractiveCommunicationChartResource ? '.highcharts-container'
27675                    : '.dv-chart-container';
27676            var $plottedChart = $chartElement
27677                    .find(plottedChartSelector);
27678            isChartVisible = ($chartElement.parent().width() > 0)
27679                    && ($chartElement.width() > 0) ? true : false;
27680            
27681            
27682            
27683            
27684            if ((isChartVisible || $plottedChart.length == 0)
27685                    && chartModel.repeatableItem) {
27686                try {
27687                    
27688                    $plottedChart.remove();
27689                    if (chartModel.jsonModel.isInteractiveCommunicationChartResource) {
27690                        chart = new fd.chart.ChartInstanceGenerator()
27691                                .generate(chartModel.jsonModel,
27692                                        chartModel.jsonModel.data);
27693                        Highcharts.chart($chartElement.attr('id'),
27694                                chart);
27695                    } else {
27696                        chart = guidelib.chartUtils.constructChart(
27697                                chartModel, $chartElement);
27698                        if (chart) {
27699                            chart.render();
27700                        }
27701                    }
27702                } catch (exception) {
27703                    this.logger().error("AF Chart view",
27704                            "Error while rendering chart " + exception);
27705                }
27706            }
27707        },
27708
27709        renderChart : function () {
27710            if (this._model.data) {
27711                var chartView = this;
27712                window.requestAnimationFrame(function () {
27713                    chartView._generateChart.apply(chartView);
27714                });
27715            }
27716        },
27717
27718        _syncGuideNodeToHtml : function (deepSync) {
27719            this.renderChart();
27720            guidelib.view.GuideChartView._super._syncGuideNodeToHtml.call(this, deepSync);
27721        },
27722
27723        setActive : function (activeItemToken, focus, muteScripts) {
27724            guidelib.view.GuideChartView._super.setActive.call(this, activeItemToken, focus, muteScripts);
27725            if (focus && !this._guideView.skipFieldFocus) {
27726                if (this.$element) {
27727                    this.$element.focus();
27728                }
27729                this._guideView.currentFocusItemSom = this._model.somExpression;
27730            }
27731            return true;
27732        }
27733    });
27734}($, guidelib));
27735(function ($, guidelib) {
27736    var GuideAdModuleView = guidelib.view.GuideAdModuleView = guidelib.view.GuideBaseView.extend({
27737
27738        initialize : function () {
27739            GuideAdModuleView._super.initialize.call(this);
27740            if (this._model) {
27741                
27742                this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
27743            }
27744            this.oldValue = null;
27745        },
27746
27747        postInitialize : function () {
27748            this._syncGuideNodeToHtml(true);
27749        },
27750
27751        handleValueChanged : function (event) {
27752            switch (event._property) {
27753                case "value":
27754                    this.$element.html(event.newText);
27755                    break;
27756            }
27757        },
27758
27759        handleVisibleChanged : function (event) {
27760            
27761            
27762            if (!event.newText) {
27763                
27764                this.$element.addClass("hidden");
27765                if (this.parentView.currentActiveItemView == this) {
27766                    this.parentView.setActive("nextItem");
27767                }
27768            }   else {
27769                
27770                this.$element.removeClass("hidden");
27771            }
27772        },
27773
27774        handleModelChanged : function (event) {
27775            GuideAdModuleView._super.handleModelChanged.apply(this, arguments);
27776        },
27777        _syncGuideNodeToHtml : function (deepSync) {
27778            if (this._model.value) {
27779                this.$element
27780                    .html(this._model.value)
27781                    .find('img')
27782                    .attr('src', function (idx, val) {
27783                        return Granite.HTTP.externalize(val);
27784                    });
27785            }
27786
27787            if (this._model.layoutConfigs) {
27788                var options = {
27789                                $element : this.$element,
27790                                layoutConfigs : this._model.layoutConfigs
27791                            };
27792                guidelib.util.AdUtil.applyLayouts(options);
27793            }
27794            if (this._model) {
27795                this.handleModelChanged(guidelib.event.GuideModelEvent.createEvent(
27796                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
27797                    this,
27798                    "visible",
27799                    this._model.visible,
27800                    this._model.visible
27801                ));
27802            }
27803        },
27804
27805        setActive : function (activeItemToken, focus, muteScripts) {
27806            guidelib.view.GuideFieldView._super.setActive.call(this, activeItemToken, focus, muteScripts);
27807            if (focus) {
27808                if (this.$element) {
27809                    this.$element.focus();
27810                }
27811                this._guideView.currentFocusItemSom = this._model.somExpression;
27812            }
27813            return true;
27814        }
27815    });
27816}($, guidelib));
27817(function ($, _, guidelib) {
27818    var GuideItemsView = guidelib.view.GuideItemsView = guidelib.view.GuideBaseView.extend({
27819        initialize : function () {
27820            GuideItemsView._super.initialize.call(this);
27821            this.childViews = [];
27822        },
27823
27824        
27825        _unloadView : function () {
27826            if (this._model._selfOrAncestorIsLazyReference) {
27827                var fragmentPlaceHolderSelector = "#" + this.id,
27828                    ind;
27829                
27830                $(fragmentPlaceHolderSelector).children().remove();
27831                
27832                var queueForLazyItems = this._guideView._queueViewForLazyItems;
27833                
27834                if ((ind = _.indexOf(queueForLazyItems, this)) !== -1) {
27835                    queueForLazyItems[ind] = undefined;
27836                }
27837                _.each(this.childViews, function (view) {
27838
27839                    view._unloadView();
27840                }, this);
27841                
27842                this.childViews = [];
27843                
27844                this._currentActiveItemView = null;
27845                
27846                this._guideView._domTemplateCacheStore.removeDomElement("#" + this._model.templateId);
27847                
27848                this._guideView._reInitializeGuideContainerDom();
27849            }
27850        },
27851        postInitialize : function () {
27852            this.childViews = _.reduce(this._model.children, function (childViews, childModel) {
27853                var childView = this._createNonRepeatChildView(childModel);
27854                if (childView) {
27855                    childViews.push(childView);
27856                }
27857                return childViews;
27858            }, [], this);
27859            
27860            this._syncGuideNodeToHtml(false);
27861        },
27862
27863        _createNonRepeatChildView : function (childModel) {
27864            
27865
27866            
27867            
27868            var childElSelector = this.guideUtil.modelElSelector(childModel.id);
27869            var $childEl = this.$element.find(childElSelector);
27870            if (!$childEl.length) {
27871                $childEl = this.$element.find(this.guideUtil.modelElSelector(childModel.templateId));
27872                this._updateIds($childEl, childModel.templateId, childModel.id);
27873            }
27874            if ($childEl.length) {
27875                var childView = guidelib.view.GuideViewRegistry.prototype.createView($childEl, this);
27876                childView.postInitialize();
27877                return childView;
27878            }
27879            return null;
27880        },
27881
27882        _syncGuideNodeToHtml : function (deepSync) {
27883            if (deepSync) {
27884                _.each(this.childViews, function (childView) {
27885                    childView._syncGuideNodeToHtml(true);
27886                }, this);
27887            }
27888            GuideItemsView._super._syncGuideNodeToHtml.call(this, deepSync);
27889        },
27890
27891        _findChildView : function (childModel) {
27892            var view = _.find(this.childViews, function (childView) {
27893                return childView._model == childModel;
27894            }, this);
27895            return view;
27896        }
27897    });
27898
27899    GuideItemsView.defineProps({
27900        itemsView : {
27901            get : function () {
27902                var views = _.filter(this.childViews, function (childView) {
27903                    return childView.isItem;
27904                }, this);
27905                return views;
27906            }
27907        }
27908    });
27909}($, _, guidelib));
27910
27911(function ($, guidelib) {
27912    var GuideAdModuleGroupView = guidelib.view.GuideAdModuleGroupView = guidelib.view.GuideItemsView.extend({
27913        initialize : function () {
27914            GuideAdModuleGroupView._super.initialize.call(this);
27915            if (this._model) {
27916                
27917                this._model.on(guidelib.event.GuideModelEvent.VALUE_CHANGED, this.handleValueChanged, this);
27918            }
27919        },
27920
27921        postInitialize : function () {
27922            if (this._model.value || this._model.value === "") {
27923                this._syncGuideNodeToHtml(true);
27924            } else {
27925                GuideAdModuleGroupView._super.postInitialize.call(this);
27926            }
27927        },
27928
27929        handleValueChanged : function (event) {
27930            switch (event._property) {
27931                case "value":
27932                    this.$element.html(event.newText);
27933                    break;
27934            }
27935        },
27936
27937        _syncGuideNodeToHtml : function (deepSync) {
27938            if (this._model.value || this._model.value === "") {
27939                this.$element
27940                    .html(this._model.value)
27941                    .find('img')
27942                    .attr('src', function (idx, val) {
27943                        return Granite.HTTP.externalize(val);
27944                    });
27945            } else {
27946                GuideAdModuleGroupView._super._syncGuideNodeToHtml.call(this, deepSync);
27947            }
27948        },
27949
27950        setActive : function (activeItemToken, focus, muteScripts) {
27951            guidelib.view.GuideAdModuleGroupView._super.setActive.call(this, activeItemToken, focus, muteScripts);
27952            if (focus) {
27953                if (this.$element) {
27954                    this.$element.focus();
27955                }
27956                this._guideView.currentFocusItemSom = this._model.somExpression;
27957            }
27958            return true;
27959        }
27960
27961    });
27962}($, guidelib));
27963(function ($, _, guidelib) {
27964
27965    var GuidePanelView = guidelib.view.GuidePanelView = guidelib.view.GuideItemsView.extend({
27966        initialize : function () {
27967            GuidePanelView._super.initialize.call(this);
27968            this._currentActiveItemView = null;
27969            this._$itemsContainer = null;
27970            this._$itemsNavContainer = null;
27971            this._$summary = null;
27972            this._$title = null;
27973            
27974            this._childInitializeWaiting = true;
27975            
27976            this._model.on(guidelib.event.GuideModelEvent.CHILD_CHANGED, this.handleChildChanged, this);
27977            this._model.on(guidelib.event.GuideModelEvent.MULTIPLE_CHILD_ADDED, this.multipleChildAdded, this);
27978            this._summarySelector = this.guideUtil.summarySelector(this._model.id);
27979            this._titleSelector = this.guideUtil.propSelector("title", this._model.id);
27980        },
27981
27982        addRemoveTemplateMarker : function () {
27983            
27984            _.each(this._model.children, function (childModel) {
27985                if (childModel instanceof guidelib.model.GuideInstanceManager) {
27986                    
27987                    var imId = childModel.id,
27988                        instanceId = (childModel._instances[0] || {}).id || childModel.instanceTemplateId,
27989                        gTemplateMarker = '<div id="' + imId + '" style="display: none" data-guide-template-marker="true"></div>',
27990                        instanceItem = this.guideUtil.itemSelector(instanceId, childModel),
27991                        navItem = this.guideUtil.itemNavSelector(instanceId);
27992                    this.$itemsContainer.find(instanceItem).before(gTemplateMarker);
27993                    this.$itemsNavContainer.find(navItem).before(gTemplateMarker);
27994                    if (childModel._instances && childModel._instances.length === 0) { 
27995                        $(navItem, this.$element).remove(); 
27996                        $(instanceItem, this.$element).remove(); 
27997                    }
27998                }
27999            }, this);
28000
28001        },
28002
28003        postInitialize : function () {
28004
28005            
28006            
28007            
28008            this.handleSummaryChanged();
28009            this.handleTitleChanged();
28010            if (this._model.repeatable) {
28011                this._toggleAddRemoveButtons();
28012            }
28013            if (!this.parentView._model.enableLayoutOptimization) {
28014                
28015                this._postInitializeChildren();
28016            } else {
28017                
28018                
28019                
28020                
28021                
28022                
28023                this.handleVisibleChanged(guidelib.event.GuideModelEvent.createEvent(
28024                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
28025                    this,
28026                    "visible",
28027                    this._model.visible,
28028                    this._model.visible
28029                ));
28030            }
28031            
28032            
28033            
28034            
28035            
28036            this.addRemoveTemplateMarker();
28037        },
28038
28039        _postInitializeChildren : function () {
28040            this._childInitializeWaiting = false;
28041            this._syncGuideNodeToHtml(true);
28042            this.handleAccessibility();
28043            
28044            
28045            
28046            if (this.parentView.$itemsNavContainer && this.parentView.$itemsNavContainer.filter(":not(.tab-navigators-mobile)").length === 0) {
28047                this.setActive("firstItem", false, true);
28048            }
28049        },
28050
28051        _syncGuideNodeToHtml : function (deepSync, currentAddedChildIndex) {
28052            if (this._childInitializeWaiting) {
28053                return;
28054            }
28055            
28056            
28057            
28058            
28059            
28060            
28061            
28062
28063            var that = this;
28064            var htmlTemplateCache = this._guideView._domTemplateCacheStore;
28065            var oldItems = {}; 
28066            var oldNonItems = {}; 
28067            var newChildren = {};
28068
28069            
28070            _.each(this.childViews, function (childView) {
28071                if (childView.isItem) {
28072                    oldItems[childView.id] = childView;
28073                } else {
28074                    oldNonItems[childView.id] = childView;
28075                }
28076            }, this);
28077
28078            
28079            
28080            
28081            
28082            
28083            
28084            
28085            _.each(this._model.items, function (childModel) {
28086                    var cTemplateId = childModel.templateId;
28087                    var childId = childModel.id,
28088                        $childItem = null,
28089                        $childItemNav = null;
28090                    
28091                    
28092                    $childItem = this._find(this.guideUtil.itemSelector(childId, childModel));
28093                    $childItemNav = this._find(this.guideUtil.itemNavSelector(childId));
28094
28095                    
28096                    
28097                    if (!$childItem.length && !newChildren[cTemplateId] && currentAddedChildIndex !== 0) {
28098                        
28099                        
28100                        $childItem = this.$itemsContainer.find(this.guideUtil.itemSelector(cTemplateId, childModel));
28101                        $childItemNav = this.$itemsNavContainer.find(this.guideUtil.itemNavSelector(cTemplateId));
28102                    }
28103                    if (!$childItem.length) {
28104                        
28105                        $childItem = htmlTemplateCache.cloneDomElement(this.guideUtil.itemSelector(cTemplateId, childModel));
28106                        $childItemNav = htmlTemplateCache.cloneDomElement(this.guideUtil.itemNavSelector(cTemplateId));
28107                        if (!$childItem.length) {
28108                            this.logger().error("AF", "Html template could not be found. cTemplateId:" + cTemplateId + ", som:" + childModel.somExpression);
28109                            return;
28110                        }
28111                    }
28112                    this._updateIds($childItem, cTemplateId, childId);
28113                    this._updateIds($childItemNav, cTemplateId, childId);
28114                    
28115                    
28116                    $childItem.attr("data-guide-parent-id", this._model.id);
28117                    $childItemNav.attr("data-guide-parent-id", this._model.id);
28118                    var view = null;
28119                    if (oldItems.hasOwnProperty(childId)) {
28120                        view = oldItems[childId];
28121                        if (view instanceof guidelib.view.GuidePanel
28121View && view._model.instanceManager.repeatable && !_.isUndefined(that._model.bindNode)) {
28122                            
28123                            this._fixChildDom(view);
28124                        }
28125                        if (deepSync) {
28126                            view._syncGuideNodeToHtml(deepSync);
28127                        } 
28128                    } else {
28129                        var $childEl = this._find("#" + childId);
28130                        if ($childEl.length) {
28131                            view = this._createChild($childEl);
28132                        } else {
28133                            $childEl = $childItem.find("#" + childId).addBack("#" + childId);
28134                            if ($childEl.length) {
28135                                view = this._createChild($childEl, $childItem, $childItemNav);
28136                            } else {
28137                                this.logger().debug("AF", "Skip creating view. could not find el for id:" + childId);
28138                            }
28139                        }
28140                        if (this._model.repeatable) {
28141                            guidelib.util.GuideUtil._initializeShortDescription($childEl);
28142                        }
28143                    }
28144                    if (view) {
28145                        newChildren[childId] = view;
28146                    }
28147                }, this
28148            );
28149
28150            
28151            this.$itemsContainer.find('[data-guide-parent-id="' + that._model.id + '"]').each(function () {
28152                var $this = $(this);
28153                var thisId = $this.attr("id");
28154                
28155                if (thisId.indexOf(that.guideUtil.GUIDE_ITEM_SUFFIX) === -1) {
28156                    thisId = $this.attr(that.guideUtil.DATA_GUIDE_ITEM);
28157                }
28158                var childId = thisId.substring(0, thisId.length - that.guideUtil.GUIDE_ITEM_SUFFIX.length);
28159                if (!newChildren.hasOwnProperty(childId) && !window.guideBridge._resolveId(childId)) {
28160                    that.logger().log("guideView", 5, "removing element as no corresponding form dom node found. id:" + thisId + ", parent id:" + that.id);
28161                    $this.remove();
28162                    that._find(that.guideUtil.itemNavSelector(childId)).remove();
28163                }
28164            });
28165
28166            this.childViews = [];
28167            _.each(this._model.children, function (childModel) {
28168                var childIsItem = childModel._isItem;
28169                var childId = childModel.id;
28170                if (childIsItem && newChildren.hasOwnProperty(childId)) {
28171                    
28172                    this.childViews.push(newChildren[childId]);
28173                } else if (!childIsItem) {
28174                    var nonItemChildView = null;
28175                    if (oldNonItems.hasOwnProperty(childId)) {
28176                        nonItemChildView = oldNonItems[childId];
28177                    } else {
28178                        nonItemChildView = this._createNonRepeatChildView(childModel);
28179                    }
28180                    if (nonItemChildView) {
28181                        if (deepSync) {
28182                            nonItemChildView._syncGuideNodeToHtml(deepSync);
28183                        }
28184                        this.childViews.push(nonItemChildView);
28185                    }
28186                }
28187            }, this);
28188            
28189            guidelib.view.GuideBaseView.prototype._syncGuideNodeToHtml.apply(this, arguments);   
28190        },
28191
28192        _createChild : function ($childEl, $item, $itemNav) {
28193            var guideViewBind = $childEl.data("guideViewBind");
28194            var model = window.guideBridge._resolveId(guideViewBind);
28195            if (model && model.getAttribute('skipViewCreation') !== 'true') {
28196                var view = guidelib.view.GuideViewRegistry.prototype.createView($childEl, this);
28197                this._fixChildDom(view, $item, $itemNav);
28198                view.postInitialize();
28199                return view;
28200            }
28201        },
28202
28203        _fixChildDom : function (view, $item, $itemNav) {
28204            
28205            
28206            
28207            var newChild = view._model;
28208            if (!(newChild instanceof guidelib.model.GuidePanel) || !newChild.repeatable) {
28209                return;
28210            }
28211            var $childItem = $item || view.$item;
28212            var $childItemNav = $itemNav || view.$itemNav;
28213            var children = this._model.children;
28214            var insertAfterId = (newChild.instanceIndex > 0) ? children[children.indexOf(newChild) - 1].id : null;
28215            
28216            var insertAfterItemSelector = insertAfterId ? this.guideUtil.itemSelector(insertAfterId, newChild) : "#" + newChild.instanceManager.id;
28217            var insertAfterNavSelector = insertAfterId ? this.guideUtil.itemNavSelector(insertAfterId) : "#" + newChild.instanceManager.id;
28218            var that = this;
28219            
28220            
28221            this.$itemsContainer.each(function (index) {
28222                var insertEl = $childItem.get(index) || $childItem.get(0),
28223                    $insertAfterItem = $(this).find(insertAfterItemSelector);
28224                
28225                if ($insertAfterItem.length == 0) {
28226                    insertAfterItemSelector = "[data-guide-template-marker=" + newChild.instanceManager.id + "]";
28227                    $insertAfterItem = $(this).find(insertAfterItemSelector);
28228                    
28229                    if (newChild.instanceIndex === 0 && $insertAfterItem.length > 0) {
28230                        $insertAfterItem.removeAttr("data-guide-template-marker");
28231                        $(insertEl).attr("data-guide-template-marker", newChild.instanceManager.id);
28232                    }
28233                }
28234                
28235                if ($insertAfterItem.get(0) !== insertEl) {
28236                    
28237                    $insertAfterItem.after($(insertEl));
28238                }
28239            });
28240            
28241            
28242            
28243            this.$itemsNavContainer.each(function (index) {
28244                var insertNavEl = $childItemNav.get(index) || $childItemNav.get(0);
28245                $(this).find(insertAfterNavSelector).after($(insertNavEl));
28246            });
28247        },
28248
28249        multipleChildAdded : function (event) {
28250            if (event.jsonModel.newText && event.jsonModel.newText.length > 0) {
28251                this._syncGuideNodeToHtml(true);
28252                this.childViews.forEach(function (childView) {
28253                    if (childView._model.repeatable) {
28254                        childView._toggleAddRemoveButtons();
28255                    }
28256                });
28257            }
28258        },
28259
28260        handleChildChanged : function (event) {
28261            var newlyCreatedInstance = null,
28262                currentAddedInstanceIndex = -1; 
28263            if (event._property == "childRemoved") {
28264                var $elementRemoved = this.$element.find("#" + event.prevText.id),
28265                    index = $elementRemoved.index();
28266            }
28267            if (event._property == "childAdded") {
28268                newlyCreatedInstance = event.newText;
28269                currentAddedInstanceIndex = newlyCreatedInstance.instanceIndex;
28270            }
28271            
28272            this._syncGuideNodeToHtml(true, currentAddedInstanceIndex);
28273            this.childViews.forEach(function (childView) {
28274                if (childView._model.repeatable) {
28275                    childView._toggleAddRemoveButtons();
28276                }
28277            });
28278            if (event._property == "childRemoved") {
28279                
28280                
28281                this.$element.trigger("panelRemoved.af", [$elementRemoved, index]);
28282                if (this.currentActiveItemView && event.prevText == this.currentActiveItemView._model) {
28283                    
28284                    this._currentActiveItemView = null;
28285                    this.setActive("nextItem");
28286                }
28287            }
28288            if (newlyCreatedInstance != null) {
28289                
28290                
28291                this.$element.trigger("panelAdded.af", [this.$element.find("#" + newlyCreatedInstance.id)]);
28292            }
28293        },
28294
28295        handleSummaryChanged : function () {
28296            if (this.$summary.length > 0) {
28297                if (this._model.summary) {
28298                    this.$summary.text(this._model.summary);
28299                } else {
28300                    var title = this._model.title;
28301                    if (this._model.instanceIndex && this._model.repeatable) {
28302                        title += " " + this._model.instanceIndex;
28303                    }
28304                    this.$summary.text(title);
28305                }
28306            }
28307        },
28308
28309        handleTitleChanged : function () {
28310            if (this.$title.length > 0) {
28311                this.$title.text(this._model.title);
28312            }
28313            
28314            var isPanelActive = $("#" + this.id + "_guide-item").hasClass("active");
28315            if (isPanelActive) {
28316                $("[data-target-guide-content]").text(this._model.title);
28317            }
28318        },
28319
28320        handleModelChanged : function (event) {
28321            switch (event._property) {
28322                case "summary":
28323                    this.handleSummaryChanged();
28324                    break;
28325                case "title":
28326                    this.handleTitleChanged();
28327                    break;
28328                default:
28329                    GuidePanelView._super.handleModelChanged.apply(this, arguments);
28330            }
28331        },
28332
28333        _createReferredView : function () {
28334            
28335            this._postInitializeChildren();
28336        },
28337
28338        _loadLazyFragment : function () {
28339            
28340            
28341            
28342            
28343            
28344            
28345            var that = this;
28346            this._model._guide().internal.liveDataUtils.updateLiveData();
28347            
28348            this._guideView._clearInactiveLazyViews(this);
28349            
28350            this._viewCreationInProgress = true;
28351
28352            this._model._loadLazyFragment({
28353                "preFetch" : function () {
28354                    $("#loadingPage").addClass("guideLoading");
28355                },
28356                "postFetch" : function () {
28357                    $("#loadingPage").removeClass("guideLoading");
28358                },
28359                "success" : function () {
28360                    
28361                    that._createReferredView();
28362                    
28363                    
28364                    that._viewCreationInProgress = undefined;
28365                    that._itemsLoaded = true;
28366                }
28367            });
28368            
28369            
28370        },
28371
28372        
28373        setActive : function (activeItemToken, focus, muteScripts) {
28374            
28375            
28376            
28377            if (this._model._lazyReference && this._model.getAttribute('autoLoad') !== false) {
28378                
28379                
28380                
28381                
28382                
28383                if (_.isUndefined(this._viewCreationInProgress) && _.isUndefined(this._itemsLoaded)
28384                    && this._guideView._currentActiveItemView !== this) {
28385                    this._loadLazyFragment();
28386                }
28387            }
28388
28389            var currentActiveItemQName = this.getOrElse(this.currentActiveItemView, "qualifiedName", null);
28390            
28391            activeItemToken = activeItemToken || currentActiveItemQName || "firstItem";
28392            if (activeItemToken != currentActiveItemQName) {
28393                var newActiveItemModel = this._model.navigationContext.getItemForNav(activeItemToken);
28394                if (!newActiveItemModel) {
28395                    this.logger().log("AF", "activeItemToken not found:" + activeItemToken + ",currentActiveItem:" +
28396                        currentActiveItemQName + ":" + this._model.somExpression);
28397                    return false;
28398                }
28399                var newActiveItemView = this.getQualifiedNamedView(newActiveItemModel._escapeQualifiedName());
28400                if (!muteScripts && this._model.completionExpReq && this.currentActiveItemView && this.currentActiveItemView.focusable() && (this.childViews.indexOf(newActiveItemView) > this.childViews.indexOf(this.currentActiveItemView))) {
28401                    var completed = true;
28402                    if (this._model.getAttribute("validateOnStepCompletion")) {
28403                        completed = window.guideBridge.validate([], this._model.panel.navigationContext.currentItem.somExpression);
28404                    }
28405                    
28406                    completed = completed && this._model.executeExpression("completionExp");
28407                    if (!completed) {
28408                        return false;
28409                    } else if (this.currentActiveItemView) {
28410                        this.currentActiveItemView.$item.addClass("completed");
28411                        this.currentActiveItemView.$itemNav.addClass("completed");
28412                    }
28413                }
28414                this.currentActiveItemView = newActiveItemView;
28415                
28416                
28417                
28418                
28419                
28420            }
28421            if (this.currentActiveItemView) {
28422                this.currentActiveItemView.setActive(null, focus, muteScripts);
28423            }
28424            return true;
28425        },
28426        
28427        _clearInactiveLazyViews : function (that) {
28428            _.each(this.childViews, function (item) {
28429                if (item && item._model.className === "guidePanel" && item._ancestorHasNavigableLayout) {
28430                    if (item._model._itemsLoaded && !that._isSelfOrAncestor(item) && !item._hasEffectiveActiveClass()
28431                        && item._model._lazyReference) {
28432                        item._model._unloadLazyReferenceModel();
28433                        item._unloadView();
28434                        
28435                        item._itemsLoaded = undefined;
28436                        
28437                        item._model._itemsLoaded = undefined;
28438                    } else {
28439                        item._clearInactiveLazyViews(that);
28440                    }
28441                }
28442            }, this);
28443        },
28444        
28445        _isSelfOrAncestor : function (panelView) {
28446
28447            var selfOrParentView = this;
28448            while (!_.isUndefined(selfOrParentView) && selfOrParentView._model.className !== "rootPanelNode") {
28449                if (panelView === selfOrParentView) {
28450                    return true;
28451                }
28452                selfOrParentView = selfOrParentView.parentView;
28453            }
28454            return false;
28455        },
28456        
28457        _hasEffectiveActiveClass : function () {
28458            var hierarchy = this;
28459            while (!_.isUndefined(hierarchy) && this._model.className !== "rootPanelNode") {
28460                if (hierarchy.$item.hasClass("active")) {
28461                    hierarchy = hierarchy.parentView;
28462                } else {
28463                    return false;
28464                }
28465            }
28466            return true;
28467        },
28468
28469        handleAccessibility : function () {
28470            var role, screenReaderText;
28471            screenReaderText = this._model._getScreenReaderText();
28472            role = this._model._getRole();
28473            if (screenReaderText) {
28474                this.$itemNav.attr("aria-label", screenReaderText);
28475            }
28476            this.$itemNav.find('a').attr("tabindex", function (index, currentValue) {
28477                return (currentValue == -1 ? currentValue : 0);
28478            });
28479        },
28480
28481        getQualifiedNamedView : function (qName) {
28482            var view = _.find(this.childViews, function (childView) {
28483                return (childView._model._escapeQualifiedName() == qName);
28484            }, this);
28485            return view;
28486        },
28487
28488        _toggleAddRemoveButtons : function () {
28489            var panelModel = this._model,
28490                instanceManager = panelModel.instanceManager;
28491            $('[data-guide-id="' + panelModel.id + '"][data-guide-addremove="remove"]').toggleClass("hidden", instanceManager.instanceCount == instanceManager.minOccur);
28492            $('[data-guide-id="' + panelModel.id + '"][data-guide-addremove="add"]').toggleClass("hidden", instanceManager.instanceCount == instanceManager.maxOccur);
28493        }
28494    });
28495
28496    GuidePanelView.defineProps({
28497        hasNavigableLayout : {
28498            get : function () {
28499                return this.$itemsNavContainer.length > 0;
28500            }
28501        },
28502        $itemsContainer : {
28503            get : function () {
28504                
28505                if (this._model._selfOrAncestorIsLazyReference || !this._$itemsContainer || this._$itemsContainer.length === 0) {
28506                    this._$itemsContainer = this._find(this.guideUtil.itemContainerSelector(this._model.id));
28507                    
28508                    if (this._$itemsContainer.length === 0) {
28509                        this._$itemsContainer = this._find(this.guideUtil.alternateItemContainerSelector(this._model.id));
28510                    }
28511                }
28512                return this._$itemsContainer;
28513            }
28514        },
28515        $itemsNavContainer : {
28516            get : function () {
28517                if (this._model._selfOrAncestorIsLazyReference || !this._$itemsNavContainer || this._$itemsNavContainer.length === 0) {
28518                    this._$itemsNavContainer = this._find(this.guideUtil.itemNavContainerSelector(this._model.id));
28519                }
28520                return this._$itemsNavContainer;
28521            }
28522        },
28523        $summary : {
28524            get : function () {
28525                if (!this._$summary) {
28526                    this._$summary = this._find(this._summarySelector);
28527                }
28528                return this._$summary;
28529            }
28530        },
28531        $title : {
28532            get : function () {
28533                if (!this._$title) {
28534                    this._$title = this._find(this._titleSelector);
28535                }
28536                return this._$title;
28537            }
28538        },
28539        currentActiveItemView : {
28540            get : function () {
28541                return this._currentActiveItemView;
28542            },
28543            set : function (value) {
28544                if (value != this._currentActiveItemView) {
28545                    if (this._currentActiveItemView) {
28546                        
28547                        this._currentActiveItemView._model.viewVisited = true;
28548                    }
28549                    if (!value) {
28550                        var itemModel = this._model.navigationContext.firstItem;
28551                        if (itemModel) {
28552                            value = this.getQualifiedNamedView(itemModel._escapeQualifiedName());
28553                        }
28554                    }
28555                    this._currentActiveItemView = value;
28556                    
28557                    this._model.navigationContext.currentItem = (this._currentActiveItemView || {})._model;
28558                    _.each(this.childViews, function (childView) {
28559                        if (childView == this._currentActiveItemView) {
28560                            childView.$item.addClass("active");
28561                            childView.$itemNav.addClass("active");
28562                            childView.$itemNav.attr("aria-selected", true);
28563                            childView.$itemNav.attr("aria-disabled", false);
28564                            childView.$itemNav.removeClass("wizard-tab-disabled");
28565                        } else {
28566                            childView.$item.removeClass("active");
28567                            childView.$itemNav.removeClass("active");
28568                            childView.$itemNav.attr("aria-selected", false);
28569                        }
28570                    }, this);
28571                    
28572                    
28573                    
28574                    
28575                    if (this._currentActiveItemView instanceof guidelib.view.GuidePanel
28575View && this._currentActiveItemView._childInitializeWaiting) {
28576                        this._currentActiveItemView._postInitializeChildren();
28577                    }
28578
28579                    if (true && _.isUndefined(this._model._ajaxCallDone)) {
28580                        
28581                        
28582                        var model = this._model;
28583                        
28584                        while (model && !(model instanceof guidelib.model.RootPanelNode)) {
28585                            if (model.toolbar) {
28586                                model.toolbar.execNavigationChangeExpression();
28587                            }
28588                            model = model.parent;
28589                        }
28590                        
28591                        if (model && model.toolbar && model instanceof  guidelib.model.RootPanelNode) {
28592                            model.toolbar.execNavigationChangeExpression();
28593                        }
28594                    }
28595                }
28596            }
28597        },
28598        
28599        _ancestorHasNavigableLayout : {
28600            get : function () {
28601                var parentView = this.parentView;
28602                while (parentView) {
28603                    if (parentView.$itemsNavContainer && parentView.$itemsNavContainer.length > 0) {
28604                        return true;
28605                    }
28606                    parentView = parentView.parentView;
28607                }
28608                return false;
28609            }
28610        }
28611    });
28612}($, _, guidelib));
28613(function ($, _, guidelib) {
28614
28615    var cloneCounter = 0;
28616
28617    var tableMobileLayoutConstants = {
28618        COLLAPSIBLE_COLUMNS : "collapsibleColumns",
28619        HEADERS_LEFT : "headersLeft",
28620        COLLAPSIBLE_COLUMNS_CONTROL_ROW_SELECTOR : "tr.child",
28621        RUNTIME_TABLE_CONTROL : "guideTableRuntimeControls",
28622        RUNTIME_TABLE_RIGHT_CONTROL : "guideTableRuntimeRightControls",
28623        RUNTIME_TABLE_LEFT_CONTROL : "guideTableRuntimeLeftControls",
28624        RUNTIME_TABLE_ADD_CONTROL : "guideTableRuntimeAddControl",
28625        RUNTIME_TABLE_DELETE_CONTROL : "guideTableRuntimeDeleteControl",
28626        RUNTIME_TABLE_EDIT_CONTROL : "guideTableRuntimeEditControl"
28627    };
28628
28629    var tableSortingComponents = {
28630        GUIDE_INSTANCE_MANAGER : "guideInstanceManager",
28631        WEB_CHANNEL_HEADER_COMPONENT : "fd/ccm/web-channel/components/tableHeader/v1/tableHeader",
28632        AF_TABLE_HEADER_COMPONENT : "fd/af/components/tableHeader",
28633        SORTING_ENABLED : "sortingEnabled"
28634    };
28635
28636    var GuideTableView = guidelib.view.GuideTableView = guidelib.view.GuidePanelView.extend({
28637
28638        
28639        TABLE_WIDTH_BUFFER : 23,
28640        
28641        _getPluginOptions : function () {
28642            var defaultOptions  = {
28643                "bAutoWidth" : this.bAutoWidth
28644            }, columnWidthArray = null,
28645                sum = 0,
28646                sWidthArray = null,
28647                numOfTableCol = this.$tableElement.find("th").length;
28648
28649            if (this.bAutoWidth === false) {
28650                columnWidthArray = this._model.columnWidth.split(",");
28651                if (columnWidthArray.length === numOfTableCol) {
28652                    
28653                    _.each(columnWidthArray, function (item) {
28654                        sum += parseInt(item, 10);
28655                    });
28656                    
28657                    sWidthArray = _.map(columnWidthArray, function (item) {
28658                        return {
28659                            "pWidth" : Math.floor((item * 100) / sum)
28660                        };
28661                    });
28662                }
28663                
28664                defaultOptions = _.extend({}, defaultOptions, {
28665                    aWidthPercentage : sWidthArray,
28666                    aWidth : columnWidthArray
28667                });
28668            }
28669            return defaultOptions;
28670
28671        },
28672
28673        
28674        setAutoWidth : function () {
28675            if (this._model.columnWidth && this._model.columnWidth.length > 0) {
28676                this.bAutoWidth = false;
28677            }  else {
28678                this.bAutoWidth = true;
28679            }
28680        },
28681
28682        
28683        createView : function (id) {
28684            var $htmlTemplate = this._guideView._domTemplateCacheStore.cloneDomElement("#" + id),
28685                formElemSelector = "#" + id + "_widget",
28686                counter = ++cloneCounter;
28687            if ($htmlTemplate.length == 0) {
28688                
28689                $htmlTemplate = this.$element.find("#" + id).clone();
28690            }
28691            
28692            $htmlTemplate.find(formElemSelector).attr("id", id + "_widget" + counter);
28693
28694            var view = guidelib.view.GuideViewRegistry.prototype.createView($htmlTemplate, this);
28695            view.postInitialize();
28696            return $htmlTemplate;
28697        },
28698
28699        initializeTableColumnWidth : function (pluginOptions) {
28700            
28701            if (this.bAutoWidth == false && this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
28702                
28703                
28704                this.$tableElement.css("table-layout", "fixed");
28705                var widthArray = pluginOptions["aWidthPercentage"],
28706                    numOfTableCol = this.$tableElement.find("th").length;
28707                if (widthArray && widthArray.length == numOfTableCol) {
28708                    
28709                    this.$tableElement.find("th").each(function (index) {
28710                        $(this).css("width", widthArray[index]["pWidth"] + "%");
28711                    });
28712                }
28713            }
28714        },
28715
28716        _checkIfTableSortingEnabled : function () {
28717            var jsonModel = this._model.jsonModel;
28718            return (jsonModel[tableSortingComponents.SORTING_ENABLED] === "true");
28719        },
28720
28721        
28722        handleParentVisibleChanged : function (event) {
28723            switch (event._property) {
28724                case "visible":
28725                    this.handleTableShown();
28726                    break;
28727            }
28728        },
28729
28730        
28731        _checkParentModelChanged : function() {
28732            var currentParent = this.parentView;
28733            while(currentParent != null) {
28734                currentParent._model.on(guidelib.event.GuideModelEvent.MODEL_CHANGED, this.handleParentVisibleChanged, this);
28735                currentParent = currentParent.parentView;
28736            }
28737        },
28738
28739        
28740        initialize : function () {
28741            GuideTableView._super.initialize.apply(this, arguments);
28742            
28743            this._checkParentModelChanged();
28744            
28745            this.$tableElement = this.$element.find("> table");
28746            
28747            this.setAutoWidth();
28748            
28749            var widgetOptions = this._getPluginOptions(),
28750                that = this;
28751            
28752            this.initializeTableColumnWidth(widgetOptions);
28753            this._fixTableControls(true);
28754            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
28755                widgetOptions = _.extend({}, widgetOptions, {
28756                    
28757                    bControlRowHiddenCells : false,
28758
28759                    
28760                    bDisableControlRowCells : true,
28761                    
28762                    viewCallback : $.proxy(this.createView, this),
28763                    
28764                    tableRuntimeEditControlClass : tableMobileLayoutConstants.RUNTIME_TABLE_EDIT_CONTROL,
28765                    
28766                    fixTableControls : $.proxy(this._fixTableControls, this)
28767                });
28768                
28769                this.jqwidget = this.$tableElement.responsiveTablePlugin(widgetOptions).data("responsiveTablePlugin");
28770            }  else {
28771                
28772                $(window).on("resize orientationchange", function (event) {
28773                    that._fixTableControls(event);
28774                });
28775            }
28776            
28777            if (this._checkIfTableSortingEnabled()) {
28778                this.$tableElement.tableSorting = this.guideTableSorter.initialize;
28779                this.$tableElement.tableSorting({
28780                    model : this._model,
28781                    tableContext : this
28782                });
28783            }
28784        },
28785
28786        handleVisibleChanged : function (event) {
28787            GuideTableView._super.handleVisibleChanged.apply(this, arguments);
28788            
28789            this.handleTableShown();
28790            this._resetTableCellWidth();
28791        },
28792
28793        handleTableShown : function () {
28794            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
28795                
28796                this.jqwidget._initializeColumnVisibility();
28797                
28798                if (this.jqwidget.isColumnHidden()) {
28799                    
28800                    this.$tableElement.find(".guideFieldNode").addClass("dontSyncEnabled");
28801                    
28802                    this.$tableElement.find("input, select, textarea, button").attr("disabled", "disabled");
28803                }
28804            }
28805        },
28806
28807        _resetTableCellWidth : function () {
28808            var that = this,
28809                tableWidthBuffer = this.TABLE_WIDTH_BUFFER;
28810            
28811            this.$tableElement.find("." + tableMobileLayoutConstants.RUNTIME_TABLE_CONTROL).each(function () {
28812                var element = this;
28813                setTimeout(function () {
28814                    that._resetTableCell($(element), tableWidthBuffer);
28815                }, 1);
28816            });
28817        },
28818
28819        _resetTableCell : function ($element, tableWidthBuffer) {
28820            var componentWidth;
28821            
28822            if ($element.hasClass(tableMobileLayoutConstants.RUNTIME_TABLE_RIGHT_CONTROL)) {
28823                var $component = $element.prev(),
28824                    $td = $element.parent();
28825                
28826                
28827                if ($element.is(":visible")) {
28828                    
28829                    $component.css("display", "inline-block");
28830                    $component.css("float", "left");
28831                    componentWidth = $td.width() - $element.outerWidth() - tableWidthBuffer;
28832                    var percentage = ((componentWidth / $td.width()) * 100);
28833                    
28834                    
28835                    $component.width(percentage + "%");
28836                } else {
28837                    
28838                    
28839                    $component.css("display", "block");
28840                    $component.css("float", "none");
28841                    $component.width($td.width());
28842                }
28843            } else if ($element.hasClass(tableMobileLayoutConstants.RUNTIME_TABLE_LEFT_CONTROL)) {
28844                
28845                if ($element.is(":visible")) {
28846                    $element.next().css("display", "inline-block");
28847                    componentWidth = $element.parent().width() - $element.outerWidth() - tableWidthBuffer;
28848                    var percentage = ((componentWidth / $element.parent().width()) * 100);
28849                    $element.next().width(percentage + "%");
28850                } else {
28851                    
28852                    $element.next().css("display", "block");
28853                }
28854            }
28855        },
28856
28857        _fixTableControls : function (event) {
28858            
28859            
28860            
28861            if ((this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) && (this.jqwidget)) {
28862                
28863                if (this.jqwidget.isColumnHidden()) {
28864                    
28865                    this.$tableElement.find("tr:not(.child)").find(".guideFieldNode").addClass("dontSyncEnabled");
28866                    
28867                    this.$tableElement.find("tr:not(.child)").find("input, select, textarea, button").attr("disabled", "disabled");
28868                } else {
28869                    
28870                    this.$tableElement.find(".guideFieldNode").removeClass("dontSyncEnabled");
28871                    
28872                    this.$tableElement.find("input, select, textarea, button").removeAttr("disabled");
28873                }
28874            }
28875            
28876            
28877            if (event) {
28878                this._resetTableCellWidth();
28879            }
28880        },
28881
28882        
28883        _fixChildDom : function (view, $item, $itemNav) {
28884            GuideTableView._super._fixChildDom.apply(this, arguments);
28885            
28886            
28887            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
28888                
28889                this.jqwidget._fixControlRows();
28890            }
28891            
28892            this._fixTableControls();
28893            
28894            this._resetTableCellWidth();
28895        },
28896
28897        _postInitializeChildren : function () {
28898            
28899            GuideTableView._super._postInitializeChildren.call(this);
28900            
28901            
28902            
28903            
28904            
28905            if (this._model.mobileLayout ===  tableMobileLayoutConstants.COLLAPSIBLE_COLUMNS) {
28906                
28907                this.handleTableShown();
28908            }
28909            
28910            
28911            else if (this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
28912                this._fixTableCellForHeaderLeftLayout();
28913            }
28914            this._resetTableCellWidth();
28915        },
28916
28917        _fixTableCellForHeaderLeftLayout : function () {
28918            var that = this,
28919                guideUtil = guidelib.util.GuideUtil;
28920            this.$tableElement.find("tr td").each(function () {
28921                guideUtil._setGuideDataHeader($(this), that.$tableElement);
28922            });
28923        },
28924
28925        
28926        handleChildChanged : function (event) {
28927            GuideTableView._super.handleChildChanged.apply(this, arguments);
28928            
28929            
28930            if (this._model.mobileLayout === tableMobileLayoutConstants.HEADERS_LEFT) {
28931                this._fixTableCellForHeaderLeftLayout();
28932            }
28933            if (event._property == "childAdded") {
28934                this._resetTableCellWidth();
28935            }
28936        },
28937
28938        addRemoveTemplateMarker : function () {
28939            
28940            _.each(this._model.children, function (childModel) {
28941                if (childModel instanceof guidelib.model.GuideInstanceManager) {
28942                    
28943                    var imId = childModel.id,
28944                        instanceId = (childModel._instances[0] || {}).id || childModel.instanceTemplateId,
28945                        gTemplateMarker = null,
28946                        
28947                        instanceItem = this.guideUtil.itemSelector(instanceId, childModel._instances[0]),
28948                        navItem = this.guideUtil.itemNavSelector(instanceId),
28949                        $instanceItem = this.$itemsContainer.find(instanceItem);
28950                    if ($instanceItem.is("tr")) {
28951                        $instanceItem.attr("data-guide-template-marker", imId);
28952                    }
28953                    
28954                    
28955                    
28956                    
28957                    
28958                }
28959            }, this);
28960        },
28961
28962        tableSortComparator : {
28963            DATE : function (tableModelDataRows, sortList, tableContext) {
28964                    return tableModelDataRows.sort(function (a, b) {
28965                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
28966                            guideTableSorter = tableContext.guideTableSorter,
28967                            value_a = guideTableSorter.formatDateValue(guideTableSorter.getValueFromJsonModel(a, currColumn)),
28968                            value_b = guideTableSorter.formatDateValue(guideTableSorter.getValueFromJsonModel(b, currColumn));
28969                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
28970                    });
28971                },
28972            NUMBER : function (tableModelDataRows, sortList, tableContext) {
28973                    return tableModelDataRows.sort(function (a, b) {
28974                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
28975                            guideTableSorter = tableContext.guideTableSorter,
28976                            value_a = guideTableSorter.formatRegexFloatData(guideTableSorter.getValueFromJsonModel(a, currColumn)),
28977                            value_b = guideTableSorter.formatRegexFloatData(guideTableSorter.getValueFromJsonModel(b, currColumn));
28978                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
28979                    });
28980
28981                },
28982            STRING : function (tableModelDataRows, sortList, tableContext) {
28983                    return tableModelDataRows.sort(function (a, b) {
28984                        var currColumn = sortList[0][0], currOrder = sortList[0][1],
28985                            guideTableSorter = tableContext.guideTableSorter,
28986                            value_a = guideTableSorter.formatRichTextString(guideTableSorter.getValueFromJsonModel(a, currColumn, true)),
28987                            value_b = guideTableSorter.formatRichTextString(guideTableSorter.getValueFromJsonModel(b, currColumn, true));
28988                        return guideTableSorter.ComparedOrder(value_a, value_b, currOrder);
28989                    });
28990                }
28991        },
28992
28993        
28994        guideTableSorter : new function () {
28995            this.initialize = function (tableSortingConfig) {
28996                return this.each(function () {
28997                    this.tableConfig = {};
28998                    var defaultSortingConfig = {sortList : [], selectorsHeaders : 'thead th',
28999                        headerCss : {asc : "asc", desc : "desc", random : "random"}
29000                    };
29001                    if (!this.tHead || !this.tBodies) {return;}
29002                    var table = $(this), tableConfig = {};
29003                    tableConfig = $.extend(this.tableConfig, defaultSortingConfig, tableSortingConfig);
29004                    var tableHeaderModel, tableModel = tableConfig.model;
29005                    for (var index = 0 ; index < tableModel.children.length ; index++) {
29006                        if (isTableHeaderRow(tableModel.children[index])) {
29007                            tableHeaderModel = tableModel.children[index];
29008                            tableConfig.tableHeader = tableHeaderModel;
29009                            break;
29010                        }
29011                    }
29012                    var $tableHeaders = filterSortableHeaders(tableConfig, this);
29013                    $tableHeaders.click(function () {
29014                        if (this.sortingAllowed) {
29015                            sortCurrentColumn(this, table, tableConfig, $tableHeaders);
29016                        }
29017                    });
29018                    
29019                    $tableHeaders.each(function (index) {
29020                        if (this.sortingAllowed) {
29021                            sortOnFirstColumn(this, tableModel);
29022                            return false;
29023                        }
29024                    });
29025                });
29026            };
29027
29028            
29029            function sortOnFirstColumn(firstColumn, tableModel) {
29030                if (typeof tableModel._guide !== "undefined" && tableModel._guide()) {
29031                    var isSubmittedData = guidelib.util.GuideUtil._fetchJSONNodeValue(tableModel._guide().runtime.guideContext.guidePrefillJson, "afSubmissionInfo");
29032                    isSubmittedData = isSubmittedData || guidelib.util.GuideUtil.fetchXMLNodeValue(tableModel._guide().runtime.guideContext.guidePrefillXml, "afSubmissionInfo");
29033                    if (!isSubmittedData) {
29034                        $(firstColumn).trigger("click");
29035                    }
29036                }
29037            }
29038
29039            
29040            function filterSortableHeaders(tableConfig, tableDom) {
29041                var $tableHeaders = $(tableConfig.selectorsHeaders, tableDom).each(function (index) {
29042                    this.column = index;
29043                    this.order = 1;
29044                });
29045                for (var column = 0 ; column < tableConfig.tableHeader.children.length ; column++) {
29046                    var currColumnModel = tableConfig.tableHeader.children[column];
29047                    $tableHeaders[column].sortingAllowed = true;
29048                    var sortDataType = currColumnModel.jsonModel["sortingDataType"];
29049                    sortDataType = !sortDataType ? "STRING" : sortDataType;
29050                    currColumnModel.jsonModel.sortingDataType = sortDataType;
29051                    if (!tableConfig.tableHeader.visible || sortDataType === "noSort") {
29052                        $tableHeaders[column].sortingAllowed = false;
29053                        $($tableHeaders[column]).removeClass("sortEnabled");
29054                        var $sortingButton = $($tableHeaders[column]).find(".sortingButton").remove();
29055                    }
29056                }
29057                return $tableHeaders;
29058            }
29059
29060            
29061            function sortCurrentColumn(currentHeader, table, tableConfig, $tableHeaders) {
29062                var tableRows = (table[0].tBodies[0] && table[0].tBodies[0].rows.length) || 0;
29063                if (tableRows > 0) {
29064                    currentHeader.order = (++(currentHeader.order) % 2);
29065                    tableConfig.sortList = [];
29066                    tableConfig.sortList.push([currentHeader.column, currentHeader.order]);
29067                    setTimeout(function () {
29068                        updateTableHeaderStyles($tableHeaders, tableConfig.sortList, tableConfig);
29069                        sortGuideTableDataModel(tableConfig, tableConfig.sortList, tableConfig.model);
29070                    }, 1);
29071                }
29072            }
29073
29074            
29075            function updateTableHeaderStyles($headers, sortingList, tableConfig) {
29076                var order, headerCSS = [tableConfig.headerCss.asc, tableConfig.headerCss.desc, tableConfig.headerCss.random];
29077                $headers.each(function (index) {
29078                    var $sortingButton = $(this).find(".sortingButton");
29079                    $sortingButton.removeClass(headerCSS[0]).removeClass(headerCSS[1]).removeClass(headerCSS[2]);
29080                    if ($headers[index].sortingAllowed) {
29081                        if (index === sortingList[0][0]) {
29082                            order = sortingList[0][1];
29083                            $sortingButton.addClass(headerCSS[order]);
29084                        } else {
29085                            $sortingButton.addClass(tableConfig.headerCss.random);
29086                        }
29087                    }
29088                });
29089            }
29090
29091            
29092            function sortGuideTableDataModel(tableConfig, sortList, tableModel) {
29093                var i,j = 0,tableModelChildren = tableModel.children, tableDataRows = [], prevTableModel = tableModel,
29094                    modifiedGuideTableModel = [], tableContext = tableConfig.tableContext;
29095                
29096                for (i = 0; i < tableModelChildren.length; i++) {
29097                    if (tableModelChildren[i].className !== tableSortingComponents.GUIDE_INSTANCE_MANAGER) {
29098                        if (isTableRowsWithData(tableModelChildren[i])) {
29099                            tableDataRows.push(tableModelChildren[i]);
29100                        }
29101                    }
29102                }
29103                var dataType = tableConfig.tableHeader.children[[sortList[0][0]]].jsonModel.sortingDataType;
29104                tableDataRows = tableContext.tableSortComparator[dataType].call(tableConfig, tableDataRows, sortList, tableContext);
29105                for (i = 0; i < tableModel.children.length; i++) {
29106                    if (isTableRowsWithData(tableModel.children[i])) {
29107                        modifiedGuideTableModel.push(tableDataRows[j]);
29108                        j++;
29109                    } else {
29110                        modifiedGuideTableModel.push(tableModel.children[i]);
29111                    }
29112                }
29113                tableModel.children = modifiedGuideTableModel;
29114                tableModel._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "tableModelSorted", prevTableModel, tableModel);
29115                syncNewModelToHTML(tableConfig.tableContext, tableModel);
29116            }
29117
29118            
29119            function isTableRowsWithData(tableModelChildElement) {
29120                var resourceType = tableModelChildElement.options.jsonModel["sling:resourceType"],
29121                    childElementClassName = tableModelChildElement.className;
29122                return !((childElementClassName === tableSortingComponents.GUIDE_INSTANCE_MANAGER) || (resourceType === tableSortingComponents.AF_TABLE_HEADER_COMPONENT) || (resourceType === tableSortingComponents.WEB_CHANNEL_HEADER_COMPONENT));
29123            }
29124
29125            function isTableHeaderRow(tableModelChildElement) {
29126                var resourceType = tableModelChildElement.options.jsonModel["sling:resourceType"];
29127                return ((resourceType === tableSortingComponents.AF_TABLE_HEADER_COMPONENT) || (resourceType === tableSortingComponents.WEB_CHANNEL_HEADER_COMPONENT));
29128            }
29129
29130            this.formatRegexFloatData = function (data) {
29131                return (isNaN(parseFloat(data))) ? 0 : parseFloat(data);
29132            };
29133
29134            this.formatDateValue = function (data) {
29135                return (isNaN(new Date(data).getTime())) ? 0 : new Date(data).getTime();
29136            };
29137
29138            this.formatRichTextString = function (data) {
29139                data = "<div>" + data + "</div>";
29140                return $(data).text().trim();
29141            };
29142
29143            this.ComparedOrder = function (value_a, value_b, currOrder) {
29144                if (value_a > value_b) {
29145                    return (currOrder === 0) ? 1 : -1;
29146                } else if (value_a < value_b) {
29147                    return (currOrder === 0) ? -1 : 1;
29148                } else {
29149                    return -1;
29150                }
29151            };
29152
29153            this.getValueFromJsonModel = function (tableRow, currColumn, isString) {
29154                var jsonModel = tableRow.children[getValidCurrentColumn(tableRow.children, currColumn)].jsonModel, value = null;
29155                if (!isString && jsonModel.defaultValue && jsonModel.defaultValue.length === 1) {
29156                    value = jsonModel.defaultValue[0];
29157                }
29158                if (!value) {
29159                    value = jsonModel._value;
29160                }
29161                return value === null ? "" : this.formatRichTextString(value);
29162            };
29163
29164            
29165            function getValidCurrentColumn(tableRowModel, currColumn) {
29166                var validCurrColumn = currColumn, index = 0 ;
29167                while (currColumn > 0) {
29168                    if (tableRowModel[index].jsonModel.guideNodeClass === tableSortingComponents.GUIDE_INSTANCE_MANAGER) {
29169                        validCurrColumn++;
29170                    } else {
29171                        currColumn--;
29172                    }
29173                    index++;
29174                }
29175                return validCurrColumn;
29176            }
29177
29178            
29179            function syncNewModelToHTML(tableContext, tableModel) {
29180                var tableItemsViews = {}, childView, index;
29181                
29182                for (index = 0; index < tableContext.childViews.length; index++) {
29183                    childView = tableContext.childViews[index];
29184                    if (childView.isItem) {
29185                        tableItemsViews[childView.id] = childView;
29186                    }
29187                }
29188                for (index = 1; index < tableContext._model.items.length; index++) {
29189                    var childModel = tableContext._model.items[index], childId = childModel.id, view = tableItemsViews[childId],newChild = view._model,
29190                        $childItem = view.$item, $childItemNav = view.$itemNav, insertBeforeId, insertAfterId;
29191                    if (index === 1) {
29192                        if (tableModel.items.length > 2) {
29193                            insertBeforeId = tableModel.items[index + 1].id;
29194                        }
29195                    } else {
29196                        insertAfterId = tableModel.items[index - 1].id;
29197                    }
29198                    var insertAfterItemSelector = insertAfterId ? tableContext.guideUtil.itemSelector(insertAfterId, newChild) : "#" + newChild.instanceManager.id,
29199                        insertBeforeItemSelector = insertBeforeId ? tableContext.guideUtil.itemSelector(insertBeforeId, newChild) : "#" + newChild.instanceManager.id;
29200                    tableContext.$itemsContainer.each(function (index) {
29201                        var insertEl = $childItem.get(index) || $childItem.get(0),
29202                            $insertBeforeItem,
29203                            $insertAfterItem = $(this).find(insertAfterItemSelector);
29204                        if ($insertAfterItem.get(0) !== insertEl) {
29205                            $insertAfterItem.after($(insertEl));
29206                        } else {
29207                            $insertBeforeItem = $(this).find(insertBeforeItemSelector);
29208                            $insertBeforeItem.before($(insertEl));
29209                        }
29210                    });
29211                }
29212            }
29213        }
29214    });
29215}($, _, guidelib));
29216
29217(function ($, guidelib) {
29218    var GuideTableRowView = guidelib.view.GuideTableRowView = guidelib.view.GuidePanelView.extend({
29219
29220        handleChildChanged : function (event) {
29221            
29222        }
29223
29224    });
29225}($, guidelib));
29226(function ($, guidelib, _) {
29227    var GuideContainerView = guidelib.view.GuideContainerView =  guidelib.view.GuideItemsView.extend({
29228        initialize : function () {
29229            this._queueViewForLazyItems = [];
29230            
29231            window.guideBridge._guideView = this;
29232            var $htmlTemplateDom =  $(this.options.element).clone();
29233            this._domTemplateCacheStore =
29234                new guidelib.view.util.DomTemplateCacheStore({$htmlTemplateDom : $htmlTemplateDom});
29235            this._lastFocussedPanelForNonActionFields = null;
29236            GuideContainerView._super.initialize.call(this);
29237            this._currentFocusItemSom = null;
29238            
29239            
29240            this._previousFocusItemSom = "FIRST_TIME";
29241            $(window).on("keydown.guides", $.proxy(this.hotKeys, this));
29242            this.postInitialize();
29243            this._model.on(guidelib.event.GuideModelEvent.MODEL_REFRESH, function (evnt) {
29244                switch (evnt._property) {
29245                case "jsonModel":
29246                    this._syncGuideNodeToHtml(true);
29247                    break;
29248                default:
29249                    this._model.logger().error("unexpected event property " + evnt._property);
29250                }
29251            }, this);
29252        },
29253
29254        _reInitializeGuideContainerDom : function () {
29255            var $guideContainerDom = $('div.guideContainerWrapperNode');
29256            this.$element = $guideContainerDom;
29257        },
29258
29259        setFocus : function (somExp, focusOpt, runNavScr) {
29260            var options,
29261                focusOption,
29262                runNavScript,
29263                somExpression,
29264                muteScripts;
29265            if (_.isObject(somExp)) {
29266                options = somExp;
29267                somExpression = options.somExpression;
29268                focusOption = options.focusOption;
29269                runNavScript = options.runCompletionScript;
29270            } else {
29271                somExpression = somExp;
29272                focusOption = focusOpt;
29273                runNavScript = runNavScr;
29274            }
29275            muteScripts = !runNavScript;
29276            if (focusOption == "nextItemDeep" || focusOption == "prevItemDeep") {
29277                
29278                if (somExpression) {
29279                    this.logger().warn("AF", "somExpression is currently not supported for deepNavigation:" + somExpression + ":" + focusOption);
29280                    return false;
29281                }
29282                var existingFocusNavItem = this.getSomOnNavigableAncestor(this._lastFocussedPanelForNonActionFields);
29283                var existingNavView = this.getView(existingFocusNavItem);
29284                var siblingNavName = (focusOption == "nextItemDeep") ? "nextItem" : "prevItem";
29285                
29286                while (existingNavView && (existingNavView.parentView != this) && !existingNavView.getSiblingItemView(siblingNavName)) {
29287                    var navigableParentItem = this.getSomOnNavigableAncestor(existingNavView.parentView._model.somExpression);
29288                    existingNavView = this.getView(navigableParentItem);
29289                }
29290                if (existingNavView && existingNavView.parentView != this && existingNavView.getSiblingItemView(siblingNavName)) {
29291                    var madeActive = existingNavView.parentView.setActive(siblingNavName, false, muteScripts); 
29292                    if (!madeActive) {
29293                        this.logger().log("AF", "could not setActive for the deepNav:" + existingNavView._model.somExpression);
29294                        return false;
29295                    }
29296                    
29297                    var deepChildNav = (siblingNavName == "nextItem") ? "firstItem" : "lastItem";
29298                    var currentActiveChildView = existingNavView.parentView.currentActiveItemView;
29299                    while (currentActiveChildView) {
29300                        currentActiveChildView.setActive(deepChildNav, !currentActiveChildView.currentActiveItemView, true); 
29301                        currentActiveChildView = currentActiveChildView.currentActiveItemView;
29302                    }
29303                    return true;
29304                } else {
29305                    this.logger().warn("AF", "could not locate view for given somExpression:" + somExpression + ":" + focusOption);
29306                    return false;
29307                }
29308            }
29309
29310            if (!somExpression) {
29311                
29312                somExpression = this.guideModel.rootPanel.somExpression;
29313            }
29314            var currentView = this.rootPanelView;
29315            
29316            
29317            if (currentView) {
29318                var relativeSom = this.guideUtil.relativeSom(this.guideModel.rootPanel.somExpression, somExpression);
29319                if (relativeSom) {
29320                    var somTokens = relativeSom.split(".");
29321                    var error =
29322                        _.find(somTokens, function (qName) {
29323                            currentView.setActive(qName, false, muteScripts);
29324                            if (currentView instanceof guidelib.view.GuidePanelView && (currentView.currentActiveItemView == null || currentView.currentActiveItemView.qualifiedName != qName)) {
29325                                this.logger().log("AF", "could not find token:" + qName + ", som:" + somExpression);
29326                                return true; 
29327                            } else {
29328                                if (currentView.currentActiveItemView != null) {
29329                                    currentView = currentView.currentActiveItemView;
29330                                }
29331                            }
29332                        }, this);
29333                    if (error) {
29334                        return false;
29335                    }
29336                }
29337            } else {
29338                
29339                var $element = this._getGuideDomElement(somExpression);
29340                
29341                
29342                if ($element && $element.length > 0) {
29343                    
29344                    
29345                    currentView = $element.data("guideView");
29346                }
29347            }
29348
29349            if (currentView) {
29350                return currentView.setActive(focusOption, true, muteScripts);
29351            } else {
29352                return false;
29353            }
29354        },
29355
29356        _getGuideDomElement : function (somExpression, option) {
29357            var nav = "", res, node, nodeElSelector;
29358            if (somExpression && typeof somExpression === 'string') {
29359                node = this.guideModel.resolveNode(somExpression);
29360                if (!node) {
29361                    return;
29362                }
29363                nodeElSelector = "#" + node.id;
29364                if (option === "nav") {
29365                    nodeElSelector = this.guideUtil.itemNavSelector(node.id);
29366                }
29367                res = this.$element.find(nodeElSelector);
29368                return res;
29369            }
29370        },
29371
29372        getView : function (somExpression) {
29373            if (!somExpression) {
29374                return null;
29375            }
29376            var $focusEl = this._getGuideDomElement(somExpression),
29377                view = null,
29378                ancestorView = null;
29379            if ($focusEl && $focusEl.length > 0) {
29380                if (!$focusEl.data("guideView")) {
29381                    var rootPanelSom = this.guideModel.rootPanel.somExpression;
29382                    var relativeSom = guidelib.util.GuideUtil.relativeSom(rootPanelSom, somExpression) || "";
29383                    
29384                    _.reduce(relativeSom.split("."), function (currentSom, somToken) {
29385                        currentSom = currentSom ? currentSom + "." + somToken : somToken;
29386                        ancestorView = this.getView(currentSom);
29387                        if (ancestorView instanceof guidelib.view.GuidePanelView && ancestorView._childInitializeWaiting) {
29388                            ancestorView._postInitializeChildren();
29389                        }
29390                        return currentSom;
29391                    }, rootPanelSom, this);
29392                }
29393                view = $focusEl.data("guideView");
29394                if (view instanceof guidelib.view.GuidePanelView && view._childInitializeWaiting) {
29395                    view._postInitializeChildren();
29396                }
29397
29398                return view;
29399            }
29400            return null;
29401        },
29402
29403        hotKeys : function (evnt) {
29404            var handled = false, currentFocusItemSom;
29405
29406            switch (evnt.keyCode) {
29407            case 37: 
29408                if (evnt.altKey) {
29409                    window.guideBridge.setFocus(null, 'prevItemDeep', true);
29410                    handled = true;
29411                }
29412                break;
29413            case 39: 
29414                if (evnt.altKey) {
29415                    window.guideBridge.setFocus(null, 'nextItemDeep', true);
29416                    handled = true;
29417                }
29418                break;
29419            case 82: 
29420                if (evnt.altKey) {
29421                    window.guideBridge.reset();
29422                    handled = true;
29423                }
29424                break;
29425            case 83: 
29426                if (evnt.altKey) {
29427                    window.guideBridge.submit();
29428                    handled = true;
29429                }
29430                break;
29431            }
29432            if (handled) {
29433                evnt.preventDefault();
29434            }
29435        },
29436
29437        getSomOnNavigableAncestor : function (somExpression) {
29438            if (!somExpression || somExpression === "") {
29439                return null;
29440            }
29441
29442            var index, parentView, parentSom, isNavigable;
29443            index = somExpression.lastIndexOf(".");
29444
29445            if (index !== -1) {
29446                parentSom = somExpression.substring(0, index);
29447                parentView = this.getView(parentSom);
29448                if (parentView) {
29449                    isNavigable = parentView.hasNavigableLayout;
29450                }
29451                if (isNavigable) {  
29452                    return somExpression;
29453                }
29454                return this.getSomOnNavigableAncestor(parentSom);
29455            }
29456            
29457            return this.guideModel.rootPanel.somExpression;
29458        },
29459
29460        __printSyncPending : function () {
29461            
29462            _.each(this.childViews, function (childView) {
29463                if (childView._syncPending) {
29464                    this.logger().error("AF", childView._model.somExpression);
29465                } else {
29466                    GuideContainerView.prototype.__printSyncPending.call(childView);
29467                }
29468            }, this);
29469        },
29470        
29471        _clearInactiveLazyViews : function (that) {
29472            _.each(this.childViews, function (item) {
29473                if (item._model.className === "rootPanelNode") {
29474                    item._clearInactiveLazyViews(that);
29475                }
29476            });
29477        }
29478
29479    });
29480
29481    GuideContainerView.defineProps({
29482        guideModel : {
29483            get : function () {
29484                return this._model;
29485            }
29486        },
29487
29488        rootPanelView : {
29489            get : function () {
29490                return this._findChildView(this.guideModel.rootPanel);
29491            }
29492        },
29493
29494        currentFocusItemSom : {
29495            get : function () {
29496                return this._currentFocusItemSom;
29497            },
29498            set : function (newSom) {
29499                if (this._currentFocusItemSom !== newSom) {
29500                    var oldValue = this._currentFocusItemSom;
29501                    if (oldValue) {
29502                        this._previousFocusItemSom = oldValue;
29503                    }
29504                    this._currentFocusItemSom = newSom;
29505                    
29506                    if (newSom != null && this._model.resolveNode(newSom).parent.className !== "guideToolbar") {
29507                        this._lastFocussedPanelForNonActionFields = this.get
29507SomOnNavigableAncestor(this._currentFocusItemSom);
29508                        
29509                        
29510                        this._model._currentNavigablePanelSom =  this._lastFocussedPanelForNonActionFields;
29511                    }
29512                    if (newSom) {
29513                        this._triggerOnBridge("elementFocusChanged", this._model.resolveNode(newSom), "focus", this._previousFocusItemSom, newSom);
29514                        if (this._previousFocusItemSom) {
29515                            var getPreviousItemNavigableSom = this.getSomOnNavigableAncestor(this._previousFocusItemSom),
29516                                getCurrentItemNavigableSom = this.getSomOnNavigableAncestor(newSom);
29517                            if (getCurrentItemNavigableSom !== getPreviousItemNavigableSom) {
29518                                this._triggerOnBridge("elementNavigationChanged", this._model.resolveNode(getCurrentItemNavigableSom),
29519                                    "navigate", getPreviousItemNavigableSom, getCurrentItemNavigableSom);
29520                            }
29521                        }
29522                    }
29523                }
29524            }
29525        },
29526
29527        skipFieldFocus : {
29528            
29529            get : function () {
29530                return this._skipFieldFocus;
29531            },
29532            
29533            set : function (newVal) {
29534                this._skipFieldFocus = newVal;
29535            }
29536        }
29537    });
29538}($, guidelib, _));
29539(function (_, guidelib) {
29540    guidelib.model.mixin.ValidationsDisabled = {
29541        normalProperties : {
29542            setParentValidationsDisabled : function (bParentValidationsDisabled) {
29543                var oldValidationsDisabled = this.validationsDisabled,
29544                    newValidationsDisabled;
29545                this._bParentValidationsDisabled = bParentValidationsDisabled;
29546                newValidationsDisabled = this.validationsDisabled;
29547                this.handleChildValidationsDisabled(newValidationsDisabled, oldValidationsDisabled);
29548            },
29549
29550            handleChildValidationsDisabled : function (newValidationsDisabled, oldValidationsDisabled) {
29551                if (newValidationsDisabled !== oldValidationsDisabled) {
29552                    if (this instanceof guidelib.model.Field) {
29553                        if (newValidationsDisabled === true) {
29554                            if (this.validationState === false) {
29555                                this._errorText = "";
29556                                this.validationState = true;
29557                                this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
29558                                    "validationStatus", this.validationState, this._errorText);
29559                            }
29560                        }
29561                    }
29562                    _.each(this._children, function (child) {
29563                        if (child instanceof guidelib.model.Field || child instanceof guidelib.model.GuideItemsContainer) {
29564                            child.setParentValidationsDisabled(newValidationsDisabled);
29565                        }
29566                    });
29567                }
29568            }
29569        },
29570        propertyDescriptors : {
29571            validationsDisabled : {
29572                get : function () {
29573                    return this._bParentValidationsDisabled || this._validationsDisabled;
29574                },
29575                set : function (bValidationsDisabled) {
29576                    var oldValidationsDisabled = this.validationsDisabled,
29577                        newValidationsDisabled;
29578                    this._validationsDisabled = bValidationsDisabled;
29579                    newValidationsDisabled = this.validationsDisabled;
29580                    this.handleChildValidationsDisabled(newValidationsDisabled, oldValidationsDisabled);
29581                }
29582            }
29583        }
29584    };
29585
29586}(_, guidelib));
29587(function (_, guidelib) {
29588
29589    
29590    var GuideItemsContainer = guidelib.model.GuideItemsContainer = guidelib.model.Scriptable.extend({
29591        msClassName : "guideItemsContainer",
29592
29593        initialize : function () {
29594            GuideItemsContainer._super.initialize.call(this);
29595            this._children = [];
29596            this._nameArray = {};
29597            this._private = {};
29598            this._initChildren();
29599            this._normalizeChildren();
29600            this._bParentValidationsDisabled = false;
29601            this._validationsDisabled = false;
29602        },
29603
29604        _postInitialize : function () {
29605            
29606            
29607            GuideItemsContainer._super._postInitialize.call(this);
29608            _.each(this._children, function (childNode) {
29609                childNode._postInitialize();
29610            }, this);
29611        },
29612
29613        
29614        validate : function (errorList) {
29615            var validationStatus = true,
29616                tempValidationStatus;
29617            
29618            if (!this.visible) {
29619                return true;
29620            }
29621            if (_.isUndefined(errorList)) {
29622                errorList = [];
29623            }
29624
29625            var subContainerErrorArray = [],
29626                arrLen;
29627            _.each(this.children, function (child) {
29628                tempValidationStatus = child.validate(subContainerErrorArray);
29629                if (tempValidationStatus === false) {
29630                    validationStatus = false;
29631                }
29632            }, this);
29633
29634            tempValidationStatus = GuideItemsContainer._super.validate.call(this, subContainerErrorArray);
29635            if (tempValidationStatus === false) {
29636                validationStatus = false;
29637            }
29638            arrLen = subContainerErrorArray.length;
29639            while (arrLen > 0) {
29640                errorList[errorList.length] = subContainerErrorArray[subContainerErrorArray.length - arrLen];
29641                arrLen--;
29642            }
29643            return validationStatus;
29644        },
29645
29646        prepare : function () {
29647            _.each(this._children, function (childNode) {
29648                childNode.prepare();
29649            }, this);
29650            GuideItemsContainer._super.prepare.call(this);
29651        },
29652
29653        syncXFAProps : function () {
29654            GuideItemsContainer._super.syncXFAProps.apply(this, arguments);
29655            _.each(this._children, function (childNode) {
29656                childNode.syncXFAProps();
29657            });
29658        },
29659
29660        _initChildren : function (bLazyInitialization) {
29661            var panelItems = [],
29662                jsonModelItemsWithoutRepeatJson = {},
29663                keyLengthForJsonWithoutRepeat = 0,
29664                keyLengthJsonItemsOriginal = 0;
29665            
29666            
29667            
29668            
29669            
29670            _.each(this.jsonModel.items, function (item) {
29671                
29672                
29673                
29674                if (item.templateId && item.templateId.indexOf("GUID") === -1) {
29675                    jsonModelItemsWithoutRepeatJson[item.templateId] = item;
29676                }
29677            });
29678            keyLengthForJsonWithoutRepeat = _.keys(jsonModelItemsWithoutRepeatJson).length;
29679            
29680            keyLengthJsonItemsOriginal = _.keys(this.jsonModel.items || {}).length;
29681            if (keyLengthForJsonWithoutRepeat > 0 && keyLengthForJsonWithoutRepeat !== keyLengthJsonItemsOriginal) {
29682                this.jsonModel.items = jsonModelItemsWithoutRepeatJson;
29683            }
29684            _.each(this.jsonModel.items,
29685                function (item) {
29686                    if (_.isObject(item)) {
29687                        
29688                        
29689                        
29690                        
29691                        var options = {};
29692                        if (this.options._guideContainer) {
29693                            options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
29694                        }
29695                        var panelItemModel = guidelib.model.GuideModelRegistry.prototype.createModel(item, options);
29696                        panelItemModel._isItem = true;
29697                        this._initializeChild(panelItemModel);
29698                        panelItems.push(panelItemModel);
29699                    }
29700                },
29701                this);
29702            this._children = panelItems;
29703        },
29704
29705        _initializeChild : function (childItem) {
29706            childItem.parent = this;
29707        },
29708
29709        _normalizeChildren : function () {
29710            this._nameArray = {};
29711            this._private = {};
29712            _.each(this.children, function (child) {
29713                child._index = this._addProperty(child);
29714                
29715                child.getNaked(child._index, guidelib.__runtime__, null);
29716                child.getNaked(child._index, this._guide().runtime, null);
29717            }, this);
29718        },
29719
29720        nakedChildReferences : function (nIndex, obj) {
29721            var i, oNode;
29722            for (i = 0; i < this._children.length; i++) {
29723                oNode = this._children[i];
29724                oNode.getNaked(nIndex, obj, this);
29725            }
29726        },
29727        _getReducedJSON : function (isRepeatable) {
29728            var reducedJSONChildren,
29729                that = this,
29730                index =  0;
29731            
29732            reducedJSONChildren = GuideItemsContainer._super._getReducedJSON.call(this);
29733            reducedJSONChildren.items = {};
29734            
29735            
29736            
29737            
29738            _.each(this.jsonModel.items, function (childNode, key) {
29739                reducedJSONChildren.items[key] = that.items[index]._getReducedJSON(isRepeatable);
29740                index += 1;
29741            });
29742            return reducedJSONChildren;
29743        },
29744
29745        _addProperty : function (oValueObject) {
29746            var sName = oValueObject.getAttribute("name"),
29747                nIndex = 0;
29748            
29749            
29750            
29751            this._nameArray[sName] = this._nameArray[sName] || nIndex;
29752            nIndex = this._nameArray[sName]++;
29753            if (nIndex === 0) {
29754                
29755                
29756                
29757                
29758                guidelib.util.GuideUtil._createGetterSetter(this, sName, oValueObject);
29759            }
29760            return nIndex;
29761        },
29762
29763        _getTitle : function () {
29764            return this.jsonModel["jcr:title"];
29765        },
29766
29767        visit : function (callback, context) {
29768            GuideItemsContainer._super.visit.apply(this, arguments);
29769            _.each(this._children, function (child, index) {
29770                child.visit(callback, context);
29771            });
29772        },
29773
29774        playJson : function (pJsonModel) {
29775            if (pJsonModel) {
29776                var pJsonItems = _.filter(pJsonModel.items, function (item) {
29777                    if (_.isObject(item)) {
29778                        return true;
29779                    }
29780                    return false;
29781                }, this);
29782                
29783                _.each(this.items, function (childNode, index) {
29784                    childNode.playJson(pJsonItems[index]);
29785                }, this);
29786                GuideItemsContainer._super.playJson.call(this, pJsonModel);
29787            }
29788
29789        },
29790
29791        _collectValues : function (keyValue) {
29792            _.each(this._children, function (childNode) {
29793                childNode._collectValues(keyValue);
29794            }, this);
29795        },
29796
29797        getElement : function (elClassName) {
29798            var element = _.find(this._children, function (childModel) {
29799                return childModel.className === elClassName;
29800            }, this);
29801            return element;
29802        },
29803
29804        
29805        _unloadModel : function () {
29806            _.each(this.children, function (child) {
29807                child._unloadModel();
29808            }, this);
29809            GuideItemsContainer._super._unloadModel.call(this);
29810        },
29811
29812        _findChildren : function (oSOM, bMultiple) {
29813            var arr = [],
29814                elemFound = false;
29815            _.find(this._children, function (child) {
29816                if (oSOM === child._escapeQualifiedName()) {
29817                    arr.push(child._getNakedThis());
29818                    elemFound = true;
29819                }
29820                if (elemFound && !bMultiple) {
29821                    return true; 
29822                }
29823                if (elemFound && oSOM.indexOf("[*]") < 0) {
29824                    return true; 
29825                }
29826            }, this);
29827            return arr;
29828        },
29829
29830        
29831        resetData : function () {
29832            _.each(this._children, function (childNode) {
29833                childNode.resetData();
29834            }, this);
29835        },
29836
29837        
29838        _changeDescendantsAccess : function (value) {
29839            _.each(this.items, function (child) {
29840                child._setParentAccess(value);
29841                if (child instanceof guidelib.model.GuideItemsContainer) {
29842                    child._changeDescendantsAccess(value);
29843                }
29844            }, this);
29845        },
29846
29847        
29848        _changeContainerAccess : function (value) {
29849            this._changeDescendantsAccess(value);
29850        },
29851
29852        
29853        _changeDescendantsProperty : function (value, property, leafNodesOnly) {
29854            _.each(this.items, function (child) {
29855                if (child instanceof guidelib.model.GuideItemsContainer) {
29856                    if (!leafNodesOnly) {
29857                        child[property] = value;
29858                    }
29859                    child._changeDescendantsProperty(value, property);
29860                } else {
29861                    child[property] = value;
29862                }
29863            }, this);
29864        },
29865
29866        
29867        disableAllFields : function () {
29868            this.enabled = false;
29869            var property = "enabled";
29870            this._changeDescendantsProperty(false, property, true);
29871        }
29872
29873    });
29874
29875    GuideItemsContainer.defineProps({
29876        children : {
29877            get : function () {
29878                return (this._children || []).slice(0); 
29879            },
29880            set : function (value) {
29881                this._children = value;
29882            }
29883        },
29884
29885        
29886        items : {
29887            get : function () {
29888                var itemChildren = _.filter(this._children, function (child) {
29889                    if (child._isItem) {
29890                        return true;
29891                    }
29892                    return false;
29893                }, this);
29894                return itemChildren;
29895            }
29896        },
29897        
29898        _selfOrAncestorIsLazyReference : {
29899            get : function () {
29900                if (this._lazyReference) {
29901                    return true;
29902                }
29903                return guidelib.util.GuideUtil._checkIfAncestorIsALazyReference(this);
29904            }
29905        },
29906        _lazyReference : {
29907            get : function () {
29908                return !_.isUndefined(this.jsonModel["fragRef"])
29909                    && !_.isUndefined(this.jsonModel["optimizeRenderPerformance"]);
29910            }
29911        }
29912    });
29913
29914    GuideItemsContainer.addMixins([
29915        guidelib.model.mixin.ValidationsDisabled
29916    ]);
29917
29918}(_, guidelib));
29919
29920(function (_, guidelib) {
29921    var GuideToolbar = guidelib.model.GuideToolbar = guidelib.model.GuideItemsContainer.extend({
29922        msClassName : "guideToolbar",
29923
29924        initialize : function () {
29925            GuideToolbar._super.initialize.call(this);
29926        },
29927
29928        execNavigationChangeExpression : function () {
29929            _.each(this.items, function (childModel) {
29930                if (childModel.navigationChangeExp) {
29931                    this._guide().queueExpressions(childModel, "navigationChangeExp");
29932                }
29933            }, this);
29934        }
29935
29936    });
29937
29938})(_, guidelib);
29939
29940(function (_, guidelib) {
29941
29942    
29943    var GuideCompositeField = guidelib.model.GuideCompositeField = guidelib.model.GuideItemsContainer.extend({
29944        msClassName : "guideCompositeField",
29945        initialize : function () {
29946            this._uuid = guideBridge._produceUUID();
29947            GuideCompositeField._super.initialize.call(this);
29948        },
29949
29950        _setGuideValue : function (value) {
29951            if (!_.isEmpty(value)) {
29952                _.each(this.items, function (item) {
29953                    if (value.hasOwnProperty(item.name) && _.isFunction(item._setGuideValue)) {
29954                        item._setGuideValue(value[item.name]);
29955                    }
29956                }, this);
29957            }
29958        },
29959
29960        _collectExpressions : function () {
29961            GuideCompositeField._super._collectExpressions.apply(this);
29962            if (this.valueCommitScript) {
29963                
29964                this._compiledScripts.valueCommitScript = this._compileExpression(this.valueCommitScript, null);
29965            }
29966        }
29967    });
29968
29969    GuideCompositeField.defineProps({
29970        valueCommitScript : {
29971            get : function () {
29972                return this.getAttribute("valueCommitScript");
29973            }
29974        },
29975        uuid : {
29976            get : function () {
29977                return this._uuid;
29978            },
29979            set : function (newUuid) {
29980                if (this._uuid != newUuid) {
29981                    this._uuid = newUuid;
29982                }
29983            }
29984        }
29985    });
29986
29987})(_, guidelib);
29988
29989(function (_, guidelib) {
29990    
29991    var GuideTermsAndConditions = guidelib.model.GuideTermsAndConditions =  guidelib.model.GuideCompositeField.extend({
29992        msClassName : "guideTermsAndConditions",
29993
29994        playJson : function (pJsonModel) {
29995            this.jsonModel.clickStatus = pJsonModel.clickStatus;
29996            GuideTermsAndConditions._super.playJson.apply(this, arguments);
29997        },
29998
29999        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
30000            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, '_updateLiveData');
30001        },
30002
30003        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
30004            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, '_playLiveData');
30005            if (this.reviewStatus.value === "true") {
30006                this.clickStatus = "agree";
30007            } else {
30008                this.clickStatus = "unreviewed";
30009            }
30010        },
30011
30012        _syncModelAndData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
30013            if (_.isString(recurse)) {
30014                var dataContext = this._guide().internal.liveDataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
30015                if (dataContext.xmlSec === this._guide().internal.liveDataUtils.constants.BOUND_TAG) {
30016                    bound_indexedXpathSoFar = dataContext.indexedXpath;
30017                } else {
30018                    unBound_indexedXpathSoFar = dataContext.indexedXpath;
30019                }
30020                _.each(this.items, function (item) {
30021                    if (_.isFunction(item[recurse])) {
30022                        item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
30023                    }
30024                });
30025            }
30026        }
30027    });
30028
30029    GuideTermsAndConditions.defineProps({
30030        showLink : {
30031            get : function () {
30032                return this.getAttribute("showLink");
30033            }
30034        },
30035
30036        
30037        clickStatus : {
30038            get : function () {
30039                return this.getAttribute("clickStatus");
30040            },
30041            set : function (status) {
30042                this.setAttribute(status, "clickStatus");
30043            }
30044        },
30045
30046        showAsPopUp : {
30047            get : function () {
30048                return this.getAttribute("showAsPopUp");
30049            }
30050        }
30051    });
30052
30053})(_, guidelib);
30054(function (_, guidelib) {
30055
30056    
30057    var GuideFileUpload = guidelib.model.GuideFileUpload = guidelib.model.GuideCompositeField.extend({
30058        msClassName : "guideFileUpload",
30059
30060        _getReducedJSON : function () {
30061            this._syncModelToAttachments();
30062            var reducedJSONChildren = GuideFileUpload._super._getReducedJSON.call(this),
30063                addtionalWhitelistedProperties = ["id", "files"];
30064            guidelib.model.util.CommonUtils.returnMinimalJSON(addtionalWhitelistedProperties, reducedJSONChildren, this);
30065            var fileAttachmentValue = reducedJSONChildren.files;
30066            reducedJSONChildren.files = this._getFileAttachmentNames(fileAttachmentValue);
30067            return reducedJSONChildren;
30068        },
30069
30070        _getContentType : function(fileUrl) {
30071            var contentType = null,
30072                self = this;
30073            if (self._fileAttachmentWrapper) {
30074                var element = self._fileAttachmentWrapper.find(function(x) { return x.data === fileUrl});
30075                if (element) {
30076                    contentType = element.contentType;
30077                }
30078            }
30079            return contentType
30080        },
30081
30082        
30083        _getFileAttachmentNames : function (fileAttachmentValue) {
30084            var value = fileAttachmentValue || this.value;
30085            if (value) {
30086                var self = this,
30087                    fileNames = _.map(value.split("\n"), function (val) {
30088                        if (self._fileAttachmentWrapper) {
30089                            var element = self._fileAttachmentWrapper.find(function(x) { return x.data === val});
30090                            if (element) {
30091                                return element.name;
30092                            }
30093                        }
30094                        var fName = val;
30095                        
30096                        if (fName.lastIndexOf("/") === fName.length - 1) {
30097                            fName = fName.substring(0, fName.length - 1);
30098                        }
30099                        return fName.substring(fName.lastIndexOf("/") + 1);
30100                }).join("\n");
30101                return fileNames;
30102            }
30103        },
30104
30105        _triggerFileListChange : function () {
30106            var currValue = this._fileList;
30107            this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
30108                guidelib.event.GuideModelEvent.createEvent(
30109                    guidelib.event.GuideModelEvent.MODEL_CHANGED,
30110                    this,
30111                    "fileList",
30112                    currValue,
30113                    currValue
30114                )
30115            );
30116        },
30117
30118        _getCurrentFileAttachmentWrapper : function(attachments) {
30119            var currentListOfAttachments = null,
30120                effectiveBindRef = this._getEffectiveBindRef(),
30121                self = this;
30122            if (_.isArray(attachments) && attachments.length > 0) {
30123                currentListOfAttachments = attachments.filter(function(x) {
30124                    return x.bindRef === effectiveBindRef;
30125                })
30126            }
30127            return currentListOfAttachments;
30128        },
30129
30130        _playAttachmentWrappers : function(currentAttachmentWrappers) {
30131            var currValue = this.fileAttachment.value,
30132                _guide = this._guide();
30133            if (_.isArray(currentAttachmentWrappers) && currentAttachmentWrappers.length > 0) {
30134                this._fileAttachmentWrapper = currentAttachmentWrappers;
30135                
30136                if (this.valueCommitScript && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_PREFILL) && currValue) {
30137                    
30138                    _guide.queueExpressions(this, ["valueCommitScript"]);
30139                }
30140                var data = currentAttachmentWrappers.map(function(x) {return x.data});
30141                
30142                var fieldValue = data.join("\n");
30143                this.fileAttachment._setGuideValue(fieldValue);
30144                if (!_.isEmpty(fieldValue)) {
30145                    this._fileList = fieldValue.split("\n");
30146                }
30147            }
30148        },
30149
30150        playJson : function (pJsonModel, attachments) {
30151            if (attachments) {
30152                var currentListOfAttachments = this._getCurrentFileAttachmentWrapper(attachments);
30153                this._playAttachmentWrappers(currentListOfAttachments);
30154            } else {
30155                
30156                GuideFileUpload._super.playJson.call(this, pJsonModel);
30157            }
30158        },
30159
30160        _syncModelToAttachments : function () {
30161            var files = this.fileAttachment.value || "",
30162                filesArray = files.split('\n'),
30163                uniqueNames = guideBridge._makeFileNameUnique();
30164            var isIOS = guidelib.util.GuideUtil._isIOS();
30165            var files = this.fileAttachment.value || "",
30166                filesArray = files.split('\n'),
30167                areNamesUnique = (new Set(filesArray)).size === filesArray.length;
30168            this.jsonModel.files =
30169                _.map(files.split('\n'), function (file, index) {
30170                    if (!_.isEmpty(file)) {
30171                        if ((uniqueNames || (!areNamesUnique && isIOS))  && file[0] !== '/') {
30172                            file = this.uuid + "-" + (index + 1) + "__afAttachment__" + file; 
30173                        }
30174                    }
30175                    return file;
30176                }, this).join('\n');
30177        },
30178
30179        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
30180            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, "_updateLiveData");
30181        },
30182
30183        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
30184            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, "_playLiveData");
30185        },
30186
30187        _handleFileAttachmentItem : function (fileAttachmentModel, bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
30188            
30189            var dataUtils = this._guide().internal.liveDataUtils,
30190                dataContext = dataUtils._getDataContext(fileAttachmentModel, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
30191            if (recurse == "_updateLiveData") {
30192                dataUtils._updateLazyAttachmentMapFromModel(this);
30193                dataUtils.setDataValue(dataContext.indexedXpath, dataContext.xmlSec,
30194                    !fileAttachmentModel.isEmpty(), fileAttachmentModel.isEmpty() ? "" : this._getFileAttachmentValue());
30195            } else {
30196                var data = dataUtils._getAttachmentDataForModel(this);
30197                if (!_.isArray(data) && !_.isEmpty(data)) {
30198                    this.fileList = data.fileList;
30199                    var fileAttachmentValue = [];
30200                    var value = data.value.split("\n");
30201                    _.each(value, function (value, index) {
30202                        if (value[0] != '/') {
30203                            
30204                            
30205                            var name = value.substr(value.lastIndexOf("_") + 1);
30206                            fileAttachmentValue.push(name);
30207                        } else {
30208                            
30209                            fileAttachmentValue.push(value);
30210                        }
30211                    });
30212                    fileAttachmentModel.value = fileAttachmentValue.join("\n");
30213                }
30214                if (_.isArray(data) && data.length > 0) {
30215                    this._playAttachmentWrappers(data);
30216                }
30217                this._syncModelToAttachments();
30218            }
30219        },
30220
30221        _syncModelAndData : func
30221tion (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse) {
30222            if (_.isString(recurse)) {
30223                var liveDataUtils = this._guide().internal.liveDataUtils;
30224                var dataContext = liveDataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
30225                if (dataContext.xmlSec === liveDataUtils.constants.BOUND_TAG) {
30226                    bound_indexedXpathSoFar = dataContext.indexedXpath;
30227                } else {
30228                    unBound_indexedXpathSoFar = dataContext.indexedXpath;
30229                }
30230                _.each(this.items, function (item) {
30231                    if (_.isFunction(item[recurse])) {
30232                        if (item.name == "fileAttachment") {
30233                            
30234                            
30235                            this._handleFileAttachmentItem(item, bound_indexedXpathSoFar, unBound_indexedXpathSoFar, recurse);
30236                        } else {
30237                            item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
30238                        }
30239                    }
30240                }, this);
30241            }
30242        },
30243
30244        
30245        _getIndexedXpath : function (model, bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
30246            var name = model.getAttribute("name").replace(/\s+/g, '');
30247            return unBound_indexedXpathSoFar ? unBound_indexedXpathSoFar + '/' + name : bound_indexedXpathSoFar + '/' + name;
30248        },
30249
30250        
30251        _getFileAttachmentValue : function () {
30252            
30253            
30254            
30255            this._syncModelToAttachments();
30256            return this._getFileAttachmentNames(this.jsonModel.files);
30257        }
30258
30259    });
30260
30261    GuideFileUpload.defineProps({
30262        
30263        multiSelection : {
30264            get : function () {
30265                return this.getAttribute("multiSelection");
30266            }
30267        },
30268
30269        buttonText : {
30270            get : function () {
30271                return this.getAttribute("buttonText");
30272            }
30273        },
30274
30275        showComment : {
30276            get : function () {
30277                return this.getAttribute("showComment");
30278            }
30279        },
30280
30281        
30282        fileSizeLimit : {
30283            get : function () {
30284                return this.getAttribute("fileSizeLimit");
30285            }
30286        },
30287
30288        fileList : {
30289            get : function () {
30290                return this._fileList;
30291            },
30292
30293            set : function (newValue) {
30294                var oldValue = this._fileList;
30295                var newTypedValue = newValue;
30296                if (newTypedValue != oldValue) {
30297                    this._fileList = newTypedValue;
30298                }
30299                
30300                
30301                
30302                var isIOS = guidelib.util.GuideUtil._isIOS(),
30303                    fileList = this._fileList,
30304                    that = this;
30305                if (isIOS && fileList) {
30306                    
30307                    this._fileAttachmentWrapperIOS = [];
30308                    
30309                    for (var i = 0; i < fileList.length; i++) {
30310                        if (!_.isString(fileList[i])) {
30311                            
30312                            var files = fileList[i].get(0).files,
30313                                _readFile = function (file) {
30314                                    
30315                                    that._fileAttachmentWrapperIOS.push(
30316                                        new Promise(function(resolve, reject){
30317                                            var reader = new FileReader();
30318                                            reader.onload = function() {
30319                                                var faWrapper = new guidelib.model.FileAttachmentWrapper({
30320                                                    name: file.name,
30321                                                    data: this.result,
30322                                                    formElementName : that.name,
30323                                                    contentType: file.type,
30324                                                    bindRef: that._getEffectiveBindRef()
30325                                                });
30326                                                resolve(faWrapper);
30327                                            };
30328                                            reader.onerror = reject;
30329                                            reader.readAsDataURL(file);
30330                                        })
30331                                    )
30332                                };
30333                            if (files) {
30334                                
30335                                [].forEach.call(files, _readFile);
30336                            }
30337                        }
30338                    }
30339                }
30340                this._triggerFileListChange();
30341            }
30342        },
30343        value : {
30344            get : function () {
30345                this._syncModelToAttachments();
30346                return this.jsonModel.files;
30347            }
30348        }
30349    });
30350
30351})(_, guidelib);
30352
30353(function (_, guidelib) {
30354    var GuideAdModuleGroup = guidelib.model.GuideAdModuleGroup = guidelib.model.GuideItemsContainer.extend({
30355        msClassName : "guideAdModuleGroup",
30356
30357        _getTypedValue : function (value) {
30358            
30359            if (_.isUndefined(value) || value === null) {
30360                return null;
30361            }
30362            return value + "";
30363        },
30364
30365        playJson : function (pJsonModel) {
30366            var typedValue = this._getTypedValue(pJsonModel._value);
30367            
30368            if (typedValue || typedValue === "") {
30369                
30370                var olval = this.jsonModel._value;
30371                this.jsonModel._value = pJsonModel._value;
30372                this._triggerOnBridge("elementValueChanged", this, "value", olval, this.jsonModel._value);
30373            } else {
30374                
30375                GuideAdModuleGroup._super.playJson.call(this, pJsonModel);
30376            }
30377        }
30378    });
30379
30380    GuideAdModuleGroup.defineProps({
30381        
30382        value : {
30383            get : function () {
30384                return this._getTypedValue(this.jsonModel._value);
30385            },
30386            set : function (newValue) {
30387                var oldValue = this._getTypedValue(this.jsonModel._value),
30388                    newTypedValue = this._getTypedValue(newValue);
30389                
30390                if (newTypedValue !== undefined && (newTypedValue !== oldValue)) {
30391                    if (this.jsonModel._value !== newValue) {
30392                        this.jsonModel._value = newTypedValue || "";
30393                    }
30394                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
30395                }
30396            }
30397        }
30398    });
30399
30400}(_, guidelib));
30401(function (_, guidelib) {
30402    guidelib.model.mixin.AddDependencyMgmt = {
30403        normalProperties : {
30404            _addDependant : function (oNode, expressionType) {
30405                var dependantConf = this._findDependant(oNode);
30406                if (!dependantConf) {
30407                    dependantConf = {dependant : oNode, events : []};
30408                    this.dependants.push(dependantConf);
30409                }
30410
30411                if (dependantConf.events.indexOf(expressionType) < 0) {
30412                    dependantConf.events.push(expressionType);
30413                    oNode.on(guidelib.event.GuideModelEvent.OBJECT_DESTROYED, this._handleDependentDestroyed, this);
30414                }
30415            },
30416
30417            _notifyDependants : function () {
30418                _.each(this.dependants, function (dependantConf) {
30419                    this._guide().queueExpressions(dependantConf.dependant, dependantConf.events);
30420                }, this);
30421            },
30422
30423            _removeDependant : function (oNode) {
30424                oNode.off(guidelib.event.GuideModelEvent.OBJECT_DESTROYED, this._handleDependentDestroyed, this);
30425                var dependantConf = this._findDependant(oNode);
30426                this.dependants = _.without(this.dependants, dependantConf);
30427            },
30428
30429            _findDependant : function (oNode) {
30430                return _.find(this.dependants, function (conf) { return (conf.dependant === oNode); });
30431            },
30432
30433            _handleDependentDestroyed : function (event) {
30434                this._removeDependant(event.target);
30435            }
30436        }
30437    };
30438})(_, guidelib);
30439
30440(function (_, guidelib) {
30441    var GuideChart = guidelib.model.GuideChart = guidelib.model.Scriptable.extend({
30442        msClassName : "guideChart",
30443
30444        _collectExpressions : function () {
30445            GuideChart._super._collectExpressions.apply(this);
30446            this._compiledExpressions["aggregateExp"] = this._compileExpression('guidelib.chartUtils.gatherAxisData(this);', "data");
30447        }
30448    });
30449
30450    GuideChart.defineProps({
30451        
30452        data : {
30453            get : function () {
30454                var context = this._guide()._currentContext;
30455                if (context && context.contextNode && context.expression
30456                    && !(context.contextNode === this && context.expression === "aggregateExp")) {
30457                    this._addDependant(context.contextNode, context.expression);
30458                }
30459                return this.jsonModel.data;
30460            },
30461
30462            set : function (newValue) {
30463                var oldValue = this.jsonModel.data;
30464                this.jsonModel.data = newValue;
30465                
30466                var valueHasChanged = !_.isEqual(oldValue, newValue);
30467                if (valueHasChanged) {
30468                    
30469                    this._notifyDependants();
30470                    this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "data", oldValue, newValue);
30471                }
30472            }
30473        },
30474
30475        
30476        dataSourceType : {
30477            get : function () {
30478                return this.getAttribute("dataSourceType");
30479            },
30480            set : function (newValue) {
30481                var oldValue = this.jsonModel.dataSourceType;
30482                this.jsonModel.dataSourceType = newValue;
30483                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "dataSourceType", oldValue, newValue);
30484            }
30485        },
30486
30487        
30488        width : {
30489            get : function () {
30490                return this.getAttribute("width");
30491            },
30492
30493            set : function (newValue) {
30494                this.jsonModel.width = newValue;
30495            }
30496        },
30497        
30498        height : {
30499            get : function () {
30500                return this.getAttribute("height");
30501            },
30502
30503            set : function (newValue) {
30504                this.jsonModel.height = newValue;
30505            }
30506        },
30507        
30508        xAxisTitle : {
30509            get : function () {
30510                return this.getAttribute("xAxisTitle");
30511            },
30512            set : function (newValue) {
30513                this.jsonModel.chartType = newValue;
30514            }
30515        },
30516        
30517        yAxisTitle : {
30518            get : function () {
30519                return this.getAttribute("yAxisTitle");
30520            },
30521            set : function (newValue) {
30522                this.jsonModel.chartType = newValue;
30523            }
30524        },
30525        
30526        chartType : {
30527            get : function () {
30528                return this.getAttribute("chartType");
30529            },
30530            set : function (newValue) {
30531                var oldValue = this.jsonModel.chartType;
30532                this.jsonModel.chartType = newValue;
30533                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "chartType", oldValue, newValue);
30534            }
30535        },
30536        
30537        repeatableItem : {
30538            get : function () {
30539                return this.getAttribute("repeatableItem");
30540            },
30541            set : function (newValue) {
30542                this.jsonModel.repeatableItem = newValue;
30543            }
30544        },
30545        
30546        xExp : {
30547            get : function () {
30548                return this.getAttribute("xExp");
30549            },
30550            set : function (newValue) {
30551                this.jsonModel.xExp = newValue;
30552            }
30553        },
30554        
30555        reducerXFunction : {
30556            get : function () {
30557                return this.getAttribute("reducerXFunction");
30558            },
30559            set : function (newValue) {
30560                this.jsonModel.reducerXFunction = newValue;
30561                if (newValue !== 'none') {
30562                    this.jsonModel.reducerYFunction = 'none';
30563                }
30564            }
30565        },
30566        
30567        yExp : {
30568            get : function () {
30569                return this.getAttribute("yExp");
30570            },
30571            set : function (newValue) {
30572                this.jsonModel.yExp = newValue;
30573            }
30574        },
30575        
30576        reducerYFunction : {
30577            get : function () {
30578                return this.getAttribute("reducerYFunction");
30579            },
30580            set : function (newValue) {
30581                this.jsonModel.reducerYFunction = newValue;
30582                if (newValue !== 'none') {
30583                    this.jsonModel.reducerXFunction = 'none';
30584                }
30585            }
30586        },
30587        
30588        innerRadius : {
30589            get : function () {
30590                return this.getAttribute("innerRadius");
30591            },
30592            set : function (newValue) {
30593                this.jsonModel.innerRadius = newValue;
30594            }
30595        },
30596        
30597        lineColor : {
30598            get : function () {
30599                return this.getAttribute("lineColor");
30600            },
30601            set : function (newValue) {
30602                this.jsonModel.lineColor = newValue;
30603            }
30604        },
30605        
30606        pointColor : {
30607            get : function () {
30608                return this.getAttribute("pointColor");
30609            },
30610            set : function (newValue) {
30611                this.jsonModel.pointColor = newValue;
30612            }
30613        },
30614        
30615        areaColor : {
30616            get : function () {
30617                return this.getAttribute("areaColor");
30618            },
30619            set : function (newValue) {
30620                this.jsonModel.areaColor = newValue;
30621            }
30622        },
30623        
30624        tooltipHtml : {
30625            get : function () {
30626                return this.getAttribute("tooltipHtml");
30627            },
30628            set : function (newValue) {
30629                this.jsonModel.tooltipHtml = newValue;
30630            }
30631        },
30632        
30633        showLegends : {
30634            get : function () {
30635                return this.getAttribute("showLegends");
30636            },
30637            set : function (newValue) {
30638                this.jsonModel.showLegends = newValue;
30639            }
30640        },
30641        
30642        legendPosition : {
30643            get : function () {
30644                return this.getAttribute("legendPosition");
30645            },
30646            set : function (newValue) {
30647                this.jsonModel.legendPosition = newValue;
30648            }
30649        }
30650    });
30651
30652    GuideChart.addMixins([
30653        guidelib.model.mixin.AddDependencyMgmt
30654    ]);
30655}(_, guidelib));
30656(function (_, guidelib) {
30657    
30658    var GuideInstanceManager = guidelib.model.GuideInstanceManager = guidelib.model.GuideNode.extend({
30659        msClassName : "guideInstanceManager",
30660        initialize : function () {
30661            GuideInstanceManager._super.initialize.call(this);
30662            this._instances = [];
30663            this.dependants = [];
30664            this.deafen = false; 
30665            this._bindPending = true;
30666        },
30667
30668        _postInitializeBinding : function () {
30669            
30670            
30671            
30672            if (!this._bindPending) {
30673                return;
30674            } else {
30675                this._bindPending = false; 
30676            }
30677            
30678            
30679            
30680            
30681            
30682            
30683            var instance = this._instances[this.instanceCount - 1];
30684            if (!instance) {
30685                this.logger().log("There was no instance found for InstanceManager at postInitialize:" + this.somExpression);
30686            }
30687            if (instance.bindNode && instance.bindNode.instanceManager) {
30688                this.bindNode = instance.bindNode.instanceManager;
30689                this.bindNode.parent.on(xfalib.script.XfaModelEvent.CHILD_ADDED, this);
30690                this.bindNode.parent.on(xfalib.script.XfaModelEvent.CHILD_REMOVED, this);
30691            }
30692        },
30693
30694        _unloadModel : function () {
30695            var instance = this._instances[this.instanceCount - 1];
30696
30697            if (instance.bindNode && instance.bindNode.instanceManager) { 
30698                this.bindNode.parent.off(xfalib.script.XfaModelEvent.CHILD_ADDED, this);
30699                this.bindNode.parent.off(xfalib.script.XfaModelEvent.CHILD_REMOVED, this);
30700            }
30701
30702            GuideInstanceManager._super._unloadModel.call(this);
30703        },
30704
30705        
30706        handleEvent : function (event) {
30707            if (!this.deafen && event instanceof xfalib.script.XfaModelEvent) {
30708                switch (event.name) {
30709                    case xfalib.script.XfaModelEvent.CHILD_ADDED:
30710                        var addedInstance = event.newText;
30711                        if (addedInstance.instanceManager == this.bindNode) {
30712                            this._insertInstance(addedInstance.instanceIndex, addedInstance);
30713                        }
30714                        break;
30715                    case xfalib.script.XfaModelEvent.CHILD_REMOVED:
30716                        var removedInstance = event.prevText;
30717                        if (removedInstance.instanceManager == this.bindNode) {
30718                            this._removeInstance(removedInstance.instanceIndex, false);
30719                        }
30720                        break;
30721                    case xfalib.script.XfaModelEvent.CHILD_MOVED:
30722                        this.logger().log("CHILD_REMOVED should never be dispatched. It's achieved via ad and remove child.");
30723                        break;
30724                    default:
30725                        
30726                        break;
30727                }
30728            }
30729        },
30730
30731        _instanceTemplate : function () {
30732            return this._guide()._modelTemplateCacheStore.cloneJsonTemplate(this.jsonModel.instanceTemplateId);
30733        },
30734
30735        
30736        addInstance : function (addedXfaInstance) {
30737            return this._insertInstance(undefined, addedXfaInstance);
30738        },
30739
30740        
30741        addInstances : function (instancesConfig, addedXfaInstances) {
30742            var instanceCount = instancesConfig.instanceCount,
30743                instancesToAdd, availableInstances;
30744            if (this.maxOccur == -1) {
30745                instancesToAdd = instanceCount;
30746            }else {
30747                availableInstances = this.maxOccur - this.instanceCount;
30748                
30749                instancesToAdd = instanceCount > availableInstances ? availableInstances : instanceCount;
30750            }
30751            var oChildsAdded = [];
30752            for (var i = 0; i < instancesToAdd ; i++) {
30753                oChildsAdded.push(this._insertInstance(undefined, addedXfaInstances, true));
30754            }
30755            var oParentContainer = this.parent;
30756            oParentContainer._triggerEvent(guidelib.event.GuideModelEvent.MULTIPLE_CHILD_ADDED, "multipleChildAdded",
30757                null, oChildsAdded);
30758        },
30759
30760        _manageChild : function (oCreatedChild, nIndex) {
30761            oCreatedChild._instanceManager = this;
30762            if (nIndex === undefined) {
30763                this._instances.push(oCreatedChild);
30764            } else {
30765                this._instances.splice(nIndex, 0, oCreatedChild);
30766            }
30767        },
30768
30769        
30770        _insertInstance : function (nIndex, addedXfaInstance, muteEvent) {
30771            if ((+this.maxOccur >= 0) && (+this.maxOccur == this.instanceCount)) {
30772                return null;
30773            }
30774            
30775            if (nIndex !== undefined && nIndex > +this.maxOccur && +this.maxOccur > -1) {
30776                return null;
30777            }
30778
30779            var addedBindNode = addedXfaInstance;
30780            if (addedXfaInstance && this.bindNode == null) {
30781                this.logger().error("AF", "Invalid argument addedXfaInstance.");
30782            }
30783            if (!addedXfaInstance && this.bindNode) {
30784                this.deafen = true;
30785                try {
30786                    
30787                    addedBindNode = this.bindNode.insertInstance(nIndex);
30788                }
30789                finally {
30790                    this.deafen = false;
30791                }
30792            }
30793            var template = this._instanceTemplate();
30794            
30795            
30796            
30797            var clonedJson = {};
30798            var uniquePrefix = this.guideUtil.generateUID(),
30799                that = this;
30800            this.copyObject(template, clonedJson,
30801                {
30802                    transformMaps : {
30803                        "id" : function (srcValue, options, parentObj) {
30804                            return uniquePrefix + "__" + parentObj.templateId;
30805                        },
30806
30807                        
30808                        
30809                        "bindRef" : function (originalBindRef, options, src) {
30810                            if (addedBindNode != null && that.bindNode != null) {
30811                                if (template.bindRef === originalBindRef) {
30812                                    return addedBindNode.somExpression;
30813                                } else if (originalBindRef.substring(0, template.bindRef.length) === template.bindRef) {
30814                                    return originalBindRef.replace(template.bindRef, addedBindNode.somExpression);
30815                                }
30816                            }
30817
30818                            return originalBindRef;
30819                        }
30820                    }
30821                }
30822            );
30823            
30824            var options = ((addedBindNode && this.bindNode) ? {bindNode : addedBindNode} : null);
30825            if (this.options._guideContainer) {
30826                options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
30827            }
30828            var oChildAdded = guidelib.model.GuideModelRegistry.prototype.createModel(clonedJson, options);
30829            if (oChildAdded != null) {
30830                
30831                
30832                
30833                this._manageChild(oChildAdded, nIndex);
30834                var oParentContainer = this.parent;
30835                if (oParentContainer != null) {
30836                    if (this._instances.length > 0) {
30837                        
30838                        
30839                        
30840                        
30841                        nIndex = nIndex !== undefined ? nIndex : this._instances.length - 1 ;
30842                        if(nIndex === 0 ) {
30843                            
30844                            
30845                            
30846                            oParentContainer._addChildAt(oChildAdded, oParentContainer._children.indexOf(this) + 1, muteEvent);
30847                        } else {
30848                            var lastInstanceIndex = oParentContainer._children.indexOf(this._instances[nIndex - 1]);
30849                            oParentContainer._addChildAt(oChildAdded, lastInstanceIndex + 1, muteEvent);
30850                        }
30851                    } else {
30852                        
30853                        
30854                        
30855                        
30856                        oParentContainer._addChildAt(oChildAdded, oParentContainer._children.indexOf(this) + 1, muteEvent);
30857                    }
30858                    var guideStateConstants = guidelib.model.GuideSchema.prototype.GuideStateConstants;
30859                    var dataUtils = this._guide().internal.liveDataUtils;
30860                    if (this._isDataNodeUpdateRequired(oChildAdded)) {
30861                        var parentNode = dataUtils.getParentDataNode(this._getDataContext(oChildAdded), true, {});
30862                        var index = dataUtils._convertModelIndexToDataIndex(oChildAdded.instanceIndex);
30863                        var node = dataUtils._getElement(parentNode, oChildAdded._getDataNodeName(), {index : index});
30864                        
30865                        
30866                        if (!node || (node && !(oChildAdded.instanceIndex == this._instances.length - 1))) {
30867                            var dataNode = dataUtils.insertNode(parentNode, oChildAdded._getDataNodeName(), oChildAdded.instanceIndex);
30868                            if (!dataNode) {
30869                                this.logger().warn("AF", "Unable to store the data of the element");
30870                            }
30871                        }
30872                    }
30873                }
30874                this._execExpressions(nIndex);
30875                return oChildAdded;
30876            } else {
30877                this.logger().log("guide", "insertInstance could not create child" + this.jsonModel.instanceTemplateId);
30878            }
30879            return null;
30880        },
30881
30882        
30883        insertInstance : function (nIndex) {
30884            return this._insertInstance(nIndex);
30885        },
30886
30887        
30888        removeInstance : function (index) {
30889            this._removeInstance(index, true);
30890        },
30891
30892        
30893        _removeInstance : function (index, removeXfaInstance) {
30894            
30895            if (this.instanceCount == 0 || this.minOccur >= this.instanceCount) {
30896                return;
30897            }
30898
30899            if (index >= +this.instanceCount) {
30900                return;
30901            }
30902
30903            if (removeXfaInstance && this.bindNode) {
30904                this.deafen = true;
30905                try {
30906                    this.bindNode.removeInstance(index);
30907                }
30908                finally {
30909                    this.deafen = false;
30910                }
30911            }
30912            
30913            
30914            
30915            var oChild =  this._instances[index];
30916            var dataUtils = this._guide().internal.liveDataUtils;
30917            if (this._isDataNodeUpdateRequired(oChild)) {
30918                var parentNode = dataUtils.getParentDataNode(this._getDataContext(oChild));
30919                dataUtils.removeChild(parentNode, oChild._getDataNodeName(), oChild.instanceIndex);
30920            }
30921            this._instances.splice(index, 1);
30922            var parent = oChild.parent;
30923            parent._removeChild(oChild);
30924            this._execExpressions(index);
30925        },
30926
30927        _isDataNodeUpdateRequired : function (child) {
30928            var guideStateConstants = guidelib.model.GuideSchema.prototype.GuideStateConstants,
30929                guide = guideBridge._guide;
30930            return guide && guide.getGuideState() === guideStateConstants.GUIDE_STATE_MODEL_COMPLETE
30931                && child._hasLazyDescendant;
30932        },
30933
30934        _getDataContext : function (model) {
30935            var dataUtils = this._guide().internal.liveDataUtils,
30936                elementContext = dataUtils._getXpathContext(model),
30937                xmlContext = dataUtils._getDataContext(model, elementContext.bound,
30938                    elementContext.unBound),
30939                xpath = xmlContext.indexedXpath;
30940            xpath = dataUtils.addIndexToPath(xpath, model.instanceIndex);
30941            return {
30942                indexedXpath : xpath,
30943                xmlSec : xmlContext.xmlSec
30944            };
30945        },
30946
30947        _getInstanceName : function () {
30948            return this.jsonModel.instanceName;
30949        },
30950
30951        _instanceIsTableRow : function () {
30952            
30953            return this._instanceTemplate()["guideNodeClass"] === "guideTableRow";
30954        },
30955
30956        
30957        _execExpressions : function (modifiedIndex) {
30958            try {
30959                
30960                this._notifyDependants();
30961                
30962                
30963                for (var i = modifiedIndex; i < this.instances.length; i++) {
30964                    this.instances[i]._notifyDependants();
30965                }
30966                
30967                this._guide().runPendingExpressions();
30968            } catch (ex) {
30969                this.logger().error("guide", ex.message);
30970            }
30971        }
30972
30973    });
30974    GuideInstanceManager.defineProps({
30975        
30976        minOccur : {
30977            get : function () {
30978                var isTableRow = this._instanceIsTableRow();
30979                
30980                if (isTableRow) {
30981                    return ((+this.jsonModel.minOccur) || 1);
30982                } else {
30983                    return this.getOrElse(this.jsonModel.minOccur, 1);
30984                }
30985            }
30986        },
30987
30988        
30989        maxOccur : {
30990            get : function () {
30991                return this.getOrElse(this.jsonModel.maxOccur, 1);
30992            }
30993        },
30994
30995        initialOccur : {
30996            get : function () {
30997                return this.getOrElse(this.jsonModel.initialOccur, 1);
30998            }
30999        },
31000
31001        
31002        instanceTemplateId : {
31003            get : function () {
31004                return this.jsonModel.instanceTemplateId;
31005            }
31006        },
31007
31008        
31009        instanceCount : {
31010            get : function () {
31011                var context = this._guide()._currentContext;
31012                if (context && context.managedExp) {
31013                    
31014                    this._addDependant(context.contextNode, context.expression);
31015                }
31016                return this._instances.length ;
31017            }
31018        },
31019
31020        
31021        repeatable : {
31022            get : function () {
31023                return (this.minOccur != 1 || this.maxOccur != 1);
31024            }
31025        },
31026        
31027        instances : {
31028            
31029            get : function () {
31030                var context = this._guide()._currentContext;
31031                if (context && context.managedExp) {
31032                    
31033                    this._addDependant(context.contextNode, context.expression);
31034                }
31035                return (this._instances || []).slice(0);
31036            }
31037        }
31038    });
31039
31040    GuideInstanceManager.addMixins([
31041        guidelib.model.mixin.AddDependencyMgmt
31042    ]);
31043})(_, guidelib);
31044(function (_, guidelib) {
31045
31046    
31047    var Field = guidelib.model.Field = guidelib.model.Scriptable.extend({
31048        msClassName : "field",
31049        
31050        _runValidation : true,
31051        initialize : function () {
31052            Field._super.initialize.call(this);
31053            this.jsonModel["{default}"] = this.getOrElse(this.jsonModel, "{default}", this.jsonModel._value);
31054            this.isValid = true;
31055            this.forceErrorShow = false;
31056            
31057            this._bParentValidationsDisabled = false;
31058            
31059            this._validationsDisabled = false;
31060            
31061            this._failedTest = null;
31062
31063            
31064            this._errorText = "";
31065
31066            var effectiveBindRef = this._getEffectiveBindRef();
31067            
31068            if (this.isGlobal || (this._guide() && this._guide().internal.liveModel.isLive(effectiveBindRef))) {
31069                this._guide().internal.liveModel.add(effectiveBindRef, this);
31070            }
31071        },
31072        _postInitialize: function() {
31073            Field._super._postInitialize.call(this);
31074            if (this.getAttribute("dorExclusion") !== null && this.jsonModel.visible === false) {
31075                if ((this._guide().getAttribute("excludeFromDoRIfHidden") === "true")
31076                    ||
31077                    (this._guide().print &&
31078                        this._guide().print["excludeFromDoRIfHidden"] === "true")) {
31079                    this.dorExclusion = true;
31080                }
31081            }
31082        },
31083        _unloadModel : function () {
31084            var effectiveBindRef = this.bindRef || this.getAttribute("name");
31085            if (this.isGlobal || this._guide().internal.liveModel.isLive(effectiveBindRef)) {
31086                this._guide().internal.liveModel.remove(effectiveBindRef, this);
31087            }
31088            Field._super._unloadModel.call(this);
31089        },
31090
31091        _collectExpressions : function () {
31092            Field._super._collectExpressions.apply(this);
31093            if (this.calcExp) {
31094                this._compiledExpressions.calcExp = this._compileExpression(this.calcExp, "value");
31095            }
31096            if (this.validateExp) {
31097                
31098                this._compiledScripts.validateExp = this._compileExpression(this.validateExp, null);
31099            }
31100            if (this.valueCommitScript) {
31101                
31102                
31103                this._compiledScripts.valueCommitScript = this._compileExpression(this.valueCommitScript, null);
31104            }
31105            
31106            this._compiledScripts.validateAllExp = this._compileExpression("this._runTests()", null);
31107        },
31108
31109        _handleXfaModelChanged : function (event) {
31110            if (event._property === "rawValue") {
31111                this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value",
31112                    event.prevText, event.newText);
31113            } else if (event._property == "ClearError" || event._property == "ValidationState") {
31114                
31115                this._guide().queueExpressions(this, ["validateAllExp"]);
31116            } else {
31117                Field._super._handleXfaModelChanged.call(this, event);
31118            }
31119        },
31120
31121        
31122        
31123        validate : function (errorList) {
31124            
31125            if (!this.visible) {
31126                return true;
31127            }
31128            if (_.isUndefined(errorList)) {
31129                errorList = [];
31130            }
31131            var status = true;
31132            this._runTests(true);
31133            if (this._errorText) {
31134                errorList.push({
31135                    som : this.somExpression,
31136                    errorText : this._errorText
31137                });
31138                status = false;
31139            }
31140            return status;
31141        },
31142
31143        _getTypedValue : function (value) {
31144            if (this.checkIfNull(value)) {
31145                return null;
31146            }
31147            return value + "";
31148        },
31149
31150        _getFormattedValue : function (value) {
31151            if (_.isUndefined(value) || value === null || value === "") {
31152                return null;
31153            }
31154
31155            var picture = this.jsonModel.displayPictureClause;
31156            
31157            if (picture) {
31158                try {
31159                    
31160                    var formattedValue = xfalib.ut.PictureFmt.format(value + "", picture, null, true);
31161                    
31162                    return formattedValue != null && formattedValue !== "" ? formattedValue : value;
31163                } catch (exception) {
31164                    
31165                }
31166            }
31167            return value;
31168        },
31169
31170        _getValue : function () {
31171            if (this.bindNode) {
31172                return this.bindNode.rawValue;
31173            }
31174            return this._getTypedValue(this.jsonModel._value);
31175        },
31176
31177        _triggerDisplayFormatChange : function () {
31178            var currValue = this._getValue();
31179            this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value",
31180                currValue, this._getFormattedValue(currValue));
31181        },
31182
31183        
31184        checkIfNull : function (value) {
31185            return value == null || value === ""; 
31186        },
31187
31188        
31189        isEmpty : function () {
31190            return this.checkIfNull(this.value);
31191        },
31192
31193        _setXFAValue : function (value) {
31194            this.bindNode.rawValue = value;
31195        },
31196
31197        
31198        _setXFAMandatory : function (value) {
31199            
31200            
31201            var convertor = this._guide()._guideSchema.getConvertor("mandatory");
31202            if (convertor) {
31203                
31204                
31205                this.bindNode.validate.nullTest = convertor.guideToXfa.apply(this, [!!value]);
31206            }
31207        },
31208
31209        _setGuideValue : function (value) {
31210            this.jsonModel._value = (value === undefined || value === null) ? null : value;
31211        },
31212
31213        _runMandatoryTest : function () {
31214            var currValue = this._getValue(),
31215                isNull = this.checkIfNull(currValue);
31216            return !isNull;
31217        },
31218
31219        _runValidatePictureTest : function () {
31220            var value = this._getValue(),
31221                validateFlag = true,
31222                regex;
31223            if (!this.checkIfNull(value) && this.validatePictureClause) {
31224                
31225                try {
31226                    value = xfalib.ut.PictureFmt.format(value + "", this.validatePictureClause, null, false);
31227                } catch (exception) {
31228                    
31229                    this.logger().log("AF", exception);
31230                    
31231                    if (exception.indexOf("Invalid picture clause") !== -1) {
31232                        value = undefined;
31233                    } else {
31234                        value = null;
31235                    }
31236                }
31237            }
31238            if (_.isUndefined(value)) {
31239                try {
31240                    
31241                    regex = new RegExp(this.validatePictureClause);
31242                    if (regex) {
31243                        validateFlag = regex.test(this._getValue());
31244                    }
31245                } catch (exception) {
31246                    
31247                    this.logger().error("AF", "Invalid Regular Expression" + exception);
31248                    validateFlag = false;
31249                }
31250            } else if (value === null) {
31251                validateFlag = false;
31252            }
31253
31254            return validateFlag;
31255        },
31256
31257        
31258        _runTests : function (forceRun) {
31259            
31260            var validFlag = true,
31261                prevErrorText = this._errorText,
31262                prevValidationState = this.validationState,
31263                obj = {
31264                    'validFlag' : validFlag,
31265                    'forceRun' : forceRun
31266                };
31267
31268            if (this.validationsDisabled === true) {
31269                
31270                
31271                return true;
31272            }
31273
31274            this._runValidations(obj);
31275            validFlag = obj.validFlag;
31276
31277            if (validFlag) {
31278                this._errorText = "";
31279                this.validationState = true;
31280                
31281                this._failedTest = null;
31282            } else {
31283                this.validationState = false;
31284            }
31285            
31286            if ((prevErrorText !== this._errorText) || (prevValidationState !== this.validationState) || forceRun) {
31287                
31288                if (forceRun) {
31289                    this.forceErrorShow = true;
31290                }
31291                this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
31292                    "validationStatus", this.validationState, this._errorText);
31293            }
31294
31295            return this.validationState;
31296        },
31297
31298        playJson : function (pJsonModel) {
31299            var currValue = pJsonModel._value,
31300                _guide = this._guide();
31301            
31302            if (this.valueCommitScript && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_PREFILL) && currValue) {
31303                
31304                _guide.queueExpressions(this, ["valueCommitScript"]);
31305            }
31306            this._setGuideValue(pJsonModel._value);
31307        },
31308
31309        
31310        _runValidations : function (obj) {
31311            var isRegex = false,
31312                INVALID_PICTURE_CLAUSE_LIST = ["date.default{}", "date.short{}", "date.medium{}",
31313                    "date.long{}", "date.full{}", "num.percent{}", "num.decimal{}", "num.currency{}"];
31314            if (this.bindNode) {
31315                if (this.validatePictureClause && (this.value || this.value === 0)) {
31316                    
31317                    
31318                    try {
31319                        xfalib.ut.PictureFmt.format(this.value + "", this.validatePictureClause, null, false);
31320                    } catch (exception) {
31321                        if (INVALID_PICTURE_CLAUSE_LIST.indexOf(this.validatePictureClause) >= 0) {
31322                            isRegex = false;
31323                        } else if (exception.indexOf("Invalid picture clause") !== -1) {
31324                            isRegex = true;
31325                        }
31326                    }
31327                }
31328                if (isRegex) {
31329                    try {
31330                        
31331                        var regex = new RegExp(this.validatePictureClause);
31332                        if (regex) {
31333                            obj.validFlag = regex.test(this._getValue());
31334                        }
31335                    } catch (exception) {
31336                        this.logger().error("AF", "Error in running regular expression" + exception);
31337                        obj.validFlag = false;
31338                    }
31339                    if (!obj.validFlag) {
31340                        this.bindNode._setErrorData("formatTest", this.getOrElse(this.bindNode.validate.formatTest, this.bindNode._defaults.validate.formatTest), this.bindNode.formatMessage);
31341                        this._errorText = this.bindNode._errorText;
31342                        xfalib.ut.XfaUtil.prototype._triggerOnBridge("elementValidationStatusChanged", this.bindNode, "validationStatus", false, true);
31343                        this.bindNode.execEvent("validationState");
31344                    }
31345                } else {
31346                    if (obj.forceRun) {
31347                        this.bindNode.execValidate();
31348                    }
31349                    this._errorText = this.bindNode._errorText;
31350                    if (this._errorText) {
31351                        obj.validFlag = false;
31352                    }
31353                }
31354                
31355                this._failedTest = this.bindNode._mFailedValTest;
31356            } else {
31357                
31358                if (this.mandatory) {
31359                    obj.validFlag = this._runMandatoryTest();
31360                    if (!obj.validFlag) {
31361                        this._errorText = this.mandatoryMessage;
31362                        this._failedTest = this.guideUtil.MANDATORY_TEST;
31363                    }
31364                }
31365                if (obj.validFlag && this.validatePictureClause && !this.checkIfNull(this.value)) {
31366                    obj.validFlag = this._runValidatePictureTest();
31367                    if (!obj.validFlag) {
31368                        this._errorText = this.validatePictureClauseMessage;
31369                        this._failedTest = this.guideUtil.FORMAT_TEST;
31370                    }
31371                }
31372            }
31373
31374            if (obj.validFlag && this.validateExp) {
31375                obj.validFlag = this.executeExpression("validateExp");
31376                if (!obj.validFlag) {
31377                    this._errorText = this.validateExpMessage;
31378                    this._failedTest = this.guideUtil.SCRIPT_TEST;
31379                }
31380            }
31381        },
31382
31383        _collectValues : function (keyValue) {
31384            
31385            keyValue[this.name] = this.value;
31386        },
31387
31388        
31389        resetData : function () {
31390            this._runValidation = false;
31391            this.value = this.jsonModel["{default}"];
31392            this._runValidation = true;
31393            
31394            this._errorText = "";
31395            this.validationState = true;
31396            this._failedTest = null;
31397            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_RESET,
31398                "validationStatus", this.validationState, this._errorText);
31399        },
31400
31401        _preserveLazyValue : function () {
31402            return !(_.contains(['guideButton', 'guideTextDraw', 'guideAdobeSignBlock'], this.className) || this._isXfaNode());
31403        },
31404
31405        
31406        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31407            if (this._preserveLazyValue()) {
31408                var dataUtils = this._guide().internal.liveDataUtils,
31409                    dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar,
31410                        unBound_indexedXpathSoFar),
31411                    isRichText = this instanceof guidelib.model.GuideTextBox && this.allowRichText,
31412                    setValue = isRichText ? dataUtils.setRichTextValue : dataUtils.setDataValue;
31413                setValue.apply(dataUtils, [dataContext.indexedXpath, dataContext.xmlSec,
31414                    !this.isEmpty(), this.isEmpty() ? "" : this.value]);
31415            }
31416        },
31417
31418        
31419        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
31420            if (this._preserveLazyValue()) {
31421                var dataUtils = this._guide().internal.liveDataUtils,
31422                    dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar,
31423                        unBound_indexedXpathSoFar),
31424                    isRichText = this instanceof guidelib.model.GuideTextBox && this.allowRichText,
31425                    getValue = isRichText ? dataUtils.getRichTextValue : dataUtils.getDataValue;
31426                var value = getValue.apply(dataUtils, [dataContext.indexedXpath, dataContext.xmlSec]);
31427                if (value != undefined) {
31428                    this.value = value;
31429                } else if (this.jsonModel && this.jsonModel._value) {
31430                    
31431                    var _guide = this._guide();
31432                    
31433                    if (this.valueCommitScript && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_PREFILL)) {
31434                        
31435                        _guide.queueExpressions(this, ["valueCommitScript"]);
31436                    }
31437                }
31438            }
31439        },
31440
31441        
31442        _allowEmptyValueString : function () {
31443            return false;
31444        },
31445
31446        markAsInvalid : function (errorText, shouldShowError) {
31447            shouldShowError = (typeof shouldShowError !== 'undefined') ? shouldShowError : false;
31448            this.validationState = false;
31449            if (!errorText) {
31450                errorText = this.validateExpMessage;
31451            }
31452            if(shouldShowError) {
31453                this._errorText = errorText;
31454                this.forceErrorShow = true;
31455            }
31456            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
31457                "validationStatus", this.validationState, errorText);
31458        },
31459
31460        
31461        _isStateOverridden : function (property) {
31462            return this.getOrElse(this.jsonModel.stateOverrides, property, null) != null;
31463        }
31464    });
31465
31466    Field.defineProps({
31467        calcExp : {
31468            get : function () {
31469                return this.getAttribute("calcExp");
31470            }
31471        },
31472
31473        
31474        isGlobal : {
31475            get : function () {
31476                return this.getAttribute('isGlobal') === "true";
31477            }
31478        },
31479
31480        
31481        title : {
31482            get : function () {
31483                return this.getAttribute("jcr:title");
31484            },
31485            set : function (title) {
31486                this.setAttribute(title, "jcr:title");
31487            }
31488        },
31489
31490        valueCommitScript : {
31491            get : function () {
31492                return this.getAttribute("valueCommitScript");
31493            }
31494        },
31495
31496        validateExp : {
31497            get : function () {
31498                return this.getAttribute("validateExp");
31499            }
31500        },
31501
31502        
31503        placeholderText : {
31504            get : function () {
31505                return this.getAttribute("placeholderText");
31506            }
31507        },
31508
31509        
31510        value : {
31511            get : function () {
31512                var context = this.getOrElse(this._guide(), "_currentContext", null);
31513                if (context && context.managedExp
31514                    
31515                    && !(context.contextNode === this
31516                    && context.expression === "calcExp")) {
31517                    
31518                    this._addDependant(context.contextNode, context.expression);
31519                }
31520                return this._getValue();
31521            },
31522            set : function (newValue) {
31523                var oldValue = this._getValue(),
31524                    newTypedValue = this._getTypedValue(newValue),
31525                    _guide = this._guide();
31526                
31527                if (this._allowEmptyValueString() && newValue === "") {
31528                    newTypedValue = "";
31529                }
31530
31531                
31532                if (newTypedValue !== undefined && !(this.checkIfNull(newTypedValue) && this.checkIfNull(oldValue))
31533                    && (newTypedValue !== oldValue)) {
31534                    if (this.bindNode) {
31535                        this._setXFAValue(newTypedValue);
31536                    } else if (this.jsonModel._value !== newValue) {
31537                        this._setGuideValue(newTypedValue);
31538                    }
31539                    if (_guide && _guide.version.isOn(_guide.version.Flags.RUN_VALUE_COMMMIT_ON_SCRIPT_CHANGE)) {
31540                        var context = _guide._currentContext,
31541                            contextNode = this.getOrElse(context, "contextNode", null),
31542                            contextExpression = this.getOrElse(context, "expression", null);
31543                        if (!context || contextNode != this || contextExpression != "valueCommitScript") {
31544                            
31545                            _guide.queueExpressions(this, ["valueCommitScript"]);
31546                        }
31547                    }
31548                    
31549                    this._notifyDependants();
31550                    
31551                    if (this._runValidation && _guide) {
31552                        _guide.queueExpressions(this, ["validateAllExp"]);
31553                    }
31554                    this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
31555                    
31556                    
31557                    if (!this.bindNode || (this.bindNode && this.getAttribute("html5Type") !== undefined)) {
31558                        this._triggerDisplayFormatChange();
31559                    }
31560                }
31561            }
31562        },
31563
31564        
31565        formattedValue : {
31566            get : function () {
31567                var value;
31568                if (this.bindNode) {
31569                    value = this.bindNode.formattedValue;
31570                } else {
31571                    value = this._getFormattedValue(this._getValue());
31572                }
31573                return value;
31574            }
31575        },
31576
31577        
31578        displayPictureClause : {
31579            get : function () {
31580                return this.getAttribute("displayPictureClause");
31581            }
31582        },
31583
31584        
31585        validatePictureClause : {
31586            get : function () {
31587                if (this.jsonModel.displayIsSameAsValidate) {
31588                    return this.displayPictureClause;
31589                }
31590                return this.getAttribute("validatePictureClause");
31591            }
31592        },
31593
31594        
31595        editPictureClause : {
31596            get : function () {
31597                if (this.jsonModel.isEditSameAsDisplayPattern) {
31598                    return this.displayPictureClause;
31599                }
31600                return this.getAttribute("editPictureClause");
31601            }
31602        },
31603
31604        
31605        isEditPictureClausePresent : {
31606            get : function () {
31607                return typeof this.editPictureClause !== 'undefined';
31608            }
31609        },
31610
31611        
31612        mandatory : {
31613            get : function () {
31614                return this.getAttribute("mandatory");
31615            },
31616
31617            set : function (newValue) {
31618                var oldValue = this.getAttribute("mandatory");
31619                if (newValue !== undefined && oldValue !== newValue) {
31620                    if (this.bindNode) {
31621                        this._setXFAMandatory(newValue);
31622                    } else {
31623                        
31624                        this.jsonModel.mandatory = !!newValue;
31625                    }
31626                    
31627                    this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, "mandatory", oldValue, newValue);
31628                }
31629            }
31630        },
31631
31632        
31633        mandatoryMessage : {
31634            get : function () {
31635                return this.getAttribute("mandatoryMessage");
31636            }
31637        },
31638
31639        
31640        validateExpMessage : {
31641            set : function (message) {
31642                
31643                if (this.isValid) {
31644                    this.jsonModel.validateExpMessage = message;
31645                } else {
31646                    this.setAttribute(message, "validateExpMessage");
31647                }
31648            },
31649            get : function () {
31650                return this.getAttribute("validateExpMessage");
31651            }
31652        },
31653
31654        
31655        validatePictureClauseMessage : {
31656            get : function () {
31657                return this.getAttribute("validatePictureClauseMessage");
31658            }
31659        },
31660
31661        
31662        validationState : {
31663            get : function () {
31664                return this.isValid;
31665            },
31666            set : function (newValue) {
31667                var oldVal = this.isValid;
31668                if (oldVal != newValue) {
31669                    this.isValid = newValue;
31670                    this._triggerOnBridge("elementValidationStatusChanged", this,
31671                        "validationStatus", oldVal, newValue);
31672                }
31673            }
31674        },
31675        
31676        width : {
31677            get : function () {
31678                return this.getAttribute("width");
31679            },
31680
31681            set : function (newValue) {
31682                this.jsonModel.width = newValue;
31683            }
31684        },
31685        
31686        height : {
31687            get : function () {
31688                return this.getAttribute("height");
31689            },
31690
31691            set : function (newValue) {
31692                this.jsonModel.height = newValue;
31693            }
31694        }
31695    });
31696
31697    Field.addMixins([
31698        guidelib.model.mixin.AddDependencyMgmt,
31699        guidelib.model.mixin.ValidationsDisabled
31700    ]);
31701}(_, guidelib));
31702
31703(function (_, guidelib) {
31704    
31705    var GuideButton = guidelib.model.GuideButton = guidelib.model.Field.extend({
31706        msClassName : "guideButton",
31707        defaultClickExpressions : {
31708            "moveNext" : "window.guideBridge.setFocus(this.panel.somExpression, 'nextItem', true)",
31709            "movePrev" : "window.guideBridge.setFocus(this.panel.somExpression, 'prevItem', true)"
31710        },
31711        defaultNavigationExpressions : {
31712            "moveNext" : "this.visible=this.panel.navigationContext.hasNextItem",
31713            "movePrev" : "this.visible=this.panel.navigationContext.hasPrevItem"
31714        },
31715
31716        _collectExpressions : function () {
31717            GuideButton._super._collectExpressions.apply(this);
31718            if (this.clickExp) {
31719                this._compiledScripts["clickExp"] = this._compileExpression(this.clickExp, null);
31720            } else if (this.targetVersion >= 1.1 && this.defaultClickExpressions[this.type]) {                  
31721                this.jsonModel.clickExp = this.defaultClickExpressions[this.type];                              
31722                this._compiledScripts["clickExp"] = this._compileExpression(this.clickExp, null);               
31723            }
31724            if (this.navigationChangeExp) {
31725                this._compiledScripts["navigationChangeExp"] = this._compileExpression(this.navigationChangeExp, null);
31726            } else if (this.targetVersion >= 1.1 &&  this.defaultNavigationExpressions[this.type]) {
31727                this.jsonModel.navigationChangeExp = this.defaultNavigationExpressions[this.type];
31728                this._compiledScripts["navigationChangeExp"] = this._compileExpression(this.navigationChangeExp, null);
31729            }
31730        },
31731
31732    });
31733
31734    GuideButton.defineProps({
31735        clickExp : {
31736            get : function () {
31737                return this.jsonModel.clickExp;
31738            }
31739        },
31740        navigationChangeExp : {
31741            get : function () {
31742                return this.jsonModel.navigationChangeExp;
31743            }
31744        },
31745        
31746        type : {
31747            get : function () {
31748                return this.getAttribute("type");
31749            }
31750        }
31751    });
31752})(_, guidelib);
31753
31754(function (_, guidelib) {
31755    var GuideListFileAttachmentButton = guidelib.model.GuideListFileAttachmentButton = guidelib.model.GuideButton.extend({
31756        msClassName : "guideListFileAttachmentButton",
31757        initialize : function () {
31758            
31759            if (_.isUndefined(this.jsonModel.clickExp)) {
31760                this.jsonModel.clickExp = "guideBridge._updateFileListing.call(this,this)";
31761
31762            }
31763            GuideListFileAttachmentButton._super.initialize.apply(this, arguments);
31764        }
31765    });
31766
31767})(_, guidelib);
31768(function (_, guidelib) {
31769    var GuideCompositeFieldItem = guidelib.model.GuideCompositeFieldItem = guidelib.model.Field.extend({
31770        msClassName : "GuideCompositeFieldItem"
31771    });
31772
31773    GuideCompositeFieldItem.defineProps({
31774        
31775        bindRef : {
31776            get : function () {
31777                if (this.parent && !this.parent._isXfaNode() && !_.isEmpty(this.parent.bindRef)) {
31778                    return this.parent.bindRef + '/' + this.getAttribute("name").replace(/\s+/g, '');
31779                } else {
31780                    return (this.getAttribute("bindRef") || "").replace(/\s+/g, '');
31781                }
31782            }
31783        }
31784    });
31785
31786})(_, guidelib);
31787(function (_, guidelib) {
31788    var GuideTextDraw = guidelib.model.GuideTextDraw = guidelib.model.Field.extend({
31789        msClassName : "guideTextDraw",
31790
31791        _valueEscapeRegex : new RegExp('\\$', 'g'),
31792
31793        
31794        _getValue : function () {
31795            if (this.bindNode) {
31796                return this.bindNode._getValue(null, true);
31797            }
31798            return this._getTypedValue(this.jsonModel._value);
31799        },
31800
31801        
31802        playJson : function (pJsonModel) {
31803            
31804            this._setGuideValue(this._floatingFieldResolutionFunction(pJsonModel));
31805        },
31806
31807        _allowEmptyValueString : function () {
31808            return true;
31809        },
31810
31811        _isFloatingField : function () {
31812            return this.documentFragmentVariables && this.documentFragmentVariables.length > 0;
31813        },
31814
31815        _floatingFieldResolutionFunction : function (jsonModel) {
31816            var resolvedValue = this.value,
31817                variableRegexMap = this._variableRegexMap,
31818                valueEscapeRegex = this._valueEscapeRegex,
31819                somExpression = this.somExpression,
31820                self = this,
31821
31822                
31823                variablesDefaultValue = [],
31824                documentFragmentVariables = this.documentFragmentVariables;
31825            if (jsonModel.documentFragmentVariables) {
31826                for (var index = 0 ; index < jsonModel.documentFragmentVariables.length ; index++) {
31827                    variablesDefaultValue[index] = jsonModel.documentFragmentVariables[index]._value;
31828                }
31829            }
31830            this.jsonModel.defaultValue = variablesDefaultValue;
31831            _.each(variableRegexMap, function (regexPattern, variableId) {
31832                var textVariable,
31833                    bindRef,
31834                    floatingFieldValue;
31835                textVariable = documentFragmentVariables.filter(function (variable) {
31836                    return variable.variableId === variableId;
31837                })[0];
31838                bindRef = textVariable.bindRef;
31839                if (!bindRef) {
31840                    bindRef = textVariable.name;
31841                }
31842                
31843                if (jsonModel && jsonModel.documentFragmentVariables && jsonModel.documentFragmentVariables.length > 0) {
31844                    var variableFromPlayJson = jsonModel.documentFragmentVariables.filter(function (variable) {
31845                        return variable.variableId === variableId;
31846                    })[0];
31847                    floatingFieldValue = variableFromPlayJson._value;
31848                } else {
31849                    floatingFieldValue = guidelib.util.GuideUtil.getValueForBindRefField(bindRef, somExpression, this._guide());
31850                }
31851                if (!floatingFieldValue) {
31852                    
31853                    floatingFieldValue = "";
31854                } else {
31855                    
31856                    
31857                    floatingFieldValue = floatingFieldValue.replace(valueEscapeRegex, '$$$$');
31858                }
31859                if (floatingFieldValue) {
31860                    var dataType = textVariable.dataType,
31861                        displayPattern = textVariable.displayPictureClause;
31862                    if (dataType === 'number' || dataType === 'integer') {
31863                        displayPattern = displayPattern ? displayPattern : 'num{zzz,zzz,zzz,zzz,zzz,zzz,zzz.zzzzzzzzzzzzzzz}';
31864                    } else if (dataType === 'date-time' || dataType === 'date') {
31865                        displayPattern = displayPattern ? displayPattern : 'date{' + guidelib.i18n.datePatterns.med + '}';
31866                    }
31867
31868                    if (displayPattern) {
31869                        if (floatingFieldValue.indexOf(',') !== -1) {
31870                            
31871                            var valArray = floatingFieldValue.split(','),
31872                            tmpValue = "";
31873                            valArray.forEach(function (val) {
31874                                tmpValue = tmpValue + guidelib.util.GuideUtil.formatValue(val, displayPattern, dataType) + ", " ;
31875                            });
31876                            floatingFieldValue = tmpValue.substr(0, tmpValue.length - 2);
31877                        } else {
31878                            floatingFieldValue = guidelib.util.GuideUtil.formatValue(floatingFieldValue, displayPattern, dataType);
31879                        }
31880                    }
31881                }
31882                resolvedValue = resolvedValue.replace(regexPattern, floatingFieldValue);
31883            });
31884            return resolvedValue;
31885        },
31886
31887        initialize : function () {
31888            if (this._isFloatingField()) {
31889                var variableRegexMap = this._variableRegexMap = {};
31890                _.each(this.documentFragmentVariables, function (documentFragmentVariable) {
31891                    var variableId = documentFragmentVariable.variableId,
31892                        regexPattern;
31893                    if (!variableRegexMap[variableId]) {
31894                        
31895                        regexPattern = '(?:<df-variable[^>]*variableid="' + variableId + '"[^>]*>)[^<]*(?:<\/df-variable>)';
31896                        variableRegexMap[variableId] = new RegExp(regexPattern, 'ig');
31897                    }
31898                });
31899            }
31900            GuideTextDraw._super.initialize.apply(this, [arguments]);
31901        }
31902    });
31903
31904    GuideTextDraw.defineProps({
31905        calcExp : {
31906            get : function () {
31907                return this._calcExp;
31908            }
31909        },
31910
31911        documentFragmentVariables : {
31912            get : function () {
31913                return this.jsonModel.documentFragmentVariables;
31914            }
31915        }
31916    });
31917}(_, guidelib));
31918
31919(function (_, guidelib) {
31920    var GuideAdobeSignBlock = guidelib.model.GuideAdobeSignBlock = guidelib.model.GuideTextDraw.extend({
31921        msClassName : "guideAdobeSignBlock"
31922    });
31923}(_, guidelib));
31924 (function (_, guidelib) {
31925    var GuideFootnotePlaceHolder = guidelib.model.GuideFootnotePlaceHolder = guidelib.model.GuideTextDraw.extend({
31926        msClassName : "guideFootnotePlaceHolder",
31927
31928        initialize : function () {
31929            GuideFootnotePlaceHolder._super.initialize.apply(this);
31930        }
31931    });
31932    GuideFootnotePlaceHolder.defineProps({
31933        footnoteMap : {
31934            get : function () {
31935            if (this.options._guideContainer.jsonModel.textReplacementMap) {
31936                var footnoteMap = {};
31937                var footnoteArray = Object.entries(this.options._guideContainer.jsonModel.textReplacementMap)
31938                var parentDiv = document.createElement("p");
31939                parentDiv.setAttribute("class", "footnoteClass");
31940                for (var i = 0; i < footnoteArray.length; i++) {
31941                    var pTag = $("p[id=\"" + footnoteArray[i][0] + "\"]")[0];   
31942                    if (pTag != null && pTag.tagName == 'P') {
31943                        var childTag = document.createElement("p");
31944                        
31945                        childTag.setAttribute("role", "footnote");
31946                        childTag.setAttribute("aria-live", "polite");
31947                        childTag.setAttribute("aria-atomic", "true");
31948                        var supTag = document.createElement('sup');
31949                        var anchorTag = document.createElement('a');
31950                        var parentTag = pTag.cloneNode(true);
31951                         parentTag.removeAttribute("id");
31952                        anchorTag.setAttribute('id', footnoteArray[i][0]+ "_ftn");
31953                        anchorTag.innerHTML = footnoteArray[i][1];
31954                        supTag.appendChild(anchorTag);
31955                        parentTag.insertBefore(supTag, parentTag.children[0]);
31956                        parentTag.style.display = "block";
31957                        childTag.appendChild(parentTag);
31958                        footnoteMap[footnoteArray[i][0]] = childTag.outerHTML;
31959                    }
31960                }
31961                return footnoteMap;
31962            }
31963            return null;
31964        }
31965        }
31966    });
31967
31968}(_, guidelib));
31969
31970
31971(function (_, guidelib) {
31972    
31973    var GuideTextBox = guidelib.model.GuideTextBox = guidelib.model.Field.extend({
31974        msClassName : "guideTextBox",
31975
31976        
31977        _runMinimumLengthTest : function () {
31978            return this.value && this.value.length >= this.minLength;
31979        },
31980
31981        
31982        _runTotalLengthTest : function () {
31983            return this.value && this.value.length === this.length;
31984        },
31985
31986        
31987        _runValidations : function (obj) {
31988            GuideTextBox._super._runValidations.call(this, obj);
31989            if (obj.validFlag) {
31990
31991                if (this.length != null) {
31992                    obj.validFlag = this._runTotalLengthTest();
31993                    if (!obj.validFlag) {
31994                        this._errorText = this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalLengthMessage, [this.length]);
31995                        this._failedTest = this.guideUtil.LENGTH_TEST;
31996                    }
31997                } else if (this.minLength != null) {
31998                    obj.validFlag =  this._runMinimumLengthTest();
31999                    if (!obj.validFlag) {
32000                        this._errorText = this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minimumLengthMessage, [this.minLength]);
32001                        this._failedTest = this.guideUtil.MINIMUM_LENGTH_TEST;
32002                    }
32003                }
32004
32005            }
32006        },
32007
32008        
32009        _runMandatoryTest : function () {
32010            if (this.allowRichText) {
32011                
32012                
32013                var getTextContent = function (htmlString) {
32014                        var result = htmlString,
32015                            regex = null;
32016                        if (htmlString != null) {
32017                            
32018                            
32019                            regex = /(<([^>]+)>)/ig;
32020                            result = htmlString.replace(regex, "");
32021                        }
32022                        return result;
32023                    },
32024                    currValue = getTextContent(this._getValue()),
32025                    isNull = this.checkIfNull(currValue);
32026                return !isNull;
32027            } else {
32028                return GuideTextBox._super._runMandatoryTest.apply(this, arguments);
32029            }
32030        },
32031
32032        _allowEmptyValueString : function () {
32033            return true;
32034        }
32035
32036    });
32037
32038    GuideTextBox.defineProps({
32039        
32040        "multiLine" : {
32041            get : function () {
32042                return this.getAttribute("multiLine");
32043            }
32044        },
32045
32046        
32047        "maxChars" : {
32048            get : function () {
32049                return this.getAttribute("maxChars");
32050            }
32051        },
32052
32053        
32054        "minLength" : {
32055            get : function () {
32056                return this.getAttribute("minLength");
32057            }
32058        },
32059
32060        
32061        "length" : {
32062            get : function () {
32063                return this.getAttribute("length");
32064            }
32065        },
32066        
32067        "allowRichText" : {
32068            get : function () {
32069                return this.getAttribute("allowRichText");
32070            }
32071        }
32072    });
32073
32074}(_, guidelib));
32075
32076(function (_, guidelib) {
32077    
32078    var countriesDialingCodesMap = {
32079        '441481' : 'Guernsey',
32080        '441624' : 'Isle of Man',
32081        '441534' : 'Jersey',
32082        '1868' : 'Trinidad and Tobago',
32083        '1473' : 'Grenada',
32084        '1670' : 'Northern Mariana Islands',
32085        '1869' : 'Saint Kitts and Nevis',
32086        '1758' : 'Saint Lucia',
32087        '1671' : 'Guam',
32088        "1684" : "American Samoa",
32089        "1268" : "Antigua and Barbuda",
32090        "1264" : "Anguilla",
32091        "1242" : "Bahamas",
32092        "1246" : "Barbados",
32093        '1441' : 'Bermuda',
32094        '1284' : 'British Virgin Islands',
32095        '1345' : 'Cayman Islands',
32096        '1787' : 'Puerto Rico',
32097        '1876' : 'Jamaica',
32098        '1939' : 'Puerto Rico',
32099        '1767' : 'Dominica',
32100        '1809' : 'Dominican Republic',
32101        '1829' : 'Dominican Republic',
32102        '1664' : 'Montserrat',
32103        '1849' : 'Dominican Republic',
32104        '1340' : 'U.S. Virgin Islands',
32105        '1784' : 'Saint Vincent and the Grenadines',
32106        '1649' : 'Turks and Caicos Islands',
32107        '1721' : 'Sint Maarten',
32108        "355" : "Albania",
32109        "213" : "Algeria",
32110        "376" : "Andorra",
32111        "244" : "Angola",
32112        "672" : "Antarctica",
32113        "374" : "Armenia",
32114        "297" : "Aruba",
32115        "994" : "Azerbaijan",
32116        "973" : "Bahrain",
32117        "880" : "Bangladesh",
32118        "375" : "Belarus",
32119        "501" : "Belize",
32120        "229" : "Benin",
32121        '975' : 'Bhutan',
32122        '591' : 'Bolivia',
32123        '387' : 'Bosnia and Herzegovina',
32124        '267' : 'Botswana',
32125        '246' : 'British Indian Ocean Territory',
32126        '673' : 'Brunei',
32127        '359' : 'Bulgaria',
32128        '226' : 'Burkina Faso',
32129        '257' : 'Burundi',
32130        '855' : 'Cambodia',
32131        '237' : 'Cameroon',
32132        '238' : 'Cape Verde',
32133        '236' : 'Central African Republic',
32134        '235' : 'Chad',
32135        '269' : 'Comoros',
32136        '682' : 'Cook Islands',
32137        '506' : 'Costa Rica',
32138        '385' : 'Croatia',
32139        
32140        '357' : 'Cyprus',
32141        '420' : 'Czech Republic',
32142        '243' : 'Democratic Republic of the Congo',
32143        '253' : 'Djibouti',
32144        '670' : 'East Timor',
32145        '593' : 'Ecuador',
32146        '503' : 'El Salvador',
32147        '240' : 'Equatorial Guinea',
32148        '291' : 'Eritrea',
32149        '372' : 'Estonia',
32150        '251' : 'Ethiopia',
32151        '500' : 'Falkland Islands',
32152        '298' : 'Faroe Islands',
32153        '679' : 'Fiji',
32154        '358' : 'Finland',
32155        '689' : 'French Polynesia',
32156        '241' : 'Gabon',
32157        '220' : 'Gambia',
32158        '995' : 'Georgia',
32159        '233' : 'Ghana',
32160        '350' : 'Gibraltar',
32161        '299' : 'Greenland',
32162        '502' : 'Guatemala',
32163        '224' : 'Guinea',
32164        '245' : 'Guinea-Bissau',
32165        '592' : 'Guyana',
32166        '509' : 'Haiti',
32167        '504' : 'Honduras',
32168        '852' : 'Hong Kong',
32169        '354' : 'Iceland',
32170        '964' : 'Iraq',
32171        '353' : 'Ireland',
32172        '972' : 'Israel',
32173        '225' : 'Ivory Coast',
32174        '962' : 'Jordan',
32175        '254' : 'Kenya',
32176        '686' : 'Kiribati',
32177        '383' : 'Kosovo',
32178        '965' : 'Kuwait',
32179        '996' : 'Kyrgyzstan',
32180        '856' : 'Laos',
32181        '371' : 'Latvia',
32182        '961' : 'Lebanon',
32183        '266' : 'Lesotho',
32184        '231' : 'Liberia',
32185        '218' : 'Libya',
32186        '423' : 'Liechtenstein',
32187        '370' : 'Lithuania',
32188        '352' : 'Luxembourg',
32189        '853' : 'Macau',
32190        '389' : 'Macedonia',
32191        '261' : 'Madagascar',
32192        '265' : 'Malawi',
32193        '960' : 'Maldives',
32194        '223' : 'Mali',
32195        '356' : 'Malta',
32196        '692' : 'Marshall Islands',
32197        '222' : 'Mauritania',
32198        '230' : 'Mauritius',
32199        
32200        '691' : 'Micronesia',
32201        '373' : 'Moldova',
32202        '377' : 'Monaco',
32203        '976' : 'Mongolia',
32204        '382' : 'Montenegro',
32205        
32206        '258' : 'Mozambique',
32207        '264' : 'Namibia',
32208        '674' : 'Nauru',
32209        '977' : 'Nepal',
32210        '599' : 'Netherlands Antilles',
32211        '687' : 'New Caledonia',
32212        '505' : 'Nicaragua',
32213        '227' : 'Niger',
32214        '234' : 'Nigeria',
32215        '683' : 'Niue',
32216        '850' : 'North Korea',
32217        '968' : 'Oman',
32218        '680' : 'Palau',
32219        '970' : 'Palestine',
32220        '507' : 'Panama',
32221        '675' : 'Papua New Guinea',
32222        '595' : 'Paraguay',
32223        '351' : 'Portugal',
32224        '974' : 'Qatar',
32225        '242' : 'Republic of the Congo',
32226        '262' : 'Reunion',
32227        '250' : 'Rwanda',
32228        
32229        '290' : 'Saint Helena',
32230        '590' : 'Saint Martin',
32231        '508' : 'Saint Pierre and Miquelon',
32232        '685' : 'Samoa',
32233        '378' : 'San Marino',
32234        '239' : 'Sao Tome and Principe',
32235        '966' : 'Saudi Arabia',
32236        '221' : 'Senegal',
32237        '381' : 'Serbia',
32238        '248' : 'Seychelles',
32239        '232' : 'Sierra Leone',
32240        '421' : 'Slovakia',
32241        '386' : 'Slovenia',
32242        '677' : 'Solomon Islands',
32243        '252' : 'Somalia',
32244        '211' : 'South Sudan',
32245        '249' : 'Sudan',
32246        '597' : 'Suriname',
32247        '268' : 'Swaziland',
32248        '963' : 'Syria',
32249        '886' : 'Taiwan',
32250        '992' : 'Tajikistan',
32251        '255' : 'Tanzania',
32252        '228' : 'Togo',
32253        '690' : 'Tokelau',
32254        '676' : 'Tonga',
32255        '216' : 'Tunisia',
32256        '993' : 'Turkmenistan',
32257        '688' : 'Tuvalu',
32258        '256' : 'Uganda',
32259        '380' : 'Ukraine',
32260        '971' : 'United Arab Emirates',
32261        '598' : 'Uruguay',
32262        '998' : 'Uzbekistan',
32263        '678' : 'Vanuatu',
32264        '379' : 'Vatican',
32265        '681' : 'Wallis and Futuna',
32266        '212' : 'Western Sahara',
32267        '967' : 'Yemen',
32268        '260' : 'Zambia',
32269        '263' : 'Zimbabwe',
32270        '60' : 'Malaysia',
32271        '58' : 'Venezuela',
32272        '30' : 'Greece',
32273        '84' : 'Vietnam',
32274        '44' : 'United Kingdom',
32275        '45' : 'Denmark',
32276        '53' : 'Cuba',
32277        '46' : 'Sweden',
32278        '52' : 'Mexico',
32279        '41' : 'Switzerland',
32280        '40' : 'Romania',
32281        
32282        '36' : 'Hungary',
32283        
32284        "43" : "Austria",
32285        '34' : 'Spain',
32286        '91' : 'India',
32287        '62' : 'Indonesia',
32288        '98' : 'Iran',
32289        '94' : 'Sri Lanka',
32290        '27' : 'South Africa',
32291        '95' : 'Myanmar',
32292        '65' : 'Singapore',
32293        '39' : 'Italy',
32294        '82' : 'South Korea',
32295        "32" : "Belgium",
32296        '81' : 'Japan',
32297        '31' : 'Netherlands',
32298        '20' : 'Egypt',
32299        "54" : "Argentina",
32300        "93" : "Afghanistan",
32301        
32302        '56' : 'Chile',
32303        '86' : 'China',
32304        '51' : 'Peru',
32305        '63' : 'Philippines',
32306        '64' : 'Pitcairn',
32307        '48' : 'Poland',
32308        '47' : 'Norway',
32309        '33' : 'France',
32310        
32311        '61' : 'Cocos Islands',
32312        '55' : 'Brazil',
32313        '92' : 'Pakistan',
32314        '49' : 'Germany',
32315        '57' : 'Colombia',
32316        '66' : 'Thailand',
32317        '90' : 'Turkey',
32318        
32319        '1' : 'Canada',
32320        
32321        '7' : 'Russia'
32322    };
32323
32324    var GuideTelephone = guidelib.model.GuideTelephone = guidelib.model.GuideTextBox.extend({
32325        msClassName : "guideTelephone",
32326
32327        _extractNumericDigits : function (telephoneNumber) {
32328            var digitArray,
32329                number = "";
32330            if (telephoneNumber) {
32331                digitArray = telephoneNumber.match(/\d+/g);
32332                if (digitArray) {
32333                    number = digitArray.join("");
32334                }
32335            }
32336            return number;
32337        },
32338
32339        _extractCountryCode : function (telephoneNumber) {
32340            var number = this._extractNumericDigits(telephoneNumber);
32341            if (!number || (telephoneNumber && number && telephoneNumber.lastIndexOf("+", 0) !== 0)) {
32342                return "";
32343            }
32344            for (var countryCode in countriesDialingCodesMap) {
32345                if (number && number.lastIndexOf(countryCode, 0) === 0) {
32346                    return countryCode;
32347                }
32348            }
32349            return "";
32350        },
32351
32352        _extractPhoneNumber : function (telephoneNumber) {
32353            var countryCode = this._extractCountryCode(telephoneNumber),
32354                number = this._extractNumericDigits(telephoneNumber),
32355                phoneNumber = "";
32356            if (number) {
32357                phoneNumber = number.substr(countryCode.length);
32358            }
32359            return phoneNumber;
32360        }
32361    });
32362
32363    GuideTelephone.defineProps({
32364        
32365        countryCode : {
32366            get : function () {
32367                var value = this._getValue();
32368                return this._extractCountryCode(value);
32369            }
32370        },
32371
32372        
32373        phoneNumber : {
32374            get : function () {
32375                var value = this._getValue();
32376                return this._extractPhoneNumber(value);
32377            }
32378        }
32379    });
32380
32381}(_, guidelib));
32382
32383(function (_, guidelib) {
32384    
32385    var GuideCaptcha = guidelib.model.GuideCaptcha = guidelib.model.Field.extend({
32386        msClassName : "guideCaptcha",
32387
32388        initialize : function () {
32389            GuideCaptcha._super.initialize.call(this);
32390            var invisibleMandatoryRecaptchaInitialization = "af.invisibleMandatoryRecaptchaInitialization";
32391            if ((FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)
32392                && (this.isWidgetHcaptcha || this.isWidgetTurnstile) && this.captchaInvisible)
32393                || (this.isWidgetRecaptcha && ((this.captchaEnterprise && !this.checkBoxkey) || (this.captchaInvisible && this.mandatory)))) {
32394                
32395                this.captchaValidate = false;
32396                this._triggerOnBridge(invisibleMandatoryRecaptchaInitialization, this, null, null, null);
32397            }
32398        },
32399        
32400        showCaptchaError : function (serverErrorMessage) {
32401            if (this.captchaEnterprise) {
32402                if (this.checkBoxkey) {
32403                    serverErrorMessage = this.errorMessage;
32404                } else {
32405                    window.alert(this.errorMessage);
32406                    return;
32407                }
32408            }
32409            if (this.captchaInvisible) {
32410                if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA)) {
32411                    window.alert(this.errorMessage);
32412                }
32413                return;
32414            }
32415            if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && this.isWidgetRecaptcha) {
32416                serverErrorMessage = this.errorMessage;
32417            } else {
32418                if (_.isEmpty(serverErrorMessage)) {
32419                    serverErrorMessage = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-006"]);
32420                }
32421            }
32422            
32423            this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
32424                "validationStatus", false, serverErrorMessage);
32425        },
32426
32427        validate : function (errorList) {
32428            if (_.isUndefined(errorList)) {
32429                errorList = [];
32430            }
32431
32432            if(!this.captchaValidate) {
32433                return;
32434            }
32435            if (window.guideBridge.hostName !== "server") {
32436                if ((this.visible && !this.value) || (this.mandatory && !this.visible)) {
32437                    errorList.push({
32438                    som : this.somExpression,
32439                    errorText : this.mandatoryMessage
32440                });
32441                    this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
32442                                "validationStatus", false, this.mandatoryMessage);
32443                    return false;
32444                } else {
32445                    this._triggerEvent(guidelib.event.GuideModelEvent.ERROR_CHANGED,
32446                                "validationStatus", true, null);
32447                }
32448            }
32449        },
32450        
32451        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
32452            if (!FD.isToggleEnabled("FT_FORMS-4185")) {
32453                GuideCaptcha._super._updateLiveData.call(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
32454            }
32455        },
32456
32457        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
32458            if (!FD.isToggleEnabled("FT_FORMS-4185")) {
32459                GuideCaptcha._super._playLiveData.call(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
32460            }
32461        }
32462    });
32463
32464    GuideCaptcha.defineProps({
32465        value : {
32466            get : function () {
32467                return this.jsonModel._value;
32468            },
32469            set : function (value) {
32470                var oldValue = this.jsonModel._value,
32471                    newTypedValue;
32472                
32473                this.jsonModel._value = (value === undefined) ? oldValue : value;
32474                newTypedValue = this.jsonModel._value;
32475                this.validate();
32476                this._triggerOnBridge("elementValueChanged", this, "value", oldValue, newTypedValue);
32477            }
32478        },
32479        captchaWidget : {
32480            get : function () {
32481                return this.getAttribute("captchaService");
32482            }
32483        },
32484        captchaValidate : {
32485            get : function () {
32486                return this._captchaValidate == undefined ? true : this._captchaValidate;
32487            },
32488            set : function (value) {
32489                this._captchaValidate = value;
32490            }
32491        },
32492        captchaInvisible : {
32493            get : function () {
32494                if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && this.captchaWidget === "turnstile") {
32495                    return this.getAttribute("widgetType") == "invisible" ? true : false;
32496                } else if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && this.captchaWidget === "hcaptcha") {
32497                    return this.getAttribute("size") == "invisible" ? true : false;
32498                } else {
32499                    return this.getAttribute("rcSize") == "invisible" ? true : false;
32500                }
32501            }
32502        },
32503        captchaEnterprise : {
32504            get : function () {
32505                return (FD.isToggleEnabled("FT_FORMS-4185") && this.getAttribute("rcVersion") === "enterprise") ? true : false;
32506            }
32507        },
32508        checkBoxkey : {
32509            get : function () {
32510                return this.getAttribute("rcKeyType") === "checkbox" ? true : false;
32511            }
32512        },
32513        errorMessage : {
32514            get: function () {
32515                return this.getAttribute("errorMessage");
32516            }
32517        },
32518        isWidgetRecaptcha : {
32519            get: function () {
32520                return (this.captchaWidget === "recaptcha");
32521            }
32522        },
32523        isWidgetHcaptcha : {
32524            get: function () {
32525                return (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && (this.captchaWidget === "hcaptcha"));
32526            }
32527        },
32528        isWidgetTurnstile : {
32529            get: function () {
32530                return (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_TURNSTILE_HCAPTCHA) && (this.captchaWidget === "turnstile"));
32531            }
32532        }
32533
32534
32535    });
32536
32537}(_, guidelib));
32538
32539(function (_, guidelib) {
32540    var GuidePasswordBox = guidelib.model.GuidePasswordBox = guidelib.model.Field.extend({
32541        msClassName : "guidePasswordBox",
32542        
32543        _getReducedJSON : function () {
32544            
32545            
32546            if (this.submitPassword) {
32547                return GuidePasswordBox._super._getReducedJSON.call(this);
32548            }
32549            
32550            var whitelistedProperties = ["name", "templateId", "guideNodeClass"],
32551                reducedJsonObject = {};
32552            guidelib.model.util.CommonUtils.returnMinimalJSON(whitelistedProperties, reducedJsonObject, this);
32553            return reducedJsonObject;
32554        },
32555
32556        _preserveLazyValue : function () {
32557            return !!this.submitPassword && GuidePasswordBox._super._preserveLazyValue.call(this);
32558        },
32559
32560        _allowEmptyValueString : function () {
32561            return true;
32562        }
32563    });
32564    GuidePasswordBox.defineProps({
32565        submitPassword : {
32566            get : function () {
32567                return this.getAttribute("submitPassword");
32568            }
32569        }
32570    });
32571
32572})(_, guidelib);
32573
32574(function (_, guidelib) {
32575    var GuideScribble = guidelib.model.GuideScribble = guidelib.model.Field.extend({
32576        msClassName : "guideScribble"
32577    });
32578})(_, guidelib);
32579
32580
32581(function (_, guidelib) {
32582    var AbstractField = guidelib.model.AbstractField = guidelib.model.GuideNode.extend({
32583        msClassName : "abstractField",
32584
32585        initialize : function () {
32586            this._name = this.options.name || "";
32587            this._className = this.options.className || "";
32588            this._bindRef = this.options.bindRef || "";
32589            this._afDataSom = this.options.afDataSom || "";
32590            this._dataSom = this._isXfaNode() ? this.options.dataSom : "";
32591            this.dependants = [];
32592            
32593            this._depdendantIds = [];
32594        },
32595
32596        _getValue : function () {
32597            return this.jsonModel._value;
32598        },
32599
32600        _setValue : function (value) {
32601            this.jsonModel._value = value;
32602        },
32603
32604        resetData : function () {
32605            return guidelib.model.Field.prototype.resetData.call(this);
32606        },
32607
32608        _isXfaNode : function () {
32609            return this.bindRef.indexOf("xfa[0].form[0].") === 0;
32610        },
32611
32612        getAttribute : function (attrName) {
32613            var attrValue;
32614            switch (attrName) {
32615                case "name":
32616                    attrValue = this.name;
32617                    break;
32618                case "bindRef":
32619                    attrValue = this.bindRef;
32620                    break;
32621                default:
32622                    attrValue = null;
32623                    break;
32624            }
32625            return attrValue;
32626        }
32627    });
32628
32629    AbstractField.defineProps({
32630        somExpression : {
32631            get : function () {
32632                return "";
32633            }
32634        },
32635        name : {
32636            get : function () {
32637                return (this._name || "").replace(/\s+/g, '');
32638            }
32639        },
32640        className : {
32641            get : function () {
32642                return (this._className || "");
32643            }
32644        },
32645        bindRef : {
32646            get : function () {
32647                return (this._bindRef || "").replace(/\s+/g, '');
32648            }
32649        },
32650        dataSom : {
32651            get : function () {
32652                return this._dataSom;
32653            }
32654        },
32655        afDataSom : {
32656            get : function () {
32657                return this._afDataSom.replace(/\s+/g, '');
32658            }
32659        },
32660
32661        value : {
32662            get : function () {
32663                var context = this._guide()._currentContext;
32664                if (context && context.managedExp && context.contextNode && context.expression) {
32665                    this._addDependant(context.contextNode, context.expression);
32666                    
32667                    this._depdendantIds.push(context.contextNode.id);
32668                }
32669                return this.jsonModel._value;
32670            },
32671            set : function (newValue) {
32672                if (this.jsonModel._value !== newValue) {
32673                    this.jsonModel._value = newValue;
32674                    
32675                    var guideDirtyMarkerAndVisitor = this._guide().internal.GuideDirtyMarkerAndVisitor,
32676                        visitMap = guideDirtyMarkerAndVisitor.visitMap,
32677                        listOfDependents = this._depdendantIds;
32678                    guideDirtyMarkerAndVisitor._findAndMarkDirty(visitMap, listOfDependents);
32679                    this._notifyDependants();
32680                }
32681            }
32682        }
32683    });
32684
32685    AbstractField.addMixins([
32686        guidelib.model.mixin.AddDependencyMgmt
32687    ]);
32688}(_, guidelib));
32689
32690(function ($, guidelib, _) {
32691    var ModelTemplateCacheStore = guidelib.model.util.ModelTemplateCacheStore = xfalib.ut.Class.extend({
32692        initialize : function () {
32693            ModelTemplateCacheStore._super.initialize.apply(this);
32694            this._modelIdCache = {};
32695            this._templateIdCache = {};
32696            
32697            
32698            
32699            
32700            this._lazyTemplateIdCache = {};
32701            var guideJson = JSON.parse(JSON.stringify(this.options.modelTemplateJson));
32702            this._putTemplate(guideJson);
32703        },
32704
32705        
32706        putModel : function (model) {
32707            if (model.id) {
32708                var modelId = model.id;
32709                this._modelIdCache[modelId] = model;
32710                if (model.children) {
32711                    _.each(model.children, function (child) {
32712                        this.putModel(child);
32713                    }, this);
32714                }
32715            } else {
32716                this.logger().log("no Id found for model" + model.getAttribute("name"));
32717            }
32718        },
32719
32720        
32721        removeModel : function (id) {
32722            if (this._modelIdCache.hasOwnProperty(id)) {
32723                delete this._modelIdCache[id];
32724            }
32725        },
32726
32727        getModel : function (id) {
32728            if (this._modelIdCache.hasOwnProperty(id)) {
32729                return this._modelIdCache[id];
32730            }
32731        },
32732
32733        
32734        _putTemplate : function (jsonTemplate) {
32735            if (jsonTemplate.templateId && jsonTemplate.guideNodeClass) {
32736                this._templateIdCache[jsonTemplate.templateId] = jsonTemplate;
32737            }
32738            _.each(jsonTemplate, function (childTemplate, key) {
32739                if (_.isObject(childTemplate)) {
32740                    this._putTemplate(childTemplate);
32741                }
32742            }, this);
32743        },
32744
32745        
32746        _putLazyTemplate : function (lazyTemplateJson) {
32747            if (lazyTemplateJson.templateId && lazyTemplateJson.guideNodeClass) {
32748                this._lazyTemplateIdCache[lazyTemplateJson.templateId] = lazyTemplateJson;
32749            }
32750        },
32751
32752        cloneJsonTemplate : function (templateId) {
32753            if (this._templateIdCache[templateId]) {
32754                var template = this._templateIdCache[templateId];
32755                return JSON.parse(JSON.stringify(template)); 
32756            }
32757        },
32758        
32759        _getTemplate : function (templateId, lookupLazyStore) {
32760            var template = this._templateIdCache[templateId];
32761            
32762            
32763            
32764            if (lookupLazyStore && guidelib.util.GuideUtil.isLazyJson(template)) {
32765                template = this._lazyTemplateIdCache[templateId];
32766            }
32767
32768            if (!_.isUndefined(template)) {
32769                return JSON.parse(JSON.stringify(template));
32770
32771            }
32772        }
32773    });
32774
32775    ModelTemplateCacheStore.defineProps({
32776    });
32777}($, guidelib, window._));
32778(function ($, guidelib) {
32779    var DomTemplateCacheStore = guidelib.view.util.DomTemplateCacheStore = xfalib.ut.Class.extend({
32780        cloneDomElement : function (htmlId) {
32781            return this.$htmlTemplateDom.find(htmlId).clone();
32782        },
32783
32784        putDomElement : function (parentIdSelector, $child) {
32785            
32786            this.$htmlTemplateDom.find(parentIdSelector).eq(0).append($child);
32787        },
32788
32789        removeDomElement : function (parentIdSelector) {
32790            
32791            this.$htmlTemplateDom.find(parentIdSelector).children().remove();
32792        }
32793    });
32794
32795    DomTemplateCacheStore.defineProps({
32796        $htmlTemplateDom : {
32797            get : function () {
32798                return this.options.$htmlTemplateDom;
32799            }
32800        }
32801    });
32802}($, guidelib));
32803(function (_, guidelib) {
32804    
32805    var AddMinMaxValidation = guidelib.model.mixin.AddMinMaxValidation = {
32806        normalProperties : {
32807
32808            _runMaximumValueTest : function () {
32809                if (this.exclusiveMaximum) {
32810                    return this.value < this.maximum;
32811                } else {
32812                    return this.value <= this.maximum;
32813                }
32814            },
32815
32816            _runMinimumValueTest : function () {
32817                if (this.exclusiveMinimum) {
32818                    return this.value > this.minimum;
32819                } else {
32820                    return this.value >= this.minimum;
32821                }
32822            },
32823
32824            
32825            _minMaxValidation : function (value, obj) {
32826                if (value != null && obj.validFlag) {
32827
32828                    if (this.maximum) {
32829                        obj.validFlag = this._runMaximumValueTest();
32830                        if (!obj.validFlag) {
32831                            var maxFormattedValue = this._getFormattedValue(this.maximum);
32832                            this._errorText = this.exclusiveMaximum ? this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.exclusiveMaxValErrorMessage, [maxFormattedValue]) :
32833                                this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.maxValErrorMessage, [maxFormattedValue]);
32834                            this._failedTest = this.guideUtil.MAXIMUM_VALUE_TEST;
32835                        }
32836                    }
32837
32838                    if (obj.validFlag && this.minimum !== null) {
32839                        obj.validFlag = this._runMinimumValueTest();
32840                        if (!obj.validFlag) {
32841                            var minFormattedValue = this._getFormattedValue(this.minimum);
32842                            this._errorText = this.exclusiveMinimum ? this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.exclusiveMinValErrorMessage, [minFormattedValue]) :
32843                                this.guideUtil.getLocalizedMessage("", guidelib.i18n.strings.minValErrorMessage, [minFormattedValue]);
32844                            this._failedTest = this.guideUtil.MINIMUM_VALUE_TEST;
32845                        }
32846                    }
32847                }
32848            }
32849
32850        },
32851        propertyDescriptors : {
32852            
32853            maximum : {
32854                get : function () {
32855                    return this.getAttribute("maximum");
32856                }
32857            },
32858
32859            
32860            minimum : {
32861                get : function () {
32862                    return this.getAttribute("minimum");
32863                }
32864            },
32865
32866            
32867            exclusiveMaximum : {
32868                get : function () {
32869                    return this.getAttribute("exclusiveMaximum");
32870                }
32871            },
32872
32873            
32874            exclusiveMinimum : {
32875                get : function () {
32876                    return this.getAttribute("exclusiveMinimum");
32877                }
32878            }
32879
32880        }
32881    };
32882
32883}(_, guidelib));
32884(function (_, guidelib) {
32885
32886    
32887    var GuideNumericBox = guidelib.model.GuideNumericBox = guidelib.model.Field.extend({
32888        msClassName : "guideNumericBox",
32889
32890        _getTypedValue : function (value) {
32891            var dataType = this.dataType,
32892                tmpValue, str, leadD, fracD;
32893
32894            if (this.checkIfNull(value)) {
32895                return null;
32896            }
32897            switch (dataType) {
32898                case "integer":
32899                    tmpValue = parseInt(value);
32900                    break;
32901                case "float":
32902                    tmpValue = parseFloat(value);
32903                    break;
32904                case "decimal":
32905                    tmpValue = parseFloat(value);
32906                    if (!isNaN(tmpValue)) {
32907                        str =  tmpValue.toString();
32908                        leadD = str.indexOf(".");
32909                        leadD = leadD === -1 ? str.length : leadD;
32910                        leadD = str.indexOf("-") === 0 ? leadD - 1 : leadD;
32911                        fracD = str.length - leadD - 1;
32912                        if (fracD > this.fracDigits && this.fracDigits !== -1) {
32913                            tmpValue = parseFloat(tmpValue.toFixed(this.fracDigits));
32914                        }
32915                        if (leadD > this.leadDigits && this.leadDigits !== -1) {
32916                            return undefined;
32917                        }
32918                    }
32919                    break;
32920            }
32921            if (isNaN(tmpValue)) {
32922                return undefined;
32923            }
32924            return tmpValue;
32925        },
32926        _getFormattedValue : function (value) {
32927            if (_.isUndefined(value) || value === null || value === "") {
32928                return null;
32929            }
32930
32931            var picture = this.jsonModel.displayPictureClause,
32932                defaultPattern = "zzzzzzzzzzzzzzzzzzzzz.zzzzzzzzzzzzzzz";
32933
32934            
32935            try {
32936                if (picture && this.jsonModel.html5Type !== "number") {
32937                    return xfalib.ut.PictureFmt.format(value + "", picture, guideBridge._readRuntimeLocale(), true);
32938                } else {
32939                    var pattern = (this.jsonModel.html5Type === "number") ? defaultPattern : guidelib.i18n.numberPatterns.numeric;
32940                    return xfalib.ut.PictureFmt.format(value + "", "num{" + pattern + "}",
32941                        guideBridge._readRuntimeLocale(), true, true);
32942                }
32943            } catch (exception) {
32944                this.logger().error("Cannot format value " + value + " " + exception);
32945                
32946                return value;
32947            }
32948        },
32949
32950        
32951        _totalDigitValidation : function (value, obj) {
32952            if (value && obj.validFlag && this.leadDigits > -1) {
32953                obj.validFlag = true;
32954                if (this.dataType === "integer") {
32955                    obj.validFlag = this.value.toString().length <= this.leadDigits;
32956                }
32957                if (!obj.validFlag) {
32958                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.totalDigitMessage, [this.leadDigits]);
32959                    this._failedTest = this.guideUtil.TOTAL_DIGITS_TEST;
32960                }
32961            }
32962        },
32963
32964        
32965        _datatypeValidation : function (obj) {
32966            if (obj.validFlag) {
32967                var value = this.getAttribute("_value");
32968                obj.validFlag = !isNaN(value);
32969                if (!obj.validFlag) {
32970                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.datatypeMessage, ["numeric"]);
32971                    this._failedTest = this.guideUtil.FORMAT_TEST;
32972                }
32973            }
32974        },
32975
32976        
32977        _runValidations : function (obj) {
32978            var value = this.value;
32979            GuideNumericBox._super._runValidations.call(this, obj);
32980            this._datatypeValidation(obj);
32981            this._minMaxValidation(value, obj);
32982            this._totalDigitValidation(value, obj);
32983        }
32984    });
32985    GuideNumericBox.defineProps({
32986        
32987        dataType : {
32988            get : function () {
32989                return this.getAttribute("dataType");
32990            }
32991        },
32992
32993        
32994        leadDigits : {
32995            get : function () {
32996                return this.getAttribute("leadDigits");
32997            }
32998        },
32999
33000        
33001        fracDigits : {
33002            get : function () {
33003                return this.getAttribute("fracDigits");
33004            }
33005        }
33006    });
33007
33008    GuideNumericBox.addMixins([
33009        guidelib.model.mixin.AddMinMaxValidation
33010    ]);
33011
33012})(_, guidelib);
33013
33014(function (_, guidelib) {
33015    
33016    var GuideDatePicker = guidelib.model.GuideDatePicker = guidelib.model.Field.extend({
33017        msClassName : "guideDatePicker",
33018        errorList : [],
33019        that : this,
33020
33021        initialize : function () {
33022            GuideDatePicker._super.initialize.call(this);
33023            if (_.isEmpty(this.jsonModel._value) && this.jsonModel.defaultToCurrentDate === "true") {
33024                this._setGuideValue(new Date().toISOString().slice(0, 10));
33025            }
33026        },
33027
33028        _setGuideValue : function (value) {
33029            var retVal = guidelib.util.GuideUtil._reformatDate(value, this.isEditPictureClausePresent);
33030            GuideDatePicker._super._setGuideValue.call(this, retVal);
33031        },
33032
33033        _getTypedValue : function (value) {
33034            if (value) {
33035                return value;
33036            }
33037            return null;
33038        },
33039
33040        
33041        _datatypeValidation : function (obj) {
33042            if (obj.validFlag) {
33043                var value = this.getAttribute("_value");
33044                obj.validFlag = true;
33045                if (value != null && xfalib.ut.DateInfo.Parse(value, undefined, this.isEditPictureClausePresent) == null) {
33046                    obj.validFlag = false;
33047                }
33048                if (!obj.validFlag) {
33049                    this._errorText = guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.datatypeMessage, ["date"]);
33050                    this._failedTest = this.guideUtil.FORMAT_TEST;
33051                }
33052            }
33053        },
33054
33055        _validateDatePart : function (field, datePart, errorList) {
33056            if (field === "D") {
33057                if (datePart > 31) {
33058                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.month, guidelib.i18n.calendarSymbols.more, 31, guidelib.i18n.calendarSymbols.days]));
33059                }
33060                if (datePart < 1) {
33061                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.month, guidelib.i18n.calendarSymbols.less, 1, guidelib.i18n.calendarSymbols.days]));
33062                }
33063            }
33064            if (field === "M") {
33065                if (datePart > 12) {
33066                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.year, guidelib.i18n.calendarSymbols.more, 12, guidelib.i18n.calendarSymbols.months]));
33067                }
33068                if (datePart < 1) {
33069                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidDatePart, [guidelib.i18n.calendarSymbols.year, guidelib.i18n.calendarSymbols.less, 1, guidelib.i18n.calendarSymbols.months]));
33070                }
33071            }
33072            if (field === "Y") {
33073                if (datePart.length < 4) {
33074                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.genericInvalidYearPart));
33075                }
33076
33077            }
33078        },
33079        _getOrderedDateParts : function (value) {
33080            var dateFormat = this.jsonModel.dateDisplayFormat || "date{M/D/YYYY}";
33081            var separator = dateFormat.match(/^date\{.*([^mdy]).*\}$/i)[1];
33082            var fieldOrder = ['M', 'D', 'Y']
33083                .map(function (val) {
33084                    return {
33085                        value : val,
33086                        index : dateFormat.indexOf(val)
33087                    };
33088                })
33089                .sort(function (a, b) {
33090                    return a.index - b.index;
33091                })
33092                .map(function (obj) {
33093                    return obj.value;
33094                });
33095            var dateParts = value.split(separator);
33096            return [dateParts, fieldOrder];
33097        },
33098        _checkIsolatedDateValidity : function (obj, value, errorList) {
33099            var orderedParts = this._getOrderedDateParts(value);
33100            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33101            for (var i = 0; i < fieldOrder.length; i++) {
33102                var field = fieldOrder[i];
33103                var datePart = dateParts[i];
33104                if (!_.isEmpty(datePart)) {
33105                    this._validateDatePart(field, datePart, errorList);
33106                }
33107            }
33108        },
33109        _validateDaysOfMonth : function (obj, value, errorList) {
33110            var orderedParts = this._getOrderedDateParts(value);
33111            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33112                month = dateParts[fieldOrder.indexOf('M')],
33113                day = dateParts[fieldOrder.indexOf('D')],
33114                year = dateParts[fieldOrder.indexOf('Y')];
33115            if (month !== "" && day !== "") {
33116                month = Number(month) || 0;
33117                day = Number(day) || 0;
33118                var currentMonthName = guidelib.i18n.calendarSymbols.monthNames[month - 1];
33119                if (31 === day && [4,6,9,11].includes(month)) {
33120                    errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.nonFebruaryMessage, [currentMonthName, day - 1]));
33121                }
33122            }
33123        },
33124        _validateFieldCompleteness : function (obj, value, errorList) {
33125            var orderedParts = this._getOrderedDateParts(value);
33126            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33127            var localizedFieldMapping = {
33128                M : guidelib.i18n.calendarSymbols.month,
33129                D : guidelib.i18n.calendarSymbols.day,
33130                Y : guidelib.i18n.calendarSymbols.year
33131            };
33132            var emptyFields = fieldOrder
33133                .map(function (fieldName) {
33134                    return localizedFieldMapping[fieldName];
33135                })
33136                .filter(function (_, index) {
33137                    return dateParts[index] === "";
33138                });
33139            if (emptyFields.length !== 3 && emptyFields.length > 0) {
33140                errorList.push("These fields still need to be filled: [" + emptyFields.join(", ") + "]");
33141            }
33142        },
33143        _validateFullDate : function (obj, value, errorList) {
33144            var orderedParts = this._getOrderedDateParts(value);
33145            var dateParts = orderedParts[0], fieldOrder = orderedParts[1]; 
33146                month = dateParts[fieldOrder.indexOf('M')],
33147                day = dateParts[fieldOrder.indexOf('D')],
33148                year = dateParts[fieldOrder.indexOf('Y')];
33149            if (month !== "" && day !== "" && year !== "") {
33150                month = Number(month) || 0;
33151                day = Number(day) || 0;
33152                year = Number(year) || 0;
33153                var isLeapYear = (year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0));
33154                if (month === 2) {
33155                    var maxFebruary = isLeapYear ? 29 : 28;
33156                    if (day === 29 && !isLeapYear) {
33157                        errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.februaryMessage, [maxFebruary, year]));
33158                    }
33159                    if (day >= 30) {
33160                        errorList.push(guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.strings.februaryMessage, [maxFebruary, year]));
33161                    }
33162                }
33163            }
33164        },
33165        _computeErrors : function (obj, errorList) {
33166            var that = this;
33167            obj.validFlag = errorList.length === 0;
33168            if (!obj.validFlag) {
33169                that._errorText = errorList.join(" ");
33170                that._failedTest = that.guideUtil.FORMAT_TEST;
33171            }
33172        },
33173
33174        
33175        _runValidations : function (obj) {
33176            var value = this.value;
33177            if (this.jsonModel.titleDay || this.jsonModel.titleMonth || this.jsonModel.titleYear) {
33178                if (null === value) {
33179                    value = "//";
33180                }
33181                var errorList = [];
33182                
33183                this._checkIsolatedDateValidity(obj, value, errorList);
33184                
33185                if (errorList.length === 0) {
33186                    this._validateDaysOfMonth(obj, value, errorList);
33187                }
33188                
33189                if (errorList && errorList.length === 0 && window.FD && window.FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_DATE_PICKER_ERRORMESSAGE) ) {
33190
33191                    this._validateFieldCompleteness(obj, value, errorList);
33192                }
33193                
33194                if (errorList.length === 0) {
33195                    this._validateFullDate(obj, value, errorList);
33196                }
33197                this._computeErrors(obj, errorList);
33198
33199                
33200                if (errorList.length === 0) {
33201                    this.value = value = this.value === "//" ? "" : this.value;
33202                    GuideDatePicker._super._runValidations.call(this, obj);
33203                    try {
33204                        this.value = value = this.value !== null && this.value !== "" ? xfalib.ut.PictureFmt.parseDate(this.value, (this.jsonModel.dateDisplayFormat || "date{M/D/YYYY}")) : this.value;
33205                    } catch (error) {}
33206                    this._minMaxValidation(value, obj);
33207                }
33208            } else {
33209                GuideDatePicker._super._runValidations.call(this, obj);
33210                this._datatypeValidation(obj);
33211                this._minMaxValidation(value, obj);
33212            }
33213        }
33214    });
33215
33216    GuideDatePicker.addMixins([
33217        guidelib.model.mixin.AddMinMaxValidation
33218    ]);
33219
33220})(_, guidelib);
33221
33222(function (guidelib, $, _) {
33223    var ErrorConstants = guidelib.util.ErrorConstants = {
33224        DATA_ATTRIBUTE_ERROR_ITEM : "data-af-global-error-item",
33225        DATA_ATTRIBUTE_DISPLAY_ON : "data-af-global-errors-display-on",
33226        DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER : "data-af-global-error-text",
33227        DATA_ATTRIBUTE_ERROR_CONTAINER : "data-af-global-errors",
33228        DATA_ATTRIBUTE_SOM : "data-af-som",
33229        CONTEXT_SUBMISSION : "form",
33230        CONTEXT_NAVIGATION : "panel",
33231        CONTEXT_FIELD : "field" 
33232
33233    };
33234    ErrorConstants[ErrorConstants.CONTEXT_SUBMISSION] = 4;
33235    ErrorConstants[ErrorConstants.CONTEXT_NAVIGATION] = 2;
33236    ErrorConstants[ErrorConstants.CONTEXT_FIELD] = 1;
33237
33238    var GlobalErrorContainer = function ($el, options) {
33239        this.$container = $el;
33240        var $items = $el.find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_ITEM + "]").first(),
33241            displayOnAttribute = $el.attr(ErrorConstants.DATA_ATTRIBUTE_DISPLAY_ON) || "";
33242        this.displayOn = 0;
33243        this.errorCount = 0;
33244        this.$container.addClass("no-validation-errors");
33245        _.each(displayOnAttribute.split(","), function (displayOn) {
33246            var val = ErrorConstants[displayOn] || 0;
33247            this.displayOn += val;
33248        }, this);
33249        this.$item = $items.eq(0).clone();
33250        $items.remove();
33251    };
33252    _.extend(GlobalErrorContainer.prototype, {
33253        
33254        showError : function (msg, context, fieldSom) {
33255            var nContext,
33256            $el  = this.$container.find('[' + ErrorConstants.DATA_ATTRIBUTE_SOM + '="' + fieldSom + '"]');;
33257            if ($el.length > 0) {
33258                $el.find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
33259                    .addBack("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
33260                    .text(msg);
33261            } else {
33262                if (typeof ErrorConstants[context] !== "number") {
33263                    return;
33264                }
33265                nContext = ErrorConstants[context];
33266                if ((nContext & this.displayOn) === nContext) {
33267                    if (this.errorCount === 0) {
33268                        this.$container.removeClass("no-validation-errors");
33269                    }
33270                    this.errorCount++;
33271                    this.$item.clone()
33272                        .find("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
33273                        .addBack("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_TEXT_CONTAINER + "]")
33274                        .text(msg)
33275                        .click(function (evnt) {
33276                            guideBridge.setFocus(fieldSom);
33277                        })
33278                        .end()
33279                        .end()
33280                        .attr(ErrorConstants.DATA_ATTRIBUTE_SOM, fieldSom)
33281                        .appendTo(this.$container);
33282                }
33283            }
33284        },
33285        hideError : function (fieldSom) {
33286            var $err = this.$container.find('[' + ErrorConstants.DATA_ATTRIBUTE_SOM + '="' + fieldSom + '"]');
33287            if ($err.length > 0) {
33288                $err.remove();
33289                this.errorCount--;
33290            }
33291            if (this.errorCount === 0) {
33292                this.$container.addClass("no-validation-errors");
33293            }
33294        }
33295    });
33296
33297    $.fn.globalErrorContainer = function (options) {
33298        var args = arguments;
33299        return this.each(function () {
33300            var $this = $(this),
33301                obj = $this.data("global-error-container");
33302            if (obj === undefined) {
33303                obj = new GlobalErrorContainer($this, $.extend({}, typeof options === "object" && options));
33304                $this.data("global-error-container", obj);
33305            }
33306            if (typeof options === "string" && typeof obj[options] === "function") {
33307                obj[options].apply(obj, [].splice.apply(args, [1]));
33308            }
33309        });
33310    };
33311}(guidelib, $, _));
33312
33313(function (guidelib, $, _) {
33314
33315    var ErrorConstants = guidelib.util.ErrorConstants,
33316        $GlobalErrorContainer;
33317    var GuideErrorManager = guidelib.util.GuideErrorManager = xfalib.ut.Class.extend({
33318
33319        _defaultErrorMessage : "There is an error in this field !",
33320
33321        initialize : function () {
33322            GuideErrorManager._super.initialize.apply(arguments);
33323            $GlobalErrorContainer = $("[" + ErrorConstants.DATA_ATTRIBUTE_ERROR_CONTAINER + "]").globalErrorContainer();
33324        },
33325
33326        
33327        
33328        markError : function (msg, wrapper, fieldSom, context, type) {
33329            var errorDiv;
33330            
33331            if (_.isUndefined(msg)) {
33332                msg = this._defaultErrorMessage;
33333            }
33334
33335            msg = msg.trim();
33336
33337            $GlobalErrorContainer.globalErrorContainer("showError", msg, context, fieldSom);
33338
33339            
33340            if (wrapper) {
33341                if (wrapper.length >= 1) {
33342                    errorDiv = wrapper.find(".guideFieldError");
33343                    if (errorDiv.length < 1) {
33344                        $("<div class='guideFieldError'></div>").appendTo(wrapper).text(msg);
33345                    } else {
33346                        errorDiv.text(msg);
33347                        var roleAttr = errorDiv.attr('role');
33348                        if (roleAttr != undefined || roleAttr !== false) {
33349                            errorDiv.attr('role', 'alert');
33350                        }
33351                        errorDiv.show();
33352                    }
33353
33354                }
33355            }
33356        },
33357
33358        unMarkError : function (wrapper, fieldSom) {
33359            
33360            
33361            wrapper.find(".guideFieldError").text("");
33362            $GlobalErrorContainer.globalErrorContainer("hideError", fieldSom);
33363        }
33364    });
33365})(guidelib, $, _);
33366(function (_, guidelib) {
33367    guidelib.model.mixin.ChoiceGroupOptionHandler = {
33368        normalProperties : {
33369            
33370            _getOptionsArray : function (saveValueKey, displayValueKey) {
33371                var items = [], items1 = this.items;
33372                saveValueKey = saveValueKey || "saveValue";
33373                displayValueKey = displayValueKey || "displayValue";
33374                if (_.isArray(items1)) {
33375                    _.each(items1, function (val) {
33376                        
33377                        
33378                        var temp = val.split('='),
33379                            obj = {};
33380                        obj[saveValueKey] = temp[0];
33381                        obj[displayValueKey] = temp[1] || temp[0];
33382                        items.push(obj);
33383                    });
33384                }
33385                return items;
33386            },
33387
33388            
33389            _getPossibleValueArray : function () {
33390                var values = [], items1 = this.items;
33391                if (_.isArray(items1)) {
33392                    _.each(items1, function (val) {
33393                        
33394                        var temp = val.split('=');
33395                        values.push(temp[0]);
33396                    });
33397                }
33398                return values;
33399            },
33400
33401            
33402            _triggerItemsChange : function (oldValue, newValue) {
33403                this.trigger(guidelib.event.GuideModelEvent.ITEMS_CHANGED,
33404                    guidelib.event.GuideModelEvent.createEvent(
33405                        guidelib.event.GuideModelEvent.ITEMS_CHANGED,
33406                        this,
33407                        "items",
33408                        oldValue,
33409                        newValue
33410                    )
33411                );
33412            },
33413
33414            _resetModelValueForOptionChange : function () {
33415                if (!_.isUndefined(this.jsonModel._value) && this.jsonModel._value != null) {
33416                    var valueArr = this.jsonModel._value.split(",");
33417                    var possibleValues = this._getPossibleValueArray();
33418                    var modelValue = "";
33419                    _.each(valueArr, function (val) {
33420                        if ($.inArray(val, possibleValues, 0) !== -1) {
33421                            modelValue += val + ",";
33422                        }
33423                    }, this);
33424                    if (modelValue.length > 0) {
33425                        modelValue = modelValue.substring(0, modelValue.length - 1);
33426                    }
33427                    this.jsonModel._value = modelValue;
33428                }
33429            }
33430        }
33431    };
33432
33433}(_, guidelib));
33434(function (_, guidelib) {
33435    var GuideCheckBox = guidelib.model.GuideCheckBox = guidelib.model.Field.extend({
33436        msClassName : "guideCheckBox",
33437        
33438        _collectExpressions : function () {
33439            GuideCheckBox._super._collectExpressions.apply(this);
33440            if (this.optionsExp) {
33441                this._compiledExpressions.optionsExp = this._compileExpression(this.optionsExp, "items");
33442            }
33443        },
33444
33445        getOnOffValues : function (index) {
33446            var temp = this.jsonModel.options || [], items = [], on, off;
33447            if (this.bindNode) {
33448                on = this.bindNode.getSaveItem(0);
33449                off = this.bindNode.getSaveItem(1);
33450            } else {
33451
33452                if (temp.length == 0) {
33453                    on = "0";
33454                } else {
33455                    on = temp[index].split('=')[0].trim();
33456                }
33457                off = "-100";
33458            }
33459
33460            items = [on, off];
33461            return items;
33462        },
33463
33464        _setXFAValue : function (value) {
33465            
33466            if (value === "" || value === null) {
33467                this.bindNode.rawValue = this.bindNode.getSaveItem(1) || null;
33468            } else {
33469                this.bindNode.rawValue = value;
33470            }
33471        },
33472
33473        _getCustomAssist : function (index) {
33474            var customAssist, item;
33475
33476            if (index == null) {
33477
33478                if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
33479                    return this.bindNode.assist.speak.value;
33480                }
33481                return null;
33482            }
33483
33484            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33485                item = this.bindNode.members.item(index);
33486                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33487                    customAssist = item.assist.speak.value;
33488                }
33489            } else if (this.jsonModel.custom) {
33490
33491                var custom;
33492                custom = this.jsonModel.custom || [];
33493                if (_.isString(custom) && index <= 0) {
33494                    customAssist = custom;
33495                } else if (!custom.length === 0) {
33496                    customAssist = custom[index];
33497                }
33498            }
33499            return customAssist;
33500        },
33501        _getToolTip : function (index) {
33502            var toolTip, item;
33503            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33504                item = this.bindNode.members.item(index);
33505
33506                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33507                    toolTip = item.assist.toolTip.value;
33508                }
33509
33510            }
33510 else if (this.jsonModel.shortDescription) {
33511                toolTip = this.jsonModel.shortDescription;
33512            }
33513            return toolTip;
33514        },
33515        _getCaption : function (index) {
33516            var item, caption, option;
33517            if (index == null) {
33518
33519                if (this.bindNode && this.bindNode.caption && this.bindNode.caption.value && this.bindNode.caption.value.oneOfChild && this.bindNode.caption.value.oneOfChild.value) {
33520                    return this.bindNode.caption.value.oneOfChild.value;
33521                }
33522                return null;
33523            }
33524            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33525                item = this.bindNode.members.item(index);
33526                if (item.caption && item.caption.value && item.caption.value.oneOfChild && item.caption.value.oneOfChild.value) {
33527                    caption = item.caption.value.oneOfChild.value;
33528                }
33529
33530            } else if (this.jsonModel.options) {
33531                var options;
33532                options = this.jsonModel.options || [];
33533                if (index < 0) {
33534                    index = 0;
33535                }
33536                if (!options.length == 0) {
33537                    option = options[index];
33538                    caption = guidelib.util.GuideUtil.getOptionsKeyValue(option).pop();
33539                }
33540
33541            }
33542            return caption;
33543        },
33544        _getName : function (index) {
33545            if (this.bindNode && this.bindNode.members && this.bindNode.members.item && this.bindNode.members.item(index)) {
33546                
33547                return this.bindNode.members.item(index).name;
33548            }
33549            return null;
33550        },
33551
33552        _getScreenReaderText : function (index) {
33553            var screenReaderText, assistPriority = this._getAssistPriority() || "caption";
33554
33555            if (this.bindNode) {
33556                screenReaderText = GuideCheckBox._super._getScreenReaderText.apply(this, [index]);
33557            } else {
33558                if (assistPriority == "custom") {
33559                    screenReaderText = this._getCustomAssist(index) || this._getCaption(index);
33560                } else if (assistPriority == "caption") {
33561                    screenReaderText = this._getCaption(index);
33562                }
33563            }
33564            return screenReaderText;
33565        }
33566    });
33567
33568    GuideCheckBox.defineProps({
33569        
33570        optionsExp : {
33571            get : function () {
33572                return this.getAttribute("optionsExp");
33573            }
33574        },
33575
33576        
33577        items : {
33578            get : function () {
33579                var items  =  this.jsonModel.options;
33580                if (items && !_.isArray(items)) {
33581                    items = items.split(",");
33582                } else if (items) {
33583                    items = items.slice(0);
33584                }
33585                return items;
33586            },
33587            set : function (newValue) {
33588                if (!this.bindNode) {
33589                    var oldValue = this.jsonModel.options;
33590                    if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
33591                        
33592                        this.jsonModel.options = newValue;
33593                        this._resetModelValueForOptionChange();
33594                        this._addStateOverride("options", {"option" : this._getOptionsArray()});
33595                        this._triggerItemsChange(oldValue, newValue);
33596                    }
33597                }
33598            }
33599        }
33600    });
33601
33602    GuideCheckBox.addMixins([
33603        guidelib.model.mixin.ChoiceGroupOptionHandler
33604    ]);
33605})(_, guidelib);
33606(function (_, guidelib) {
33607    var GuideSwitch = guidelib.model.GuideSwitch = guidelib.model.GuideCheckBox.extend({
33608        msClassName : "guideSwitch",
33609
33610        initialize : function () {
33611            
33612            var uncheckedValue = this.getOnOffValues()[1];
33613            this.jsonModel["_value"] = this.getOrElse(this.jsonModel, "_value", uncheckedValue);
33614            GuideSwitch._super.initialize.call(this);
33615        },
33616
33617        getOnOffValues : function (index) {
33618            var options, checkedLabel, uncheckedLabel, items;
33619            if (this.bindNode) {
33620                checkedLabel = this.bindNode.getSaveItem(0);
33621                uncheckedLabel = this.bindNode.getSaveItem(1);
33622            } else {
33623                items = this.jsonModel.options;
33624                
33625                if (Array.isArray(items) && items.length > 0) {
33626                    checkedLabel = items[0].split('=')[0].trim();
33627                } else if (!_.isUndefined(items) && items.length > 0) {
33628                    checkedLabel = items.split('=')[0].trim();
33629                } else {
33630                    checkedLabel = "1";
33631                }
33632                if (Array.isArray(items) && items.length > 1) {
33633                    uncheckedLabel = items[1].split('=')[0].trim();
33634                } else {
33635                    uncheckedLabel = "0";
33636                }
33637            }
33638            options = [checkedLabel, uncheckedLabel];
33639            return options;
33640        },
33641
33642        resetData : function () {
33643            this.value = this.jsonModel["{default}"];
33644        }
33645    });
33646})(_, guidelib);
33647(function (_, guidelib) {
33648    var GuideRadioButton = guidelib.model.GuideRadioButton = guidelib.model.Field.extend({
33649        msClassName : "guideRadioButton",
33650        prevOnItem : null,
33651        initialize : function () {
33652            
33653            GuideRadioButton._super.initialize.call(this);
33654        },
33655
33656        _postInitialize : function () {
33657            GuideRadioButton._super._postInitialize.call(this);
33658            this.prevOnItem = this.getSelectedIndex(this.value);
33659            if (this.bindNode && this.bindNode.members) {
33660                for (var i = 0; i < this.bindNode.members.length; i++) {
33661                    var field = this.bindNode.members.item(i);
33662                    field.on(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
33663                }
33664            }
33665        },
33666
33667        _unloadModel : function () {
33668            if (this.bindNode && this.bindNode.members) {
33669                for (var i = 0; i < this.bindNode.members.length; i++) {
33670                    var field = this.bindNode.members.item(i);
33671                    field.off(xfalib.script.XfaModelEvent.FORM_MODEL_CHANGED, this);
33672                }
33673            }
33674
33675            GuideRadioButton._super._unloadModel.call(this);
33676        },
33677
33678        
33679        _collectExpressions : function () {
33680            GuideRadioButton._super._collectExpressions.apply(this);
33681            if (this.optionsExp) {
33682                this._compiledExpressions.optionsExp = this._compileExpression(this.optionsExp, "items");
33683            }
33684        },
33685
33686        
33687        getItemIdentifier : function (index) {
33688            if (this.bindNode) {
33689                return this.bindNode.members.item(index).somExpression;
33690            } else {
33691                return index;
33692            }
33693
33694        },
33695
33696        playJson : function (pJsonModel) {
33697            GuideRadioButton._super.playJson.call(this, pJsonModel);
33698            this.prevOnItem = this.getSelectedIndex(this.jsonModel._value);
33699        },
33700
33701        getOnOffValues : function (index) {
33702            var temp = this.jsonModel.options || [],
33703                items = [],
33704                on,
33705                off;
33706            if (this.bindNode) {
33707                var item = this.bindNode.members.item(index);
33708                on = item.getSaveItem(0);
33709                off = item.getSaveItem(1) ? item.getSaveItem(1) : null;
33710            } else {
33711
33712                if (temp.length == 0) {
33713                    on = "0";
33714                } else {
33715                    on = temp[index].split('=')[0].trim();
33716                }
33717                off = null;
33718            }
33719
33720            items = [on, off];
33721            return items;
33722        },
33723
33724        _handleXfaModelChanged : function (event) {
33725            if (event._property == "rawValue") {
33726                this.trigger(guidelib.event.GuideModelEvent.VALUE_CHANGED,
33727                    guidelib.event.GuideModelEvent.createEvent(
33728                        guidelib.event.GuideModelEvent.VALUE_CHANGED,
33729                        this,
33730                        "value",
33731                        event.target.somExpression,
33732                        event.newText
33733                    )
33734                );
33735            } else {
33736                GuideRadioButton._super._handleXfaModelChanged.call(this, event);
33737            }
33738        },
33739
33740        getSelectedIndex : function (value) {
33741            var index = null;
33742            if (!_.isEmpty(this.jsonModel.options) && !_.isArray(this.jsonModel.options)) {
33743                this.jsonModel.options = [this.jsonModel.options];
33744            }
33745            var currOption = _.find(this.jsonModel.options, function (opt, i) {
33746                var items = this.getOnOffValues(i);
33747                index = i;
33748                return (items[0] == value);
33749            }, this);
33750
33751            if (currOption) {
33752                return index;
33753            } else {
33754                return null;
33755            }
33756
33757        },
33758
33759        
33760
33761        _triggerDisplayFormatChange : function () {
33762            if (!this.bindNode) {
33763                var currValue = this._getValue();
33764                var currSelected = this.getSelectedIndex(currValue);
33765
33766                if (this.prevOnItem !== null) {
33767                    this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value", this.prevOnItem, null);
33768                }
33769                if (currSelected !== null) {
33770                    this._triggerEvent(guidelib.event.GuideModelEvent.VALUE_CHANGED, "value", currSelected, this._getFormattedValue(currValue));
33771                }
33772                this.prevOnItem = currSelected;
33773            }
33774        },
33775        _getCustomAssist : function (index) {
33776            var customAssist, item;
33777
33778            if (index == null) {
33779
33780                if (this.bindNode && this.bindNode.assist && this.bindNode.assist.speak && this.bindNode.assist.speak.value) {
33781                    return this.bindNode.assist.speak.value;
33782                }
33783                return null;
33784            }
33785
33786            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33787                item = this.bindNode.members.item(index);
33788                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33789                    customAssist = item.assist.speak.value;
33790                }
33791            } else if (this.jsonModel.custom) {
33792
33793                var custom;
33794                custom = this.jsonModel.custom || [];
33795                if (_.isString(custom) && index <= 0) {
33796
33797                    customAssist = custom;
33798                } else {
33799                    if (!custom.length == 0) {
33800                        customAssist = custom[index];
33801                    }
33802                }
33803            }
33804            return customAssist;
33805        },
33806        _getToolTip : function (index) {
33807            var toolTip, item;
33808            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33809                item = this.bindNode.members.item(index);
33810
33811                if (item && item.assist && item.assist.speak && item.assist.speak.value) {
33812                    toolTip = item.assist.toolTip.value;
33813                }
33814
33815            }
33815 else if (this.jsonModel.shortDescription) {
33816                toolTip = this.jsonModel.shortDescription;
33817            }
33818            return toolTip;
33819        },
33820        _getCaption : function (index) {
33821            var item, caption, option;
33822            if (index == null) {
33823
33824                if (this.bindNode && this.bindNode.caption && this.bindNode.caption.value && this.bindNode.caption.value.oneOfChild && this.bindNode.caption.value.oneOfChild.value) {
33825                    return this.bindNode.caption.value.oneOfChild.value;
33826                }
33827                return null;
33828            }
33829            if (this.bindNode && this.bindNode.members && this.bindNode.members.item) {
33830                item = this.bindNode.members.item(index);
33831                if (item.caption && item.caption.value && item.caption.value.oneOfChild && item.caption.value.oneOfChild.value) {
33832                    caption = item.caption.value.oneOfChild.value;
33833                }
33834
33835            } else if (this.jsonModel.options) {
33836                var options;
33837                options = this.jsonModel.options || [];
33838                if (index < 0) {
33839                    index = 0;
33840                }
33841                if (!options.length == 0) {
33842                    option = options[index];
33843                    caption = guidelib.util.GuideUtil.getOptionsKeyValue(option).pop();
33844                }
33845
33846            }
33847            return caption;
33848        },
33849        _getName : function (index) {
33850            if (this.bindNode && this.bindNode.members && this.bindNode.members.item && this.bindNode.members.item(index)) {
33851                
33852                return this.bindNode.members.item(index).name;
33853            }
33854            return null;
33855        },
33856
33857        _getScreenReaderText : function (index) {
33858            var screenReaderText, assistPriority = this._getAssistPriority() || "caption";
33859
33860            if (this.bindNode) {
33861                screenReaderText = GuideRadioButton._super._getScreenReaderText.apply(this, [index]);
33862            } else {
33863                if (assistPriority == "custom") {
33864                    screenReaderText = this._getCustomAssist(index) || this._getCaption(index);
33865                } else if (assistPriority == "caption") {
33866                    screenReaderText = this._getCaption(index);
33867                }
33868            }
33869            return screenReaderText;
33870        }
33871    });
33872
33873    GuideRadioButton.defineProps({
33874        
33875        optionsExp : {
33876            get : function () {
33877                return this.getAttribute("optionsExp");
33878            }
33879        },
33880
33881        
33882        items : {
33883            get : function () {
33884                var items  =  this.jsonModel.options;
33885                if (items && !_.isArray(items)) {
33886                    items = items.split(",");
33887                } else if (items) {
33888                    items = items.slice(0);
33889                }
33890                return items;
33891            },
33892            set : function (newValue) {
33893                if (!this.bindNode && newValue && newValue.length > 1) {
33894                    var oldValue = this.jsonModel.options;
33895                    if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
33896                        
33897                        this.jsonModel.options = newValue;
33898                        this._resetModelValueForOptionChange();
33899                        this._addStateOverride("options", {"option" : this._getOptionsArray()});
33900                        this._triggerItemsChange(oldValue, newValue);
33901                    }
33902                }
33903            }
33904        }
33905    });
33906
33907    GuideRadioButton.addMixins([
33908        guidelib.model.mixin.ChoiceGroupOptionHandler
33909    ]);
33910})(_, guidelib);
33911
33912(function (_, guidelib) {
33913
33914    
33915    var GuideDropDownList = guidelib.model.GuideDropDownList = guidelib.model.Field.extend({
33916        msClassName : "guideDropDownList" ,
33917
33918        _collectExpressions : function () {
33919            GuideDropDownList._super._collectExpressions.apply(this);
33920            if (this.optionsExp) {
33921                this._compiledExpressions["optionsExp"] = this._compileExpression(this.optionsExp, "items");
33922            }
33923        },
33924
33925        _handleXfaModelChanged : function (event) {
33926            if (event._property === "addItem" || event._property === "clearItems" || event._property === "deleteItem") {
33927                this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_CHANGED, event._property, event.prevText, event.newText);
33928            } else {
33929                GuideDropDownList._super._handleXfaModelChanged.call(this, event);
33930            }
33931        },
33932
33933        _getDisplayValue : function (saveValue) {
33934            var items = this._getOptionsArray(),
33935                displayValue = null;
33936            _.each(items, function (val) {
33937                if (saveValue === val.saveValue) {
33938                    displayValue = val.displayValue;
33939                }
33940            }, this);
33941            return displayValue;
33942        },
33943
33944        _getItems : function () {
33945            return this.jsonModel.options;
33946        },
33947
33948        _setXFAItems : function (options) {
33949            var optionsStr = this._getXFAOptionStringFromGuideItems(options);
33950            var SET_ITEMS_INSERT_MODE_PAIR = 2;
33951            if (optionsStr) {
33952                this.bindNode.setItems(optionsStr, SET_ITEMS_INSERT_MODE_PAIR);
33953            } else {
33954                this.bindNode.clearItems();
33955            }
33956        },
33957
33958        
33959        _allowEmptyValueString : function () {
33960            return true;
33961        }
33962
33963    });
33964
33965    GuideDropDownList.defineProps({
33966
33967        
33968        
33969        multiSelect : {
33970            get : function () {
33971                return this.getAttribute("multiSelect");
33972            },
33973            set : function () {
33974                this.setAttribute("multiSelect");
33975            }
33976        },
33977
33978        optionsExp : {
33979            get : function () {
33980                return this.getAttribute("optionsExp");
33981            }
33982        },
33983
33984        
33985        displayValue : {
33986            get : function () {
33987                return this._getDisplayValue(this.value);
33988            }
33989        },
33990
33991        
33992        
33993        items : {
33994            get : function () {
33995                var items = [];
33996                if (this.bindNode) {
33997                    var that = this.bindNode;
33998                    for (var index = 0; index < that.length; index++) {
33999                        var item = that.getSaveItem(index) + "=" + that.getDisplayItem(index);
34000                        items.push(item);
34001                    }
34002                    return items;
34003                } else {
34004                    items  =  this._getItems();
34005                    if (items && !_.isArray(items)) {
34006                        items = items.split(",");
34007                    } else if (items) {
34008                        items = items.slice(0);
34009                    }
34010                    return items;
34011                }
34012            },
34013            set : function (newValue) {
34014                var oldValue = this._getItems();
34015                if (JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
34016                    if (this.bindNode) {
34017                        this._setXFAItems(newValue);
34018                    } else {
34019                        this.jsonModel.options = newValue;
34020                    }
34021                    if (this.multiSelect) {
34022                        this._resetModelValueForOptionChange();
34023                    }
34024                    this._addStateOverride("options", {"option" : this._getOptionsArray()});
34025                    this._triggerItemsChange(oldValue, this.items);
34026                }
34027            }
34028        }
34029    });
34030    GuideDropDownList.addMixins([
34031        guidelib.model.mixin.ChoiceGroupOptionHandler
34032    ]);
34033})(_, guidelib);
34034
34035
34036(function (guidelib, $, _) {
34037
34038    var GuideLazyUtil = guidelib.util.GuideLazyUtil = xfalib.ut.Class.extend({
34039
34040        
34041        putDirtyToTemplateCacheIfMissing : function (guide) {
34042            var guideDirtyMarker = guide.internal.GuideDirtyMarkerAndVisitor || this._guide().internal.GuideDirtyMarkerAndVisitor,
34043                listOfDirtyChildren = guideDirtyMarker._flattenDirtyPanelToList();
34044            this._getAllDirtyJsonTemplateInCache(listOfDirtyChildren);
34045        },
34046        
34047
34048        _getAllDirtyJsonTemplateInCache : function (listOfTemplateIds) {
34049            var modelTemplateCache = window.guideBridge._guide._modelTemplateCacheStore,
34050                toGetFromServer = this._generateListOfCacheMissFromTemplateJson(listOfTemplateIds);
34051            if (toGetFromServer.length > 0 && window.guideBridge.panelProvider) {
34052                var options = {
34053                    path : window.guideBridge._getGuidePathUrl(".jsonhtmlemitter"),
34054                    listOfTemplateIds : toGetFromServer,
34055                    success : addToTemplateCache
34056                };
34057                window.guideBridge.panelProvider.getMultipleTemplateJson(options);
34058            }
34059
34060            function addToTemplateCache(toInsertToTemplateCache) {
34061                _.each(toInsertToTemplateCache, function (jsonModelString) {
34062                    var template = JSON.parse(jsonModelString);
34063                    modelTemplateCache._putLazyTemplate(template);
34064                });
34065            }
34066        },
34067
34068        
34069        _generateListOfCacheMissFromTemplateJson : function (listOfTemplateIds) {
34070            var templateCache = window.guideBridge._guide._modelTemplateCacheStore,
34071                cacheMiss = [];
34072            _.each(listOfTemplateIds, function (templateID) {
34073                var templateJson = templateCache._getTemplate(templateID, true);
34074                if (guidelib.util.GuideUtil.isLazyJson(templateJson)) {
34075                    cacheMiss.push(templateID);
34076                }
34077            });
34078            return cacheMiss;
34079        },
34080
34081        _guide : function () {
34082            return this.options._guideContainer;
34083        }
34084
34085    });
34086})(guidelib, $, _);
34087(function (_, guidelib) {
34088    var guideSchema = {},
34089        convertor = {
34090            "visible" : {
34091                "xfaToGuide" : function (xfaValue) {
34092                    return xfaValue === "visible";
34093                },
34094                "guideToXfa" : function (guideValue) {
34095                    return guideValue === true ? "visible" : "hidden";
34096                }
34097            },
34098            "enabled" : {
34099                "xfaToGuide" : function (xfaValue) {
34100                    return xfaValue === "open";
34101                },
34102                "guideToXfa" : function (guideValue) {
34103                    return guideValue === true ? "open" : "readOnly";
34104                }
34105            },
34106            "assistPriority" : {
34107                "xfaToGuide" : function (xfaValue) {
34108                    return {
34109                        "custom" : "custom",
34110                        "toolTip" : "shortDescription",
34111                        "caption" : "label",
34112                        "name" : "name"
34113                    }[xfaValue];
34114                },
34115                "guideToXfa" : function (guideValue) {
34116                    return {
34117                        "custom" : "custom",
34118                        "shortDescription" : "toolTip",
34119                        "title" : "caption",
34120                        "name" : "name"
34121                    }[guideValue];
34122                }
34123            },
34124            "mandatory" : {
34125                "xfaToGuide" : function (xfaValue) {
34126                    return xfaValue === "error";
34127                },
34128                "guideToXfa" : function (guideValue) {
34129                    return guideValue === true ? "error" : "disabled";
34130                }
34131            },
34132            "multiLine" : {
34133                "xfaToGuide" : function (xfaValue) {
34134                    return xfaValue == 1;
34135                },
34136                "guideToXfa" : function (guideValue) {
34137                    return guideValue === true ? 1 : 0;
34138                }
34139            },
34140            
34141            
34142            "options" : {
34143                "xfaToGuide" : function (xfaValue) {
34144                    var items = [];
34145                    if (xfaValue) {
34146                        var bndNode = this.bindNode;
34147                        _.each(xfaValue, function (item, index, list) {
34148                            items.push(bndNode.getSaveItem(index) + "=" + bndNode.getDisplayItem(index));
34149                        });
34150                    }
34151                    return items;
34152                },
34153                "guideToXfa" : function (guideValue) {
34154                    return guideValue;
34155                }
34156            },
34157            "multiSelect" : {
34158                "xfaToGuide" : function (xfaValue) {
34159                    return xfaValue === "multiSelect";
34160                },
34161                "guideToXfa" : function (guideValue) {
34162                    return guideValue === true ? "multiSelect" : "userControl";
34163                }
34164            },
34165            "calcExp" : {
34166                "xfaToGuide" : function (xfaValue) {
34167                    return xfaValue !== null && xfaValue !== "" ? null : undefined;
34168                },
34169                "guideToXfa" : function (guideValue) {
34170                    return guideValue !== null && guideValue !== "" ? null : undefined;
34171                }
34172            },
34173            "dataType" : {
34174                "xfaToGuide" : function (xfaValue) {
34175                    return xfaValue;
34176                },
34177                "guideToXfa" : function (guideValue) {
34178                    return undefined;
34179                }
34180            }
34181        };
34182    convertor.validateExp = convertor.visibleExp =
34183                          convertor.enabledExp =
34184                          convertor.clickExp =
34185                          convertor.calcExp;
34186
34187    guidelib.model.GuideSchema = xfalib.ut.Class.extend({
34188
34189        GuideStateConstants : {
34190            
34191            GUIDE_STATE_MODEL_CREATION : 0,
34192            
34193            GUIDE_STATE_MODEL_CREATED : 1,
34194            
34195            GUIDE_STATE_MERGE_PROGRESS : 2,
34196            
34197            GUIDE_STATE_MERGE_COMPLETE : 3,
34198            
34199            GUIDE_STATE_MODEL_COMPLETE : 4
34200        },
34201
34202        initialize : function () {
34203            
34204            this.addSchema('guideNode',
34205                [
34206                    ["name", "string", null],
34207                    ["id", "string", null],
34208                    ["jcr:title", "string", null],
34209                    ["jcr:description", "string", null],
34210                    ["css", "string", ""],
34211                    ["fd:targetVersion", "float", 1.0]
34212                ]);
34213
34214            this.addSchema("scriptable",
34215                [
34216                    ["visibleExp", "string", null],
34217                    ["enabledExp", "string", null],
34218                    ["visible", "boolean", true, "presence"],
34219                    ["enabled", "boolean", true, "access"],
34220                    ["assistPriority", "string", null, "assist.speak.priority"],
34221                    ["custom", "string", null, "assist.speak.value"],
34222                    ["shortDescription", "string", null, "assist.toolTip.value"],
34223                    ["longDescription", "string", null]
34224                ],
34225                'guideNode');
34226
34227            this.addSchema("guideInstanceManager", [], "guideNode");
34228
34229            this.addSchema("esign", [], "guideNode");
34230
34231            this.addSchema("verify", [], "guideNode");
34232
34233            this.addSchema("guideItemsContainer", [], "scriptable");
34234
34235            this.addSchema("guideImage", [], "scriptable");
34236
34237            this.addSchema("guideContainerNode",
34238            [
34239                ["disableSwipeGesture", "boolean", false]
34240            ],
34241            "guideItemsContainer");
34242
34243            this.addSchema("guidePanel",
34244                [
34245                  ["validateOnStepCompletion","boolean",false]
34246                ],
34247                "guideItemsContainer");
34248
34249            this.addSchema("rootPanelNode", [], "guidePanel");
34250
34251            this.addSchema("guideTable", [], "guidePanel");
34252
34253            this.addSchema("guideTableRow", [], "guidePanel");
34254
34255            this.addSchema("guideToolbar", [], "guideItemsContainer");
34256
34257            this.addSchema("guideCompositeField", [], "guideItemsContainer");
34258
34259            this.addSchema("guideFileUpload",
34260                [
34261                    ["multiSelection", "boolean", false],
34262                    ["buttonText", "string", null],
34263                    ["fileSizeLimit", "integer", 2],
34264                    ["showComment", "boolean", false]
34265                ],
34266                "guideCompositeField");
34267
34268            
34269            
34270            this.addSchema("guideField",
34271                [
34272                    ["jcr:title", "string", null, "caption.value.oneOfChild.value","Guide"],
34273                    ["calcExp", "string", null, "calculate.script.value", "Guide"],
34274                    ["validateExp", "string", null, "validate.script.value", "Guide"],
34275                    ["_value", "string", null, "rawValue"],
34276                    ["displayPictureClause", "string", null, "format.picture.value"],
34277                    ["validatePictureClause", "string", null, "validate.picture.value"],
34278                    ["mandatory", "boolean", false, "validate.nullTest"],
34279                    ["mandatoryMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-005"]),
34280                        "mandatoryMessage"],
34281                    ["validateExpMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-006"]),
34282                        "validationMessage","Guide"],
34283                    ["validatePictureClauseMessage", "string", guidelib.util.GuideUtil.getLocalizedMessage("", guidelib.i18n.LogMessages["AEM-AF-901-007"]),
34284                        "formatMessage"],
34285                    ["validationState", "boolean", false], 
34286                    ["width", "string", null],
34287                    ["height", "string", null]
34288                ],
34289                "scriptable");
34290
34291            this.addSchema("guideTextBox",
34292                [
34293                    ["multiLine", "boolean", false, "ui.textEdit.multiLine"],
34294                    ["maxChars", "integer", 0, "value.text.maxChars"],
34295                    ["minLength", "integer", null],
34296                    ["length", "integer", null]
34297                ],
34298                "guideField");
34299
34300            this.addSchema("guideCaptcha", [], "guideField");
34301
34302            this.addSchema("guideTelephone", [], "guideField");
34303
34304            this.addSchema("guideNumericBox",
34305                [
34306                    ["dataType", "string", "decimal", "value.oneOfChild.className"],
34307                    ["leadDigits", "integer", -1, "value.decimal.leadDigits"],
34308                    ["fracDigits", "integer", 2, "value.decimal.fracDigits"],
34309                    ["maximum", "integer", null],
34310                    ["minimum", "integer", null],
34311                    ["exclusiveMaximum", "boolean", null],
34312                    ["exclusiveMinimum", "boolean", null]
34313                ],
34314                "guideField");
34315
34316            this.addSchema("guidePasswordBox", [], "guideField");
34317
34318            this.addSchema("guideRadioButton", [
34319                ["optionsExp", "string", null],
34320                ["options", "object", null, "items"]
34321            ], "guideField");
34322
34323            this.addSchema("guideCheckBox", [
34324                ["optionsExp", "string", null],
34325                ["options", "object", null, "items"]
34326            ], "guideField");
34327
34328            this.addSchema("guideSwitch", [], "guideCheckBox");
34329
34330            this.addSchema("guideScribble", [], "guideField");
34331
34332            this.addSchema("guideDatePicker",
34333                [
34334                    ["maximum", "string", null],
34335                    ["minimum", "string", null],
34336                    ["exclusiveMaximum", "boolean", null],
34337                    ["exclusiveMinimum", "boolean", null]
34338                ], "guideField");
34339
34340            this.addSchema("guideButton", [], "guideField");
34341
34342            this.addSchema("guideListFileAttachmentButton", [], "guideButton");
34343
34344            this.addSchema("guideTextDraw",
34345                [
34346                    ["documentFragmentVariables", "string", null]
34347                ],
34348                "guideField");
34349
34350            this.addSchema("guideFootnotePlaceHolder",[], "guideTextDraw");
34351
34352            this.addSchema("guideAdobeSignBlock",
34353                [
34354                    ["documentFragmentVariables", "string", null]
34355                ],
34356                "guideField");
34357
34358            this.addSchema("guideCompositeFieldItem", [], "guideField");
34359
34360            this.addSchema("guideDropDownList",
34361                [
34362                    ["title", "string", "DropDown"],
34363                    ["multiSelect", "boolean", false, "ui.oneOfChild.open"],
34364                    ["optionsExp", "string", null],
34365                    ["options", "object", null, "items"]
34366                ],
34367                "guideField");
34368
34369            this.addSchema("guideTermsAndConditions",
34370                [
34371                    ["showLink", "boolean", false],
34372                    ["showAsPopUp", "boolean", false],
34373                    ["clickStatus", "string", null]
34374                ],
34375                "guideCompositeField");
34376
34377            this.addSchema("guideChart", [
34378                ["height", "integer", 300],
34379                ["width", "integer", 100],
34380                ["data", "object", null],
34381                ["xAxisTitle", "string", null],
34382                ["yAxisTitle", "string", null],
34383                ["chartType", "string", "linepoint"],
34384                ["repeatableItem", "string", null],
34385                ["xExp", "string", null],
34386                ["reducerXFunction", "string", "none"],
34387                ["yExp", "string", null],
34388                ["reducerYFunction", "string", "none"],
34389                ["innerRadius", "integer", 0],
34390                ["lineColor", "string", "#000000"],
34391                ["pointColor", "string", "#000000"],
34392                ["areaColor", "string", "#000000"],
34393                ["tooltipHtml", "string", "<p>${x}(${y})</p>"],
34394                ["showLegends", "boolean", false],
34395                ["legendPosition", "string", "right"]
34396            ], "scriptable");
34397
34398            this.addSchema("guideAdModule", [["_value", "string", null]], "scriptable");
34399            this.addSchema("guideAdModuleGroup", [["_value", "string", null]], "scriptable");
34400        },
34401
34402        addSchema : function (elementName, attrArray, superElement) {
34403            var el = {};
34404            if (typeof superElement === "object") {
34405                _.extend(el, superElement);
34406            } else if (typeof superElement === "string" && guideSchema[superElement]) {
34407                _.extend(el, guideSchema[superElement]);
34408            }
34409            this.addAttributes(el, attrArray);
34410            guideSchema[elementName] = el;
34411        },
34412
34413        addAttributes : function (element, attrArray) {
34414            _.each(attrArray, function (elem) {
34415                element[elem[0]] = {
34416                    "type" : elem[1],
34417                    "default" : elem[2],
34418                    "xfaProp" : elem[3],
34419                    "priority" : elem[4]
34420                };
34421            });
34422        },
34423
34424        getAttributeProps : function (element, attribute) {
34425            try {
34426                return guideSchema[element][attribute] || {};
34427            } catch (e) {
34428                this.logger().error("AF", "schema has no element " + element);
34429            }
34430        },
34431        getAttributes : function (element) {
34432            return guideSchema[element];
34433        },
34434
34435        getTypedValue : function (type, value) {
34436            if (value === null || value === undefined) {
34437                return value;
34438            }
34439            if (type instanceof Array) {
34440                return value;
34441            }
34442            switch (type) {
34443                case "string":
34444                    return value + "";
34445                case "integer":
34446                    return parseInt(value);
34447                case "boolean":
34448                    return value === true || value === "true" ? true : false;
34449                case "float":
34450                    return parseFloat(value);
34451                default :
34452                    return value;
34453            }
34454        },
34455
34456        getConvertor : function (attr) {
34457            return convertor[attr];
34458        }
34459    });
34460
34461}(_, guidelib));
34462
34463(function (_, guidelib) {
34464
34465    
34466    
34467    var GuideContainerNode = guidelib.model.GuideContainerNode = guidelib.model.GuideItemsContainer.extend({
34468        msClassName : "guideContainerNode",
34469
34470        setGuideState : function (guideState) {
34471            var isStateValid = _.some(guidelib.model.GuideSchema.prototype.GuideStateConstants, function (val) {
34472                return val === guideState;
34473            });
34474            if (isStateValid === true) {
34475                this._guideState = guideState;
34476            }
34477        },
34478
34479        getGuideState : function () {
34480            return this._guideState;
34481        },
34482
34483        initialize : function () {
34484            var configString = "";
34485            
34486            guidelib.__runtime__.guide = this;
34487
34488            
34489            
34490            this._guideState = guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MODEL_CREATION;
34491
34492            
34493            this.internal = this.internal || {};
34494            
34495            
34496            this.internal.liveDataUtils = this.options.liveDataUtils || new guidelib.model.LiveXmlUtils();
34497            this.internal.liveModel = this.options.liveModel || new guidelib.model.LiveModel();
34498            this.internal.GuideDirtyMarkerAndVisitor = new guidelib.model.GuideDirtyMarkerAndVisitor();
34499
34500            
34501            this.runtime =  {
34502                guideContext : {},
34503                _private : {},
34504                errorManager : {}
34505            };
34506
34507            
34508            this.runtime.errorManager = new guidelib.util.GuideErrorManager();
34509
34510            this._modelTemplateCacheStore =
34511                new guidelib.model.util.ModelTemplateCacheStore({modelTemplateJson : this.jsonModel});
34512            this._guideSchema = new guidelib.model.GuideSchema();
34513            this.guideLazyUtil = new guidelib.util.GuideLazyUtil({"_guideContainer" : this});
34514            this._pendingQueues = {
34515                calcExp : [],
34516                valueCommitScript : [],
34517                enabledExp : [],
34518                visibleExp : [],
34519                validateAllExp : [],
34520                optionsExp : [],
34521                navigationChangeExp : [],
34522                summaryExp : [],
34523                autoSaveStartExp : [],
34524                aggregateExp : [],
34525                submitSuccess : [],
34526                submitError : [],
34527                saveSuccess : [],
34528                saveError : []
34529            };
34530            this._resetExpressionCounters();
34531            this._currentContext = null;
34532            GuideContainerNode._super.initialize.call(this);
34533            this.autoSaveStart = false;
34534            
34535            
34536            this._modelTemplateCacheStore.putModel(this);
34537            this._postInitialize();
34538            var xfaHost = this.getOrElse(xfalib, "runtime.xfa.host", null);
34539            if (xfaHost !== null) {
34540                xfaHost.on(xfalib.script.XfaModelEvent.FORM_MODEL_REFRESH,
34541                    function (evnt) {
34542                        switch (evnt.name) {
34543                        case xfalib.script.XfaModelEvent.FORM_MODEL_REFRESH:
34544                            this._triggerEvent(guidelib.event.GuideModelEvent.MODEL_REFRESH, "jsonModel", null, null);
34545                            break;
34546                        default:
34547                        
34548                        }
34549                    },
34550                    this);
34551            }
34552        },
34553
34554        _resetExpressionCounters : function () {
34555            this._runningExpressionCount = {
34556                calcExp : {},
34557                valueCommitScript : {},
34558                enabledExp : {},
34559                visibleExp : {},
34560                validateAllExp : {},
34561                optionsExp : {},
34562                navigationChangeExp : {},
34563                summaryExp : {},
34564                autoSaveStartExp : {},
34565                aggregateExp : {},
34566                submitSuccess : {},
34567                submitError : {},
34568                saveSuccess : {},
34569                saveError : {}
34570            };
34571        },
34572
34573        _getReducedJSON : function () {
34574            
34575            
34576            var reducedJSONChildren = guidelib.model.GuideNode.prototype._getReducedJSON.call(this),
34577                addtionalWhitelistedProperties = ["xdpRef", "xsdRef", "id", "dorTemplateRef", "dorType", "excludeFromDoRIfHidden", "schemaRef", "schemaType"];
34578            guidelib.model.util.CommonUtils.returnMinimalJSON(addtionalWhitelistedProperties, reducedJSONChildren, this);
34579            reducedJSONChildren["rootPanel"] = this["rootPanel"]._getReducedJSON();
34580            if (this.jsonModel.toolbar) {
34581                reducedJSONChildren["toolbar"]  = this["toolbar"]._getReducedJSON();
34582            }
34583            return reducedJSONChildren;
34584        },
34585
34586        _initChildren : function () {
34587            
34588            var options =  {"_guideContainer" : this};
34589            this.rootPanel = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.rootPanel, options);
34590            this._initializeChild(this.rootPanel);
34591            this._children.push(this.rootPanel);
34592            
34593            var instanceManager = guidelib.model.GuideModelRegistry.prototype.createInstanceManager(this.rootPanel);
34594            this._initializeChild(instanceManager);
34595            this._children.splice(this._children.indexOf(this.rootPanel), 0, instanceManager);
34596            instanceManager._manageChild(this.rootPanel);
34597
34598            if (this.jsonModel.toolbar) {
34599                var options = {};
34600                if (this._guide()) {
34601                    options = _.extend({}, options, {"_guideContainer" : this._guide()});
34602                }
34603                this.toolbar = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.toolbar, options);
34604                this._initializeChild(this.toolbar);
34605                this._children.push(this.toolbar);
34606            }
34607        },
34608
34609        
34610        _addToExcludeFromDorMap : function (fieldTemplateId, bExcludeFromDor) {
34611            this._excludeFromDorMap = this._excludeFromDorMap || {};
34612            this._excludeFromDorMap[fieldTemplateId] = bExcludeFromDor;
34613        },
34614
34615        
34616        _getExcludeFromDorMap : function () {
34617            var that = this;
34618            if (!_.isUndefined(that._excludeFromDorMap)) {
34619                return _.keys(that._excludeFromDorMap).map(function (key) {
34620                    
34621                    return key  + "="  + that._excludeFromDorMap[key];
34622                });
34623            }
34624        },
34625
34626        
34627        _addToStateOverrideMap : function (fieldName, fieldsOverrid
34627denMap) {
34628            this._stateOverrideMap = this._stateOverrideMap || {};
34629            this._stateOverrideMap[fieldName] = fieldsOverriddenMap;
34630        },
34631
34632        
34633        _getStateOverrideMap : function () {
34634            var that = this;
34635            var retval = {};
34636            if (!_.isUndefined(that._stateOverrideMap)) {
34637                var elementsArray = _.keys(that._stateOverrideMap).map(function (key) {
34638                    return that._stateOverrideMap[key];
34639                });
34640                retval = {"element" : elementsArray};
34641            }
34642            return retval;
34643
34644        },
34645
34646        
34647        _resolveAfDataSom : function (afDataSom) {
34648            var resolvedField = null;
34649            
34650            
34651            _.each(this.internal.liveModel.getCrossFragmentFields(), function (fields) {
34652                
34653                var globalFieldModels = this.internal.liveModel.getAllAbstractFieldModels(_.keys(fields));
34654                _.each(globalFieldModels, function (globalField) {
34655                    if (globalField.afDataSom === afDataSom) {
34656                        resolvedField = globalField;
34657                        return false;
34658                    }
34659                });
34660                if (resolvedField) {
34661                    return false;
34662                }
34663            });
34664            return resolvedField;
34665        },
34666
34667        
34668        _getSigners : function () {
34669           var signers = {};
34670           
34671           if (this.enableAdobeSign && (_.isString(this.xdpRef) ||  _.isString(this.xsdRef) || (!_.isString(this.jsonModel.schemaRef)))) {
34672               var signer,
34673                  that = this,
34674                  email,
34675                  number,
34676                  countryCode,
34677                   evalExp = function (fldSom, fldAfDataSom, type) {
34678                       var val = null,
34679                           resolvedField;
34680                       try {
34681                           resolvedField = guideBridge._guide.resolveNode(fldSom);
34682                           if (!resolvedField) {
34683                               resolvedField = guideBridge._guide._resolveAfDataSom(fldAfDataSom);
34684                           }
34685                           val = resolvedField.value;
34686                           if (resolvedField.className === 'guideTelephone') {
34687                               if (type === 'countryCode') {
34688                                   val = guidelib.model.GuideTelephone.prototype._extractCountryCode(val);
34689                               } else if (type === 'phone') {
34690                                   val = guidelib.model.GuideTelephone.prototype._extractPhoneNumber(val);
34691                               }
34692                           }
34693                       } catch (e) {
34694                           
34695                       }
34696                       
34697                       
34698                       return val ? val.toString() : val;
34699                   };
34700               if (this.signerInfo) {
34701                   _.each(_.keys(this.signerInfo), function (name) {
34702                       signer = that.signerInfo[name];
34703                       if (signer && typeof signer === "object") {
34704                           email = null;
34705                           number = null;
34706                           countryCode = null;
34707                           if (signer.emailSource === 'form' && signer.email) {
34708                               email = evalExp(signer.email, signer.emailAfDataSom, 'email');
34709                           }
34710                           signers[name] = {};
34711                           signers[name].email = email ? email : "";
34712                           if (signer.securityOption === 'PHONE') {
34713                               if (signer.phoneSource === 'form' && signer.phone) {
34714                                   number = evalExp(signer.phone, signer.phoneAfDataSom, 'phone');
34715                               }
34716                               if (signer.countryCodeSource === 'form' && signer.countryCode) {
34717                                   countryCode = evalExp(signer.countryCode, signer.countryCodeAfDataSom, 'countryCode');
34718                               }
34719                               signers[name].phone = {};
34720                               signers[name].phone.countryCode = countryCode ? countryCode : "";
34721                               signers[name].phone.number = number ? number : "";
34722                           }
34723                       }
34724                   });
34725               }
34726           }
34727
34728           return signers;
34729       },
34730
34731        
34732        defaultSubmitSuccess : "window.guideBridge._defaultSubmitSuccessHandler($event.data)",
34733
34734        
34735        defaultSubmitError : "window.guideBridge._handleServerValidationError($event.data)",
34736
34737        
34738        defaultSaveSuccess : "window.guideBridge._defaultSaveSuccessHandler($event.data)",
34739        defaultSaveError : "window.guideBridge._defaultSaveErrorHandler($event.data)",
34740
34741        
34742        _collectExpressions : function () {
34743            if (this.autoSaveStartExpression) {
34744                this._compiledExpressions["autoSaveStartExp"] = this._compileExpression(this.autoSaveStartExpression, "autoSaveStart");
34745            }
34746
34747            
34748            if (!this.submitSuccess) {
34749                this.jsonModel.submitSuccess = this.defaultSubmitSuccess;
34750            }
34751            this._compiledScripts.submitSuccess = this._compileExpression(this.submitSuccess, null);
34752
34753            if (!this.submitError) {
34754                this.jsonModel.submitError = this.defaultSubmitError;
34755            }
34756            this._compiledScripts.submitError = this._compileExpression(this.submitError, null);
34757
34758            if (!this.saveSuccess) {
34759                this.jsonModel.saveSuccess = this.defaultSaveSuccess;
34760            }
34761            this._compiledScripts.saveSuccess = this._compileExpression(this.saveSuccess, null);
34762
34763            if (!this.saveError) {
34764                this.jsonModel.saveError = this.defaultSaveError;
34765            }
34766            this._compiledScripts.saveError = this._compileExpression(this.saveError,  null);
34767        },
34768
34769        prepare : function () {
34770            
34771            
34772            if ((this.getGuideState() !== guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_PROGRESS) && (this.getGuideState() !== guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MODEL_CREATION)) {
34773                _.each(this._children, function (childNode) {
34774                    childNode.prepare();
34775                }, this);
34776                this.queueExpressions(this, ["autoSaveStartExp"]);
34777                this.runPendingExpressions();
34778            }
34779        },
34780
34781        runPendingExpressions : function () {
34782            
34783            this._runExpressionQueue("calcExp");
34784            this._runExpressionQueue("enabledExp");
34785            this._runExpressionQueue("visibleExp");
34786            this._runExpressionQueue("valueCommitScript");
34787            this._runExpressionQueue("validateAllExp");
34788            this._runExpressionQueue("optionsExp");
34789            this._runExpressionQueue("navigationChangeExp");
34790            this._runExpressionQueue("summaryExp");
34791            this._runExpressionQueue("aggregateExp");
34792            this._runExpressionQueue("submitSuccess");
34793            this._runExpressionQueue("submitError");
34794            this._runExpressionQueue("saveSuccess");
34795            this._runExpressionQueue("saveError");
34796
34797            if (window.guideBridge.hostName !== "server") {
34798                this._runExpressionQueue("autoSaveStartExp");
34799            }
34800            this._resetExpressionCounters();
34801        },
34802
34803        _runExpressionQueue : function (expName) {
34804            var expQueue = this._pendingQueues[expName], node;
34805            if (expQueue) {
34806                while (expQueue.length > 0) {
34807                    node = this._pendingQueues[expName].shift();
34808                    if (node) {
34809                        node.executeExpression(expName);
34810                    }
34811                }
34812            }
34813        },
34814
34815        queueExpressions : function (node, expressionArray) {
34816            if (!node || !expressionArray) {
34817                return;
34818            }
34819            if (_.isString(expressionArray)) {
34820                expressionArray = [expressionArray];
34821            }
34822            _.each(expressionArray, function (expression) {
34823                var expQueue = this._pendingQueues[expression],
34824                    som = node.somExpression,
34825                    counters = this._runningExpressionCount[expression];
34826                counters[som] = counters[som] || 0;
34827                if (expQueue && expQueue.indexOf(node) < 0 && counters[som] < 10) {
34828                    expQueue.push(node);
34829                    counters[som] += 1;
34830                }
34831            }, this);
34832        },
34833
34834        playJson : function (pJsonModel, attachments) {
34835            this.rootPanel.playJson(pJsonModel.rootPanel, attachments);
34836            if (this.toolbar) {
34837                this.toolbar.playJson(pJsonModel.toolbar, attachments);
34838            }
34839        },
34840
34841        _guide : function () {
34842            return this;
34843        },
34844
34845        _collectValues : function (keyValue) {
34846            _.each(this._children, function (childNode) {
34847                childNode._collectValues(keyValue);
34848            }, this);
34849        },
34850
34851        
34852        _isFirstSignerFormFiller : function () {
34853            return this.signerInfo.firstSignerFormFiller === "true";
34854        },
34855
34856        
34857        resolveNode : function (somExpression) {
34858            if (!somExpression || somExpression === "") {
34859                return;
34860            }
34861            var hierarchy = somExpression.split("."),
34862                componentInModel = null;
34863            if (hierarchy[0] === "guide[0]") {
34864                hierarchy.shift();
34865                componentInModel = this;
34866            }
34867            if (hierarchy[0] === this._escapeQualifiedName()) {
34868                componentInModel = this;
34869                hierarchy.shift();
34870            } else if (this.hasOwnProperty(hierarchy[0])) {
34871                componentInModel = this[hierarchy[0]];
34872                hierarchy.shift();
34873            } else if (!componentInModel) {
34874                componentInModel = this.rootPanel;
34875            }
34876            _.each(hierarchy, function (element) {
34877                if (componentInModel && componentInModel._findChildren) {
34878                    componentInModel = componentInModel._findChildren(element, false)[0];
34879                } else {
34880                    componentInModel = null;
34881                }
34882            }, this);
34883            if (componentInModel == null) {
34884                
34885                var relativeName = somExpression;
34886                componentInModel = this.getOrElse(this._guide().runtime, relativeName, null);
34887            }
34888            return componentInModel;
34889        }
34890    });
34891
34892    GuideContainerNode.defineProps({
34893
34894        submitSuccess : {
34895            get : function () {
34896                return this.jsonModel.submitSuccess;
34897            }
34898        },
34899
34900        submitError : {
34901            get : function () {
34902                return this.jsonModel.submitError;
34903            }
34904        },
34905
34906        saveSuccess : {
34907            get : function () {
34908                return this.jsonModel.saveSuccess;
34909            }
34910        },
34911
34912        saveError : {
34913            get : function () {
34914                return this.jsonModel.saveError;
34915            }
34916        },
34917
34918        
34919        "autoSaveStart" : {
34920            get : function () {
34921                return this.jsonModel.autoSaveStart;
34922            },
34923
34924            set : function (newValue) {
34925                this.jsonModel.autoSaveStart = newValue;
34926                if (newValue === true) {
34927                    delete this._compiledExpressions.autoSaveStartExp;
34928                    this._triggerOnBridge(window.guideBridge.GUIDE_AUTO_SAVE_START, this);
34929                }
34930            }
34931        },
34932
34933        
34934        "enableAutoSave" : {
34935            set : function (newValue) {
34936                this.jsonModel.enableAutoSave = newValue;
34937            },
34938
34939            get : function () {
34940                return this.jsonModel.enableAutoSave || false;
34941            }
34942        },
34943
34944        
34945        "autoSaveStartExpression" : {
34946            get : function () {
34947                return this.jsonModel.autoSaveStartExpression;
34948            }
34949        },
34950
34951        
34952        "autoSaveInfo" : {
34953            get : function () {
34954                return this.jsonModel.autoSaveInfo;
34955            }
34956        },
34957
34958        
34959        "globalMetaInfo" : {
34960            get : function () {
34961                return this.jsonModel.globalMetaInfo;
34962            }
34963        },
34964
34965        
34966        "submissionMetaInfo" : {
34967            get : function () {
34968                return this.jsonModel.submissionMetaInfo;
34969            }
34970        },
34971
34972        
34973        "signerInfo" : {
34974           get : function () {
34975               return this.jsonModel.signerInfo;
34976           }
34977       },
34978
34979        "xdpRef" : {
34980            get : function () {
34981                return this.jsonModel.xdpRef;
34982            }
34983        },
34984
34985        "dorTemplateRef" : {
34986            get : function () {
34987                return this.jsonModel.dorTemplateRef;
34988            }
34989        },
34990
34991        "dorType" : {
34992            get : function () {
34993                return this.jsonModel.dorType;
34994            }
34995        },
34996
34997        "actionType" : {
34998            get : function () {
34999                return this.jsonModel.actionType;
35000            }
35001        },
35002
35003        "xsdRef" : {
35004            get : function () {
35005                return this.jsonModel.xsdRef;
35006            }
35007        },
35008
35009        
35010        panel : {
35011            get : function () {
35012                return this.rootPanel;
35013            }
35014        },
35015
35016        
35017        print : {
35018            get : function () {
35019                if (this.dorType === "generate" && this.jsonModel.view) {
35020                    return this.jsonModel.view.print;
35021                }
35022
35023                return null;
35024            }
35025        },
35026
35027        
35028        "allLazyChildren" : {
35029            get : function () {
35030                return this.jsonModel.allLazyChildren;
35031            }
35032        },
35033
35034        
35035        "enableAsyncSubmission" : {
35036            set : function (newValue) {
35037                this.jsonModel.enableAsyncSubmission = newValue;
35038            },
35039
35040            get : function () {
35041                if (this.jsonModel.enableAsyncSubmission && (this.jsonModel.enableAsyncSubmission === "true" || this.jsonModel.enableAsyncSubmission === true)) {
35042                    return true;
35043                } else {
35044                    return false;
35045                }
35046            }
35047        },
35048
35049        
35050        "enableAdobeSign" : {
35051            get : function () {
35052                return this.jsonModel._useSignedPdf;
35053            }
35054        },
35055
35056        
35057        "enableFocusOnFirstField" : {
35058            set : function (newValue) {
35059                this.jsonModel.enableFocusOnFirstField = newValue;
35060            },
35061
35062            get : function () {
35063                if (this.jsonModel.enableFocusOnFirstField === undefined) {
35064                    return true;
35065                }
35066                return this.jsonModel.enableFocusOnFirstField;
35067            }
35068        }
35069    });
35070}(_, guidelib));
35071(function (_, guidelib) {
35072    guidelib.model.mixin.AddNavigationContext = {
35073        propertyDescriptors : {
35074            "navigationContext" : {
35075                get : function () {
35076                    if (!this._navigationContext) {
35077                        this._navigationContext = new guidelib.model.util.GuideNavigationContext({
35078                            currentItem : null,
35079                            parentPanel : this.panel
35080                        });
35081                    }
35082                    return this._navigationContext;
35083                }
35084            }
35085        }
35086    };
35087})(_, guidelib);
35088
35089(function (_, guidelib) {
35090
35091    
35092    var GuidePanel = guidelib.model.GuidePanel = guidelib.model.GuideItemsContainer.extend({
35093        msClassName : "guidePanel",
35094        defaultExpressions : {
35095            "summary" : "this.title + (this.instanceIndex > 0 ? ' ' + this.instanceIndex : '')"
35096        },
35097
35098        initialize : function () {
35099            GuidePanel._super.initialize.call(this);
35100            this._currentItem = null;
35101            
35102            this._navigationContext = null;
35103        },
35104
35105        _collectExpressions : function () {
35106            GuidePanel._super._collectExpressions.call(this);
35107            if (this.completionExp) {
35108                this._compiledScripts.completionExp = this._compileExpression(this.completionExp, null);
35109            }
35110            if (this.jsonModel.summaryExp) {
35111                this._compiledExpressions.summaryExp = this._compileExpression(this.jsonModel.summaryExp, "summary");
35112            } else {
35113                this._compiledExpressions.summaryExp = this._compileExpression(this.defaultExpressions["summary"], "summary");
35114            }
35115        },
35116
35117        _initializeInstanceManager : function (child, index, insertOffset) {
35118            var instanceManager = guidelib.model.GuideModelRegistry.prototype.createInstanceManager(child);
35119            this._initializeChild(instanceManager);
35120            
35121            this._children.splice(index + insertOffset++, 0, instanceManager);
35122            instanceManager._manageChild(child);
35123            
35124            var bindNode = child._getBindNode(),
35125                bindNodeInstCount = this.getOrElse(bindNode, "instanceManager.count", 0),
35126            
35127                panelInstancesToAdd = Math.max(child.minOccur, bindNodeInstCount) - 1,
35128                bindNodeOffset = 1,
35129                addedXfaInstance;
35130            while (panelInstancesToAdd > 0) {
35131                
35132                addedXfaInstance = null;
35133                if (bindNodeInstCount > 1) {
35134                    
35135                    addedXfaInstance = bindNode.instanceManager.instances[bindNodeOffset++];
35136                }
35137                instanceManager.addInstance(addedXfaInstance);
35138                panelInstancesToAdd -= 1;
35139                insertOffset += 1;
35140            }
35141            return insertOffset;
35142        },
35143
35144        
35145        _initChildren : function (bLazyInitialization) {
35146            GuidePanel._super._initChildren.call(this);
35147            if (!bLazyInitialization) {
35148                this._instanceManager = null;
35149            }
35150            this._childInitializeGoingOn = true;
35151            var currentChildren = this.children,
35152                insertOffset = 0;
35153            _.each(currentChildren, function (child, index) {
35154                if (child instanceof guidelib.model.GuidePanel) {
35155                    insertOffset = this._initializeInstanceManager(child, index, insertOffset);
35156                }
35157            }, this);
35158            if (this.jsonModel.toolbar) {
35159                var options = {};
35160                if (this.options._guideContainer) {
35161                    options = _.extend({}, options, {"_guideContainer" : this.options._guideContainer});
35162                }
35163                var toolbar = guidelib.model.GuideModelRegistry.prototype.createModel(this.jsonModel.toolbar, options);
35164                this._initializeChild(toolbar);
35165                this._children.push(toolbar);
35166            }
35167            this._summary = null;
35168            this._childInitializeGoingOn = false;
35169        },
35170
35171        _postInitialize : function () {
35172            GuidePanel._super._postInitialize.call(this);
35173            
35174            this.instanceManager._postInitializeBinding();
35175        },
35176
35177        _addChildAt : function (child, childIndex, muteEvent) {
35178            if (child) {
35179                this._initializeChild(child);
35180                this._guide()._modelTemplateCacheStore.putModel(child);
35181                var newItemIndex = this._getItemsInsertIndex(childIndex - 1);
35182                var newItems = {};
35183                var newItemKey = child.id;
35184                var lastItemIndex = -1;
35185                _.each(this.jsonModel.items, function (value, key) {
35186                    if (lastItemIndex == newItemIndex - 1) {
35187                        newItems[newItemKey] = child.jsonModel;
35188                    }
35189                    newItems[key] = value;
35190                    lastItemIndex++;
35191                }, this);
35192                if (lastItemIndex == newItemIndex - 1) {
35193                    newItems[newItemKey] = child.jsonModel;
35194                }
35195                this.jsonModel.items = newItems;
35196                child._isItem = true;
35197                this._children.splice(childIndex, 0, child);
35198                this._normalizeChildren();
35199                child._postInitialize();
35200                if (this._guide().getGuideState() >= guidelib.model.GuideSchema.prototype.GuideStateConstants.GUIDE_STATE_MERGE_COMPLETE) {
35201                    child.prepare();
35202                }
35203                
35204                
35205                
35206                if (!(this._lazyReference && this._childInitializeGoingOn)) {
35207                    if (!muteEvent) {
35208                        this._triggerEvent(guidelib.event.GuideModelEvent.CHILD_CHANGED, "childAdded", null, child);
35209                    }
35210                }
35211            }
35212        },
35213
35214        
35215        validate : function (errorList) {
35216            var markInvalid = false;
35217
35218            
35219            if (!this.visible) {
35220                return true;
35221            }
35222            var lazyModelUnloadPending = false;
35223            
35224            if (this._lazyReference && this.guideUtil.isLazyJson(this.jsonModel)) {
35225                var guideDirtyMarker = this._guide().internal.GuideDirtyMarkerAndVisitor,
35226                    visitMap = guideDirtyMarker.visitMap,
35227                    modelTemplateCacheStore = this._guide()._modelTemplateCacheStore,
35228                    guideUtil = guidelib.util.GuideUtil,
35229                    templateJson,
35230                    templateId = this.templateId,
35231                    uniquePrefix;
35232                
35233                if (visitMap[templateId] === 0) {
35234                    if (this._ancestorRepeatable) {
35235                        uniquePrefix = guideUtil.generateUID();
35236                    }
35237                    
35238                    templateJson = modelTemplateCacheStore._getTemplate(templateId, true);
35239                    
35240                    
35241                    if (!_.isEmpty(templateJson)) {
35242                        this._embedJson(templateJson.items, uniquePrefix);
35243                        this._guide().internal.liveDataUtils.playLiveData(this);
35244                        
35245                        this.prepare();
35246                        this._guide().runPendingExpressions();
35247                        this._guide().internal.liveDataUtils.updateLiveData(); 
35248                        lazyModelUnloadPending = true;
35249                    } else {
35250                        
35251                        markInvalid = true;
35252                    }
35253
35254                }
35255
35256            }
35257            var validationResult = GuidePanel._super.validate.call(this, errorList);
35258            if (lazyModelUnloadPending) {
35259                
35260                
35261                this._unloadLazyReferenceModel(true);
35262            }
35263            if (markInvalid === true) {
35264                validationResult = false;
35265            }
35266            return validationResult;
35267        },
35268
35269        _loadLazyFragment : function (options) {
35270            options = options || {};
35271            if (_.isUndefined(this._itemsLoaded)) {
35272                
35273                var path = this.jsonModel["jcr:path"],
35274                    externalizedPath;
35275                
35276                externalizedPath = guideBridge._getGuidePathUrl(".jsonhtmlemitter");
35277                this._fetchFromAjaxCall(externalizedPath, options);
35278            } else {
35279                if (_.isFunction(options.success)) {
35280                    options.success.call(this);
35281                }
35282            }
35283            
35284            
35285        },
35286
35287        _fetchFromAjaxCall : function (externalizedPath, options) {
35288            if (options && _.isFunction(options.preFetch)) {
35289                options.preFetch.call(this);
35290            }
35291            var that = this,
35292                urlSuffix = "",
35293                lazyOptions,
35294                commonCallbacks = {
35295                    success: fetchCallback,
35296                    error: (options && _.isFunction(options.error)) ? options.error : errorCallback,
35297                    complete: completeCallback,
35298                    async: options.async
35299                };
35300
35301            if (FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_CACHE_LAZY_LOADED_FRAGMENTS)) {
35302                
35303                urlSuffix = [
35304                    "/templateId-" + that.templateId,
35305                    "/fetchJSON-true",
35306                    "/fetchHTML-true",
35307                    ".json"  
35308                ].join("");
35309                
35310                lazyOptions = _.extend({
35311                    path: externalizedPath + urlSuffix
35312                }, commonCallbacks);
35313            } else {
35314                lazyOptions = _.extend({
35315                    path: externalizedPath,
35316                    templateId: that.templateId,
35317                    fetchJSON: true,
35318                    fetchHTML: true
35319                }, commonCallbacks);
35320            }
35321
35322            window.guideBridge.panelProvider.getHtmlJson(lazyOptions);
35323
35324            function fetchCallback(jsonHtml) {
35325                var uniquePrefix;
35326                
35327                
35328                
35329                if (that.repeatable || that._ancestorRepeatable) {
35330                    uniquePrefix = that.guideUtil.generateUID();
35331                }
35332                if (guidelib.util.GuideUtil._embedHtml(that, jsonHtml["html"], uniquePrefix)) {
35333                    that._ajaxCallDone = true;
35334
35335                    
35336                    
35337                    
35338                    var referredJson = JSON.parse(jsonHtml["json"])["items"];
35339                    that._embedJson(referredJson, uniquePrefix);
35340                    
35341                    var guideDirtyMarkerAndVisitor = that._guide().internal.GuideDirtyMarkerAndVisitor;
35342                    
35343                    if (!that.repeatable) {
35344                        guideDirtyMarkerAndVisitor._updateCountOrInsert(guideDirtyMarkerAndVisitor.visitMap, that.templateId);
35345                    }
35346                    
35347                    that._guide().internal.liveDataUtils.playLiveData(that);
35348                    
35349                    that.prepare();
35350                    that._itemsLoaded = true;
35351                    that._guide().trigger(guidelib.event.GuideModelEvent.LAZY_LOADED);
35352                    
35353                    that._triggerOnBridge("elementLazyLoaded", that);
35354                    
35355                    
35356                    if (options && _.isFunction(options.success)) {
35357                        options.success.call(this);
35358                    }
35359                    
35360                    
35361                    
35362                }
35363            }
35364
35365            function errorCallback() {
35366                that.logger().error("AF", "Failed to fetch HTML and JSON for :" + externalizedPath);
35367            }
35368
35369            function completeCallback() {
35370                if (options && _.isFunction(options.postFetch)) {
35371                    options.postFetch.call(this);
35372                }
35373            }
35374
35375        },
35376
35377        
35378        _unloadLazyReferenceModel : function (muteValidation) {
35379            try {
35380                if (this._lazyReference) {
35381                    window.guideBridge._populateBindRefToSomMap(this);
35382                    if (!muteValidation) {
35383                        var validationStatus = this.validate(),
35384                            visitMap = this._guide().internal.GuideDirtyMarkerAndVisitor.visitMap;
35385                        if (validationStatus === false && visitMap[this.id] > 0) {
35386                            visitMap[this.id] = 0;
35387                        }
35388                    }
35389                    
35390                    
35391                    _.each(this.children, function (child) {
35392                        child._unloadModel(muteValidation);
35393                        var nIndex = this._children.indexOf(child);
35394                        
35395                        this._children.splice(nIndex, 1);
35396                        var childKey = null;
35397                        
35398                        _.each(this.jsonModel.items, function (value, key) {
35399                            if (value === child.jsonModel) {
35400                                childKey = key;
35401                            }
35402                        }, this);
35403                        if (childKey) {
35404                            delete this.jsonModel.items[childKey];
35405                        }
35406                        
35407                        this._normalizeChildren();
35408                    }, this);
35409                    
35410                    this._navigationContext = null;
35411                    this._currentItem = null;
35412                }
35413            } catch (exception) {
35414                this.logger().error(exception);
35415            }
35416
35417        },
35418        
35419        _unloadModel : function (muteValidation) {
35420            var visitMap = this._guide().internal.GuideDirtyMarkerAndVisitor.visitMap;
35421            _.each(this.children, function (child) {
35422                if (this._lazyReference && !muteValidation) {
35423                    var validationStatus = child.validate();
35424                    if (validationStatus === false) {
35425                        if (!_.isUndefined(visitMap[this.templateId])) {
35426                            visitMap[this.templateId] = 0;
35427                        }
35428                    }
35429                }
35430                child._unloadModel(muteValidation);
35431            }, this);
35432            guidelib.model.Scriptable.prototype._unloadModel.call(this);
35433        },
35434
35435        _removeChild : function (oChild) {
35436            oChild._unloadModel();
35437            var nIndex = this._children.indexOf(oChild);
35438            this._children.splice(nIndex, 1);
35439            var childKey = null;
35440            _.each(this.jsonModel.items, function (value, key) {
35441                if (value === oChild.jsonModel) {
35442                    childKey = key;
35443                }
35444            }, this);
35445            if (childKey) {
35446                delete this.jsonModel.items[childKey];
35447            }
35448            this._normalizeChildren();
35449            this._triggerEvent(guidelib.event.GuideModelEvent.CHILD_CHANGED, "childRemoved", oChild, null);
35450        },
35451
35452        
35453        _embedJson : function (referredJson, uniquePrefix) {
35454            
35455            var bIsSuccess = false;
35456            var clonedJson = JSON.parse(JSON.stringify(referredJson)),
35457                currentPanelId = this.id,
35458                referredPanelRoot = null,
35459                referredPanelRootName = null,
35460                bindRefPrefix = this.jsonModel.bindRef;
35461            
35462            currentPanelId = currentPanelId.slice(0, -2);
35463            if (referredJson) {
35464                
35465                if (this.repeatable || this._ancestorRepeatable) {
35466                    this.copyObject(referredJson, clonedJson,
35467                        {
35468                            transformMaps : {
35469                                "id" : function (srcValue, options, parentObj) {
35470                                    return uniquePrefix + "__" + parentObj.templateId;
35471                                }
35472                            }
35473                        }
35474                    );
35475                }
35476                
35477                
35478                _.each(clonedJson, function (panelJson, panelName) {
35479                    if (_.isObject(panelJson)) {
35480                        bIsSuccess = true;
35481                        
35482                        this.jsonModel.items = this.jsonModel.items || {};
35483                        this.jsonModel.items[panelName] = panelJson;
35484                        
35485                        this._guide()._modelTemplateCacheStore._putTemplate(JSON.parse(JSON.stringify(panelJson)));
35486                    }
35487                }, this);
35488                
35489                this._embedModel();
35490
35491            }
35492            if (bIsSuccess === true) {
35493                
35494            }
35495            return bIsSuccess;
35496        },
35497
35498        
35499        _embedModel : function () {
35500            
35501            this._initChildren(true);
35502            
35503            
35504            this._guide()._modelTemplateCacheStore.putModel(this);
35505            
35506            this._postInitialize();
35507            
35508            this._normalizeChildren();
35509        },
35510
35511        _getItemsInsertIndex : function (childIndex) {
35512            var itemIndex = 0;
35513            _.find(this._children, function (child, index) {
35514                if (child._isItem) {
35515                    itemIndex++;
35516                }
35517                if (index >= childIndex) {
35518                    return true; 
35519                }
35520            }, this);
35521            return itemIndex;
35522        },
35523
35524        playJson : function (pJsonModel, attachments) {
35525            var playNonPanelItems = {};
35526            var playPanelItems = {};
35527            _.each(pJsonModel.items, function (item) {
35528                if (_.isObject(item)) {
35529                    
35530                    if (item.guideNodeClass === "guidePanel" || item.guideNodeClass === "guideTable" || item.guideNodeClass === "guideTableRow") {
35531                        if (playPanelItems[item.name]) {
35532                            playPanelItems[item.name].push(item);
35533                        } else {
35534                            playPanelItems[item.name] = [item];
35535                        }
35536                    } else {
35537                        if (playNonPanelItems[item.name]) {
35538                            playNonPanelItems[item.name].push(item);
35539                        } else {
35540                            playNonPanelItems[item.name] = [item];
35541                        }
35542                    }
35543                }
35544            }, this);
35545
35546            
35547            var panelIMs = _.filter(this._children, function (child) {
35548                return child instanceof guidelib.model.GuideInstanceManager;
35549            }, this);
35550
35551            _.each(panelIMs, function (instanceManager) {
35552                var panelName = instanceManager._getInstanceName();
35553                var newPanelItems = playPanelItems[panelName] || []; 
35554                var panelInstances = instanceManager._instances.slice(0);
35555                _.each(panelInstances, function (panelInstance, index) {
35556                    if (newPanelItems.length > 0) {
35557                        var panelJson = newPanelItems.shift();
35558                        panelInstance.playJson(panelJson, attachments);
35559                    } else {
35560                        instanceManager.removeInstance(index);
35561                    }
35562                }, this);
35563                if (newPanelItems.length > 0) {
35564                    _.each(newPanelItems, function (paneljson) {
35565                        var addedInstance = instanceManager.addInstance();
35566                        if (addedInstance) {
35567                            addedInstance.playJson(paneljson, attachments);
35568                        }
35569                    }, this);
35570                }
35571            }, this);
35572
35573            
35574            _.each(this.items, function (child) {
35575                if (!(child instanceof guidelib.model.GuidePanel)) {
35576                    var nonPanelItemName = child.name;
35577                    var nonPanelItem = playNonPanelItems[nonPanelItemName];
35578                    if (nonPanelItem && nonPanelItem.length > 0) {
35579                        child.playJson(nonPanelItem.shift(), attachments);
35580                    }
35581                }
35582            }, this);
35583
35584            
35585            if (this.toolbar) {
35586                this.toolbar.playJson(pJsonModel.toolbar, attachments);
35587            }
35588        },
35589        
35590        _getReducedJSON : function (isParentRepeatable) {
35591            var reducedJSONChildren,
35592                isRepeatable;
35593            isRepeatable = isParentRepeatable || this.canBeRepeatable;
35594            reducedJSONChildren = GuidePanel._super._getReducedJSON.call(this, isRepeatable);
35595            
35596            
35597            if (this.jsonModel.toolbar) {
35598                reducedJSONChildren["toolbar"] = this.toolbar._getReducedJSON();
35599            }
35600            return reducedJSONChildren;
35601        },
35602
35603        _getRole : function () {
35604            var guideRole, xfaRole, roleMap;
35605            
35606            roleMap = {
35607                "Table" : "grid",
35608                "Header Row" : "rowHeader",
35609                "Body Row" : "rowGroup",
35610                "Footer Row" : "rowGroup",
35611                "List" : "list"
35612            };
35613            if (this.bindNode) {
35614                xfaRole = this.getOrElse(this.bindNode.assist && this.bindNode.assist.role, null);
35615                if (xfaRole) {
35616                    guideRole = roleMap[xfaRole];
35617                }
35618            }
35619            return guideRole;
35620        },
35621        _getAssistPriority : function () {
35622            return (this.getAttribute("assistPriority") || "description");
35623        },
35624
35625        _getScreenReaderText : function () {
35626            var screenReaderText, assistPriority = this._getAssistPriority();
35627            if (assistPriority !== "description") {
35628                screenReaderText = GuidePanel._super._getScreenReaderText.apply(this);
35629            }
35630            return screenReaderText;
35631        },
35632
35633        execCompletion : function () {
35634            var complete = true;
35635            _.find(this.children, function (childModel) {
35636                
35637                if (childModel instanceof guidelib.model.GuidePanel && !childModel.execCompletion()) {
35638                    complete = false;
35639                    return true;    
35640                }
35641            }, this);
35642            if (complete && this.completionExp) {
35643                complete = this.executeExpression("completionExp");
35644            }
35645            return complete;
35646        },
35647
35648        _preserveLazyValue : function () {
35649            return !this._isXfaNode() && !(this instanceof guidelib.model.RootPanelNode)
35650                && (this.canBeRepeatable || this._guide().internal.liveDataUtils.isIndexedPath(this.bindRef));
35651        },
35652
35653        
35654        _syncModelAndData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateInstances, recurse) {
35655            var dataUtils = this._guide().internal.liveDataUtils;
35656            if (this._preserveLazyValue()) {
35657
35658                var dataContext = dataUtils._getDataContext(this, bound_indexedXpathSoFar, unBound_indexedXpathSoFar),
35659                    indexedXpath = dataContext.indexedXpath;
35660
35661                if (this.canBeRepeatable) {
35662                    
35663                    if (_.isFunction(updateInstances) && this.instanceIndex === 0) {
35664                        updateInstances(dataUtils.getDataInstances(dataContext, this._getDataNodeName()),
35665                            dataUtils.getParentDataNode(dataContext));
35666                    }
35667                    indexedXpath = dataUtils.addIndexToPath(indexedXpath, this.instanceIndex);
35668                }
35669
35670                
35671                if (dataContext.xmlSec === dataUtils.constants.UNBOUND_TAG) {
35672                    unBound_indexedXpathSoFar = indexedXpath;
35673                } else if (dataContext.xmlSec === dataUtils.constants.BOUND_TAG) {
35674                    bound_indexedXpathSoFar = indexedXpath;
35675                }
35676            }
35677
35678            if (_.isString(recurse)) {
35679                
35680                _.each(this.items, function (item) {
35681                    if (_.isFunction(item[recurse])) {
35682                        item[recurse](bound_indexedXpathSoFar, unBound_indexedXpathSoFar);
35683                    }
35684                });
35685            }
35686
35687            return {
35688                'bound' : bound_indexedXpathSoFar,
35689                'unBound' : unBound_indexedXpathSoFar
35690            };
35691        },
35692
35693        _getDataNodeName : function () {
35694            var bindRef = this.bindRef,
35695                dataNodeName;
35696            if (bindRef) {
35697                dataNodeName = bindRef.substring(bindRef.lastIndexOf("/") + 1);
35698            } else {
35699                
35700                dataNodeName = this.getAttribute("name");
35701            }
35702            return dataNodeName;
35703        },
35704
35705        _updateLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
35706            var dataUtils = this._guide().internal.liveDataUtils,
35707                that = this;
35708
35709            function updateDataInstances(dataNodes, parentNode) {
35710                var count = that.instanceManager.instanceCount;
35711                if (dataNodes && (dataNodes.length > count)) {
35712                    
35713                    
35714                    for (var i = dataNodes.length -1; i >= count; --i) {
35715                        dataUtils.removeChild(parentNode, that._getDataNodeName(), i);
35716                    }
35717                }
35718            }
35719
35720            var contextSoFar = this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateDataInstances, '_updateLiveData');
35721        },
35722
35723        _playLiveData : function (bound_indexedXpathSoFar, unBound_indexedXpathSoFar) {
35724            var parentArgs = arguments,
35725                that = this;
35726
35727            function updateModelInstances(dataNodes, parentNode) {
35728                var _dataNodes = dataNodes;
35729                if (_dataNodes == null) {
35730                    _dataNodes = []; 
35731                }
35732                
35733                var i;
35734                if (_dataNodes && (_dataNodes.length < that.instanceManager.instanceCount)) {
35735                    
35736                    for (i = Math.max(_dataNodes.length, Math.abs(that.minOccur)); i < that.instanceManager.instanceCount; ++i) {
35737                        that.instanceManager.removeInstance(i);
35738                    }
35739                } else if (_dataNodes && (_dataNodes.length > that.instanceManager.instanceCount)) {
35740                    
35741                    var totalInstances = that.maxOccur < 0 ? _dataNodes.length : Math.min(_dataNodes.length, that.maxOccur);
35742                    for (i = that.instanceManager.instanceCount; i < totalInstances; ++i) {
35743                        var addedInstance = that.instanceManager.addInstance();
35744                        if (addedInstance) {
35745                            that._playLiveData.apply(addedInstance, parentArgs);
35746                        }
35747                    }
35748                }
35749            }
35750
35751            this._syncModelAndData(bound_indexedXpathSoFar, unBound_indexedXpathSoFar, updateModelInstances, '_playLiveData');
35752        }
35753    });
35754
35755    GuidePanel.defineProps({
35756        
35757        completionExp : {
35758            get : function () {
35759                return this.getAttribute("completionExp");
35760            }
35761        },
35762
35763        completionExpReq : {
35764            get : function () {
35765                return this.getAttribute("completionExpReq");
35766            }
35767        },
35768
35769        
35770        minOccur : {
35771            get : function () {
35772                return this.getOrElse(this.jsonModel.minOccur, 1);
35773            }
35774        },
35775
35776        
35777        maxOccur : {
35778            get : function () {
35779                return this.getOrElse(this.jsonModel.maxOccur, 1);
35780            }
35781        },
35782        initialOccur : {
35783            get : function () {
35784                return this.getOrElse(this.jsonModel.initialOccur, 1);
35785            }
35786        },
35787        
35788        repeatable : {
35789            get : function () {
35790                return (this.minOccur != 1 || this.maxOccur != 1);
35791            }
35792        },
35793
35794        
35795        canBeRepeatable : {
35796            get : function () {
35797                return (this.maxOccur < 0 || this.maxOccur > 1);
35798            }
35799        },
35800        
35801        panel : {
35802            get : function () {
35803                return this;
35804            }
35805        },
35806        toolbar : {
35807            get : function () {
35808                this.getElement("guideToolbar");
35809            }
35810        },
35811        
35812        instanceManager : {
35813            get : function () {
35814                return this._instanceManager;
35815            }
35816        },
35817
35818        
35819        instanceIndex : {
35820            get : function () {
35821                var context = this._guide()._currentContext;
35822                if (context && context.managedExp) {
35823                    this._addDependant(context.contextNode, context.expression);
35824                }
35825                return this.instanceManager._instances.indexOf(this);
35826            }
35827        },
35828        
35829        title : {
35830            get : function () {
35831                return this.jsonModel["jcr:title"];
35832            },
35833            set : function (value) {
35834                var oldTitle = this.title;
35835                if (oldTitle !== value) {
35836                    this.jsonModel["jcr:title"] = value;
35837                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
35838                        guidelib.event.GuideModelEvent.createEvent(
35839                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
35840                            this,
35841                            "title",
35842                            oldTitle,
35843                            value
35844                        )
35845                    );
35846                }
35847            }
35848        },
35849        
35850        summary : {
35851            get : function () {
35852                return this._summary;
35853            },
35854            set : function (value) {
35855                var oldSummary = this._summary;
35856                if (oldSummary !== value) {
35857                    this._summary = value;
35858                    this.trigger(guidelib.event.GuideModelEvent.MODEL_CHANGED,
35859                        guidelib.event.GuideModelEvent.createEvent(
35860                            guidelib.event.GuideModelEvent.MODEL_CHANGED,
35861                            this,
35862                            "summary",
35863                            oldSummary,
35864                            this._summary
35865                        )
35866                    );
35867                }
35868            }
35869        },
35870        enableLayoutOptimization : {
35871            get : function () {
35872                return this.getOrElse(this.jsonModel, "layout.enableLayoutOptimization", false);
35873            }
35874        },
35875
35876        
35877        isNavigable : {
35878            get : function () {
35879                var isNonNavigable = this.getOrElse(this.jsonModel, "layout.nonNavigable", false);
35880                
35881                
35882                if (typeof isNonNavigable === 'string') {
35883                    return !(isNonNavigable === "true");
35884                } else {
35885                    return !isNonNavigable;
35886                }
35887            }
35888        },
35889        
35890        _hopsToRootPanel : {
35891            get : function () {
35892                return guidelib.util.GuideUtil._countHopsToRootPanel(this);
35893            }
35894
35895        },
35896        
35897        _ancestorRepeatable : {
35898            get : function () {
35899                var parentOrAncestor = this.parent;
35900                while (parentOrAncestor) {
35901                    if (parentOrAncestor && parentOrAncestor.repeatable) {
35902                        return true;
35903                    }
35904                    parentOrAncestor = parentOrAncestor.parent;
35905                }
35906
35907                return false;
35908            }
35909        },
35910
35911        
35912        enabled : {
35913            get : function () {
35914                return guidelib.model.Scriptable.prototype._getEnabled.call(this);
35915            },
35916
35917            set : function (value) {
35918                var oldValue = this.enabled;
35919                guidelib.model.Scriptable.prototype._setEnabled.call(this, value);
35920                if (this._parentAccess && value != oldValue) {
35921                    this._changeContainerAccess(value);
35922                }
35923            }
35924        },
35925
35926        
35927        _hasLazyDescendant : {
35928            get : function () {
35929                if (!_.isEmpty(guideBridge._guide.allLazyChildren)) {
35930                    return true;  
35931                }
35932                return false;
35933            }
35934        }
35935    });
35936
35937    
35938    GuidePanel.addMixins([
35939        guidelib.model.mixin.AddNavigationContext,
35940        guidelib.model.mixin.AddDependencyMgmt
35941    ]);
35942
35943})(_, guidelib);
35944
35945(function (_, guidelib) {
35946    var GuideTableRow = guidelib.model.GuideTableRow = guidelib.model.GuidePanel.extend({
35947        msClassName : "guideTableRow"
35948    });
35949}(_, guidelib));
35950(function (_, guidelib) {
35951
35952    
35953    var GuideTable = guidelib.model.GuideTable = guidelib.model.GuidePanel.extend({
35954        msClassName : "guideTable"
35955    });
35956
35957    GuideTable.defineProps({
35958        
35959        mobileLayout : {
35960            get : function () {
35961                return this.jsonModel.layout.mobileLayout;
35962            }
35963        },
35964
35965        columnWidth : {
35966            get : function () {
35967                return this.jsonModel.columnWidth;
35968            }
35969        }
35970    });
35971})(_, guidelib);
35972
35973(function (_, guidelib) {
35974    var RootPanelNode = guidelib.model.RootPanelNode = guidelib.model.GuidePanel.extend({
35975        msClassName : "rootPanelNode",
35976        
35977        _clearInactiveLazyViews : function (panelView) {
35978            _.each(this.childViews, function (item) {
35979                item._clearInactiveLazyViews(panelView);
35980            });
35981        }
35982
35983    });
35984    RootPanelNode.defineProps({
35985        toolbar : {
35986            get : function () {
35987                
35988                return this.getElement("guideToolbar") || this.parent.toolbar;
35989            }
35990        }
35991    });
35992})(_, guidelib);
35993(function ($, guidelib, _) {
35994    function negate(predicateFunc) {
35995        return function () {
35996            return !predicateFunc.apply(this, arguments);
35997        };
35998    }
35999
36000    function getPredicate(condition) {
36001        return condition instanceof Array
36002            ? Array.prototype.includes.bind(condition)
36003            : condition;
36004    }
36005
36006    var CommonUtils = {
36007        
36008        
36009        returnMinimalJSON : function (whitelistedProperties, reducedJsonObject, that) {
36010            if (!_.isObject(reducedJsonObject)) {
36011                reducedJsonObject = {};
36012            }
36013            _.each(whitelistedProperties, function (whitelistedProperty) {
36014                if (!_.isUndefined(that.jsonModel[whitelistedProperty])) {
36015                    reducedJsonObject[whitelistedProperty] = that.jsonModel[whitelistedProperty] ;
36016
36017                } else if (!_.isUndefined(that[whitelistedProperty])) {
36018                    reducedJsonObject[whitelistedProperty] = that[whitelistedProperty];
36019                }
36020            });
36021        },
36022
36023        createMap : function (list, value) {
36024            return _.mapObject(_.object(list, []), function () {
36025                return value;
36026            });
36027        },
36028
36029        updatedMapIfNot : function (map, condition, value) {
36030            return _updateMap(map, negate(getPredicate(condition)), value);
36031        },
36032
36033        updatedMap : function (map, condition, value) {
36034            return _updateMap(map, getPredicate(condition), value);
36035        },
36036
36037        _updatedMap : function (map, condition, value) {
36038            var newMap = {},
36039                prop;
36040            for (prop in map) {
36041                if (map.hasOwnProperty(prop)) {
36042                    newMap[prop] = condition(prop) ? value : map[prop];
36043                }
36044            }
36045            return newMap;
36046        },
36047
36048        _getScope : function (context) {
36049            var mergedScope = Object.assign(guidelib.runtime, context._guide().runtime);
36050            return mergedScope;
36051        }
36052    };
36053
36054    guidelib.model.util.CommonUtils = CommonUtils;
36055}($, guidelib, _));
36056(function (_, $, guidelib) {
36057    var getOrElse = xfalib.ut.XfaUtil.prototype.getOrElse,
36058        commonUtils = guidelib.model.util.CommonUtils,
36059        logger,
36060        constants = guidelib.model.GuideSchema.prototype.GuideStateConstants;
36061
36062    var initializeLogger = function (isXfaForm) {
36063        var configString = window.AF_log_config === undefined ? "0-a9"
36064            : "1-" + window.AF_log_config;
36065
36066        xfalib.ut.XfaUtil.prototype.registerLocaleProperties(guidelib.i18n);
36067        if (isXfaForm && window.formBridge) {
36068            window.formBridge.registerConfig("contextPath", window.guideBridge.userConfig["contextPath"]);
36069            window.formBridge.registerConfig("LoggerConfig", {
36070                "logConfigString" : configString,
36071                "categoryAcronyms" : {"d" : "AF"}
36072            });
36073        } else {
36074            xfalib.ut.XfaUtil.prototype.logger = new xfalib.ut.Logger({
36075                "jsonModel" : {
36076                    "logConfigString" : configString,
36077                    "categoryAcronyms" : {"d" : "AF"}
36078                }
36079            });
36080            logger = xfalib.ut.XfaUtil.prototype.logger;
36081        }
36082    };
36083
36084    var utils = {
36085        triggerEventOnWindow : function (eventPayload) {
36086            $(window).trigger(eventPayload);
36087        },
36088
36089        postExternalMessage : function (name) {
36090            window.guideBridge._postExternalMessage({name : name});
36091        }
36092    };
36093
36094    var viewOnlyUtils = {
36095        createView : function (guide, $element) {
36096            utils.postExternalMessage("_layoutstart");
36097
36098            var guideContainerView = new guidelib.view.GuideContainerView({
36099                element : $element,
36100                model : guide
36101            });
36102            
36103            
36104            window.guideBridge._setGuideView(guideContainerView);
36105            guidelib.util.GuideUtil.initializeHelp();
36106
36107            
36108            guidelib.util.AdUtil.applyDescriptionPlugin();
36109
36110            utils.postExternalMessage("_layoutend");
36111
36112            $(window).on("mousedown.guidebridge", function () {
36113                window.guideBridge.clickedOnWindow = true;
36114            });
36115        },
36116
36117        getLastFocusItem : function (guide) {
36118            var lastFocusItem;
36119            if (guide.runtime.guideContext) {
36120                lastFocusItem = guidelib.util.GuideUtil.fetchXMLNodeValue(guide.runtime.guideContext.guidePrefillXml, "lastFocusItem");
36121            }
36122            
36123            if (_.isUndefined(lastFocusItem)) {
36124                lastFocusItem = guidelib.util.GuideUtil._fetchJSONNodeValue(guide.runtime.guideContext.guidePrefillJson, "afSubmissionInfo.lastFocusItem");
36125            }
36126            
36127            if (_.isUndefined(lastFocusItem)) {
36128                lastFocusItem = window.guideBridge.customContextProperty("lastFocusItem");
36129            }
36130            return lastFocusItem;
36131        },
36132
36133        setFocus : function (item) {
36134            if (item) {
36135                window.guideBridge.setFocus(item);
36136            } else {
36137                window.guideBridge.setFocus();
36138            }
36139        },
36140
36141        preventCheckBoxMovementOnClick : function () {
36142            
36143            
36144            
36145
36146            if (xfalib.ut.XfaUtil.prototype.isSafari() && !xfalib.ut.TouchUtil.TOUCH_ENABLED) {
36147                $('#guideContainerForm').addClass('macSafariForm');
36148            }
36149        },
36150
36151        disableDefaultSubmit : function () {
36152            
36153            
36154            $("#guideContainerForm").submit(function (evnt) {
36155                evnt.preventDefault();
36156            });
36157        },
36158
36159        preventFormSubmitOnEnter : function () {
36160            
36161            
36162            $("#guideContainerForm input").keypress(function (evnt) {
36163                if (evnt.keyCode == 13 || evnt.charCode == 13 || evnt.which == 13) {
36164                    evnt.preventDefault();
36165                }
36166            });
36167        },
36168
36169        renderView : function (guide, $guideElement) {
36170            viewOnlyUtils.createView(guide, $guideElement);
36171
36172            var lastFocusItem = viewOnlyUtils.getLastFocusItem(guide);
36173            viewOnlyUtils.setFocus(lastFocusItem);
36174            utils.triggerEventOnWindow({type : "guideInitialized", guide : guide});
36175
36176            viewOnlyUtils.preventCheckBoxMovementOnClick();
36177            viewOnlyUtils.disableDefaultSubmit();
36178            viewOnlyUtils.preventFormSubmitOnEnter();
36179        }
36180
36181    };
36182
36183    
36184    guidelib.model._createXfaAndGuideModel = function (guideJson, xfaJson, options) {
36185        if (xfaJson) {
36186            xfalib.script.XfaModelRegistry.prototype.createModel(xfaJson);
36187            
36188            new xfalib.acrobat.Acrobat();
36189        }
36190        var guide = {};
36191        guide = guidelib.model.GuideModelRegistry.prototype.createModel(guideJson, options);
36192        
36193        guide._bindRefMap = {};
36194        return guide;
36195
36196    };
36197
36198    
36199    guidelib.model._getGuideJsonWithSyncXfaProps = function (guideJson, xfaJson) {
36200        
36201        var guide = guidelib.model._createXfaAndGuideModel(guideJson, xfaJson);
36202        
36203        guide.syncXFAProps();
36204
36205        
36206        return {
36207            "guidejson" : JSON.stringify(guideJson),
36208            "xfajson" : JSON.stringify(xfaJson)
36209        };
36210    };
36211
36212    guidelib.model._prepareGuide = function (prefillData, guide) {
36213        var liveDataUtils = guide.internal.liveDataUtils,
36214            liveModel = guide.internal.liveModel,
36215            _getFileAttachmentWrappers = function(prefillDataAttachments) {
36216                var fileAttachmentWrappers = [];
36217                try {
36218                    var atts = JSON.parse(prefillDataAttachments);
36219                    fileAttachmentWrappers = atts.map(function (x) {
36220                        return new guidelib.model.FileAttachmentWrapper(JSON.parse(x))
36221                    });
36222                } catch (e) {
36223                    if (e.stack) {
36224                        guide.logger().error(e.stack);
36225                    }
36226                }
36227                return fileAttachmentWrappers;
36228            };
36229        
36230        if (prefillData.isMergedJson && prefillData.data) {
36231            
36232            if (prefillData.data.guideState && prefillData.data.guideState.attachments) {
36233                prefillData.data["attachments"] = _getFileAttachmentWrappers(prefillData.data.guideState.attachments);
36234            }
36235            window.guideBridge.restoreGuideState(prefillData.data);
36236        } else if (prefillData.data) {
36237            guide.setGuideState(constants.GUIDE_STATE_MERGE_PROGRESS);
36238            liveDataUtils.initLiveData(prefillData.data,
36239                null,
36240                _.isString(guide.xdpRef),
36241                _.isString(guide.xsdRef),
36242                guide.getAttribute("xsdRootElement"),
36243                _getFileAttachmentWrappers(prefillData.attachments));
36244            liveDataUtils.playLiveData(guide.rootPanel);
36245            liveModel.prefillCrossFragFields(guide);
36246            guide.setGuideState(constants.GUIDE_STATE_MERGE_COMPLETE);
36247            guide.prepare();
36248        } else {
36249            guide.prepare();
36250            liveDataUtils.initLiveData(null, null,
36251                _.isString(guide.xdpRef), _.isString(guide.xsdRef),
36252                guide.getAttribute("xsdRootElement"));
36253        }
36254
36255        var fileAttachmentMap,
36256            obj = guideBridge.customContextProperty("fileAttachmentMap");
36257        if (!_.isUndefined(obj) && typeof(obj) === "string") {
36258            try {
36259                obj = JSON.parse(obj);
36260            } catch (e) {
36261                if (e.stack) {
36262                    guide.logger().error(e.stack);
36263                }
36264                obj = undefined;
36265            }
36266        }
36267        fileAttachmentMap = obj;
36268        
36269        var  i, node, fieldValue,
36270            fileAttachmentsList = window.guideBridge._getFileAttachmentsList();
36271        
36272        
36273        if (!_.isUndefined(fileAttachmentMap)) {
36274            for (i = 0; i < fileAttachmentsList.length; i++) {
36275                node = fileAttachmentsList[i];
36276                fieldValue = fileAttachmentMap[node.somExpression];
36277                node.fileAttachment.value = fieldValue;
36278                if (!_.isEmpty(fieldValue)) {
36279                    node._fileList = fieldValue.split("\n");
36280                }
36281            }
36282        }
36283        guide.setGuideState(constants.GUIDE_STATE_MODEL_COMPLETE);
36284    };
36285
36286    guidelib.model.markDirtyPanels = function (lazyChildren, dataString, dirtyPanels, guide) {
36287        var lazyChildrenMap = commonUtils.createMap(lazyChildren, 0);
36288        
36289        if (!_.isEmpty(dataString)) { 
36290            if (dirtyPanels === null || dirtyPanels.length === 0) {
36291                dirtyPanels = guide.internal.liveDataUtils.getListOfDirtyPanels(dataString);
36292            }
36293            if (dirtyPanels && dirtyPanels.length > 0) {
36294                lazyChildrenMap = commonUtils.updatedMapIfNot(lazyChildrenMap, dirtyPanels, 1);
36295                guide.internal.GuideDirtyMarkerAndVisitor.visitMap = lazyChildrenMap;
36296            }
36297        } else {
36298            guide.internal.GuideDirtyMarkerAndVisitor.visitMap = lazyChildrenMap;
36299        }
36300    };
36301
36302    guidelib.model.initializeLiveDataUtils = function (schemaType) {
36303        var liveDataUtils = null;
36304        if (schemaType === "formdatamodel" || schemaType === "jsonschema") {
36305            liveDataUtils = new guidelib.model.LiveJsonUtils();
36306        } else {
36307            liveDataUtils = new guidelib.model.LiveXmlUtils();
36308        }
36309        return liveDataUtils;
36310    };
36311
36312    guidelib.model.prepareInput = function (guideJsonData) {
36313        return {
36314            guideJson : JSON.parse(guideJsonData.guidejson || "null"),
36315            guideContext : JSON.parse(guideJsonData.guidecontext || "null"),
36316            guidemergedjson : JSON.parse(guideJsonData.guidemergedjson || "null"),
36317            xfaJson : JSON.parse(guideJsonData.xfajson || "null"),
36318            xfaRenderContext : JSON.parse(guideJsonData.xfarendercontext || "null")
36319        };
36320    };
36321
36322    guidelib.model.mergeData = function (prefillData, guide, guideContext) {
36323        var rawData = prefillData.data,
36324            liveDataUtils = guide.internal.liveDataUtils,
36325            dirtyPanels = [],
36326            customPropertyMap = {},
36327            mergedXfaRenderContext = null;
36328
36329        guide.runtime.guideContext = guide.runtime.guideContext || {};
36330
36331        if (prefillData.isMergedJson) {
36332            if (typeof prefillData.data === "string") {
36333                try {
36334                    prefillData.data = JSON.parse(prefillData.data);
36335                } catch (e) {
36336                    prefillData.data = "";
36337                }
36338            }
36339            rawData = getOrElse(prefillData.data,
36340                "guideState.guideLiveData",
36341                getOrElse(rawData,
36342                    "guideState.guidePrefillXml",
36343                    getOrElse(prefillData.data,
36344                        "guideState.guidePrefillJson", undefined)));
36345
36346            var dirtyPanelsStr = getOrElse(prefillData.data,
36347                "guideState.guideContext.afSubmissionInfo.afDraft", "")
36348                .replace(/\"/g, "");
36349            
36350            if (dirtyPanelsStr) {
36351                dirtyPanels = dirtyPanelsStr.split(",");
36352            }
36353            customPropertyMap = getOrElse(prefillData.data,
36354                "guideState.guideContext.customPropertyMap",
36355                {});
36356
36357            var ccpMapViaNewPrefillService = getOrElse(prefillData.data, "guideState.customContext", null);
36358            var ccpMapViaOldImplementation = getOrElse(guidelib, "__runtime__.guideContext.customPropertyMap", {});
36359            var ccpMapViaOldAndNewImplementation = _.extend({}, ccpMapViaOldImplementation, getOrElse(guide, "runtime.guideContext.customPropertyMap", {}));
36360            if (!_.isEmpty(ccpMapViaNewPrefillService) && _.isEmpty(ccpMapViaOldAndNewImplementation)) {
36361                guideBridge.customContextProperty(ccpMapViaNewPrefillService);
36362            }
36363
36364            var fileMapViaNewPrefillService = getOrElse(prefillData.data, "guideState.fileAttachmentMap", null);
36365            var fileMapViaOldImplementation = guideBridge.customContextProperty("fileAttachmentMap");
36366            if (!_.isEmpty(fileMapViaNewPrefillService) && _.isEmpty(fileMapViaOldImplementation)) {
36367                guideBridge.customContextProperty("fileAttachmentMap", fileMapViaNewPrefillService);
36368            }
36369        } else {
36370            customPropertyMap = prefillData.customContext || {};
36371            guideBridge.customContextProperty("fileAttachmentMap", prefillData.fileAttachmentMap);
36372            guideBridge.customContextProperty("fileAttachmentWrappers", prefillData.fileAttachmentWrappers);
36373        }
36374
36375        if (guide.xdpRef) {
36376            mergedXfaRenderContext = getOrElse(prefillData.data, "guideState.xfaState.xfaRenderContext", null);
36377
36378            if (mergedXfaRenderContext != null) {
36379                
36380                xfalib.runtime.renderContext = JSON.parse(mergedXfaRenderContext);
36381            }
36382
36383            xfalib.runtime.xfa.form._initialize(true);
36384            $(window).trigger("XfaInitialized");
36385        }
36386
36387        if (rawData !== "") {
36388            if (guideContext.schemaType === "formdatamodel" || guideContext.schemaType === "jsonschema") {
36389                guideContext.guidePrefillJson = rawData;
36390            } else {
36391                guideContext.guidePrefillXml = rawData;
36392            }
36393        }
36394
36395        guideContext.customPropertyMap = $.extend({}, guideContext.customPropertyMap, customPropertyMap);
36396
36397        
36398        $.extend(true, guide.runtime.guideContext, guideContext);
36399
36400        guidelib.model.markDirtyPanels(guide.allLazyChildren, rawData, dirtyPanels, guide);
36401
36402        guidelib.model._prepareGuide(prefillData, guide);
36403
36404        
36405        
36406        if (guide.allLazyChildren.length > 0 && guideBridge.customContextProperty("fileAttachmentMap")) {
36407            var fileAttachmentMap = guideBridge.customContextProperty("fileAttachmentMap");
36408            if (typeof fileAttachmentMap === "string") {
36409                fileAttachmentMap = JSON.parse(fileAttachmentMap);
36410            }
36411            guide.internal.liveDataUtils._updateLazyAttachmentMap(fileAttachmentMap);
36412        }
36413    };
36414
36415    guidelib.model.fireOnContainerDomElementReady = function (guideJsonData, fetchData, $htmlElement, localContextCustomPropertyMap) {
36416
36417        var inputData = this.prepareInput(guideJsonData),
36418            guideJson = inputData.guideJson,
36419            guideContext = inputData.guideContext,
36420            guidemergedjson = inputData.guidemergedjson,
36421            xfaJson = inputData.xfaJson,
36422            xfaRenderContext = inputData.xfaRenderContext,
36423            localStorage,
36424            guide,
36425            dataPromise;
36426        initializeLogger(xfaJson != null);
36427        if (guideJson === null || guideContext == null) {
36428            console.error("Unable to load Form. Adaptive Form Json is invalid.");
36429            return;
36430        }
36431
36432        if (window.guideBridge !== undefined) {
36433            localStorage = window.guideBridge._getStorage();
36434        }
36435        try {
36436            
36437            localContextCustomPropertyMap = _.isObject(localContextCustomPropertyMap) ?
36438                JSON.stringify(localContextCustomPropertyMap) : localContextCustomPropertyMap;
36439            localContextCustomPropertyMap = JSON.parse(localContextCustomPropertyMap);
36440        } catch(e) {
36441            localContextCustomPropertyMap = {};
36442        }
36443
36444        if (fetchData && (guidemergedjson === null || guidemergedjson === "" || getOrElse(localStorage, "guideState", null) !== null)) {
36445            if (fetchData instanceof Function) {
36446                var result = fetchData();
36447                if (result.then instanceof Function) {
36448                    dataPromise = result;
36449                } else {
36450                    dataPromise = _.extend({}, {isMergedJson : false}, fetchData());
36451                }
36452            } else if ((!(window.FD && window.FD.isToggleEnabled("FT_FORMS-14840"))) ||
36453                ((guideJson.prefillService !== undefined && guideJson.prefillService !== "none") || (new URLSearchParams(window.location.search)).get("dataRef") !== null)) {
36454                var formContainerPath = getOrElse(window.guideBridge, "userConfig.submitConfig.aemFormComponentPath", guideContext.guidePath);
36455                var guideUrl = window.guideBridge._getGuidePathUrl(".af.prefilldata.json", formContainerPath);
36456                dataPromise = this.fetchData(guideUrl + window.location.search);
36457            } else {
36458                dataPromise = {data: null, isMergedJson: false};
36459            }
36460        } else {
36461            var _mergeData = guidemergedjson;
36462            if (getOrElse(localStorage, "guideState", null) !== null) {
36463                _mergeData = localStorage;
36464            }
36465            
36466            
36467            dataPromise = {
36468                data : _mergeData,
36469                isMergedJson : true
36470            };
36471        }
36472
36473        
36474        var liveDataUtils = this.initializeLiveDataUtils(guideContext.schemaType),
36475            liveModel = new guidelib.model.LiveModel();
36476
36477        if (window.guideBridge.hostName == "server") {
36478            
36479            if (!FD.isToggleEnabled(guidelib.util.FeatureToggleConstants.FT_BROWSERLESS_SUBMISSION)) {
36480                liveModel._disableFunctions();
36481                liveDataUtils._disableFunctions();
36482            }
36483
36484            _.each(_.functions(viewOnlyUtils), function (funcName) {
36485                viewOnlyUtils[funcName] = function () {};
36486            });
36487
36488            if (window.formBridge) {
36489                
36490                
36491                
36492                window.formBridge.ajaxCallMode = "server";
36493            }
36494        }
36495
36496        liveModel.createDataNodes(guideJson.repeatBindRef);
36497        var allLazyChildren = getOrElse(guideJson, "allLazyChildren", []);
36498        
36499        var options = {};
36500        options = _.extend({}, options, {"liveModel" : liveModel, "liveDataUtils" : liveDataUtils});
36501
36502        utils.postExternalMessage("_formdomstart");
36503        try {
36504            guide = guidelib.model._createXfaAndGuideModel(guideJson, xfaJson, options);
36505            
36506            guide.runtime.guideContext.customPropertyMap = _.extend({}, guide.runtime.guideContext.customPropertyMap, localContextCustomPropertyMap);
36507            if (allLazyChildren.length > 0) {
36508                liveModel.createCrossFragFields(guideJson.guideGlobalLazyField, guide);
36509            }
36510            guide.version = new guidelib.util.Version({
36511                scriptingBehaviourVersion: guideContext.scriptingBehaviourVersion
36512            });
36513            guide.setGuideState(constants.GUIDE_STATE_MODEL_CREATED);
36514            if (xfaJson && xfaRenderContext) {
36515                xfalib.runtime.renderContext = xfaRenderContext;
36516            }
36517            utils.triggerEventOnWindow({type: "guideModelInitialized", guide: guide});
36518        } catch (e) {
36519            
36520            if (e.stack) {
36521                console.error(e.stack);
36522            }
36523        }
36524
36525        var $guideElement = $htmlElement || $("div.guideContainerWrapperNode");
36526
36527        if (dataPromise.then instanceof Function) {
36528            return dataPromise.then(function (result) {
36529                guidelib.model.mergeData(result, guide, guideContext);
36530                viewOnlyUtils.renderView(guide, $guideElement);
36531            });
36532        } else {
36533            
36534            guidelib.model.mergeData(dataPromise, guide, guideContext);
36535            viewOnlyUtils.renderView(guide, $guideElement);
36536            return guide;
36537        }
36538    };
36539
36540    guidelib.model.fetchData = function (path) {
36541        var deferred = $.Deferred();
36542        if (window.guideBridge.hostName === "server") { 
36543            deferred.resolve({
36544                data : "",
36545                isMergedJson : false
36546            });
36547        } else {
36548            $.ajax({
36549                url : path,
36550                type : 'POST',
36551                dataType : 'json'
36552            }).done(function (data) {
36553                var obj = _.extend({}, data, {isMergedJson : false});
36554                deferred.resolve(obj);
36555            }).fail(function (obj, textStatus, errorThrown) {
36556                console.error(textStatus + " " + errorThrown);
36557                deferred.resolve({
36558                    data : "",
36559                    isMergedJson : false
36560                });
36561            });
36562        }
36563        return deferred.promise();
36564    };
36565})(_, $, window.guidelib);
36566
36567(function ($) {
36568    var xfaUtil = xfalib.ut.XfaUtil.prototype;
36569    $.widget("xfaWidget.imageCheckButtonWidget", $.xfaWidget.XfaCheckBox, {
36570
36571        _widgetName : "imageCheckButtonWidget",
36572
36573        getOptionsMap : function () {
36574            var parentOptionsMap = $.xfaWidget.XfaCheckBox.prototype.getOptionsMap.apply(this, arguments);
36575            return $.extend({}, parentOptionsMap, {
36576                "displayValue" : function (val) {
36577                    parentOptionsMap.displayValue.apply(this, arguments);
36578                    var rbParent = this.$userControl.parents('.guideRadioButtonItem, .guideCheckBoxItem');
36579                    if (rbParent) {
36580                        rbParent.toggleClass('imageCheckButtonChecked', this.checkedState);
36581                    }
36582                    if (this.$userControl.attr('disabled') === 'disabled') {
36583                        rbParent.addClass('imageCheckButtonDisabled');
36584                    }
36585                }
36586            });
36587        }
36588    });
36589})($);
36590(function (_, guidelib) {
36591    var GuideModelRegistry = guidelib.model.GuideModelRegistry = xfalib.ut.Class.extend({
36592
36593        _nodeClassToFactoryMap : {
36594
36595        },
36596
36597        createModel : function (jsonModel, options) {
36598            var model = null;
36599            var guideNodeClassTag = "GuideNode";
36600            if (jsonModel.guideNodeClass && jsonModel.guideNodeClass.length > 0)     {
36601                guideNodeClassTag = jsonModel.guideNodeClass.charAt(0).toUpperCase() + jsonModel.guideNodeClass.substr(1);
36602            }
36603            var factoryFnName = "create" + guideNodeClassTag ;
36604            if (jsonModel.guideNodeClass && this._nodeClassToFactoryMap[jsonModel.guideNodeClass]) {
36605                factoryFnName = this._nodeClassToFactoryMap[jsonModel.guideNodeClass];
36606            }
36607            if (this[factoryFnName]) {
36608                model = this[factoryFnName].call(this, jsonModel, options);
36609            }
36610
36611            if (!model && guidelib.model[guideNodeClassTag]) {
36612                model = new guidelib.model[guideNodeClassTag](this._getOptions(jsonModel, options));
36613            }
36614
36615            if (!model) {
36616                if (jsonModel.items) {
36617                    model = new guidelib.model.GuideItemsContainer(this._getOptions(jsonModel, options));
36618                } else {
36619                    model = new guidelib.model.GuideNode(this._getOptions(jsonModel, options));
36620                }
36621            }
36622            return model;
36623        },
36624
36625        _getOptions : function (jsonModel, options) {
36626            return _.extend({}, options, {"jsonModel" : jsonModel});
36627        },
36628
36629        createInstanceManager : function (guidePanelModel) {
36630            var name =  guidePanelModel.getAttribute("name"),
36631                imJson = {
36632                    guideNodeClass : "guideInstanceManager",
36633                    minOccur : guidePanelModel.minOccur,
36634                    maxOccur : guidePanelModel.maxOccur,
36635                    initialOccur : guidePanelModel.initialOccur,
36636                    instanceTemplateId : guidePanelModel.templateId,
36637                    name : "_" + name,
36638                    instanceName : name,
36639                    templateId : "im_" + guidePanelModel.templateId,
36640                    id : "im_" + guidePanelModel.id
36641                };
36642            var options = {};
36643            if (guidePanelModel.options._guideContainer) {
36644                options = _.extend({}, options, {"_guideContainer" : guidePanelModel.options._guideContainer});
36645            }
36646            return guidelib.model.GuideModelRegistry.prototype.createModel(imJson, options);
36647        }
36648    });
36649})(_, guidelib);
36650
36651/*************************************************************************
36652 *
36653 * ADOBE CONFIDENTIAL
36654 * __________________
36655 *
36656 *  Copyright 2014 Adobe Systems Incorporated
36657 *  All Rights Reserved.
36658 *
36659 * NOTICE:  All information contained herein is, and remains
36660 * the property of Adobe Systems Incorporated and its suppliers,
36661 * if any.  The intellectual and technical concepts contained
36662 * herein are proprietary to Adobe Systems Incorporated and its
36663 * suppliers and may be covered by U.S. and Foreign Patents,
36664 * patents in process, and are protected by trade secret or copyright law.
36665 * Dissemination of this information or reproduction of this material
36666 * is strictly forbidden unless prior written permission is obtained
36667 * from Adobe Systems Incorporated.
36668 **************************************************************************/
36669
36670/**
36671 * Created with IntelliJ IDEA.
36672 * User: rismehta
36673 * Date: 1/15/14
36674 * Time: 5:49 PM
36675 * To change this template use File | Settings | File Templates.
36676 */
36677
36678/*anonymous function to handle show of file list view */
36679(function ($, guidelib) {
36680
36681    // Was causing problem in IE9
36682    // hence have added timeout to ensure that once button is rendered, event handler is registered
36683    // todo: may have to think of better namespace ?
36684    guidelib.intervals = guidelib.intervals || {};
36685    guidelib.intervals.intId = setInterval(function () {
36686        var fileAttachmentListingBtn = $("div.fileattachmentlisting button[data-guide-fileListing]");
36687        if (fileAttachmentListingBtn.length > 0) {
36688            clearInterval(guidelib.intervals.intId);
36689            var self;
36690            fileAttachmentListingBtn.click(function () {
36691                self = $(this);
36692                // added because in mobile devices it was causing problem of backdrop
36693                $("#fileAttachment").addClass("fileAttachmentDialog")
36694                $("#fileAttachment").appendTo('body');
36695                $("#fileAttachment").modal("show");
36696            });
36697            // bring focus back to file attachment listing button on dialog hide
36698            $(".fileAttachmentDialog").on('hidden.bs.modal', function (e) {
36699                $(this).removeClass("fileAttachmentDialog");
36700                self.focus();
36701            });
36702        }
36703    }, 1000);
36704}($, guidelib));
36705
36706/*************************************************************************
36707 *
36708 * ADOBE CONFIDENTIAL
36709 * __________________
36710 *
36711 *  Copyright 2014 Adobe Systems Incorporated
36712 *  All Rights Reserved.
36713 *
36714 * NOTICE:  All information contained herein is, and remains
36715 * the property of Adobe Systems Incorporated and its suppliers,
36716 * if any.  The intellectual and technical concepts contained
36717 * herein are proprietary to Adobe Systems Incorporated and its
36718 * suppliers and may be covered by U.S. and Foreign Patents,
36719 * patents in process, and are protected by trade secret or copyright law.
36720 * Dissemination of this information or reproduction of this material
36721 * is strictly forbidden unless prior written permission is obtained
36722 * from Adobe Systems Incorporated.
36723 **************************************************************************/
36724
36725(function ($) {
36726
36727    // GUIDE ADD REMOVE CLASS DEFINITION
36728    // ====================
36729
36730    var GuideAddRemove = function (element) {
36731        this.element = $(element);
36732    };
36733
36734    GuideAddRemove.prototype.add = function () {
36735        $this = this.element;
36736        var id = $this.attr("data-guide-id"),
36737            nextPanel;
36738
36739        if (id) {
36740            if (window.guideBridge) {
36741                var guidePanel = window.guideBridge._resolveId(id);
36742                if (guidePanel) {
36743                    nextPanel = guidePanel.instanceManager.insertInstance(guidePanel.instanceIndex + 1);
36744                    if (nextPanel) {
36745                        window.guideBridge.setFocus(nextPanel.somExpression, "firstItem");
36746                    }
36747                }
36748            } else {
36749                console.log("could not add new instance" + id);
36750            }
36751        }
36752    };
36753
36754    GuideAddRemove.prototype.remove = function () {
36755        $this = this.element;
36756        var id       = $this.attr("data-guide-id");
36757
36758        if (id) {
36759            if (window.guideBridge) {
36760                var guidePanel = window.guideBridge._resolveId(id);
36761                if (guidePanel) {
36762                    guidePanel.instanceManager.removeInstance(guidePanel.instanceIndex);
36763                }
36764            } else {
36765                console.log("could not remove instance");
36766            }
36767        }
36768    };
36769
36770    // GUIDE ADD REMOVE PLUGIN DEFINITION
36771    // =====================
36772
36773    var old = $.fn.guideAddRemove;
36774
36775    $.fn.guideAddRemove = function (option) {
36776        return this.each(function () {
36777            var $this = $(this);
36778            var data  = $this.data('guideAddRemove');
36779
36780            if (!data) {
36781                $this.data('guideAddRemove', (data = new GuideAddRemove(this)));
36782            }
36783            if (typeof option == 'string') {
36784                data[option]();
36785            }
36786        });
36787    };
36788
36789    $.fn.guideAddRemove.Constructor = GuideAddRemove();
36790
36791    // ADD REMOVE NO CONFLICT
36792    // ===============
36793
36794    $.fn.guideAddRemove.noConflict = function () {
36795        $.fn.guideAddRemove = old;
36796        return this;
36797    };
36798
36799    // ADD REMOVE DATA-API
36800    // ============
36801
36802    $(document).on('click.guideAddRemove.data-api keypress.guideAddRemove.data-api', '[data-guide-addremove="add"]', function (e) {
36803        if (e.type == "keypress" && !guidelib.util.GuideUtil.isEnterKeyPressed(e)) {
36804            return;
36805        }
36806        e.preventDefault();
36807        //This is required for setting the focus on the new panel. Otherwise the focus remains on the previous panel.
36808        e.stopImmediatePropagation();
36809        $(this).guideAddRemove('add');
36810    }).on('click.guideAddRemove.data-api keypress.guideAddRemove.data-api', '[data-guide-addremove="remove"]', function (e) {
36811            if (e.type == "keypress" && !guidelib.util.GuideUtil.isEnterKeyPressed(e)) {
36812                return;
36813            }
36814            e.preventDefault();
36815            $(this).guideAddRemove('remove');
36816        });
36817
36818}($));
36819
36820/*************************************************************************
36821 *
36822 * ADOBE CONFIDENTIAL
36823 * __________________
36824 *
36825 *  Copyright <year> Adobe Systems Incorporated
36826 *  All Rights Reserved.
36827 *
36828 * NOTICE:  All information contained herein is, and remains
36829 * the property of Adobe Systems Incorporated and its suppliers,
36830 * if any.  The intellectual and technical concepts contained
36831 * herein are proprietary to Adobe Systems Incorporated and its
36832 * suppliers and may be covered by U.S. and Foreign Patents,
36833 * patents in process, and are protected by trade secret or copyright law.
36834 * Dissemination of this information or reproduction of this material
36835 * is strictly forbidden unless prior written permission is obtained
36836 * from Adobe Systems Incorporated.
36837 **************************************************************************/
36838
36839(function ($) {
36840
36841    // TABLE LAYOUT PLUGIN
36842    // ============
36843
36844    $(document).on('panelRemoved.af', '.guideTableNode', function (e, $childRemoved, index) {
36845        // this plugin is specific to a layout
36846        // one can also check the layout based on CSS class set and perform things accordingly
36847        // prevent the bubbling up of the event
36848        e.stopPropagation();
36849        // this would work only in runtime
36850        var $bodyRows = $(e.target).find("tr.guideTableRowNode:not(.guideTableHeader)");
36851        // Set focus to first child
36852        if (index > 1) {
36853            // set focus on prev row since index is greater than 1
36854            var $prevRow = $bodyRows.eq(index - 1);
36855            guidelib.util.GuideUtil.setFocusOnFirstItemOfTableRow($prevRow);
36856        } else if (index == 1) {
36857            var $nextRow = $bodyRows.eq(1);
36858            // may there is only one row which has got deleted, hence check if next row actually exists
36859            if ($nextRow.length > 0) {
36860                guidelib.util.GuideUtil.setFocusOnFirstItemOfTableRow($nextRow);
36861            }
36862        }
36863    });
36864
36865}($));
36866
36867/*************************************************************************
36868 *
36869 * ADOBE CONFIDENTIAL
36870 * __________________
36871 *
36872 *  Copyright 2014 Adobe Systems Incorporated
36873 *  All Rights Reserved.
36874 *
36875 * NOTICE:  All information contained herein is, and remains
36876 * the property of Adobe Systems Incorporated and its suppliers,
36877 * if any.  The intellectual and technical concepts contained
36878 * herein are proprietary to Adobe Systems Incorporated and its
36879 * suppliers and may be covered by U.S. and Foreign Patents,
36880 * patents in process, and are protected by trade secret or copyright law.
36881 * Dissemination of this information or reproduction of this material
36882 * is strictly forbidden unless prior written permission is obtained
36883 * from Adobe Systems Incorporated.
36884 **************************************************************************/
36885
36886/*handle click of default next and previous navigator*/
36887$(function ($) {
36888    var getPanelSom = function (panelId) {
36889            var panel = window.guideBridge._resolveId(panelId);
36890            if (panel === undefined || panel === null) {
36891                return "";
36892            }
36893            return panel.somExpression;
36894        },
36895        pointerup_evnt = xfalib.ut.TouchUtil.POINTER_UP;
36896
36897    if (pointerup_evnt === "touchend") {
36898        // touchend happens before blur, hence the value of the current
36899        // focused field is not committed and setFocus API receives the old
36900        // value. So as a hack we are using mouseup instead of touchend to
36901        // make sure that the value gets committed
36902        pointerup_evnt = "mouseup";
36903    }
36904    $('body').on(pointerup_evnt + " keydown", '[data-guide-wizard-nav]', function (e) {
36905        var triggerKeyEvent = false;
36906        //  check for event type  and key press space/enter
36907        if (e.type === "keydown" && (e.keyCode === 32 || e.keyCode === 13)) {
36908            e.preventDefault();
36909            triggerKeyEvent =  true; // set to trigger key event
36910        }
36911
36912        //  when event is pointerup(click) or space/enter key is pressed, trigger navigation
36913        if (e.type === "pointerup" || triggerKeyEvent) {
36914            var $this = $(this),
36915                options = $this.data("guide-wizard-nav");
36916            if (_.isObject(options)) { //case of all the options, get som expression out of id
36917                options.somExpression = getPanelSom(options.panelId);
36918            } else { //case where its value of somId
36919                var somExpr = getPanelSom(options),
36920                    navType = $(this).data("guide-wizard-nav-type");
36921                options = {
36922                    somExpression: somExpr,
36923                    focusOption: navType,
36924                    runCompletionScript: true
36925                };
36926            }
36927            window.guideBridge.setFocus(options);
36928        }
36929    });
36930
36931    window.guideBridge.on("elementNavigationChanged",
36932        function (evntName, evnt) {
36933            var activePanelSom = evnt.newText,
36934                activePanel = window.guideBridge._guideView.getView(activePanelSom),
36935                scrollDirection,
36936                scrollStep,
36937                scrollPos,
36938                list,
36939                $listElements;
36940            if (activePanel instanceof guidelib.view.GuidePanelView) {
36941                $listElements = activePanel.parentView.$element.find('[id*="' + guidelib.util.GuideUtil.GUIDE_ITEM_NAV_CONTAINER_SUFFIX + '"]');
36942                if (!_.isUndefined($listElements) && !_.isNull($listElements) && $listElements.length > 0) {
36943                    list = $listElements.eq(0);
36944                    if (_.isUndefined(list.data("guideNavScrollPos"))) {
36945                        list.data("guideNavScrollPos", 0);
36946                    }
36947                    scrollPos = list.data("guideNavScrollPos");
36948                    //Find index among the visible panels
36949                    var parentChildViews = activePanel.parentView.childViews,
36950                        iterator,
36951                        navPos = 0;
36952                    for (iterator = 0; iterator < parentChildViews.length; iterator++) {
36953                        if (activePanel === parentChildViews[iterator]) {
36954                            break;
36955                        }
36956                        if (parentChildViews[iterator]._model.visible) {
36957                            navPos = navPos + 1;
36958                        }
36959                    }
36960                    if (navPos > scrollPos) {
36961                        scrollDirection = "right";
36962                    } else {
36963                        scrollDirection = "left";
36964                    }
36965                    scrollStep = Math.abs(navPos - scrollPos);
36966                    guidelib.util.GuideUtil.navScroll(list, scrollDirection, scrollStep, '[id*="' + guidelib.util.GuideUtil.GUIDE_ITEM_
36966NAV_SUFFIX + '"]:not(.hidden)');
36967                }
36968            }
36969        });
36970});
36971
36972/*************************************************************************
36973 *
36974 * ADOBE CONFIDENTIAL
36975 * __________________
36976 *
36977 *  Copyright 2014 Adobe Systems Incorporated
36978 *  All Rights Reserved.
36979 *
36980 * NOTICE:  All information contained herein is, and remains
36981 * the property of Adobe Systems Incorporated and its suppliers,
36982 * if any.  The intellectual and technical concepts contained
36983 * herein are proprietary to Adobe Systems Incorporated and its
36984 * suppliers and may be covered by U.S. and Foreign Patents,
36985 * patents in process, and are protected by trade secret or copyright law.
36986 * Dissemination of this information or reproduction of this material
36987 * is strictly forbidden unless prior written permission is obtained
36988 * from Adobe Systems Incorporated.
36989 **************************************************************************/
36990
36991$(function ($) {
36992
36993    /* handle swipe*/
36994    var setSwipeGestureState = function () {
36995        var swipeEnabled = !window.guideBridge._guide.getAttribute("disableSwipeGesture");
36996        window.guideBridge.enableSwipeGesture(swipeEnabled, swipeEnabled);
36997    };
36998    window.guideBridge.connect(setSwipeGestureState, this);
36999
37000    /*show scroll indication on mobile devices*/
37001    var scrollIndicator = function () {
37002        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
37003            $('[data-guide-scroll-indicator]').removeClass('mobileScrollIndicator');
37004        } else if ($(window).scrollTop() < $(document).height() - $(window).height()) {
37005            $('[data-guide-scroll-indicator]').addClass('mobileScrollIndicator');
37006        }
37007    };
37008
37009    //this should be changed back to $(document).ready(scrollIndicator) instead of windows onload,
37010    //once jquery version is bumped
37011    $(window).on('load scroll resize', scrollIndicator);
37012    window.guideBridge.on('elementNavigationChanged', scrollIndicator);
37013});
37014
37015/*************************************************************************
37016 *
37017 * ADOBE CONFIDENTIAL
37018 * __________________
37019 *
37020 *  Copyright 2014 Adobe Systems Incorporated
37021 *  All Rights Reserved.
37022 *
37023 * NOTICE:  All information contained herein is, and remains
37024 * the property of Adobe Systems Incorporated and its suppliers,
37025 * if any.  The intellectual and technical concepts contained
37026 * herein are proprietary to Adobe Systems Incorporated and its
37027 * suppliers and may be covered by U.S. and Foreign Patents,
37028 * patents in process, and are protected by trade secret or copyright law.
37029 * Dissemination of this information or reproduction of this material
37030 * is strictly forbidden unless prior written permission is obtained
37031 * from Adobe Systems Incorporated.
37032 **************************************************************************/
37033/*anonymous function to handle click of default next and previous navigator*/
37034(function ($) {
37035    window.guideBridge.on("elementNavigationChanged",
37036        function (evntName, evnt) {
37037            var activePanelSom = evnt.newText,
37038                activePanel = window.guideBridge.resolveNode(activePanelSom);
37039            if (activePanel) {
37040                var dynamicContentSelector = "[data-target-guide-content]",
37041                    text = $(dynamicContentSelector).text();
37042                // if there is an active panel already set and active panel is not an instance of root panel node
37043                // only then set the active panel title to the content
37044                if (text != null && text.length > 0
37045                    && (!(activePanel instanceof guidelib.model.RootPanelNode)
37046                        && !(activePanel instanceof guidelib.model.GuideToolbar))) {
37047                    $(dynamicContentSelector).text(activePanel.title ? activePanel.title : "");
37048                }
37049            }
37050        });
37051}($));
37052
37053// jscs:disable requireDotNotation
37054/*
37055 * ***********************************************************************
37056 * ADOBE CONFIDENTIAL
37057 * __________________
37058 *
37059 * Copyright 2015 Adobe Systems Incorporated
37060 * All Rights Reserved.
37061 *
37062 * NOTICE:  All information contained herein is, and remains
37063 * the property of Adobe Systems Incorporated and its suppliers,
37064 * if any.  The intellectual and technical concepts contained
37065 * herein are proprietary to Adobe Systems Incorporated and its
37066 * suppliers and may be covered by U.S. and Foreign Patents,
37067 * patents in process, and are protected by trade secret or copyright law.
37068 * Dissemination of this information or reproduction of this material
37069 * is strictly forbidden unless prior written permission is obtained
37070 * from Adobe Systems Incorporated.
37071 * ***********************************************************************
37072 */
37073
37074(function ($, guidelib, _) {
37075    var GuideUtil = guidelib.util.GuideUtil,
37076        CHART_TYPE = GuideUtil.chartType,
37077
37078        ChartUtils = guidelib.chartUtils = {
37079
37080            reducerOptions : window.chartReducer.reducerOptions,
37081
37082            /**
37083             * Returns the display format of axis data
37084             * @param dataType {string} representing data type of axis
37085             * @returns {string}
37086             */
37087            getDisplayFormat : function (dataType) {
37088                var displayFormat = "";
37089                if (dataType === 'date' || dataType === 'date-time') {
37090                    displayFormat = 'date{' + guidelib.i18n.datePatterns.med + '}';
37091                }
37092                return displayFormat;
37093            },
37094
37095            /**
37096             * Reads chart model for chart configuration and computes the data for chart
37097             * @param chartModel
37098             * @returns {{}}
37099             */
37100            gatherAxisData : function (chartModel) {
37101                var categoryExp,
37102                    valueExp,
37103                    reducerFunction,
37104                    repeatableInstances,
37105                    repeatableItem,
37106                    seriesRepeatableItem,
37107                    series,
37108                    relativeSeriesNameExp,
37109                    currentSeries,
37110                    repeatablePath,
37111                    seriesLength = 0,
37112                    seriesRepeatableInstances,
37113                    relativeSeriesRefExp,
37114                    data = new Map(),
37115                    chartBuildOptions = {},
37116                    isWebChannelChart = chartModel.jsonModel["sling:resourceType"] === 'fd/ccm/web-channel/components/chart/v1/chart',
37117                    dataToFill = {};
37118                chartBuildOptions.isFDMDataSource = chartModel.dataSourceType === "fdm" ? true : false;
37119                chartBuildOptions.chartModel = chartModel;
37120                dataToFill.valueDisplayFormat = "";
37121                dataToFill.labelDisplayFormat = "";
37122                dataToFill.categoryDataType = "";
37123                dataToFill.valueDataType = "";
37124
37125                repeatableItem = chartModel.getOrElse(chartModel._guide().runtime, chartModel.repeatableItem, undefined);
37126
37127                //Do not support reducer functions on x-axis for Web channel charts
37128                if (chartModel.reducerXFunction && chartModel.reducerXFunction !== 'none' && !isWebChannelChart) {
37129                    chartBuildOptions.categoryExp = chartModel.yExp;
37130                    chartBuildOptions.valueExp = chartModel.xExp;
37131                    chartBuildOptions.reducerFunction = chartModel.reducerXFunction;
37132                    dataToFill = ChartUtils._setProp(dataToFill, "categoryDataType", chartModel.jsonModel.yDataType);
37133                    dataToFill = ChartUtils._setProp(dataToFill, "valueDataType", chartModel.jsonModel.xDataType);
37134                } else {
37135                    chartBuildOptions.categoryExp = chartModel.xExp;
37136                    chartBuildOptions.valueExp = chartModel.yExp;
37137                    dataToFill = ChartUtils._setProp(dataToFill, "categoryDataType", chartModel.jsonModel.yDataType);
37138                    dataToFill = ChartUtils._setProp(dataToFill, "valueDataType", chartModel.jsonModel.xDataType);
37139                    if (chartModel.reducerYFunction && chartModel.reducerYFunction !== 'none') {
37140                        chartBuildOptions.reducerFunction = chartModel.reducerYFunction;
37141                    }
37142                }
37143
37144                if (chartBuildOptions.isFDMDataSource) {
37145                    dataToFill.valueDisplayFormat = ChartUtils.getDisplayFormat(dataToFill.valueDataType);
37146                    dataToFill.labelDisplayFormat = ChartUtils.getDisplayFormat(dataToFill.categoryDataType);
37147                    repeatableItem = chartModel.repeatableItem;
37148                    chartBuildOptions.categoryExp = chartBuildOptions.categoryExp.substring(repeatableItem.length + 1, chartBuildOptions.categoryExp.length).split("/");
37149                    chartBuildOptions.valueExp = chartBuildOptions.valueExp.substring(repeatableItem.length + 1, chartBuildOptions.valueExp.length).split("/");
37150                    if (isWebChannelChart) {
37151                        dataToFill.series = series = [];
37152                        if (chartModel.jsonModel.chartType === 'quadrant') {
37153                            chartBuildOptions.isXYReferencePointSet = false;
37154                            if (chartModel.jsonModel.referencePointType === 'staticReferencePoint') {
37155                                if (chartModel.jsonModel.xDataType === 'date' || chartModel.jsonModel.xDataType === 'date-time') {
37156                                    //Whenx-axis is of Date type we need to compute reference value in milliseconds.
37157                                    chartModel.jsonModel.xAxisReferencePoint = new Date(chartModel.jsonModel.xAxisReferencePoint).getTime();
37158                                }
37159                                chartBuildOptions.isXYReferencePointSet = true;
37160                            }
37161                        }
37162                    }
37163                    if ("true" == chartModel.jsonModel.multiSeries) {
37164                        seriesRepeatableItem = chartModel.jsonModel.seriesRepeatableItem;
37165                        relativeSeriesNameExp = chartModel.jsonModel.seriesName.substring(seriesRepeatableItem.length + 1, chartModel.jsonModel.seriesName.length);
37166                        seriesRepeatableInstances = this._getRepeatableInstances(seriesRepeatableItem, null, chartModel);
37167                        seriesLength = seriesRepeatableInstances ? seriesRepeatableInstances.length : seriesLength;
37168                        repeatablePath = repeatableItem.substring(seriesRepeatableItem.length, repeatableItem.length);
37169                        if (chartModel.jsonModel.chartType === 'quadrant' && chartModel.jsonModel.referencePointType === 'fdmReferencePoint') {
37170                            relativeSeriesRefExp = chartModel.jsonModel.seriesReferenceExp.substring(seriesRepeatableItem.length + 1, chartModel.jsonModel.seriesReferenceExp.length);
37171                        }
37172                        for (var i = 0; i < seriesLength; i++) {
37173                            chartBuildOptions.repeatableInstances = this._getRepeatableInstances(repeatablePath, seriesRepeatableInstances[i], chartModel);
37174                            chartBuildOptions.repeatableItemForReferencePoint;
37175                            if (relativeSeriesRefExp && !chartBuildOptions.isXYReferencePointSet) {
37176                                chartBuildOptions.repeatableItemForReferencePoint = undefined;
37177                                if (this.matchUserInputWithFDM(chartModel.jsonModel.seriesReferenceDataType, seriesRepeatableInstances[i][relativeSeriesRefExp], chartModel.jsonModel.seriesReferenceValue)) {
37178                                    chartBuildOptions.repeatableItemForReferencePoint = repeatableItem;
37179                                }
37180                            }
37181                            currentSeries = this.buildChartData(chartBuildOptions);
37182                            currentSeries.name = seriesRepeatableInstances[i][relativeSeriesNameExp];
37183                            series.push(currentSeries);
37184                        }
37185                    } else {
37186                        chartBuildOptions.repeatableInstances = this._getRepeatableInstances(repeatableItem, null, chartModel);
37187                        chartBuildOptions.repeatableItemForReferencePoint = repeatableItem;
37188                        currentSeries = this.buildChartData(chartBuildOptions);
37189                        series.push(currentSeries);
37190                    }
37191                    if (isWebChannelChart && chartModel.jsonModel.chartType === 'quadrant' && chartModel.jsonModel.referencePointType === 'fdmReferencePoint' && !chartBuildOptions.isXYReferencePointSet) {
37192                        chartModel.jsonModel.xAxisReferencePoint = undefined;
37193                        chartModel.jsonModel.yAxisReferencePoint = undefined;
37194                    }
37195                    chartBuildOptions.repeatableInstances = null;
37196                } else if (repeatableItem) {
37197                    chartBuildOptions.repeatableInstances = repeatableItem.instanceManager.instances;
37198                }
37199                if (chartBuildOptions.repeatableInstances) {
37200                    var chartData = this.buildChartData(chartBuildOptions);
37201                    dataToFill.label = chartData.label;
37202                    dataToFill.value = chartData.value;
37203                }
37204                return dataToFill;
37205            },
37206
37207            buildChartData : function (chartBuildOptions) {
37208                var dataToFill = {},
37209                    data = new Map(),
37210                    referencePointExp,
37211                    isFDMReferencePointSet = false;
37212                dataToFill.value = [];
37213                dataToFill.label = [];
37214
37215                if (chartBuildOptions.chartModel.jsonModel.chartType === 'quadrant' && chartBuildOptions.chartModel.jsonModel.referencePointType === 'fdmReferencePoint' && chartBuildOptions.repeatableItemForReferencePoint) {
37216                    referencePointExp = chartBuildOptions.chartModel.jsonModel.xyReferencePointExp.substring(chartBuildOptions.repeatableItemForReferencePoint.length + 1, chartBuildOptions.chartModel.jsonModel.xyReferencePointExp.length).split("/");
37217                }
37218                var that = this;
37219                _.each(chartBuildOptions.repeatableInstances, function (repeatableInstance, index) {
37220                    var categoryPropVal,
37221                        valuePropVal,
37222                        xyReferenceVal;
37223                    if (chartBuildOptions.isFDMDataSource) {
37224                        if (_.isArray(chartBuildOptions.categoryExp) && _.isArray(chartBuildOptions.valueExp)) {
37225                            //Handling composite key case.
37226                            var temp = repeatableInstance;
37227                            _.each(chartBuildOptions.categoryExp, function (obj) {
37228                                temp = temp[obj];
37229                            });
37230                            categoryPropVal = temp;
37231
37232                            temp = repeatableInstance;
37233                            _.each(chartBuildOptions.valueExp, function (obj) {
37234                                temp = temp[obj];
37235                            });
37236                            valuePropVal = temp;
37237
37238                            if (chartBuildOptions.chartModel.jsonModel.chartType === 'quadrant' && !chartBuildOptions.isXYReferencePointSet) {
37239                                if (chartBuildOptions.repeatableItemForReferencePoint && chartBuildOptions.chartModel.jsonModel.referencePointType === 'fdmReferencePoint') {
37240                                    temp = repeatableInstance;
37241                                    _.each(referencePointExp, function (obj) {
37242                                        temp = temp[obj];
37243                                    });
37244                                    xyReferenceVal = temp;
37245                                    if (that.matchUserInputWithFDM(chartBuildOptions.chartModel.jsonModel.xyReferencePointDataType, xyReferenceVal, chartBuildOptions.chartModel.jsonModel.xyReferencePointValue)) {
37246                                        //For date type x-axis FDM value we need to get time in milliseconds to send to Highcharts
37247                                        chartBuildOptions.chartModel.jsonModel.xAxisReferencePoint = (chartBuildOptions.chartModel.jsonModel.xDataType === 'date' || chartBuildOptions.chartModel.jsonModel.xDataType === 'date-time') ? new Date(categoryPropVal).getTime() : categoryPropVal;
37248                                        chartBuildOptions.chartModel.jsonModel.yAxisReferencePoint = valuePropVal;
37249                                        chartBuildOptions.isXYReferencePointSet = true;
37250                                    }
37251                                }
37252                            }
37253                        }
37254                    } else {
37255                        categoryPropVal = repeatableInstance[chartBuildOptions.categoryExp].value;
37256                        valuePropVal = repeatableInstance[chartBuildOptions.valueExp].value;
37257                    }
37258
37259                    categoryPropVal = _.isUndefined(categoryPropVal) ? '' : categoryPropVal;
37260                    valuePropVal = _.isUndefined(valuePropVal) ? '' : valuePropVal;
37261                    if (chartBuildOptions.reducerFunction) {
37262                        if (!data.has(categoryPropVal)) {
37263                            data.set(categoryPropVal, []);
37264                        }
37265                        data.get(categoryPropVal).push(valuePropVal);
37266                    } else {
37267                        dataToFill.label.push(categoryPropVal);
37268                        dataToFill.value.push(valuePropVal);
37269                    }
37270                });
37271
37272                if (chartBuildOptions.reducerFunction) {
37273                    var reducer = ChartUtils.reducerOptions[chartBuildOptions.reducerFunction] || window[chartBuildOptions.reducerFunction];
37274                    data.forEach(function (value, key) {
37275                        dataToFill.label.push(key);
37276                        dataToFill.value.push(reducer(data.get(key)));
37277                    });
37278                }
37279                return dataToFill;
37280            },
37281
37282            matchUserInputWithFDM : function (fdmObjectDataType, fdmObjectValue, userInputValue) {
37283                return (((fdmObjectDataType == 'date-time' || fdmObjectDataType == 'date')  && new Date(userInputValue).getTime() == new Date(fdmObjectValue).getTime())
37284                    || (fdmObjectDataType == 'boolean' && JSON.parse(userInputValue) == fdmObjectValue)
37285                    || (userInputValue == fdmObjectValue));
37286            },
37287
37288            /**
37289             * Returns dv.chart object created from chart model.
37290             * @param chartModel
37291             * @param $chartElement
37292             * @returns {dv.chart}
37293             */
37294            constructChart : function (chartModel, $chartElement) {
37295                var chartType = chartModel.chartType,
37296                    showLegends = chartModel.showLegends,
37297                    legendPosition = chartModel.legendPosition,
37298                    tooltipHtml = chartModel.tooltipHtml,
37299                    innerRadius = chartModel.innerRadius,
37300                    lineColor = chartModel.lineColor,
37301                    pointColor = chartModel.pointColor,
37302                    areaColor = chartModel.areaColor,
37303                    dataToFill = chartModel.data,
37304                    chartBehavior = [],
37305                    axisMap = {},
37306                    axisScale = {},
37307                    chartLayers,
37308                    chart,
37309                    categoryAxis,
37310                    valueAxis;
37311                if (chartModel.reducerXFunction && chartModel.reducerXFunction !== 'none') {
37312                    categoryAxis = 'y';
37313                    valueAxis = 'x';
37314                } else {
37315                    categoryAxis = 'x';
37316                    valueAxis = 'y';
37317                }
37318
37319                if (dataToFill.labelDisplayFormat) {
37320                    dataToFill.label = dataToFill.label.map(function (value) {
37321                        return guidelib.util.GuideUtil.formatValue(value,
37322                            dataToFill.labelDisplayFormat,
37323                            dataToFill.categoryDataType);
37324                    });
37325                }
37326
37327                if (dataToFill.valueDisplayFormat) {
37328                    dataToFill.value = dataToFill.value.map(function (value) {
37329                        return guidelib.util.GuideUtil.formatValue(value,
37330                            dataToFill.valueDisplayFormat,
37331                            dataToFill.valueDataType);
37332                    });
37333                }
37334
37335                axisMap[categoryAxis] = 'label';
37336                axisMap[valueAxis] = 'value';
37337                axisScale[valueAxis] = dv.scale.linear().lowerLimit(0);
37338
37339                try {
37340                    if (GuideUtil.isChartTooltipApplicable(chartType)) {
37341                        if (tooltipHtml && tooltipHtml !== '') {
37342                            var xValMap = axisMap['x'],
37343                                yValMap = axisMap['y'];
37344                            chartBehavior = [dv.behavior.rollover().content(function (d) {
37345                                var tooltip = tooltipHtml.replace(/\${x}/g, d.data[xValMap]);
37346                                tooltip = tooltip.replace(/\${y}/g, d.data[yValMap]);
37347                                return tooltip;
37348                            })];
37349                        }
37350                    }
37351                    axisScale[categoryAxis] = dv.scale.ordinal();
37352                    chart = dv.chart();
37353                    chart.map('fill', 'label')
37354                        .map('x', axisMap['x'], axisScale['x'])
37355                        .map('y', axisMap['y'], axisScale['y']);
37356
37357                    var chartPoint = dv.geom.point().set('fill', pointColor).behaviors(chartBehavior),
37358                        chartLine = dv.geom.line().set('fill', lineColor),
37359                        chartArea = dv.geom.area().set('alpha', 0.1).set('fill', areaColor),
37360                        flippedCaretesianCoord = dv.coord.cartesian().flip(true),
37361                        lineCommon = function () {
37362                            chart.set('stroke', lineColor);
37363                            chartLayers = [dv.geom.line()];
37364                        },
37365                        barTypeCommon = function () {
37366                            chartLayers = [dv.geom.bar().behaviors(chartBehavior)];
37367                            chart.map('x', 'label', axisScale[categoryAxis])
37368                                .map('y', 'value');
37369                        },
37370                        barCommon = function () {
37371                            barTypeCommon();
37372                            if (categoryAxis === 'x') {
37373                                chart.coord(flippedCaretesianCoord);
37374                            }
37375                        },
37376                        columnCommon = function () {
37377                            barTypeCommon();
37378                            if (categoryAxis === 'y') {
37379                                chart.coord(flippedCaretesianCoord);
37380                            }
37381                        },
37382                        pieCommon = function (radius) {
37383                            columnCommon();
37384                            dataToFill[categoryAxis] = Array.apply(null, Array(dataToFill["label"].length)).map(function () {
37385                                return 1;
37386                            });
37387                            axisMap[categoryAxis] = categoryAxis;
37388                            if (radius > 0) {
37389                                axisScale[categoryAxis] = axisScale[categoryAxis].padding(.3);
37390                            }
37391
37392                            chart.map('x', axisMap[categoryAxis], axisScale[categoryAxis]);
37393
37394                            chart.coord(dv.coord.polar().flip(true).innerRadius(radius))
37395                                .guide(['x', 'y'], 'none')
37396                                .position('fill');
37397                        };
37398
37399                    switch (chartType) {
37400                        case CHART_TYPE.LINE:
37401                            lineCommon();
37402                            chartLayers.push(chartLine);
37403                            break;
37404                        case CHART_TYPE.POINT:
37405                            lineCommon();
37406                            chartLayers.push(chartPoint);
37407                            break;
37408                        case CHART_TYPE.AREA:
37409                            lineCommon();
37410                            chartLayers.push(chartLine);
37411                            chartLayers.push(chartArea);
37412                            break;
37413                        case CHART_TYPE.LINE_POINT:
37414                            lineCommon();
37415                            chartLayers.push(chartPoint);
37416                            chartLayers.push(chartLine);
37417                            break;
37418                        case CHART_TYPE.BAR:
37419                            barCommon();
37420                            break;
37421                        case CHART_TYPE.COLUMN:
37422                            columnCommon();
37423                            break;
37424                        case CHART_TYPE.PIE:
37425                            pieCommon(0);
37426                            break;
37427                        case CHART_TYPE.DONUT:
37428                            pieCommon(innerRadius);
37429                            break;
37430                    }
37431
37432                    chart.layers(chartLayers);
37433                    chart.data(dataToFill)
37434                        .width(chartModel.width + '%')
37435                        .height(chartModel.height)
37436                        .parent("#" + $chartElement.attr('id'))
37437                        .padding({"left" : 10, "top" : 10, "right" : 10, "bottom" : 10});
37438
37439                    if (GuideUtil.isChartAxisTitleApplicable(chartType)) {
37440                        chart.guide('x', dv.guide.axis().title(chartModel.xAxisTitle))
37441                            .guide('y', dv.guide.axis().title(chartModel.yAxisTitle));
37442                    }
37443
37444                    if (GuideUtil.isChartLegendApplicable(chartType) && showLegends) {
37445                        chart.guide('fill', dv.guide.legend().orientation(legendPosition));
37446                    }
37447                } catch (exception) {
37448                    window.guideBridge._guide.logger().log("Error while constructing chart " + exception);
37449                }
37450                return chart;
37451            },
37452
37453            _setProp : function (object, prop, value) {
37454                if (object.constructor == {}.constructor && !_.isEmpty(value)) {
37455                    object[prop] = value;
37456                }
37457                return object;
37458            },
37459
37460            /**
37461            *   Retrieves Repeatable Instances using liveDataUtils API for the given
37462            *   repeatablePath. This API internally handles naked/non-naked case.
37463            *
37464            *   @param  repeatablePath
37465            *   @param  data
37466            *   @return Repeatable Instances for the given repeatablePath using liveDataUtils.
37467            *
37468            *   TODO Move this API to data utils.
37469            */
37470            _getRepeatableInstances : function (repeatablePath, data, chartModel) {
37471                var liveDataUtils = chartModel._guide().internal.liveDataUtils,
37472                    liveData = data ? data : liveDataUtils._liveDataDoc,
37473                    xpath = "";
37474
37475                if (_.isEmpty(liveData) || _.isEmpty(repeatablePath)) {
37476                    return;
37477                }
37478
37479                if (!_.isEmpty(liveData.afData)) {//Non-Naked data case
37480                    liveData = liveData.afData;
37481                    xpath = liveDataUtils.constants.BOUND_DATA_XPATH;
37482                } else {//Naked data case or multiple series case
37483                    repeatablePath = repeatablePath.substring(1, repeatablePath.length);
37484                }
37485
37486                //Find the repeatable instances.
37487                repeatableInstances = liveDataUtils._getElement(liveData, xpath + repeatablePath);
37488
37489                return repeatableInstances;
37490            }
37491        };
37492}($, guidelib, _));
37493
37494//Poly-filling request animation frame function for IE 9
37495(function () {
37496    var lastFramePaintTime = 0;
37497    if (!window.requestAnimationFrame) {
37498        window.requestAnimationFrame = function (callback, element) {
37499            var currTime = new Date().getTime(),
37500                timeToCall = Math.max(0, 16 - (currTime - lastFramePaintTime)), //16-16 frames per second
37501                id = window.setTimeout(function () {
37502                        callback(currTime + timeToCall);
37503                    }, timeToCall);
37504            lastFramePaintTime = currTime + timeToCall;
37505            return id;
37506        };
37507    }
37508
37509    if (!window.cancelAnimationFrame) {
37510        window.cancelAnimationFrame = function (id) {
37511            clearTimeout(id);
37512        };
37513    }
37514}());
37515
37516/*
37517 * ***********************************************************************
37518 * ADOBE CONFIDENTIAL
37519 * __________________
37520 *
37521 * Copyright 2015 Adobe Systems Incorporated
37522 * All Rights Reserved.
37523 *
37524 * NOTICE:  All information contained herein is, and remains
37525 * the property of Adobe Systems Incorporated and its suppliers,
37526 * if any.  The intellectual and technical concepts contained
37527 * herein are proprietary to Adobe Systems Incorporated and its
37528 * suppliers and may be covered by U.S. and Foreign Patents,
37529 * patents in process, and are protected by trade secret or copyright law.
37530 * Dissemination of this information or reproduction of this material
37531 * is strictly forbidden unless prior written permission is obtained
37532 * from Adobe Systems Incorporated.
37533 * ***********************************************************************
37534 */
37535
37536(function ($, guidelib, xfalib, _) {
37537    var errorHandler = function (jqXHR) {
37538         var errorPayload;
37539
37540         // Actually we need clean-up old data but its not even happening in case of success with empty data
37541        // Running output mapping with empty result set to ensure old data is cleared
37542
37543         if (jqXHR.responseText) {
37544             var inputMapping = this.inputMapping;
37545             try {
37546                 errorPayload = JSON.parse(jqXHR.responseText);
37547             } catch (error) {
37548                 // result should be json if its not wel formed json or empty then ignoring it
37549             }
37550             if(errorPayload && errorPayload.errors) {
37551
37552                 // Iterating over violations received and set it at field level using input mapping provided.
37553                 var violations = errorPayload.errors;
37554                 $.each(violations, function (i, violation) {
37555                     if(violation && violation.bindRef && violation.errorMessages) {
37556                         var key = violation.bindRef.slice(1).split("/").join(".");
37557                         var field = inputMapping[key];
37558                         if (field) {
37559                             field.markAsInvalid(violation.errorMessages.join("\n"));
37560                         }
37561                     }
37562                 });
37563             }
37564         }
37565         // Invoke author register error handler (if any)
37566         if(this.customErrorHandler) {
37567             this.customErrorHandler.call(this, jqXHR, errorPayload);
37568         }
37569    };
37570
37571    var defaultErrorHandler = function (responseJson, headerMap) {
37572        if (responseJson) {
37573            if (responseJson && responseJson.validationErrors) {
37574                var violations = responseJson.validationErrors;
37575                $.each(violations, function (key, violation) {
37576                    if (violation && violation.details && (violation.fieldName || violation.dataRef)) {
37577                        if (!window.guideBridge._guide._bindRefMap || Object.keys(window.guideBridge._guide._bindRefMap).length === 0) {
37578                            window.guideBridge._populateBindRefToSomMap();
37579                        }
37580                        var som = (violation.fieldName) ? violation.fieldName : window.guideBridge._guide._bindRefMap[violation.dataRef];
37581                        var field = window.guideBridge.resolveNode(som);
37582                        if (field) {
37583                            field.markAsInvalid(violation.details.join("\n"));
37584                        }
37585                    }
37586                });
37587            }
37588        }
37589    };
37590
37591    var defaultErrorHandlerWrapper = function(jqXHR) {
37592        if (jqXHR.responseText) {
37593            try {
37594                responseJson = JSON.parse(jqXHR.responseText);
37595            } catch (error) {
37596                // result should be json if its not well formed json or empty then ignoring it
37597            }
37598        }
37599
37600        var headers = jqXHR.getAllResponseHeaders();
37601
37602        // Convert the header string into an array
37603        // of individual headers
37604        var arr = headers.trim().split(/[\r\n]+/);
37605
37606        // Create a map of header names to values
37607        var headerMap = {};
37608        arr.forEach(function (line) {
37609            var parts = line.split(': ');
37610            var header = parts.shift();
37611            var value = parts.join(': ');
37612            headerMap[header] = value;
37613        });
37614
37615        if (this.customErrorHandler === "guidelib.dataIntegrationUtils.defaultErrorHandler") {
37616            defaultErrorHandler(responseJson, headerMap);
37617        } else {
37618            if(this.customErrorHandler) {
37619                this.customErrorHandler.call(this, responseJson, headerMap);
37620            }
37621        }
37622    }
37623
37624    // Counts the number of Array(repeatable) in the output JSON of the WSDL.
37625    var outputJsonRepeatCount = function (wsdlOutputId, outputJSONObj) {
37626        var count = 0,
37627            wsdlOutputHierarchy = wsdlOutputId.split(".");
37628        if (Array.isArray(outputJSONObj)) {
37629            count++;
37630            outputJSONObj = outputJSONObj[0];
37631        }
37632        $.each(wsdlOutputHierarchy, function (depth) {
37633            if (outputJSONObj) {
37634                outputJSONObj = outputJSONObj[wsdlOutputHierarchy[depth]];
37635                if (Array.isArray(outputJSONObj)) {
37636                    count++;
37637                    outputJSONObj = outputJSONObj[0];
37638                }
37639            }
37640        });
37641        return count;
37642    };
37643
37644    //Traversing to the highest repeatable field in hierarchy as a starting point.
37645    var outputRepeatAncestor = function (targetNode, repeatCount, targetNameHierarchy) {
37646        while (repeatCount > 0) {
37647            if (_.isNull(targetNode.parent)) {
37648                return targetNode;
37649            }
37650            targetNameHierarchy.push(targetNode.name);
37651            targetNode = targetNode.parent;
37652            if (targetNode.repeatable) {
37653                repeatCount--;
37654            }
37655        }
37656        return targetNode;
37657    };
37658
37659    /**
37660     * Extract value of a hierarchy of properties
37661     * from a nested javascript object.
37662     * @param {Object} obj Nested javascript object
37663     * @param {Array|String} props list of properties
37664     * or dot separated string from root to leaf object
37665     * @return {Array} return list of values found
37666     */
37667    function extractValues(obj, props) {
37668        // handle easy cases
37669        if (obj === null || typeof(obj) === "undefined") {
37670            return [];
37671        }
37672        if (typeof(props) == "string") {
37673            props = props.split(".");
37674        }
37675        if (props.length == 0) {
37676            return [obj];
37677        }
37678        var ret = [];
37679        if (obj instanceof Array) {
37680            for (var i = 0; i < obj.length; i++) {
37681                ret = ret.concat(extractValues(obj[i], props));
37682            }
37683            return ret;
37684        }
37685        if (!obj.hasOwnProperty(props[0])) {
37686            return [];
37687        }
37688        // handle actual case now
37689
37690        var key = props[0];
37691        var remainingKeys = props.slice(1);
37692        var values = obj[key];
37693        if (!(values instanceof Array)) {
37694            values = [values];
37695        }
37696        for (var x = 0; x < values.length; x++) {
37697            ret = ret.concat(extractValues(values[x], remainingKeys));
37698        }
37699        return ret;
37700    }
37701    //Maps the output JSON(outputJSONObj) to the Model(targetNode)
37702    var outputJsonMapping = function (wsdlOutputId, targetNode, targetNameHierarchy, outputJSONObj) {
37703        if (targetNameHierarchy.length === 0) {
37704            targetNode.value = xfalib.ut.XfaUtil.prototype.getOrElse(outputJSONObj, wsdlOutputId, "");
37705            return;
37706        }
37707        var targetName = targetNameHierarchy.pop();
37708        if (targetNode.repeatable) {
37709            //Gets respective array for this repeatable field.
37710            while (typeof outputJSONObj === "object" && !Array.isArray(outputJSONObj)) {
37711                var argsIndex = wsdlOutputId.indexOf('.');
37712                outputJSONObj = outputJSONObj[wsdlOutputId.substring(0, argsIndex)] || "";
37713                wsdlOutputId = wsdlOutputId.substring(argsIndex + 1);
37714            }
37715            //Adjust the number of instances to the number of array elements.
37716            var jsonLength = outputJSONObj.length,
37717                instanceCount = targetNode.instanceManager.instanceCount;
37718            if (instanceCount < jsonLength) {
37719                targetNode.instanceManager.addInstances({
37720                    instanceCount : jsonLength
37721                });
37722            }
37723            //Check as "" might occur too for incorrect mappings.
37724            if (Array.isArray(outputJSONObj)) {
37725                //Recursive call for every instance with corresponding value.
37726                $.each(outputJSONObj, function (index) {
37727                    // if the output from external API call contains more records, than the number
37728                    // of instances present, return
37729                    if (index >= targetNode.instanceManager.instanceCount) {
37730                        return false;
37731                    }
37732                    targetNode = targetNode.instanceManager.instances[index];
37733                    outputJsonMapping(wsdlOutputId, targetNode[targetName], targetNameHierarchy, outputJSONObj[index]);
37734                });
37735            }
37736        } else {
37737            //Recursive call down the hierarchy.
37738            outputJsonMapping(wsdlOutputId, targetNode[targetName], targetNameHierarchy, outputJSONObj);
37739        }
37740        //Pushing back the hierarchy for next instance if any.
37741        targetNameHierarchy.push(targetName);
37742    };
37743
37744    var populateWsdlOutput = function (wsdlOutput, textStatus, jqXHR) {
37745        if (wsdlOutput == null || wsdlOutput.length == 0) {
37746            return;
37747        }
37748
37749        var origOutputJSONObj,
37750            outputMappingObj = this.callbackData;
37751        try {
37752            origOutputJSONObj = JSON.parse(wsdlOutput);
37753        } catch (e) {
37754            //Handling primitive output
37755            origOutputJSONObj = {"response" : wsdlOutput};
37756        }
37757
37758        /*  For each entry in outputMappingObj, we need to find the corresponding value in responseObj.
37759         *  wsdlOutputId - wsdlOutput hierarchy, targetNode - field in the form whose value is to be set.
37760         *  e.g. {ipinfo.ip, txtfield} */
37761        $.each(outputMappingObj, function (wsdlOutputId, targetNode) {
37762            /* Gets value in outputJSONObj corresponding to targetNode.
37763             * First, It counts the number of Array in hierarchy as repeatCount.
37764             * Next, targetNode is taken to the starting point for traversal.
37765             * It's the topmost repeatable node in hierarchy.
37766             * Lastly, The outputJson is mapped to the TargetNode.*/
37767            var repeatCount = outputJsonRepeatCount(wsdlOutputId, origOutputJSONObj),
37768                targetNameHierarchy = [],
37769                targetNode = outputRepeatAncestor(targetNode, repeatCount, targetNameHierarchy);
37770            outputJsonMapping(wsdlOutputId, targetNode, targetNameHierarchy, origOutputJSONObj);
37771        });
37772        window.guideBridge._guide.runPendingExpressions();
37773    };
37774
37775    /**
37776     * Create and set items to dropdown field from wsdl response.
37777     * @this {Object} is of form {callbackData:data}
37778     */
37779    function setOptionsCallback(wsdlOutput) {
37780       var cbData = this.callbackData;
37781       var options = [];
37782       if (!_.isEmpty(wsdlOutput)) {
37783           var wsdlOutputObj = JSON.parse(wsdlOutput);
37784           var savedValues = extractValues(wsdlOutputObj, cbData.savedValue);
37785           var displayedValues = extractValues(wsdlOutputObj, cbData.displayedValue);
37786           for (var i = 0; i < savedValues.length; i++) {
37787               options.push(savedValues[i] + "=" + displayedValues[i]);
37788           }
37789       }
37790       cbData.field.items = options;
37791   }
37792
37793    function setValueCallback(wsdlOutput) {
37794        var cbData = this.callbackData;
37795        var wsdlOutputObj = JSON.parse(wsdlOutput);
37796        cbData.field.value = extractValues(wsdlOutputObj, cbData.value);
37797    }
37798
37799    function appendLoadingIcon() {
37800        $("#loadingPage").addClass("guideServiceLoading");
37801    }
37802
37803    function removeLoadingIcon() {
37804        $("#loadingPage").removeClass("guideServiceLoading");
37805    }
37806
37807    function executeOperationInternal (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler, apiVersion) {
37808        // populate operationDetails object
37809        var successHandler = processOutputCallback || populateWsdlOutput;
37810        var wsdlInputObj = {};
37811
37812        /* Iterate through the jsonInputMapping and create the input object.
37813         * wsdlInputId - wsdlInput hierarchy, targetNode - field in the form whose value is to be retrieved.*/
37814        $.each(jsonInputMappingObj, function (wsdlInputId, targetNode) {
37815            var argsHierarchy = wsdlInputId.split("."),
37816                wsdlArgObj = wsdlInputObj,
37817                argDepth,
37818                valueToBeAssigned;
37819
37820            for (argDepth = 0; argDepth < argsHierarchy.length - 1; argDepth++) {
37821                wsdlArgObj[argsHierarchy[argDepth]] = wsdlArgObj[argsHierarchy[argDepth]] || {};
37822                wsdlArgObj = wsdlArgObj[argsHierarchy[argDepth]];
37823            }
37824            // assign the value of targetNode
37825            if (typeof targetNode === "object") {
37826                valueToBeAssigned = targetNode.value;
37827            } else {
37828                valueToBeAssigned = targetNode;
37829            }
37830            wsdlArgObj[argsHierarchy[argDepth]] = valueToBeAssigned;
37831        });
37832
37833        var wsdlEndPoint = wsdlInfoObj.wsdlEndPoint,
37834            operationDetails = {};
37835        operationDetails.operationName = wsdlInfoObj.operationName;
37836        operationDetails.input = JSON.stringify(wsdlInputObj);
37837        operationDetails.port = wsdlInfoObj.port;
37838        operationDetails.soapActionURI = wsdlInfoObj.soapActionURI;
37839        operationDetails.namespace = wsdlInfoObj.namespace;
37840        operationDetails.inputRoot = wsdlInfoObj.inputRoot;
37841        operationDetails.inputAttr = JSON.stringify(wsdlInfoObj.inputAttr);
37842        operationDetails.serviceEndPoint = wsdlInfoObj.serviceEndPoint;
37843        if (!model) {
37844            console.log("No model parameter passed to this API, this may fail during server side re-validation. Please correct your scripts.");
37845        }
37846        // TODO: this needs to be fixed, this API does not have access to guideContext but would execute in context of AF always
37847        var guide = model && model._guide && model._guide();
37848        var wsdlServletURL  = ((guide ? guide.jcrPath : guidelib.__runtime__.guide.jcrPath) + ".af.dermis");
37849        var externalizedWSDLServletURL;
37850        if (guideBridge != null) {
37851            externalizedWSDLServletURL = guideBridge._getUrl(wsdlServletURL);
37852        } else {
37853            externalizedWSDLServletURL = Granite.HTTP.externalize(wsdlServletURL);
37854        }
37855
37856        var invokeData = {};
37857        if (wsdlInfoObj.wsdlEndPoint) {
37858            invokeData.functionToExecute = 'invokeWsdlOperation';
37859            invokeData.wsdlEndPoint = wsdlEndPoint;
37860            invokeData.operationName = operationDetails.operationName;
37861            invokeData.input = operationDetails.input;
37862
37863            if (operationDetails.port) {
37864                invokeData.port = operationDetails.port;
37865            }
37866            if (operationDetails.soapActionURI) {
37867                invokeData.soapActionURI = operationDetails.soapActionURI;
37868            }
37869            if (operationDetails.namespace) {
37870                invokeData.namespace = operationDetails.namespace;
37871            }
37872            if (operationDetails.inputRoot) {
37873                invokeData.inputRoot = operationDetails.inputRoot;
37874            }
37875            if (operationDetails.inputAttr) {
37876                invokeData.inputAttr = operationDetails.inputAttr;
37877            }
37878            if (operationDetails.serviceEndPoint) {
37879                invokeData.serviceEndPoint = operationDetails.serviceEndPoint;
37880            }
37881        } else if (wsdlInfoObj.formDataModelId) {
37882            invokeData.functionToExecute = 'invokeFDMOperation';
37883            invokeData.formDataModelId = wsdlInfoObj.formDataModelId;
37884            invokeData.input = JSON.stringify(wsdlInputObj);
37885            invokeData.operationName = wsdlInfoObj.operationName;
37886            invokeData.runValidation = wsdlInfoObj.runValidation;
37887            invokeData.apiVersion = apiVersion;
37888            if (wsdlInfoObj.schemaRef) {
37889                invokeData.schemaRef = wsdlInfoObj.schemaRef;
37890            }
37891            if (wsdlInfoObj.schemaType) {
37892                invokeData.schemaType = wsdlInfoObj.schemaType;
37893            }
37894        }
37895        invokeData.guideNodePath = guide ? guide._currentContext.contextNode.jcrPath : guidelib.__runtime__.guide._currentContext.contextNode.jcrPath;
37896
37897        $.ajax({
37898            type : 'POST',
37899            url : externalizedWSDLServletURL,
37900            data : invokeData,
37901            beforeSend : appendLoadingIcon,
37902            complete : removeLoadingIcon,
37903            dataType : 'text',
37904            success : successHandler,
37905            error : defaultErrorHandler,
37906            context : {callbackData : jsonOutputMappingObj, inputMapping: jsonInputMappingObj, customErrorHandler: customErrorHandler}
37907        });
37908    }
37909
37910    var DataIntegrationUtils = guidelib.dataIntegrationUtils = {
37911
37912        setOptionsFromService : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
37913            this.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setOptionsCallback);
37914            return jsonOutputMapping.field.items;
37915        },
37916
37917        setValueFromService : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
37918            this.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setValueCallback);
37919            return jsonOutputMapping.field.items;
37920        },
37921
37922        /**
37923         * @deprecated
37924         */
37925        executeOperation : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model) {
37926            var defaultErrorHandler = errorHandler;
37927            executeOperationInternal(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler);
37928        },
37929
37930        executeOperationV2 : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model) {
37931            var defaultErrorHandler = defaultErrorHandlerWrapper;
37932            var apiVersion = "2";
37933            executeOperationInternal(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj, processOutputCallback, customErrorHandler, model, defaultErrorHandler, apiVersion);
37934        },
37935
37936        defaultErrorHandler : defaultErrorHandler
37937    };
37938
37939    var WsdlUtils = guidelib.wsdlUtils = {
37940        /**
37941         *  Internal API, called for invoking webservice and setting items in a drop down
37942         */
37943        setOptionsFromWSDL : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
37944            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setOptionsCallback);
37945            return jsonOutputMapping.field.items;
37946        },
37947
37948        setValueFromWSDL : function (wsdlInfoObj, jsonInputMapping, jsonOutputMapping) {
37949            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMapping, jsonOutputMapping, setValueCallback);
37950            return jsonOutputMapping.field.items;
37951        },
37952
37953        executeWSDLFunction : function (wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj) {
37954            // populate operationDetails object
37955            DataIntegrationUtils.executeOperation(wsdlInfoObj, jsonInputMappingObj, jsonOutputMappingObj);
37956        }
37957    };
37958}($, guidelib, xfalib, _));
37959
37960/*
37961 * ***********************************************************************
37962 * ADOBE CONFIDENTIAL
37963 * __________________
37964 *
37965 * Copyright 2015 Adobe Systems Incorporated
37966 * All Rights Reserved.
37967 *
37968 * NOTICE:  All information contained herein is, and remains
37969 * the property of Adobe Systems Incorporated and its suppliers,
37970 * if any.  The intellectual and technical concepts contained
37971 * herein are proprietary to Adobe Systems Incorporated and its
37972 * suppliers and may be covered by U.S. and Foreign Patents,
37973 * patents in process, and are protected by trade secret or copyright law.
37974 * Dissemination of this information or reproduction of this material
37975 * is strictly forbidden unless prior written permission is obtained
37976 * from Adobe Systems Incorporated.
37977 * ***********************************************************************
37978 */
37979
37980/**
37981 * @package guidelib.model.GuideDirtyMarkerAndVisitor
37982 * @version 0.0.1
37983 */
37984
37985(function ($, _, guidelib) {
37986    var GuideDirtyMarkerAndVisitor = guidelib.model.GuideDirtyMarkerAndVisitor = xfalib.ut.EventClass.extend({
37987
37988        initialize : function() {
37989            // need to save the map while save and restore - will do it in getGuideState
37990            this.visitMap = {};
37991        },
37992        /**
37993         * Return a list of dirty children
37994         * @returns {Array}
37995         * @private
37996         */
37997        _flattenDirtyPanelToList : function () {
37998            var csv = this.flattenDirtyPanelMapToCSV();
37999            if (csv.length > 0) {
38000                return csv.split(",");
38001            }
38002        },
38003        /**
38004         * If any dirty element then save it to CSV
38005         */
38006        flattenDirtyPanelMapToCSV : function () {
38007            var listOfDirtyPanels = "";
38008            _.each(_.keys(this.visitMap), function (key, index) {
38009                if (this.visitMap[key] === 0) {
38010                    listOfDirtyPanels += key + ",";
38011                }
38012            }, this);
38013            if (listOfDirtyPanels.length > 0) {
38014                // strip last ,
38015                listOfDirtyPanels = listOfDirtyPanels.substring(0, listOfDirtyPanels.length - 1);
38016            }
38017            return listOfDirtyPanels;
38018        },
38019        /**
38020         * This method finds and marks dirty all the lazy children that were dependant of global field's value
38021         * @param mapOfLazyChildren
38022         * @param listOfIdsOfDependents
38023         * @private
38024         */
38025        _findAndMarkDirty : function (mapOfLazyChildren, listOfIdsOfDependents) {
38026            var listOfLazyChildren = _.keys(mapOfLazyChildren);
38027
38028            _.each(listOfIdsOfDependents, function (depenId, index) {
38029                var longestPrefixLenSoFar = 0,
38030                    currentPrefixLen = 0,
38031                    nearestLazyId = null,
38032                    i;
38033                // find hierarchically closest field by matching longest som prefix
38034                for (i = 0; i < listOfLazyChildren.length; ++i) {
38035                    currentPrefixLen = guidelib.util.GuideUtil.commonPrefixLen(depenId, listOfLazyChildren[i]);
38036                    if (longestPrefixLenSoFar < currentPrefixLen) {
38037                        longestPrefixLenSoFar = currentPrefixLen;
38038                        nearestLazyId = listOfLazyChildren[i];
38039                    }
38040                }
38041                //  Mark dirty
38042                if (longestPrefixLenSoFar > 0) {
38043                    mapOfLazyChildren[nearestLazyId] = 0;
38044                }
38045            });
38046        },
38047        /**
38048         * Iterates a map and finds the first occurrence of value found in any key
38049         * @param map
38050         * @param value
38051         */
38052        _iterateMapAndReturnKeyOnValueFound : function (map, value) {
38053            var keyToReturn;
38054            _.each(_.keys(map), function (key, index) {
38055                if (map[key] === value) {
38056                    keyToReturn =  key;
38057                }
38058            });
38059            return keyToReturn;
38060        },
38061        /**
38062         * Updates the value of the key in map by one if present otherwise puts the key with value zero
38063         * @param map
38064         * @param key
38065         * @returns {*}
38066         */
38067        _updateCountOrInsert : function (map, key) {
38068            if (_.isUndefined(map[key])) {
38069                map[key] = 0;
38070            } else {
38071                map[key]++;
38072            }
38073
38074            return map;
38075        }
38076    });
38077
38078}($, _, window.guidelib));
38079
38080/*
38081 * ***********************************************************************
38082 * ADOBE CONFIDENTIAL
38083 * __________________
38084 *
38085 * Copyright 2016 Adobe Systems Incorporated
38086 * All Rights Reserved.
38087 *
38088 * NOTICE:  All information contained herein is, and remains
38089 * the property of Adobe Systems Incorporated and its suppliers,
38090 * if any.  The intellectual and technical concepts contained
38091 * herein are proprietary to Adobe Systems Incorporated and its
38092 * suppliers and may be covered by U.S. and Foreign Patents,
38093 * patents in process, and are protected by trade secret or copyright law.
38094 * Dissemination of this information or reproduction of this material
38095 * is strictly forbidden unless prior written permission is obtained
38096 * from Adobe Systems Incorporated.
38097 * ***********************************************************************
38098 */
38099
38100(function ($) {
38101    //Firing resize as, CSS is loaded after table mobile layout, cell width is adjusted for repeatable row, to accommodate +, - controls
38102    $(function () {
38103        $(window).trigger('resize');
38104    });
38105}($));

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.