this
variable inside the function will be managed by the caller of this method. You should use the\n\t * bind
method on the Function object if you want to manage the this
reference.\n\t *\n\t * The function can optionally take two parameters. The first parameter is the current element. The second parameter\n\t * is the current index.\n\t *\n\t * @param {Function} iterationFunction The function to call.\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t each(iterationFunction) {\n\t for (let i = 0; i < this.length; i++) {\n\t iterationFunction(this[i], i);\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Shorthand for calling {@link PrimeElement.hide} on each Element in the PrimeElementList.\n\t *\n\t * Hides the Element by setting the display style to none.\n\t *\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t hide() {\n\t return this._proxyToElement('hide');\n\t }\n\n\t /**\n\t * Returns the indexOf the element that matches the parameter, either Prime Element or DOMElement.\n\t *\n\t * @param {PrimeElement|Element} element The element to look for\n\t * @returns {number} The position of the element in the list, or -1 if not present.\n\t */\n\t indexOf(element) {\n\t const domElement = (element instanceof PrimeElement) ? element.domElement : element;\n\n\t for (let i = 0; i < this.length; i++) {\n\t if (this[i].domElement === domElement) {\n\t return i;\n\t }\n\t }\n\n\t return -1;\n\t }\n\n\t /**\n\t * Removes all the matched elements in the PrimeElementList from the DOM.\n\t *\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t removeAllFromDOM() {\n\t for (let i = 0; i < this.length; i++) {\n\t this[i].removeFromDOM();\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Shorthand for calling {@link PrimeElement.removeClass} on each Element in the PrimeElementList.\n\t *\n\t * Removes the given class (or list of space separated classes) from all Elements in this PrimeElementList.\n\t *\n\t * @param {string} classNames The class name(s) separated by a space.\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t removeClass(classNames) {\n\t return this._proxyToElement('removeClass', classNames);\n\t }\n\n\t /**\n\t * Shorthand for calling {@link PrimeElement.setChecked} on each Element in the PrimeElementList.\n\t *\n\t * If this element is a checkbox or radio button, this sets the checked field on the DOM object equal to the given\n\t * value.\n\t *\n\t * @param {boolean} value The value to set the checked state of this element to.\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t setChecked(value) {\n\t return this._proxyToElement('setChecked', value);\n\t }\n\n\t /**\n\t * Shorthand for calling {@link PrimeElement.setDisabled} on each Element in the PrimeElementList.\n\t *\n\t * Sets if this element is disabled or not. This works with any element that responds to the disabled property.\n\t *\n\t * @param {boolean} value The value to set the disabled state of this element to.\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t setDisabled(value) {\n\t return this._proxyToElement('setDisabled', value);\n\t }\n\n\t /**\n\t * Shorthand for calling {@link PrimeElement.show} on each Element in the PrimeElementList.\n\t *\n\t * Shows the element.\n\t *\n\t * @returns {PrimeElementList} This PrimeElementList.\n\t */\n\t show() {\n\t return this._proxyToElement('show');\n\t }\n\n\t /**\n\t * @callback PrimeElementListPredicate\n\t *\n\t * A function that defines a condition on a PrimeElement\n\t *\n\t * @param {PrimeElement} element\n\t * @returns {boolean} True if the element matches a condition\n\t */\n\n\t /**\n\t * A function that tests for any element that matches a condition.\n\t * @param {PrimeElementListPredicate} predicate A function that defines the condition to check\n\t * @returns {boolean} True if any element matches the predicate\n\t */\n\t some(predicate) {\n\t for (let i = 0; i < this.length; ++i) {\n\t if (predicate(this[i])) {\n\t return true;\n\t }\n\t }\n\t return false;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Proxy function calls to each Element in the PrimeElementList.\n\t * The first parameter is function name, followed by a variable length of arguments.\n\t *\n\t * Example usage: this._proxyToElement('addClass', classNames);\n\t *\n\t * @returns {PrimeElementList}\n\t * @private\n\t */\n\t _proxyToElement() {\n\t const args = Array.prototype.slice.apply(arguments);\n\t for (let i = 0; i < this.length; i++) {\n\t this[i][args[0]].apply(this[i], args.slice(1));\n\t }\n\t return this;\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2012-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tconst readyFunctions = [];\n\tconst tagRegexp = /^<(\\w+)\\s*\\/?>.*(?:<\\/\\1>)?$/;\n\n\t/**\n\t * The Body element as a PrimeElement object.\n\t *\n\t * @type {?PrimeElement}\n\t */\n\tlet bodyElement = null;\n\n\tclass PrimeDocument {\n\n\t /**\n\t * @returns {PrimeElement}\n\t */\n\t static get Element() {\n\t return PrimeElement;\n\t }\n\n\t /**\n\t * @returns {PrimeElementList}\n\t */\n\t static get ElementList() {\n\t return PrimeElementList;\n\t }\n\n\t /**\n\t * @returns {Arraythis
is the object. This is extremely useful for\n\t * objects that have functions that will be used as event listeners. Rather than having to manage binding and function\n\t * references manually you can instead bind all of the functions in the object and then use them directly for event\n\t * listeners.\n\t *\n\t * Here's an example:\n\t *\n\t * \n\t * function Foo() {\n\t * Utils.bindAll(this);\n\t *\n\t * // This function is bound to this (i.e. this.handleClick = this.handleClick.bind(this)).\n\t * PrimeDocument.queryFirst('a').addEventListener('click', this.handleClick);\n\t * }\n\t *\n\t * Foo.prototype = {\n\t * handleClick: function(event) {\n\t * ...\n\t * }\n\t * };\n\t *\n\t *\n\t * @param {*} object The object to bind all the functions for.\n\t */\n\t bindAll: function(object) {\n\t Utils.getAllPropertyNames(object).forEach((property) => {\n\t if (property !== 'constructor' && typeof object[property] === 'function' &&\n\t !(object[property].name && object[property].name.startsWith('bound '))) { // name isn't defined in ie\n\t Object.defineProperty(object, property, {value: object[property].bind(object)});\n\t }\n\t });\n\t },\n\n\t /**\n\t * HTML escape a string.\n\t *\n\t * @param string The string to escape\n\t * @returns {string} the escaped string\n\t */\n\t escapeHTML: function(string) {\n\t let div = document.createElement('div');\n\t div.appendChild(document.createTextNode(string));\n\t return div.innerHTML;\n\t },\n\n\t /**\n\t * Reverses HTML escaping.\n\t * @param string\n\t * @returns {string}\n\t */\n\t unescapeHTML: function(string) {\n\t // Neat trick using a textarea\n\t let txt = document.createElement('textarea');\n\t txt.innerHTML = string;\n\t return txt.value;\n\t },\n\n\t /**\n\t * Returns all of the properties for this object and all of its\n\t * inherited properties from parent objects.\n\t *\n\t * @param object\n\t * @returns {Array
this
is the object. This is extremely useful for\n\t * objects that have functions that will be used as event listeners. Rather than having to manage binding and function\n\t * references manually you can instead bind all of the functions in the object and then use them directly for event\n\t * listeners.\n\t *\n\t * Here's an example:\n\t *\n\t * \n\t * function Foo() {\n\t * Utils.bindAll(this);\n\t *\n\t * // This function is bound to this (i.e. this.handleClick = this.handleClick.bind(this)).\n\t * PrimeDocument.queryFirst('a').addEventListener('click', this.handleClick);\n\t * }\n\t *\n\t * Foo.prototype = {\n\t * handleClick: function(event) {\n\t * ...\n\t * }\n\t * };\n\t *\n\t *\n\t * @param {*} object The object to bind all the functions for.\n\t * @param {String} arguments A varargs list of function names to bind.\n\t */\n\t bindSome: function(object) {\n\t if (arguments.length > 1) {\n\t for (let i = 1; i < arguments.length; i++) {\n\t const func = object[arguments[i]];\n\t if (!Utils.isDefined(func) || !(func instanceof Function)) {\n\t throw new TypeError('The object does not contain a function named [' + arguments[i] + ']');\n\t }\n\n\t object[arguments[i]] = func.bind(object);\n\t }\n\t }\n\t for (let property in object) {\n\t if (object[property] instanceof Function) {\n\t object[property] = object[property].bind(object);\n\t }\n\t }\n\t },\n\n\t /**\n\t * Safely binds a function to a context.\n\t *\n\t * @param {Function} func The function to bind.\n\t * @param {Object} [context] An optional context to bind the function to.\n\t * @returns {Function} Either
func
or the newly bound function.\n\t */\n\t bindSafe: function(func, context) {\n\t if (!Utils.isDefined(func)) {\n\t throw new Error('Invalid arguments');\n\t }\n\n\t if (!Utils.isDefined(context)) {\n\t return func;\n\t }\n\n\t return func.bind(context);\n\t },\n\n\t /**\n\t * Calculates the length of the given text using the style of the given element.\n\t *\n\t * @param {PrimeElement} element The element to use the style of.\n\t * @param {string} text The text to calculate the length of.\n\t * @returns {number} The length of the text.\n\t */\n\t calculateTextLength: function(element, text) {\n\t const computedStyle = element.getComputedStyle();\n\t let textCalculator = PrimeDocument.queryById('prime-text-calculator');\n\t if (textCalculator === null) {\n\t textCalculator = PrimeDocument.newElement('')\n\t .setStyles({\n\t position: 'absolute',\n\t width: 'auto',\n\t fontSize: computedStyle['fontSize'],\n\t fontFamily: computedStyle['fontFamily'],\n\t fontWeight: computedStyle['fontWeight'],\n\t letterSpacing: computedStyle['letterSpacing'],\n\t whiteSpace: 'nowrap'\n\t })\n\t .setId('prime-text-calculator')\n\t .setTop(-9999)\n\t .setLeft(-9999)\n\t .appendTo(document.body);\n\t }\n\n\t textCalculator.setHTML(text);\n\t return textCalculator.getWidth();\n\t },\n\n\t /**\n\t * Attempts to invoke a function iteratively in the background a specific number of times within a specific duration.\n\t * This might not complete in the specified duration. The functions passed in should be short functions that return as\n\t * quickly as possible. If you are using long functions, use the recursive setTimeout trick by-hand instance.\n\t *\n\t * @param {number} totalDuration The duration in milliseconds.\n\t * @param {number} timesToCall The number of times to call the function.\n\t * @param {Function} stepFunction The step function to call each iteration.\n\t * @param {Function} [endFunction] The function to invoke at the end.\n\t */\n\t callIteratively: function(totalDuration, timesToCall, stepFunction, endFunction) {\n\t const step = totalDuration / timesToCall;\n\t let count = 0;\n\t const id = setInterval(function() {\n\t count++;\n\t const last = (count >= timesToCall);\n\t stepFunction(last);\n\t if (last) {\n\t clearInterval(id);\n\n\t if (Utils.isDefined(endFunction)) {\n\t endFunction();\n\t }\n\t }\n\t }, step - 1);\n\t },\n\n\t /**\n\t * Capitalizes the given String.\n\t *\n\t * @param {string} str The String to capitalize.\n\t * @returns {string} The capitalized String.\n\t */\n\t capitalize: function(str) {\n\t return str.charAt(0).toUpperCase() + str.substring(1);\n\t },\n\n\t /**\n\t * Converts CSS style names to style JavaScript names.\n\t *\n\t * @param {string} name The CSS style name to convert\n\t * @returns {string} The converted style name.\n\t */\n\t convertStyleName: function(name) {\n\t if (name === 'float') {\n\t return 'cssFloat';\n\t }\n\n\t let dash = name.indexOf('-');\n\t if (dash === -1) {\n\t return name;\n\t }\n\n\t let start = 0;\n\t let result = '';\n\t while (dash !== -1) {\n\t const piece = name.substring(start, dash);\n\t if (start === 0) {\n\t result = result.concat(piece);\n\t } else {\n\t result = result.concat(Utils.capitalize(piece));\n\t }\n\n\t start = dash + 1;\n\t dash = name.indexOf('-', start);\n\t }\n\n\t return result + Utils.capitalize(name.substring(start));\n\t },\n\n\t /**\n\t * Return an options map {Object} of the data set values coerced to a typed value of boolean, string or number.\n\t *\n\t * @param {PrimeElement} element The element.\n\t * @returns {Object} The options object.\n\t */\n\t dataSetToOptions: function(element) {\n\t const options = {};\n\t const data = element.getDataSet();\n\t for (let prop in data) {\n\t if (!data.hasOwnProperty(prop)) {\n\t continue;\n\t }\n\t const value = data[prop];\n\t if (isNaN(value)) {\n\t if (value === 'true') {\n\t options[prop] = true;\n\t } else if (value === 'false') {\n\t options[prop] = false;\n\t } else {\n\t options[prop] = value;\n\t }\n\t } else {\n\t options[prop] = parseInt(value);\n\t }\n\t }\n\n\t return options;\n\t },\n\n\t /**\n\t * Determines if an object is an array or not.\n\t *\n\t * @param {*} o The object to check.\n\t * @returns {boolean} True if the object is an array, false otherwise.\n\t */\n\t isArray: function(o) {\n\t return Object.prototype.toString.call(o) === '[object Array]';\n\t },\n\n\t /**\n\t * Tests whether or not the value is not null and not 'undefined'.\n\t *\n\t * @param {*} value The value to test.\n\t * @returns {boolean} True if the value is defined (not null or undefined).\n\t */\n\t isDefined: function(value) {\n\t return value !== null && typeof(value) !== 'undefined';\n\t },\n\n\t /**\n\t * Left pad a number.\n\t * @param {number} number the number to pad\n\t * @param {number} width the width of the final result\n\t * @returns {string}\n\t */\n\t leftPadNumber: function(number, width) {\n\t const sign = Math.sign(number) === -1 ? '-' : '';\n\t return sign + new Array(width).concat([Math.abs(number)]).join('0').slice(-width);\n\t },\n\n\t /**\n\t * Parses a CSS measure value (12px) as an integer.\n\t *\n\t * @param {string} measure The CSS measure\n\t * @returns {number} The value as an integer.\n\t */\n\t parseCSSMeasure: function(measure) {\n\t const index = measure.indexOf('px');\n\t if (index > 0) {\n\t return parseInt(measure.substring(0, measure.length - 2));\n\t }\n\n\t return parseInt(measure) || 0;\n\t },\n\n\t /**\n\t * Parses JSON.\n\t *\n\t * @param {string} json The JSON.\n\t * @returns {Object} The JSON data as an object.\n\t */\n\t parseJSON: function(json) {\n\t return JSON.parse(json);\n\t },\n\n\t /**\n\t * Removes the objects in the toRemove array from the fromArray.\n\t *\n\t * @param {Array} fromArray The array to remove from.\n\t * @param {Array} toRemove The values to remove.\n\t */\n\t removeAllFromArray: function(fromArray, toRemove) {\n\t for (let i = 0; i < toRemove.length; i++) {\n\t Utils.removeFromArray(fromArray, toRemove[i]);\n\t }\n\t },\n\n\t /**\n\t * Removes the given object from the given array.\n\t *\n\t * @param {Array} array The array to remove from.\n\t * @param {*} obj The object to remove.\n\t */\n\t removeFromArray: function(array, obj) {\n\t const index = array.indexOf(obj);\n\t if (index !== -1) {\n\t const shift = array.splice(index + 1, array.length);\n\t array.length = index;\n\t array.push.apply(array, shift);\n\t }\n\t },\n\n\t /**\n\t * Helper function to provide a one liner to behave as if you returned 'false' from a legacy version of Prime.js.\n\t *\n\t * Calling this method is equivalent to calling event.preventDefault and event.stopPropagation.\n\t * @param event\n\t */\n\t stopEvent: function(event) {\n\t // Compatibility with older versions of IE\n\t event.cancelBubble = true;\n\t if (event.stopPropagation) {\n\t event.stopPropagation();\n\t }\n\t if (event.preventDefault) {\n\t event.preventDefault();\n\t }\n\t },\n\n\t type: function(object) {\n\t return Object.prototype.toString.call(object).match(Utils.typeRegex)[1];\n\t }\n\t};\n\n\t/*\n\t * Copyright (c) 2017-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\t/**\n\t * The singleton instance.\n\t *\n\t * @type {Overlay}\n\t */\n\tlet instance;\n\n\tclass Overlay {\n\t /**\n\t * Constructs a new Overlay instance once per DOM.\n\t *\n\t * @constructor\n\t */\n\t constructor() {\n\t Utils.bindAll(this);\n\n\t // Check if the overlay doesn't exist and add it\n\t this.overlay = PrimeDocument.queryById('prime-overlay');\n\t if (this.overlay === null) {\n\t this.overlay = PrimeDocument.newElement('').setId('prime-overlay').appendTo(document.body).hide();\n\t }\n\t this.bodyOverflow = null;\n\t }\n\n\t /**\n\t * Return the instance of the Overlay widget\n\t * @returns {Overlay}\n\t */\n\t static get instance() {\n\t return instance;\n\t }\n\n\t /**\n\t * Set the instance value of the Overlay instance\n\t * @param value {Overlay}\n\t */\n\t static set instance(value) {\n\t instance = value;\n\t }\n\n\t /**\n\t * Closes the overlay and the target element.\n\t */\n\t close() {\n\t // using null ensures that if this style is not defined, we'll remove it when we're done\n\t let overflowStyle = this.bodyOverflow || '';\n\t PrimeDocument.bodyElement.setStyle('overflow', overflowStyle);\n\t this.overlay.setStyle('zIndex', '10');\n\t this.overlay.hide();\n\t return this;\n\t }\n\n\t /**\n\t * Opens the overlay and positions the element over it.\n\t * @param zIndex {Number|string}\n\t */\n\t open(zIndex) {\n\t if (this.bodyOverflow === null) {\n\t this.bodyOverflow = PrimeDocument.bodyElement.getStyle('overflow');\n\t }\n\t PrimeDocument.bodyElement.setStyle('overflow', 'hidden');\n\t this.overlay.show();\n\n\t // Set the z-index of this dialog and the overlay\n\t this.overlay.setStyle('zIndex', zIndex.toString());\n\t return this;\n\t }\n\n\t /**\n\t * Changes the id of the Overlay element.\n\t *\n\t * @param id {string} The new id.\n\t * @returns {Overlay}\n\t */\n\t setId(id) {\n\t this.overlay.setId(id);\n\t return this;\n\t }\n\n\t /**\n\t * Updates the zindex of the overlay.\n\t *\n\t * @param zIndex {string|number} The new zIndex.\n\t */\n\t setZIndex(zIndex) {\n\t this.overlay.setStyle('zIndex', zIndex.toString());\n\t return this;\n\t }\n\t}\n\n\tPrimeDocument.onReady(function() {\n\t Overlay.instance = new Overlay();\n\t});\n\n\t/*\n\t * Copyright (c) 2014-2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass PrimeRequest {\n\t /**\n\t * Makes a new AJAX request.\n\t *\n\t * @constructor\n\t * @param {string} [url] The URL to call. This can be left out for sub-classing but should otherwise be provided.\n\t * @param {string} [method=GET] The HTTP method to use. You can specify GET, POST, PUT, DELETE, HEAD, SEARCH, etc.\n\t */\n\t constructor(url, method) {\n\t Utils.bindAll(this);\n\t this.xhr = new XMLHttpRequest();\n\t this.async = true;\n\t this.body = null;\n\t this.queryParams = null;\n\t this.contentType = null;\n\t this.inProgress = null;\n\t this.errorHandler = this.onError;\n\t this.headers = {};\n\t this.loadingHandler = this.onLoading;\n\t this.method = method || 'GET';\n\t this.openHandler = this.onOpen;\n\t this.password = null;\n\t this.sendHandler = this.onSend;\n\t this.successHandler = this.onSuccess;\n\t this.unsetHandler = this.onUnset;\n\t this.url = url;\n\t this.username = null;\n\t }\n\n\t /**\n\t * Changes the URL to call.\n\t *\n\t * @param {string} url The new URL to call.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t forURL(url) {\n\t this.url = url;\n\t return this;\n\t }\n\n\t /**\n\t * Invokes the AJAX request. If the URL is not set, this throws an exception.\n\t *\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t go() {\n\t if (!this.url) {\n\t throw new TypeError('No URL set for AJAX request');\n\t }\n\n\t let requestUrl = this.url;\n\t if ((this.method === 'GET' || this.method === 'DELETE') && this.queryParams !== null) {\n\t if (requestUrl.indexOf('?') === -1) {\n\t requestUrl += '?' + this.queryParams;\n\t } else {\n\t requestUrl += '&' + this.queryParams;\n\t }\n\t }\n\n\t if (this.async) {\n\t if (this.inProgress !== null) {\n\t this.inProgress.open();\n\t }\n\n\t this.xhr.onreadystatechange = this._handler.bind(this);\n\t }\n\n\t this.xhr.open(this.method, requestUrl, this.async, this.username, this.password);\n\n\t if (Object.keys(this.headers).length > 0) {\n\t for (let key in this.headers) {\n\t if (this.headers.hasOwnProperty(key)) {\n\t this.xhr.setRequestHeader(key, this.headers[key]);\n\t }\n\t }\n\t }\n\n\t if (this.contentType) {\n\t this.xhr.setRequestHeader('Content-Type', this.contentType);\n\t }\n\n\t this.xhr.send(this.body);\n\n\t return this;\n\t }\n\n\t /**\n\t * Default handler for the \"completed\" state and an HTTP response status of anything but 2xx. Sub-classes can override\n\t * this handler or you can pass in a handler function to the {@link #withUnsetHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onError(xhr) {\n\t }\n\n\t /**\n\t * Default handler for the \"loading\" state. Sub-classes can override this handler or you can pass in a handler function\n\t * to the {@link #withLoadingHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onLoading(xhr) {\n\t }\n\n\t /**\n\t * Default handler for the \"open\" state. Sub-classes can override this handler or you can pass in a handler function\n\t * to the {@link #withOpenHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onOpen(xhr) {\n\t }\n\n\t /**\n\t * Default handler for the \"send\" state. Sub-classes can override this handler or you can pass in a handler function\n\t * to the {@link #withSendHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onSend(xhr) {\n\t }\n\n\t /**\n\t * Default handler for the \"complete\" state and an HTTP response status of 2xx. Sub-classes can override this handler\n\t * or you can pass in a handler function to the {@link #withUnsetHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onSuccess(xhr) {\n\t }\n\n\t /**\n\t * Default handler for the \"unset\" state. Sub-classes can override this handler or you can pass in a handler function\n\t * to the {@link #withUnsetHandler}.\n\t *\n\t * @param {XMLHttpRequest} xhr The XMLHttpRequest object.\n\t */\n\t onUnset(xhr) {\n\t }\n\n\t /**\n\t * Sets the async flag to false.\n\t *\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t synchronously() {\n\t this.async = false;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the method used to make the AJAX request.\n\t *\n\t * @param {string} method The HTTP method.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t usingMethod(method) {\n\t this.method = method;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the request body for the request.\n\t *\n\t * @param {string} body The request body.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withBody(body) {\n\t this.body = body;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the content type for the request.\n\t *\n\t * @param {string} contentType The contentType.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withContentType(contentType) {\n\t this.contentType = contentType;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the data object for the request. Will store the values for query parameters or post data depending on the\n\t * method that is set. If the method is a post or put, will also set content-type to x-www-form-urlencoded.\n\t *\n\t * @param {Object} data The data object.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withData(data) {\n\t for (let prop in data) {\n\t if (data.hasOwnProperty(prop)) {\n\t if (this.method === 'PUT' || this.method === 'POST') {\n\t this.body = this._addDataValue(this.body, prop, data[prop]);\n\t } else {\n\t this.queryParams = this._addDataValue(this.queryParams, prop, data[prop]);\n\t }\n\t }\n\t }\n\n\t if (this.method === \"PUT\" || this.method === \"POST\") {\n\t this.contentType = 'application/x-www-form-urlencoded';\n\t }\n\t return this;\n\t }\n\n\t /**\n\t * Sets the data for the request using the form fields in the given form element. Will store the values for query\n\t * parameters or post data depending on the method that is set. If the method is a post or put, will also set\n\t * content-type to x-www-form-urlencoded.\n\t *\n\t * @param {PrimeElement|HTMLFormElement} form The form object.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withDataFromForm(form) {\n\t let domElement = form;\n\t if (form instanceof PrimeElement) {\n\t domElement = form.domElement;\n\t }\n\n\t for (let i = 0; i < domElement.elements.length; i++) {\n\t const primeElement = new PrimeElement(domElement.elements[i]);\n\t if (primeElement.isDisabled() || !primeElement.isInput()) {\n\t continue;\n\t }\n\n\t let type = primeElement.getAttribute('type');\n\t if (type !== null) {\n\t type = type.toLowerCase();\n\t }\n\n\t let values;\n\t if (primeElement.getTagName() === 'SELECT') {\n\t values = primeElement.getSelectedValues();\n\t } else if ((type === 'radio' || type === 'checkbox') && !primeElement.isChecked()) {\n\t continue;\n\t } else {\n\t values = primeElement.getValue();\n\t }\n\n\t const name = primeElement.domElement.name;\n\t if (this.method === 'PUT' || this.method === 'POST') {\n\t this.body = this._addDataValue(this.body, name, values);\n\t } else {\n\t this.queryParams = this._addDataValue(this.queryParams, name, values);\n\t }\n\t }\n\n\t if (this.method === \"PUT\" || this.method === \"POST\") {\n\t this.contentType = 'application/x-www-form-urlencoded';\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"complete\" and the HTTP status in the response is\n\t * not 2xx.\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withErrorHandler(func) {\n\t this.errorHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Sets an InProgress object that will be called by this AJAX request.\n\t *\n\t * @param {InProgress} inProgress The InProgress object.\n\t * @return {PrimeRequest} This.\n\t */\n\t withInProgress(inProgress) {\n\t this.inProgress = inProgress;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the body of the AJAX request to the string value of the provided JSON object. The content-type of the request\n\t * will also be set to 'application/json'. The provided JSON object may be passed as a string or an object.\n\t *\n\t * @param {Object} json The JSON object.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withJSON(json) {\n\t this.body = typeof(json) === String ? json : JSON.stringify(json);\n\t this.contentType = 'application/json';\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"loading\".\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withLoadingHandler(func) {\n\t this.loadingHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Set the request headers using the key and value.\n\t *\n\t * @param {String} key The key name.\n\t * @param {String} value The value.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withHeader(key, value) {\n\t this.headers[key] = value;\n\t return this;\n\t }\n\n\t /**\n\t * Set the key value pairs provided as request headers.\n\t *\n\t * @param {Object} headers A map of key value pairs.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withHeaders(headers) {\n\t for (let key in headers) {\n\t if (headers.hasOwnProperty(key)) {\n\t this.headers[key] = headers[key];\n\t }\n\t }\n\t return this;\n\t }\n\n\t /**\n\t * Sets the XMLHTTPRequest's response type field, which will control how the response is parsed.\n\t *\n\t * @param {string} responseType The response type.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withResponseType(responseType) {\n\t this.xhr.responseType = responseType;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"open\".\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withOpenHandler(func) {\n\t this.openHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"send\".\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withSendHandler(func) {\n\t this.sendHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"complete\" and the HTTP status in the response is\n\t * 2xx.\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withSuccessHandler(func) {\n\t this.successHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the handler to invoke when the state of the AJAX request is \"unset\".\n\t *\n\t * @param {Function} func The handler function.\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t withUnsetHandler(func) {\n\t this.unsetHandler = func;\n\t return this;\n\t }\n\n\t /**\n\t * Resets the Request back to a base state (basically just the URL + method). This can be\n\t * useful if a component is going to make many requests to the same endpoint with different parameters.\n\t *\n\t * @returns {PrimeRequest} This PrimeRequest.\n\t */\n\t reset() {\n\t this.queryParams = null;\n\t this.data = null;\n\t this.body = null;\n\t this.contentType = null;\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private Methods\n\t * ===================================================================================================================*/\n\n\t // noinspection JSMethodCanBeStatic\n\t /**\n\t * Adds the given name-value pair to the given data String. If the value is an array, it adds multiple values for each\n\t * piece. Otherwise, it assumes value is a String or can be converted to a String.\n\t *\n\t * @param {string} dataString The data String used to determine if an ampersand is necessary.\n\t * @param {string} name The name of the name-value pair.\n\t * @param {string|Array} value The value of the name-value pair.\n\t * @returns {string} The new data string.\n\t * @private\n\t */\n\t _addDataValue(dataString, name, value) {\n\t let result = '';\n\t if (value instanceof Array) {\n\t for (let i = 0; i < value.length; i++) {\n\t result += encodeURIComponent(name) + '=' + encodeURIComponent(value[i]);\n\t if (i + 1 < value.length) {\n\t result += '&';\n\t }\n\t }\n\t } else {\n\t result = encodeURIComponent(name) + '=' + encodeURIComponent(value);\n\t }\n\n\t if (dataString !== null && result !== '') {\n\t result = dataString + '&' + result;\n\t } else if (dataString !== null && result === '') {\n\t result = dataString;\n\t }\n\n\t return result;\n\t }\n\n\t /**\n\t * @private\n\t */\n\t _handler() {\n\t if (this.xhr.readyState === 0) {\n\t this.unsetHandler(this.xhr);\n\t } else if (this.xhr.readyState === 1) {\n\t this.openHandler(this.xhr);\n\t } else if (this.xhr.readyState === 2) {\n\t this.sendHandler(this.xhr);\n\t } else if (this.xhr.readyState === 3) {\n\t this.loadingHandler(this.xhr);\n\t } else if (this.xhr.readyState === 4) {\n\n\t // Call the InProgress before hand because the success handler might call another AJAX method that might open another InProgress\n\t if (this.inProgress !== null) {\n\t this.inProgress.close(function() {\n\t if (this.xhr.status >= 200 && this.xhr.status <= 299) {\n\t this.successHandler(this.xhr);\n\t } else {\n\t this.errorHandler(this.xhr);\n\t }\n\t }.bind(this));\n\t } else {\n\t if (this.xhr.status >= 200 && this.xhr.status <= 299) {\n\t this.successHandler(this.xhr);\n\t } else {\n\t this.errorHandler(this.xhr);\n\t }\n\t }\n\t }\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2012-2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass PrimeWindow {\n\t /**\n\t * Attaches an event listener to the window, returning the handler proxy.\n\t *\n\t * @param {string} event The name of the event.\n\t * @param {Function} listener The event handler.\n\t * @returns {Window} The window object.\n\t */\n\t static addEventListener(event, listener) {\n\t if (event.indexOf(':') === -1) {\n\t window.eventListeners = window.eventListeners || {};\n\t window.eventListeners[event] = window.eventListeners[event] || [];\n\t window.eventListeners[event].push(listener);\n\t if (window.addEventListener) {\n\t window.addEventListener(event, listener, false);\n\t } else if (window.attachEvent) {\n\t window.attachEvent('on' + event, listener);\n\t } else {\n\t throw new TypeError('Unable to set event onto the window. Neither addEventListener nor attachEvent methods are available');\n\t }\n\t } else {\n\t // Custom event\n\t window.customEventListeners = window.customEventListeners || {};\n\t window.customEventListeners[event] = window.customEventListeners[event] || [];\n\t window.customEventListeners[event].push(listener);\n\t }\n\n\t return window;\n\t }\n\n\t /**\n\t * Returns the inner height of the window. This includes only the rendering area and not the window chrome (toolbars,\n\t * status bars, etc). If this method can't figure out the inner height, it throws an exception.\n\t *\n\t * @returns {number} The inner height of the window.\n\t */\n\t static getInnerHeight() {\n\t if (typeof(window.innerHeight) === 'number') {\n\t // Most browsers\n\t return window.innerHeight;\n\t } else if (document.documentElement && document.documentElement.clientHeight) {\n\t // IE 6+ in 'standards compliant mode'\n\t return document.documentElement.clientHeight;\n\t } else if (document.body && document.body.clientHeight) {\n\t // IE 4 compatible\n\t return document.body.clientHeight;\n\t }\n\n\t throw new Error('Unable to determine inner height of the window');\n\t }\n\n\t /**\n\t * Returns the inner width of the window. This includes only the rendering area and not the window chrome (toolbars,\n\t * status bars, etc). If this method can't figure out the inner width, it throws an exception.\n\t *\n\t * @returns {number} The inner width of the window.\n\t */\n\t static getInnerWidth() {\n\t if (typeof(window.innerWidth) === 'number') {\n\t // Most browsers\n\t return window.innerWidth;\n\t } else if (document.documentElement && document.documentElement.clientWidth) {\n\t // IE 6+ in 'standards compliant mode'\n\t return document.documentElement.clientWidth;\n\t } else if (document.body && document.body.clientWidth) {\n\t // IE 4 compatible\n\t return document.body.clientWidth;\n\t }\n\n\t throw new Error('Unable to determine inner width of the window');\n\t }\n\n\t /**\n\t * Returns the number of pixels the Window is scrolled by.\n\t *\n\t * @returns {number} The number of pixels.\n\t */\n\t static getScrollTop() {\n\t if (typeof(window.pageYOffset) === 'number') {\n\t return window.pageYOffset;\n\t } else if (document.body && document.body.scrollTop) {\n\t return document.body.scrollTop;\n\t } else if (document.documentElement && document.documentElement.scrollTop) {\n\t return document.documentElement.scrollTop;\n\t }\n\n\t throw new Error('Unable to determine scrollTop of the window');\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2015-2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass Draggable {\n\t /**\n\t * Constructs a new Draggable object for the given element.\n\t *\n\t * @param {PrimeElement|Element|EventTarget} element The Prime Element for the Draggable widget.\n\t * @param {string} [gripSelector=] gripSelector The optional selector to identify the 'grippy' part.\n\t * @constructor\n\t */\n\t constructor(element, gripSelector) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t this.offset = {};\n\n\t if (!Utils.isDefined(gripSelector)) {\n\t this.grip = this.element;\n\t } else {\n\t this.grip = this.element.queryFirst(gripSelector);\n\t if (this.grip === null) {\n\t throw Error('Unable to find an element using the provided selector [' + gripSelector + ']');\n\t }\n\t }\n\t }\n\n\t /**\n\t * Destroys the Draggable Widget\n\t */\n\t destroy() {\n\t this.element.removeClass('active');\n\t this.element.setStyles(this.originalStyle);\n\n\t this.grip.removeEventListener('mousedown', this._handleMouseDown);\n\t PrimeDocument.removeEventListener('mousemove', this._handleMouseMove);\n\t PrimeDocument.removeEventListener('mouseup', this._handleMouseUp);\n\t }\n\n\t /**\n\t * Initializes the Draggable by attaching the event listeners.\n\t *\n\t * @returns {Draggable} This.\n\t */\n\t initialize() {\n\t this.originalStyle = {\n\t cursor: this.element.getStyle('cursor'),\n\t zIndex: this.element.getStyle('zIndex')\n\t };\n\n\t this.grip.addEventListener('mousedown', this._handleMouseDown).setStyle('cursor', 'move');\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Handle Mouse Down Event\n\t * @param {Event} event The mouse event.\n\t * @private\n\t */\n\t _handleMouseDown(event) {\n\t event.preventDefault();\n\t this.element.addClass('active');\n\n\t this.offset = {\n\t zIndex: this.element.getStyle('zIndex'),\n\t height: this.element.getOuterHeight(),\n\t width: this.element.getOuterWidth(),\n\t x: event.screenX,\n\t y: event.screenY\n\t };\n\n\t this.element.setStyle('zIndex', this.offset.zIndex + 10);\n\n\t // Remove old listeners\n\t PrimeDocument.removeEventListener('mousemove', this._handleMouseMove);\n\t PrimeDocument.removeEventListener('mouseup', this._handleMouseUp);\n\n\t // Attach all the events\n\t PrimeDocument.addEventListener('mousemove', this._handleMouseMove);\n\t PrimeDocument.addEventListener('mouseup', this._handleMouseUp);\n\t }\n\n\t /**\n\t * Handle the Mouse Move event for the body element.\n\t *\n\t * @param {Event} event The mouse event.\n\t * @private\n\t */\n\t _handleMouseMove(event) {\n\t const xDiff = event.screenX - this.offset.x;\n\t const yDiff = event.screenY - this.offset.y;\n\t this.offset.x = event.screenX;\n\t this.offset.y = event.screenY;\n\t this.element.setLeft(this.element.getLeft() + xDiff);\n\t this.element.setTop(this.element.getTop() + yDiff);\n\t }\n\n\t /**\n\t * Handle the Mouse Up event for this draggable widget.\n\t * @private\n\t */\n\t _handleMouseUp() {\n\t PrimeDocument.removeEventListener('mousemove', this._handleMouseMove);\n\t PrimeDocument.removeEventListener('mouseup', this._handleMouseUp);\n\t this.element.setStyle('zIndex', this.offset.zIndex);\n\t this.element.removeClass('active');\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2017-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass AJAXDialog {\n\t /**\n\t * Constructs a new dialog box, which is dynamically built and then populated with the HTML returned from an AJAX call.\n\t *\n\t * @constructor\n\t */\n\t constructor() {\n\t Utils.bindAll(this);\n\n\t this.draggable = null;\n\t this.element = null;\n\t this.initialized = false;\n\t this._setInitialOptions();\n\t }\n\n\t /**\n\t * Closes the dialog, destroys the HTML and updates or hides the overlay.\n\t * @returns {AJAXDialog} This.\n\t */\n\t close() {\n\t this.element.removeClass('open');\n\t if (this.draggable !== null) {\n\t this.draggable.destroy();\n\t this.draggable = null;\n\t }\n\n\t setTimeout(function() {\n\t this.element.removeFromDOM();\n\t this.element = null;\n\n\t const highestZIndex = this._determineZIndex();\n\t if (highestZIndex !== 0) {\n\t Overlay.instance.setZIndex(highestZIndex);\n\t } else {\n\t Overlay.instance.close();\n\t }\n\t }.bind(this), this.options.closeTimeout);\n\n\t return this;\n\t }\n\n\t /**\n\t * Destroys the dialog by calling the close function.\n\t * @returns {AJAXDialog} This.\n\t */\n\t destroy() {\n\t this.close();\n\t return this;\n\t }\n\n\t /**\n\t * Initializes the dialog.\n\t * @returns {AJAXDialog} This.\n\t */\n\t initialize() {\n\t return this;\n\t }\n\n\t /**\n\t * Opens the dialog by making the AJAX GET request to the given URI and the opening then dialog.\n\t *\n\t * @param uri {string} The URI to make the AJAX GET request to.\n\t * @returns {AJAXDialog} This.\n\t */\n\t open(uri) {\n\t const request = this.options.ajaxRequest || new PrimeRequest(uri, 'GET');\n\t request.withSuccessHandler(this._handleAJAXDialogResponse)\n\t .withErrorHandler(this._handleAJAXDialogResponse)\n\t .go();\n\t return this;\n\t }\n\n\t /**\n\t * Opens the dialog by making the AJAX POST request to the given URI with the given form and extra data (optional)\n\t * and then opening the dialog.\n\t *\n\t * @param uri {string} The URI to make the AJAX POST request to.\n\t * @param form {HTMLFormElement|PrimeElement} The Form element to retrieve the data from.\n\t * @param extraData [extraData=] {object} (Optional) Extra data to send with the POST.\n\t * @returns {AJAXDialog} This.\n\t */\n\t openPost(uri, form, extraData) {\n\t new PrimeRequest(uri, 'POST')\n\t .withDataFromForm(form)\n\t .withData(extraData)\n\t .withSuccessHandler(this._handleAJAXDialogResponse)\n\t .go();\n\t return this;\n\t }\n\n\t /**\n\t * Updates the HTML contents of the dialog.\n\t *\n\t * @param html {String} The HTML.\n\t * @returns {AJAXDialog} This.\n\t */\n\t setHTML(html) {\n\t this.element.setHTML(html);\n\t this._initializeDialog();\n\t return this;\n\t }\n\n\t /**\n\t * Sets any additional classes that should be on the dialog.\n\t *\n\t * @param classes {string} The list of additional classes.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withAdditionalClasses(classes) {\n\t this.options.additionalClasses = classes;\n\t return this;\n\t }\n\n\t /**\n\t * Override the default Ajax Request used to open the dialog. This does not override the\n\t * success and error handlers.\n\t *\n\t * @param request {PrimeRequest} The Ajax Request to use to open the dialog.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withAjaxRequest(request) {\n\t this.options.ajaxRequest = request;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the callback that is called after the dialog has been fetched and rendered.\n\t *\n\t * @param callback {function} The callback function.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withCallback(callback) {\n\t this.options.callback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the class name for the dialog element.\n\t *\n\t * @param className {string} The class name.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withClassName(className) {\n\t if (className.indexOf(' ') !== -1) {\n\t throw 'Invalid class name [' + className + ']. You can use the additionalClasses options to add more classes.';\n\t }\n\n\t this.options.className = className;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the close button element selector that is used to setup the close button in the HTML that was returned from\n\t * the server.\n\t *\n\t * @param selector {string} The element selector.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withCloseButtonElementSelector(selector) {\n\t this.options.closeButtonElementSelector = selector;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the timeout used in the close method to allow for transitions.\n\t *\n\t * @param timeout {int} The timeout.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withCloseTimeout(timeout) {\n\t this.options.closeTimeout = timeout;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the draggable element selector that is used for the DraggableWidget.\n\t *\n\t * @param selector {string} The element selector.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withDraggableButtonElementSelector(selector) {\n\t this.options.draggableElementSelector = selector;\n\t return this;\n\t }\n\n\t /**\n\t * Sets an error callback for AJAX form handling. This is called after a failed form submission.\n\t *\n\t * @param callback {Function} The callback function. The callback function will called with two parameters,\n\t * the first is a reference this object, the second is the XMLHttpRequest object.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withFormErrorCallback(callback) {\n\t this.options.formErrorCallback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Sets whether or not forms inside the dialog are handled via AJAX or not.\n\t *\n\t * @param enabled {boolean} The choice.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withFormHandling(enabled) {\n\t this.options.formHandling = enabled;\n\t return this;\n\t }\n\n\t /**\n\t * Sets a pre-submit callback for AJAX form handling. This is called before the form is submitted.\n\t *\n\t * @param callback {Function} The callback function.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withFormPreSubmitCallback(callback) {\n\t this.options.formPreSubmitCallback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Sets a success callback for AJAX form handling. This is called after a successful form submission.\n\t *\n\t * @param callback {Function} The callback function. The callback function will called with two parameters,\n\t * the first is a reference this object, the second is the XMLHttpRequest object.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withFormSuccessCallback(callback) {\n\t this.options.formSuccessCallback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Set more than one option at a time by providing a map of key value pairs. This is considered an advanced\n\t * method to set options on the widget. The caller needs to know what properties are valid in the options object.\n\t *\n\t * @param {Object} options Key value pair of configuration options.\n\t * @returns {AJAXDialog} This.\n\t */\n\t withOptions(options) {\n\t if (!Utils.isDefined(options)) {\n\t return this;\n\t }\n\n\t for (let option in options) {\n\t if (options.hasOwnProperty(option)) {\n\t this.options[option] = options[option];\n\t }\n\t }\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t _determineZIndex() {\n\t let highestZIndex = 0;\n\t PrimeDocument.query('.' + this.options.className).each(function(dialog) {\n\t const zIndex = parseInt(dialog.getComputedStyle()['zIndex']);\n\t if (dialog.isVisible() && zIndex > highestZIndex) {\n\t highestZIndex = zIndex;\n\t }\n\t });\n\t return highestZIndex;\n\t }\n\n\t _handleCloseClickEvent(event) {\n\t Utils.stopEvent(event);\n\t this.close();\n\t }\n\n\t _handleAJAXDialogResponse(xhr) {\n\t this.element = PrimeDocument.newElement('', {class: this.options.className + ' ' + this.options.additionalClasses}).appendTo(document.body);\n\t this.setHTML(xhr.responseText);\n\t }\n\n\t _handleAJAXFormError(xhr) {\n\t this.setHTML(xhr.responseText);\n\t this.form = this.element.queryFirst('form').addEventListener('submit', this._handleAJAXFormSubmit);\n\n\t if (this.options.formErrorCallback !== null) {\n\t this.options.formErrorCallback(this, xhr);\n\t }\n\n\t if (this.draggable !== null) {\n\t this.draggable.destroy();\n\t }\n\n\t if (this.options.draggableElementSelector !== null && this.element.queryFirst(this.options.draggableElementSelector) !== null) {\n\t this.draggable = new Draggable(this.element, this.options.draggableElementSelector).initialize();\n\t }\n\t }\n\n\t _handleAJAXFormSuccess(xhr) {\n\t if (this.options.formSuccessCallback !== null) {\n\t this.options.formSuccessCallback(this, xhr);\n\t } else {\n\t const successURI = this.form.getDataSet()['ajaxSuccessUri'];\n\t if (successURI !== undefined) {\n\t window.location = successURI;\n\t } else {\n\t window.location.reload();\n\t }\n\t }\n\t }\n\n\t _handleAJAXFormSubmit(event) {\n\t Utils.stopEvent(event);\n\n\t if (this.options.formPreSubmitCallback !== null) {\n\t this.options.formPreSubmitCallback(this);\n\t }\n\n\t new PrimeRequest(this.form.getAttribute('action'), this.form.getAttribute('method'))\n\t .withDataFromForm(this.form)\n\t .withSuccessHandler(this._handleAJAXFormSuccess)\n\t .withErrorHandler(this._handleAJAXFormError)\n\t .go();\n\t }\n\n\t _initializeDialog() {\n\t this.element.query(this.options.closeButtonElementSelector).each(function(e) {\n\t e.addEventListener('click', this._handleCloseClickEvent);\n\t }.bind(this));\n\n\t // Only set the z-index upon first open\n\t if (!this.initialized) {\n\t const highestZIndex = this._determineZIndex();\n\t Overlay.instance.open(highestZIndex + this.options.zIndexOffset);\n\t this.element.setStyle('zIndex', (highestZIndex + this.options.zIndexOffset + 10).toString());\n\t this.element.addClass('open');\n\t }\n\n\t // Call the callback before positioning to ensure all changes to the dialog have been made\n\t if (this.options.callback !== null) {\n\t this.options.callback(this);\n\t }\n\n\t // Setup forms if enabled\n\t if (this.options.formHandling) {\n\t this.form = this.element.queryFirst('form').addEventListener('submit', this._handleAJAXFormSubmit);\n\t }\n\n\t // Only set the position of the dialog when we first open it, if someone calls setHTML on the dialog we are not resizing it.\n\t if (!this.initialized) {\n\t // Position the fixed dialog in the center of the screen\n\t const windowHeight = PrimeWindow.getInnerHeight();\n\t const dialogHeight = this.element.getHeight();\n\t this.element.setTop(((windowHeight - dialogHeight) / 2) - 20);\n\t }\n\n\t if (this.options.draggableElementSelector !== null && this.element.queryFirst(this.options.draggableElementSelector) !== null) {\n\t this.draggable = new Draggable(this.element, this.options.draggableElementSelector).initialize();\n\t }\n\n\t this.initialized = true;\n\t }\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions() {\n\t // Defaults\n\t this.options = {\n\t additionalClasses: '',\n\t ajaxRequest: null,\n\t callback: null,\n\t className: 'prime-dialog',\n\t closeButtonElementSelector: '[data-dialog-role=\"close-button\"]',\n\t closeTimeout: 200,\n\t draggableElementSelector: '[data-dialog-role=\"draggable\"]',\n\t formErrorCallback: null,\n\t formHandling: false,\n\t formPreSubmitCallback: null,\n\t formSuccessCallback: null,\n\t zIndexOffset: 1000\n\t };\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2013-2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\t/**\n\t * @const {{Keys: {BACKSPACE: number, ENTER: number, ESCAPE: number, SPACE: number, TAB: number, LEFT_ARROW: number, UP_ARROW: number, RIGHT_ARROW: number, DOWN_ARROW: number, DELETE: number}} Events}\n\t */\n\tconst Events = {\n\t Keys: {\n\t BACKSPACE: 8,\n\t ENTER: 13,\n\t ESCAPE: 27,\n\t SPACE: 32,\n\t TAB: 9,\n\t LEFT_ARROW: 37,\n\t UP_ARROW: 38,\n\t RIGHT_ARROW: 39,\n\t DOWN_ARROW: 40,\n\t DELETE: 46\n\t }\n\t};\n\n\t/*\n\t * Copyright (c) 2015-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tconst PrimeDate = {\n\t DAYS_IN_MONTH: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n\n\t /**\n\t * Return the hour in a 12-hour format. AM and PM are not communicated by the returned hour.\n\t *\n\t * @param date {Date} The date object to retrieve the hour from.\n\t * @returns {Number} The hour of the day between 1 and 12.\n\t */\n\t getHourOfDay: function(date) {\n\t return (date.getHours() + 24) % 12 || 12;\n\t },\n\n\t /**\n\t * @param year The year.\n\t * @returns {boolean} True if this is a leap year, otherwise false.\n\t */\n\t isLeapYear: function(year) {\n\t return !((year % 4) || (!(year % 100) && (year % 400)));\n\t },\n\n\t /**\n\t * Return the number of days in the month.\n\t * @param year The year, the days in the month may change during a leap year.\n\t * @param month The month.\n\t * @returns {Number} The number of days in the month.\n\t */\n\t numberOfDaysInMonth: function(year, month) {\n\t if (month === 1 && this.isLeapYear(year)) {\n\t return 29;\n\t } else {\n\t return PrimeDate.DAYS_IN_MONTH[month];\n\t }\n\t },\n\n\t /**\n\t * Adds the given number of days to the given Date.\n\t *\n\t * @param date {Date} The date to add the days to.\n\t * @param number {Number} The number of days to add.\n\t */\n\t plusDays: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t let newDate = date.getDate() + number;\n\t let numberOfDaysInMonth = PrimeDate.numberOfDaysInMonth(date.getFullYear(), date.getMonth());\n\n\t if (newDate > 0) {\n\t while (newDate > numberOfDaysInMonth) {\n\t PrimeDate.plusMonths(date, 1);\n\t newDate = newDate - numberOfDaysInMonth;\n\t numberOfDaysInMonth = PrimeDate.numberOfDaysInMonth(date.getFullYear(), date.getMonth());\n\t }\n\n\t date.setDate(newDate);\n\t } else {\n\t while (newDate <= 0) {\n\t PrimeDate.plusMonths(date, -1);\n\t numberOfDaysInMonth = PrimeDate.numberOfDaysInMonth(date.getFullYear(), date.getMonth());\n\t newDate = newDate + numberOfDaysInMonth;\n\t }\n\n\t date.setDate(newDate);\n\t }\n\t },\n\n\t /**\n\t * Adds the given number of hours to the given Date. The number can be negative.\n\t *\n\t * @param date {Date} The date.\n\t * @param number {Number} The number of hours to add.\n\t */\n\t plusHours: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t const deltaDays = parseInt(number / 24);\n\t PrimeDate.plusDays(date, deltaDays);\n\n\t const deltaHours = number % 24;\n\t const newHour = date.getHours() + deltaHours;\n\t if (newHour > 23) {\n\t PrimeDate.plusDays(date, 1);\n\t date.setHours(newHour - 24);\n\t } else if (newHour < 0) {\n\t PrimeDate.plusDays(date, -1);\n\t date.setHours(24 + newHour);\n\t } else {\n\t date.setHours(newHour);\n\t }\n\t },\n\n\t /**\n\t * Adds the given number of minutes to the given Date. The number can be negative.\n\t *\n\t * @param date {Date} The date.\n\t * @param number {Number} The number of minutes to add.\n\t */\n\t plusMinutes: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t const deltaHours = parseInt(number / 60);\n\t PrimeDate.plusHours(date, deltaHours);\n\n\t const deltaMinutes = number % 60;\n\t const newMinute = date.getMinutes() + deltaMinutes;\n\t if (newMinute > 60) {\n\t PrimeDate.plusHours(date, 1);\n\t date.setMinutes(newMinute - 60);\n\t } else if (newMinute < 0) {\n\t PrimeDate.plusHours(date, -1);\n\t date.setMinutes(60 + newMinute);\n\t } else {\n\t date.setMinutes(newMinute);\n\t }\n\t },\n\n\t /**\n\t * Adds the given number of months to the given Date. The number can be negative.\n\t *\n\t * @param date {Date} The date.\n\t * @param number {Number} The number of months to add.\n\t */\n\t plusMonths: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t let deltaYears = parseInt(number / 12);\n\t let deltaMonths = number % 12;\n\t let currentMonth = date.getMonth();\n\t const newMonth = currentMonth + deltaMonths;\n\t if (newMonth < 0) {\n\t deltaYears--;\n\t deltaMonths = newMonth;\n\t currentMonth = 12;\n\t } else if (newMonth >= 12) {\n\t deltaYears++;\n\t deltaMonths = newMonth - 12;\n\t currentMonth = 0;\n\t }\n\n\t date.setYear(date.getFullYear() + deltaYears);\n\t // If the day is 31 and you set month to 1 (February) it will adjust to March 3 (Feb 28 + 3)\n\t const adjustedMonth = currentMonth + deltaMonths;\n\t if (date.getDate() > this.DAYS_IN_MONTH[adjustedMonth]) {\n\t date.setDate(this.DAYS_IN_MONTH[adjustedMonth]);\n\t }\n\t date.setMonth(adjustedMonth);\n\t },\n\n\t /**\n\t * Adds the given number of seconds to the given Date. The number can be negative.\n\t *\n\t * @param date {Date} The date.\n\t * @param number {Number} The number of seconds to add.\n\t */\n\t plusSeconds: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t const deltaMinutes = parseInt(number / 60);\n\t PrimeDate.plusMinutes(date, deltaMinutes);\n\n\t const deltaSeconds = number % 60;\n\t const newSecond = date.getSeconds() + deltaSeconds;\n\t if (newSecond > 60) {\n\t PrimeDate.plusMinutes(date, 1);\n\t date.setSeconds(newSecond - 60);\n\t } else if (newSecond < 0) {\n\t PrimeDate.plusMinutes(date, -1);\n\t date.setSeconds(60 + newSecond);\n\t } else {\n\t date.setSeconds(newSecond);\n\t }\n\t },\n\n\t /**\n\t * Adds the given number of years to the given Date. The number can be negative.\n\t *\n\t * @param date {Date} The date.\n\t * @param number {Number} The number of years to add.\n\t */\n\t plusYears: function(date, number) {\n\t if (number === 0) {\n\t return;\n\t }\n\n\t date.setFullYear(date.getFullYear() + number);\n\t },\n\n\t /**\n\t * Return a string in simplified extended ISO format (ISO 8601) truncated to only return YYYY-MM-DD.\n\t *\n\t * For example: new Date(2015, 6, 4) --> 2015-07-04\n\t *\n\t * @param date {Date} The date.\n\t * @returns {String} A date string in the format YYYY-MM-DD.\n\t */\n\t toDateOnlyISOString: function(date) {\n\t if (date instanceof Date) {\n\t return date.getFullYear()\n\t + '-' + Utils.leftPadNumber(date.getMonth() + 1, 2)\n\t + '-' + Utils.leftPadNumber(date.getDate(), 2);\n\t }\n\t throw TypeError('date parameter must be a Date object.');\n\t }\n\t};\n\n\t/*\n\t * Copyright (c) 2015-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tconst SHORT_DAY_NAMES = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];\n\tconst MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];\n\tconst DATE_SEPARATOR = '/';\n\tconst TIME_SEPARATOR = ':';\n\tconst AM_PM = ['AM', 'PM'];\n\n\tclass DateTimePicker {\n\t /**\n\t * Constructs a new DateTimePicker object for the given input element.\n\t *\n\t * @param {PrimeElement|Element|EventTarget} element The Prime Element for the DateTimePicker widget.\n\t * @constructor\n\t */\n\t constructor(element) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t if (!this.element.is('input')) {\n\t throw new TypeError('You can only use DateTimePicker with an input element');\n\t }\n\n\t this.callback = null;\n\t this.customFormatHandler = null;\n\t this._setInitialOptions();\n\t };\n\n\t static get SHORT_DAY_NAMES() {\n\t return SHORT_DAY_NAMES;\n\t }\n\n\t static get MONTHS() {\n\t return MONTHS;\n\t }\n\n\t static get DATE_SEPARATOR() {\n\t return DATE_SEPARATOR;\n\t }\n\n\t static get TIME_SEPARATOR() {\n\t return TIME_SEPARATOR;\n\t }\n\n\t static get AM_PM() {\n\t return AM_PM;\n\t }\n\n\t /**\n\t * Closes the Date Picker widget.\n\t *\n\t * @returns {DateTimePicker} This DateTimePicker.\n\t */\n\t close() {\n\t this.datepicker.removeClass('open');\n\n\t // Pause a bit to cancel focus event and allow transition to play\n\t setTimeout(function() {\n\t this.datepicker.hide();\n\t }.bind(this), this.options.closeTimeout);\n\t return this;\n\t }\n\n\t /**\n\t * Closes the months select box.\n\t *\n\t * @returns {DateTimePicker} This DateTimePicker.\n\t */\n\t closeMonthsSelect() {\n\t this.months.removeClass('open');\n\t setTimeout(function() {\n\t this.months.hide();\n\t }.bind(this), this.options.closeTimeout);\n\t return this;\n\t }\n\n\t /**\n\t * Closes the years select box.\n\t *\n\t * @returns {DateTimePicker} This DateTimePicker.\n\t */\n\t closeYearsSelect() {\n\t this.years.removeClass('open');\n\t setTimeout(function() {\n\t this.years.hide();\n\t }.bind(this), this.options.closeTimeout);\n\t return this;\n\t }\n\n\t /**\n\t * Destroys the DateTimePicker Widget\n\t */\n\t destroy() {\n\t this.datepicker.removeFromDOM();\n\t this.element.removeEventListener('click', this._handleInputClick)\n\t .removeEventListener('focus', this._handleInputClick)\n\t .removeEventListener('keydown', this._handleInputKey);\n\t PrimeDocument.removeEventListener('click', this._handleGlobalClick);\n\t PrimeDocument.removeEventListener('keydown', this._handleGlobalKey);\n\t }\n\n\t /**\n\t * Draws the calendar using the month and year from the given Date object.\n\t *\n\t * @param date {Date} The date to draw the calendar for.\n\t * @return {DateTimePicker} This DateTimePicker.\n\t */\n\t drawCalendar(date) {\n\t const month = date.getMonth();\n\t const year = date.getFullYear();\n\t const firstDay = new Date(year, month, 1);\n\t const firstDayOfMonth = firstDay.getDay();\n\t const daysInMonth = PrimeDate.numberOfDaysInMonth(year, month);\n\t const used = firstDayOfMonth + daysInMonth;\n\t const weeksInMonth = Math.ceil(used / 7);\n\n\t let rows = '';\n\t let startDay = 1;\n\t for (let i = 0; i < weeksInMonth; i++) {\n\t const startDayOfWeek = i === 0 ? firstDayOfMonth : 0;\n\t rows += this._buildCalendarWeek(date, startDayOfWeek, startDay, daysInMonth);\n\t startDay += 7 - startDayOfWeek; // increment by 7 adjusted by a week day of week offset\n\t }\n\n\t this.calendarBody.setHTML(rows);\n\n\t // update data- attributes\n\t this.monthDisplay.setDataAttribute('month', month);\n\t this.yearDisplay.setDataAttribute('year', year);\n\n\t // update text\n\t this.monthDisplay.setTextContent(DateTimePicker.MONTHS[month]);\n\t this.yearDisplay.setTextContent(year);\n\n\t return this;\n\t }\n\n\t /**\n\t * Rebuilds the entire widget using the date value. Even if the user has moved to a different month display, this will\n\t * rebuild the table completely.\n\t *\n\t * @returns {DateTimePicker} This DateTimePicker.\n\t */\n\t initialize() {\n\t const value = this.element.getValue();\n\t if (value === '' || value === null) {\n\t this.date = new Date();\n\t } else {\n\t this.date = new Date(value);\n\t }\n\n\t const year = this.date.getUTCFullYear();\n\t const timeSeparator = `${DateTimePicker.TIME_SEPARATOR}`;\n\t const dateSeparator = `${DateTimePicker.DATE_SEPARATOR}`;\n\t let html =\n\t ` `;\n\t PrimeDocument.appendHTML(html);\n\t this.datepicker = PrimeDocument.queryLast('.' + this.options.className).hide();\n\t this.element.addEventListener('click', this._handleInputClick);\n\t this.element.addEventListener('focus', this._handleInputClick);\n\t this.element.addEventListener('keydown', this._handleInputKey);\n\n\t this.calendarBody = this.datepicker.queryFirst('table tbody').addEventListener('click', this._handleDayClick);\n\t this.monthDisplay = this.datepicker.queryFirst('header .month').addEventListener('click', this._handleMonthExpand);\n\t this.yearDisplay = this.datepicker.queryFirst('header .year').addEventListener('click', this._handleYearExpand);\n\n\t this.time = this.datepicker.queryFirst('.time');\n\t this.inputs = this.datepicker.queryFirst('div.inputs');\n\t this.hourInput = this.inputs.queryFirst('input[name=hour]').addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleHourKey);\n\t this.minuteInput = this.inputs.queryFirst('input[name=minute]').addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleMinuteKey);\n\t this.secondInput = this.inputs.queryFirst('input[name=second]').addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleSecondKey);\n\t this.ampmInput = this.inputs.queryFirst('input[name=am_pm]').addEventListener('keydown', this._handleAmPmKey);\n\t this.monthInput = this.inputs.queryFirst('input[name=month]').setValue(this.date.getMonth() + 1).addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleMonthKey);\n\t this.dayInput = this.inputs.queryFirst('input[name=day]').setValue(this.date.getDate()).addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleDayKey);\n\t this.yearInput = this.inputs.queryFirst('input[name=year]').setValue(this.date.getFullYear()).addEventListener('change', this._handleDateTimeChange).addEventListener('keydown', this._handleYearKey);\n\n\t this.datepicker.queryFirst('header .next').addEventListener('click', this._handleNextMonth);\n\t this.datepicker.queryFirst('header .prev').addEventListener('click', this._handlePreviousMonth);\n\n\t PrimeDocument.addEventListener('click', this._handleGlobalClick);\n\t PrimeDocument.addEventListener('keydown', this._handleGlobalKey);\n\n\t // Setup months dropdown\n\t html = '\n\t * Also handles up and down arrow to increment and decrement the day.\n\t *\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleDayKey(event) {\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t PrimeDate.plusDays(this.date, 1);\n\t this.setDate(this.date);\n\t this.dayInput.domElement.setSelectionRange(0, this.dayInput.getValue().length);\n\t Utils.stopEvent(event);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusDays(this.date, -1);\n\t this.setDate(this.date);\n\t this.dayInput.domElement.setSelectionRange(0, this.dayInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setDate(parseInt(this.dayInput.getValue()));\n\t }\n\t }\n\n\t /**\n\t * Handles a global click event. This determines if the click was outside of the DateTimePicker and closes it.\n\t *\n\t * @param {MouseEvent} event The click event.\n\t * @private\n\t */\n\t _handleGlobalClick(event) {\n\t // Skip this function completely if they clicked the input field\n\t if (event.target === this.element.domElement) {\n\t return;\n\t }\n\n\t const top = this.datepicker.getTop();\n\t const bottom = this.datepicker.getBottom();\n\t const left = this.datepicker.getLeft();\n\t const right = this.datepicker.getRight();\n\t if (this.datepicker.isVisible() && (event.x < left || event.x > right || event.y < top || event.y > bottom)) {\n\t this.close();\n\t this.closeYearsSelect();\n\t this.closeMonthsSelect();\n\t } else {\n\t if (this.years.isVisible()) {\n\t this.closeYearsSelect();\n\t }\n\t if (this.months.isVisible()) {\n\t this.closeMonthsSelect();\n\t }\n\t }\n\t }\n\n\t /**\n\t * Handles a global key event. This determines if the DateTimePicker is open and if enter or escape was hit.\n\t *\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleGlobalKey(event) {\n\t // Skip this function completely if the DateTimePicker isn't open\n\t if (!this.datepicker.isVisible()) {\n\t return;\n\t }\n\n\t if (event.keyCode === Events.Keys.ENTER) {\n\t Utils.stopEvent(event);\n\t this.setDate(this.date);\n\t this.close();\n\t this.element.focus();\n\t } else if (event.keyCode === Events.Keys.ESCAPE) {\n\t this.close();\n\t this.element.focus();\n\t }\n\t }\n\n\t /**\n\t * Handles when a key is click in the hours input field so that tab and shift tab work properly.\n\t *
\n\t * Also handles up and down arrow to increment and decrement the hour.\n\t *\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleHourKey(event) {\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusHours(this.date, 1);\n\t this.setDate(this.date);\n\t this.hourInput.domElement.setSelectionRange(0, this.hourInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusHours(this.date, -1);\n\t this.setDate(this.date);\n\t this.hourInput.domElement.setSelectionRange(0, this.hourInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setHours(parseInt(this.hourInput.getValue()));\n\t }\n\t }\n\n\t /**\n\t * Handle the click event for the input date field. If the DateTimePicker is hidden this will call the {@link #show()}\n\t * function.\n\t *\n\t * @returns {boolean} Always true.\n\t * @private\n\t */\n\t _handleInputClick() {\n\t if (!this.datepicker.isVisible()) {\n\t this.open();\n\t this.monthInput.domElement.setSelectionRange(0, this.monthInput.getValue().length);\n\t this.monthInput.focus();\n\t }\n\t }\n\n\t /**\n\t * Handle the key event for the input date field. If the user hits tab or shift-tab, this moves the focus to the\n\t * nested inputs.\n\t *\n\t * @param {KeyboardEvent} event The keyboard event.\n\t * @private\n\t */\n\t _handleInputKey(event) {\n\t if (this.datepicker.isVisible() && event.keyCode === Events.Keys.TAB) {\n\t Utils.stopEvent(event);\n\t if (event.shiftKey) {\n\t this.ampmInput.domElement.setSelectionRange(0, this.ampmInput.getValue().length);\n\t this.ampmInput.focus();\n\t } else {\n\t this.monthInput.domElement.setSelectionRange(0, this.monthInput.getValue().length);\n\t this.monthInput.focus();\n\t }\n\t }\n\t }\n\n\t /**\n\t * Handle the key down event and capture the up and down arrow key to increment and decrement the minute.\n\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleMinuteKey(event) {\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusMinutes(this.date, 1);\n\t this.setDate(this.date);\n\t this.minuteInput.domElement.setSelectionRange(0, this.minuteInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusMinutes(this.date, -1);\n\t this.setDate(this.date);\n\t this.minuteInput.domElement.setSelectionRange(0, this.minuteInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setMinutes(parseInt(this.minuteInput.getValue()));\n\t }\n\t }\n\n\t /**\n\t * Handles the click on the month to open the month select.\n\t *\n\t * @private\n\t */\n\t _handleMonthExpand(event) {\n\t Utils.stopEvent(event);\n\t this.openMonthSelect();\n\t }\n\n\t /**\n\t * Handles when a key is click in the month input field so that tab and shift tab work properly.\n\t *
\n\t * Also handles up and down arrow to increment and decrement the month.\n\t *\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleMonthKey(event) {\n\t if (event.keyCode === Events.Keys.TAB && event.shiftKey) {\n\t Utils.stopEvent(event);\n\t if (this.options.dateOnly) {\n\t this.yearInput.domElement.setSelectionRange(0, this.yearInput.getValue().length);\n\t this.yearInput.focus();\n\t } else {\n\t this.ampmInput.domElement.setSelectionRange(0, this.ampmInput.getValue().length);\n\t this.ampmInput.focus();\n\t }\n\t return;\n\t }\n\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusMonths(this.date, 1);\n\t this.setDate(this.date);\n\t this.monthInput.domElement.setSelectionRange(0, this.monthInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusMonths(this.date, -1);\n\t this.setDate(this.date);\n\t this.monthInput.domElement.setSelectionRange(0, this.monthInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setMonth(parseInt(this.monthInput.getValue()) - 1);\n\t }\n\t }\n\n\t /**\n\t * Handle the next month button click.\n\t *\n\t * @param {MouseEvent} event The mouse event.\n\t * @private\n\t */\n\t _handleNextMonth(event) {\n\t Utils.stopEvent(event);\n\t this.nextMonth();\n\t }\n\n\t /**\n\t * Handle the previous month button click.\n\t *\n\t * @param {MouseEvent} event The mouse event.\n\t * @private\n\t */\n\t _handlePreviousMonth(event) {\n\t Utils.stopEvent(event);\n\t this.previousMonth();\n\t }\n\n\t /**\n\t * Handle the key down event and capture the up and down arrow key to increment and decrement the second.\n\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleSecondKey(event) {\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusSeconds(this.date, 1);\n\t this.setDate(this.date);\n\t this.secondInput.domElement.setSelectionRange(0, this.secondInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusSeconds(this.date, -1);\n\t this.setDate(this.date);\n\t this.secondInput.domElement.setSelectionRange(0, this.secondInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setSeconds(parseInt(this.secondInput.getValue()));\n\t }\n\t }\n\n\t /**\n\t * Handles the click on the year to open the year select.\n\t *\n\t * @private\n\t */\n\t _handleYearExpand(event) {\n\t Utils.stopEvent(event);\n\t this.openYearSelect();\n\t }\n\n\t /**\n\t * Handles when a key is click in the year input field so that tab and shift tab work properly.\n\t *
\n\t * Also handles up and down arrow to increment and decrement the year.\n\t *\n\t * @param {KeyboardEvent} event The key event.\n\t * @private\n\t */\n\t _handleYearKey(event) {\n\t if (event.keyCode === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusYears(this.date, 1);\n\t this.setDate(this.date);\n\t this.yearInput.domElement.setSelectionRange(0, this.yearInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t PrimeDate.plusYears(this.date, -1);\n\t this.setDate(this.date);\n\t this.yearInput.domElement.setSelectionRange(0, this.yearInput.getValue().length);\n\t } else if (event.keyCode === Events.Keys.TAB && this.options.dateOnly) {\n\t Utils.stopEvent(event);\n\t if (event.shiftKey) {\n\t this.dayInput.domElement.setSelectionRange(0, this.dayInput.getValue().length);\n\t this.dayInput.focus();\n\t } else {\n\t this.monthInput.domElement.setSelectionRange(0, this.monthInput.getValue().length);\n\t this.monthInput.focus();\n\t }\n\t } else if (event.keyCode === Events.Keys.ENTER) {\n\t this.date.setFullYear(parseInt(this.yearInput.getValue()));\n\t }\n\t }\n\n\t /**\n\t * Rebuilds the HTML of the DateTimePicker.\n\t * @private\n\t */\n\t _rebuild() {\n\t this.drawCalendar(this.date);\n\t this._refreshInputs();\n\n\t if (this.options.dateOnly) {\n\t this.time.hide();\n\t }\n\t }\n\n\t /**\n\t * Refresh the time inputs.\n\t *\n\t * @private\n\t */\n\t _refreshInputs() {\n\t // Set Time -- assuming 12-hour time for the input fields and ISO 24-hour time for the field\n\t const hours = PrimeDate.getHourOfDay(this.date);\n\t this.hourInput.setValue(hours);\n\n\t const minutes = this.date.getMinutes();\n\t this.minuteInput.setValue((\"00\" + minutes).slice(-2));\n\n\t const seconds = this.date.getSeconds();\n\t this.secondInput.setValue((\"00\" + seconds).slice(-2));\n\n\t if (this.date.getHours() >= 12) {\n\t this.ampmInput.setValue(DateTimePicker.AM_PM[1]);\n\t } else {\n\t this.ampmInput.setValue(DateTimePicker.AM_PM[0]);\n\t }\n\n\t this.monthInput.setValue(this.date.getMonth() + 1);\n\t this.dayInput.setValue(this.date.getDate());\n\t this.yearInput.setValue(this.date.getFullYear());\n\t }\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions() {\n\t // Defaults\n\t this.options = {\n\t className: 'prime-date-picker',\n\t closeTimeout: 200,\n\t dateOnly: false\n\t };\n\n\t const userOptions = Utils.dataSetToOptions(this.element);\n\t for (let option in userOptions) {\n\t if (userOptions.hasOwnProperty(option)) {\n\t this.options[option] = userOptions[option];\n\t }\n\t }\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass Dismissable {\n\t /**\n\t * Constructs a new Dismissable object for the given element.\n\t *\n\t * @param {PrimeElement|Element|EventTarget} element The Element for the Dismissable widget.\n\t * @param {PrimeElement|Element|EventTarget} dismissButton The Element for the Dismissable button.\n\t * @constructor\n\t */\n\t constructor(element, dismissButton) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t this.dismissButton = dismissButton;\n\t this._setInitialOptions();\n\t }\n\n\t /**\n\t * Closes the Dismissable by removing the open class from the element and setting a timer to remove the element from\n\t * the DOM.\n\t */\n\t close() {\n\t this.element.addClass('closed');\n\t setTimeout(function() {\n\t this.element.removeFromDOM();\n\t }.bind(this), this.options.closeTimeout);\n\t }\n\n\t /**\n\t * Destroys the widget.\n\t */\n\t destroy() {\n\t this.dismissButton.removeEventListener('click', this._handleClick);\n\t }\n\n\t /**\n\t * Initializes the Dismissable by binding the events to the dismiss button.\n\t *\n\t * @returns {Dismissable} This.\n\t */\n\t initialize() {\n\t this.dismissButton.addEventListener('click', this._handleClick);\n\t return this;\n\t }\n\n\t /**\n\t * Sets the timeout used in the close method to allow for transitions.\n\t *\n\t * @param timeout {int} The timeout.\n\t * @returns {Dismissable} This.\n\t */\n\t withCloseTimeout(timeout) {\n\t this.options.closeTimeout = timeout;\n\t return this;\n\t }\n\n\t /**\n\t * Set more than one option at a time by providing a map of key value pairs. This is considered an advanced\n\t * method to set options on the widget. The caller needs to know what properties are valid in the options object.\n\t *\n\t * @param {Object} options Key value pair of configuration options.\n\t * @returns {Dismissable} This.\n\t */\n\t withOptions(options) {\n\t if (!Utils.isDefined(options)) {\n\t return this;\n\t }\n\n\t for (let option in options) {\n\t if (options.hasOwnProperty(option)) {\n\t this.options[option] = options[option];\n\t }\n\t }\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Handles the click event.\n\t * @private\n\t */\n\t _handleClick(event) {\n\t Utils.stopEvent(event);\n\t this.close();\n\t }\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions() {\n\t // Defaults\n\t this.options = {\n\t closeTimeout: 400\n\t };\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass HTMLDialog {\n\t /**\n\t * Constructs a new dialog box from an element.\n\t *\n\t * @param {PrimeElement|Element|EventTarget} element The Prime Element for the HTMLDialog widget.\n\t * @constructor\n\t */\n\t constructor(element) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t this._setInitialOptions();\n\t this.draggable = null;\n\t }\n\n\t /**\n\t * Closes the dialog, destroys the HTML and updates or hides the overlay.\n\t * @returns {HTMLDialog} This.\n\t */\n\t close() {\n\t this.element.removeClass('open');\n\t if (this.draggable !== null) {\n\t this.draggable.destroy();\n\t this.draggable = null;\n\t }\n\n\t setTimeout(function() {\n\t this.element.hide();\n\n\t const highestZIndex = this._determineZIndex();\n\t if (highestZIndex !== 0) {\n\t Overlay.instance.setZIndex(highestZIndex);\n\t } else {\n\t Overlay.instance.close();\n\t }\n\t }.bind(this), this.options.closeTimeout);\n\n\t return this;\n\t }\n\n\t /**\n\t * Destroys the dialog by calling the close function.\n\t * @returns {HTMLDialog} This.\n\t */\n\t destroy() {\n\t this.close();\n\t return this;\n\t }\n\n\t /**\n\t * Initializes the dialog.\n\t * @returns {HTMLDialog} This.\n\t */\n\t initialize() {\n\t this.element.hide();\n\t return this;\n\t }\n\n\t /**\n\t * Opens the dialog.\n\t *\n\t * @returns {HTMLDialog} This.\n\t */\n\t open() {\n\t const highestZIndex = this._determineZIndex();\n\t Overlay.instance.open(highestZIndex + this.options.zIndexOffset);\n\t this.element.setStyle('zIndex', (highestZIndex + this.options.zIndexOffset + 10).toString());\n\t this.element.show();\n\t this.element.addClass('open');\n\n\t // Call the callback before positioning to ensure all changes to the dialog have been made\n\t if (this.options.callback !== null) {\n\t this.options.callback(this);\n\t }\n\n\t // Position the fixed dialog in the center of the screen\n\t const windowHeight = PrimeWindow.getInnerHeight();\n\t const dialogHeight = this.element.getHeight();\n\t this.element.setTop(((windowHeight - dialogHeight) / 2) - 20);\n\n\t this._setupButtons();\n\n\t if (this.draggable === null) {\n\t if (this.options.draggableElementSelector !== null && this.element.queryFirst(this.options.draggableElementSelector) !== null) {\n\t this.draggable = new Draggable(this.element, this.options.draggableElementSelector).initialize();\n\t }\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Updates the HTML contents of the dialog.\n\t *\n\t * @param html {String} The HTML.\n\t * @returns {HTMLDialog} This.\n\t */\n\t setHTML(html) {\n\t this.element.setHTML(html);\n\t this._setupButtons();\n\t return this;\n\t }\n\n\t /**\n\t * Sets the callback that is called after the dialog has been fetched and rendered.\n\t *\n\t * @param callback {function} The callback function.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withCallback(callback) {\n\t this.options.callback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the class name for the dialog element.\n\t *\n\t * @param className {string} The class name.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withClassName(className) {\n\t this.options.className = className;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the close button element selector that is used to setup the close button in the HTML that was returned from\n\t * the server.\n\t *\n\t * @param selector {string} The element selector.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withCloseButtonElementSelector(selector) {\n\t this.options.closeButtonElementSelector = selector;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the timeout used in the close method to allow for transitions.\n\t *\n\t * @param timeout {int} The timeout.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withCloseTimeout(timeout) {\n\t this.options.closeTimeout = timeout;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the draggable element selector that is used for the Draggable.\n\t *\n\t * @param selector {string} The element selector.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withDraggableButtonElementSelector(selector) {\n\t this.options.draggableElementSelector = selector;\n\t return this;\n\t }\n\n\t /**\n\t * Set more than one option at a time by providing a map of key value pairs. This is considered an advanced\n\t * method to set options on the widget. The caller needs to know what properties are valid in the options object.\n\t *\n\t * @param {Object} options Key value pair of configuration options.\n\t * @returns {HTMLDialog} This.\n\t */\n\t withOptions(options) {\n\t if (!Utils.isDefined(options)) {\n\t return this;\n\t }\n\n\t for (let option in options) {\n\t if (options.hasOwnProperty(option)) {\n\t this.options[option] = options[option];\n\t }\n\t }\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t _determineZIndex() {\n\t let highestZIndex = 0;\n\t PrimeDocument.query('.' + this.options.className).each(function(dialog) {\n\t const zIndex = parseInt(dialog.getComputedStyle()['zIndex']);\n\t if (dialog.isVisible() && zIndex > highestZIndex) {\n\t highestZIndex = zIndex;\n\t }\n\t });\n\t return highestZIndex;\n\t }\n\n\t _handleCloseClickEvent(event) {\n\t Utils.stopEvent(event);\n\t this.close();\n\t }\n\n\t _setupButtons() {\n\t this.element.query(this.options.closeButtonElementSelector).each(function(e) {\n\t e.addEventListener('click', this._handleCloseClickEvent);\n\t }.bind(this));\n\t }\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions() {\n\t // Defaults\n\t this.options = {\n\t callback: null,\n\t className: 'prime-dialog',\n\t closeButtonElementSelector: '[data-dialog-role=\"close-button\"]',\n\t closeTimeout: 200,\n\t draggableElementSelector: '[data-dialog-role=\"draggable\"]',\n\t zIndexOffset: 1000\n\t };\n\n\t const userOptions = Utils.dataSetToOptions(this.element);\n\t for (let option in userOptions) {\n\t if (userOptions.hasOwnProperty(option)) {\n\t this.options[option] = userOptions[option];\n\t }\n\t }\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass InProgress {\n\t /**\n\t * Constructs a In Progress widget that opens an overlay over an element while something is running and closes it when\n\t * it finishes.\n\t *\n\t * @param {PrimeElement|Element|EventTarget} element The Prime Element to overlay.\n\t * @constructor\n\t */\n\t constructor(element) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t this._setInitialOptions();\n\t this.draggable = null;\n\t }\n\n\t /**\n\t * Closes the InProgress process.\n\t *\n\t * @param {Function} callback (Optional) A callback function to invoke after the InProgress has been completely closed.\n\t */\n\t close(callback) {\n\t try {\n\t this.options.endFunction(this);\n\t } finally {\n\t const now = new Date().getTime();\n\t const duration = now - this.startInstant;\n\t if (duration < this.options.minimumTime) {\n\t setTimeout(function() {\n\t this.overlay.removeFromDOM();\n\n\t if (callback) {\n\t callback();\n\t }\n\t }.bind(this), this.options.minimumTime - duration);\n\t } else {\n\t this.overlay.removeFromDOM();\n\n\t if (callback) {\n\t callback();\n\t }\n\t }\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Opens the InProgress process.\n\t */\n\t open() {\n\t this.startInstant = new Date().getTime();\n\t this.overlay = PrimeDocument.newElement('
').setId('prime-in-progress-overlay').appendTo(document.body);\n\t PrimeDocument.newElement('', {class: 'fa fa-spin fa-' + this.options.iconName}).appendTo(this.overlay);\n\n\t const coords = this.element.getCoordinates();\n\t const bodyCoords = PrimeDocument.bodyElement.getCoordinates();\n\t this.overlay.setTop(coords.top - bodyCoords.top);\n\t this.overlay.setLeft(coords.left - bodyCoords.left);\n\t this.overlay.setWidth(this.element.getBorderedWidth());\n\t this.overlay.setHeight(this.element.getBorderedHeight());\n\t this.overlay.setStyle('zIndex', (this.element.getRelativeZIndex() + 1000).toString());\n\n\t this.options.startFunction(this);\n\n\t return this;\n\t }\n\n\t /**\n\t * Sets the end function that is called when the InProgress process is finished.\n\t *\n\t * @param f {function} The function.\n\t * @returns {InProgress} This.\n\t */\n\t withEndFunction(f) {\n\t this.options.endFunction = f;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the FontAwesome icon name to use for the overlay.\n\t *\n\t * @param iconName {string} The icon name.\n\t * @returns {InProgress} This.\n\t */\n\t withIconName(iconName) {\n\t this.options.iconName = iconName;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the minimum time that the InProgress process must run.\n\t *\n\t * @param time {number} The time in milliseconds.\n\t * @returns {InProgress} This.\n\t */\n\t withMinimumTime(time) {\n\t this.options.minimumTime = time;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the start function that is called when the InProgress process is started.\n\t *\n\t * @param f {function} The function.\n\t * @returns {InProgress} This.\n\t */\n\t withStartFunction(f) {\n\t this.options.startFunction = f;\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions() {\n\t // Defaults\n\t this.options = {\n\t endFunction: function() {\n\t },\n\t iconName: 'refresh',\n\t minimumTime: 1000,\n\t startFunction: function() {\n\t }\n\t };\n\n\t const userOptions = Utils.dataSetToOptions(this.element);\n\t for (let option in userOptions) {\n\t if (userOptions.hasOwnProperty(option)) {\n\t this.options[option] = userOptions[option];\n\t }\n\t }\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2014-2018, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tclass Searcher {\n\t /**\n\t * Constructs a Searcher object for the given text input.\n\t *\n\t * The Searcher object can be attached and used in conjunction with any other widgets in a generic manner. It\n\t * provides search capabilities and manages the search results. This is useful for MultipleSelects, IntelliSense and\n\t * other widgets. Here's the HTML for the search results.\n\t *\n\t *\n\t * <input type=\"text\" class=\"prime-search-result-input\" value=\"F\"/>\n\t * <ul>\n\t * <li>Four</li>\n\t * <li>Five</li>\n\t * <li>Fifteen</li>\n\t * <li>Add Custom Entry: F/li>\n\t * </ul>\n\t * </div>\n\t *\n\t *\n\t * The with* methods can be used to setup the configuration for this SearchResults, but here are some defaults:\n\t *\n\t *
\n\t * CallbackObject {\n\t * void deletedBeyondSearchInput()\n\t * void doesNotContainValue()\n\t * object{results:Array, tooManyResults:boolean} search(_searchString:string),\n\t * void selectSearchResult(selectedSearchResult:string),\n\t * }\n\t *\n\t *\n\t * @constructor\n\t * @param {PrimeElement|Element|EventTarget} inputElement The input element that is used to execute the search.\n\t * @param {PrimeElement|Element|EventTarget} searchResultsContainer The element that is used to store the search results.\n\t * @param {*} callbackObject The object that is used to callback for searching and numerous other functions to help\n\t * communicate state and determine how to draw the input and search results.\n\t */\n\t constructor(inputElement, searchResultsContainer, callbackObject) {\n\t Utils.bindAll(this);\n\n\t this.searchResults = PrimeElement.wrap(searchResultsContainer);\n\t this.inputElement = PrimeElement.wrap(inputElement);\n\t if (this.inputElement.domElement.tagName !== 'INPUT') {\n\t throw new TypeError('You can only use Prime.Widgets.SearchResults with INPUT elements');\n\t }\n\n\t this._setInitialOptions(callbackObject);\n\t }\n\n\t /**\n\t * A search function that works on a select box.\n\t *\n\t * @param searchText {String} The search String.\n\t * @param select {HTMLSelectElement|PrimeElement} The select box.\n\t * @returns {{results: Array, tooManyResults: boolean}}\n\t */\n\t static selectSearchFunction(searchText, select) {\n\t const options = PrimeElement.unwrap(select).options;\n\t const selectableOptions = [];\n\t for (let i = 0; i < options.length; i++) {\n\t const option = new PrimeElement(options[i]);\n\t if (option.isSelected()) {\n\t continue;\n\t }\n\n\t const html = option.getHTML();\n\t if (searchText === null || searchText === undefined || searchText === '' || html.toLowerCase().indexOf(searchText.toLowerCase()) === 0) {\n\t selectableOptions.push(html);\n\t }\n\t }\n\n\t // Alphabetize the options\n\t if (selectableOptions.length > 0) {\n\t selectableOptions.sort();\n\t }\n\n\t return {results: selectableOptions, tooManyResults: false};\n\t }\n\n\t /**\n\t * Closes the search results display, unhighlights any options that are highlighted and resets the input's value to\n\t * empty string.\n\t */\n\t closeSearchResults() {\n\t this._removeAllSearchResults();\n\t this.inputElement.setValue('');\n\t this.searchResults.removeClass('open');\n\t setTimeout(function() {\n\t this.searchResults.hide();\n\t this.resizeInput();\n\t }.bind(this), this.options.closeTimeout);\n\t }\n\n\t /**\n\t * Removes all of the event listeners from the input element.\n\t */\n\t destroy() {\n\t this.inputElement\n\t .removeEventListener('blur', this._handleBlurEvent)\n\t .removeEventListener('click', this._handleClickEvent)\n\t .removeEventListener('keyup', this._handleKeyUpEvent)\n\t .removeEventListener('keydown', this._handleKeyDownEvent)\n\t .removeEventListener('focus', this._handleFocusEvent);\n\t }\n\n\t focus() {\n\t this.inputElement.focus();\n\t }\n\n\t /**\n\t * @returns {PrimeElement} The highlighted search result or null.\n\t */\n\t getHighlightedSearchResult() {\n\t return this.searchResults.queryFirst('.selected');\n\t }\n\n\t /**\n\t * Highlights the next search result if one is highlighted. If there isn't a highlighted search result, this\n\t * highlights the first one. This method handles wrapping.\n\t *\n\t * @returns {Searcher} This Searcher.\n\t */\n\t highlightNextSearchResult() {\n\t let searchResult = this.getHighlightedSearchResult();\n\t if (searchResult !== null) {\n\t searchResult = searchResult.getNextSibling();\n\t }\n\n\t // Grab the first search result in the list if there isn't a next sibling\n\t if (searchResult === null) {\n\t searchResult = this.searchResults.queryFirst('.search-result');\n\t }\n\n\t if (searchResult !== null) {\n\t this.highlightSearchResult(searchResult);\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Highlights the previous search result if one is highlighted. If there isn't a highlighted search result, this\n\t * selects the last one. This method handles wrapping.\n\t *\n\t * @returns {Searcher} This Searcher.\n\t */\n\t highlightPreviousSearchResult() {\n\t let searchResult = this.getHighlightedSearchResult();\n\t if (searchResult !== null) {\n\t searchResult = searchResult.getPreviousSibling();\n\t }\n\n\t if (searchResult === null) {\n\t searchResult = this.searchResults.queryFirst('.search-result');\n\t }\n\n\t if (searchResult !== null) {\n\t this.highlightSearchResult(searchResult);\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Highlights the given search result.\n\t *\n\t * @param {PrimeElement} searchResult The search result to highlight.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t highlightSearchResult(searchResult) {\n\t this.searchResults.getChildren().removeClass('selected');\n\n\t searchResult.addClass('selected');\n\t const scrollTop = this.searchResults.getScrollTop();\n\t const height = this.searchResults.getHeight();\n\t const searchResultOffset = searchResult.getOffsetTop();\n\t if (searchResultOffset + 1 >= scrollTop + height) {\n\t this.searchResults.scrollTo(searchResult.getOffsetTop() - this.searchResults.getHeight() + searchResult.getOuterHeight());\n\t } else if (searchResultOffset < scrollTop) {\n\t this.searchResults.scrollTo(searchResultOffset);\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Initializes the Searcher by setting up the event listeners and closing the search result element.\n\t *\n\t * @returns {Searcher} This.\n\t */\n\t initialize() {\n\t this.inputElement\n\t .addEventListener('blur', this._handleBlurEvent)\n\t .addEventListener('click', this._handleClickEvent)\n\t .addEventListener('keyup', this._handleKeyUpEvent)\n\t .addEventListener('keydown', this._handleKeyDownEvent)\n\t .addEventListener('focus', this._handleFocusEvent);\n\n\t this.closeSearchResults();\n\t return this;\n\t }\n\n\t /**\n\t * @returns {boolean} True if the search results add custom option is being displayed currently.\n\t */\n\t isCustomAddVisible() {\n\t return this.searchResults.queryFirst('.custom-add') !== null;\n\t }\n\n\t /**\n\t * @returns {boolean} True if any search results are being displayed currently.\n\t */\n\t isSearchResultsVisible() {\n\t return this.searchResults.hasClass('open');\n\t }\n\n\t /**\n\t * Poor mans resizing of the input field as the user types into it.\n\t */\n\t resizeInput() {\n\t const text = this.inputElement.getValue() === '' ? this.inputElement.getAttribute('placeholder') : this.inputElement.getValue();\n\t const newLength = Utils.calculateTextLength(this.inputElement, text) + 35;\n\t this.inputElement.setWidth(newLength);\n\t }\n\n\t /**\n\t * Executes a search by optionally updating the input to the given value (if specified) and then rebuilding the search\n\t * results using the input's value. This method also puts focus on the input and shows the search results (in case\n\t * they are hidden for any reason).\n\t *\n\t * @param {string} [searchText] The text to search for (this value is also set into the input box). If this is not\n\t * specified then the search is run using the input's value.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t search(searchText) {\n\t // Set the search text into the input box if it is different and then lowercase it\n\t if (Utils.isDefined(searchText) && this.inputElement.getValue() !== searchText) {\n\t this.inputElement.setValue(searchText);\n\t }\n\n\t searchText = Utils.isDefined(searchText) ? searchText.toLowerCase() : this.inputElement.getValue();\n\t this.resizeInput();\n\n\t // Clear the search results (if there are any)\n\t this._removeAllSearchResults();\n\n\t // Call the callback\n\t const searchResults = this.options.callbackObject.search(searchText);\n\t if (!searchResults.hasOwnProperty('results') || !searchResults.hasOwnProperty('tooManyResults')) {\n\t throw new TypeError('The callback must return an Object that contains the properties results[Array] and tooManyResults[boolean]');\n\t }\n\n\t let count = 0;\n\t let matchingSearchResultElement = null;\n\t for (let i = 0; i < searchResults.results.length; i++) {\n\t const searchResult = searchResults.results[i];\n\t const element = PrimeDocument.newElement('')\n\t .addClass('search-result')\n\t .setAttribute('value', searchResult)\n\t .setHTML(searchResult)\n\t .addEventListener('click', this._handleClickEvent)\n\t .addEventListener('mouseover', this._handleMouseOverEvent)\n\t .appendTo(this.searchResults);\n\t if (searchResult.toLowerCase().trim() === searchText.toLowerCase().trim()) {\n\t matchingSearchResultElement = element;\n\t }\n\n\t count++;\n\t }\n\n\t // Show the custom add option if necessary\n\t const trimmedLength = searchText.trim().length;\n\t if (this.options.customAddEnabled && trimmedLength !== 0 && matchingSearchResultElement === null\n\t && (!('doesNotContainValue' in this.options.callbackObject) || this.options.callbackObject.doesNotContainValue(searchText))) {\n\t matchingSearchResultElement = PrimeDocument.newElement('')\n\t .addClass('custom-add')\n\t .addEventListener('click', this._handleClickEvent)\n\t .addEventListener('mouseover', this._handleMouseOverEvent)\n\t .setHTML(this.options.customAddLabel + Utils.escapeHTML(searchText))\n\t .appendTo(this.searchResults);\n\t count++;\n\t }\n\n\t if (count === 0 && trimmedLength !== 0) {\n\t PrimeDocument.newElement('')\n\t .addClass('no-search-results')\n\t .setHTML(this.options.noSearchResultsLabel + Utils.escapeHTML(searchText))\n\t .appendTo(this.searchResults);\n\t count++;\n\t }\n\n\t // Handle too many results\n\t if (searchResults.tooManyResults) {\n\t PrimeDocument.newElement('')\n\t .addClass('too-many-search-results')\n\t .setHTML(this.options.tooManySearchResultsLabel + Utils.escapeHTML(searchText))\n\t .appendTo(this.searchResults);\n\t count++;\n\t }\n\n\t if (count !== 0) {\n\t this.searchResults.show();\n\t this.searchResults.addClass('open');\n\n\t if (count >= 10) {\n\t this.searchResults.setHeight(this.searchResults.getChildren()[0].getOuterHeight() * 10 + 1);\n\t } else {\n\t this.searchResults.setHeight(this.searchResults.getChildren()[0].getOuterHeight() * count + 1);\n\t }\n\t } else {\n\t this.closeSearchResults();\n\t }\n\n\t if (matchingSearchResultElement !== null) {\n\t this.highlightSearchResult(matchingSearchResultElement);\n\t }\n\n\t return this;\n\t }\n\n\t /**\n\t * Selects the highlighted search result unless there isn't one highlighted, in which case, this does nothing.\n\t *\n\t * @returns {Searcher} This Searcher.\n\t */\n\t selectHighlightedSearchResult() {\n\t const searchResult = this.getHighlightedSearchResult();\n\t if (searchResult === null) {\n\t return this;\n\t }\n\n\t const custom = searchResult.hasClass('custom-add');\n\t const value = (custom) ? this.inputElement.getValue().trim() : searchResult.getHTML();\n\t if (custom) {\n\t // The client of this searcher needs to warn the user.\n\t if (!this.options.customAddCallback(value)) {\n\t return this;\n\t }\n\t }\n\n\t this.options.callbackObject.selectSearchResult(value);\n\t this.closeSearchResults();\n\n\t return this;\n\t }\n\n\t /**\n\t * Sets the timeout used in the close method to allow for transitions.\n\t *\n\t * @param timeout {int} The timeout.\n\t * @returns {Searcher} This.\n\t */\n\t withCloseTimeout(timeout) {\n\t this.options.closeTimeout = timeout;\n\t return this;\n\t }\n\n\t /**\n\t * Sets whether or not this Searcher allows custom options to be added.\n\t *\n\t * @param {boolean} enabled The flag.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t withCustomAddEnabled(enabled) {\n\t this.options.customAddEnabled = enabled;\n\t return this;\n\t }\n\n\t /**\n\t * Sets whether or not this Searcher allows custom options to be added.\n\t *\n\t * @param {Function} callback The function to call that will return true if the custom option can be added.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t withCustomAddCallback(callback) {\n\t this.options.customAddCallback = callback;\n\t return this;\n\t }\n\n\t /**\n\t * Sets the label used when custom options are added.\n\t *\n\t * @param {string} customAddLabel The label.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t withCustomAddLabel(customAddLabel) {\n\t this.options.customAddLabel = customAddLabel;\n\t return this;\n\t }\n\n\t /**\n\t * Set more than one option at a time by providing a map of key value pairs. This is considered an advanced\n\t * method to set options on the widget. The caller needs to know what properties are valid in the options object.\n\t *\n\t * @param {Object} options Key value pair of configuration options.\n\t * @returns {Searcher} This.\n\t */\n\t withOptions(options) {\n\t if (!Utils.isDefined(options)) {\n\t return this;\n\t }\n\n\t for (let option in options) {\n\t if (options.hasOwnProperty(option)) {\n\t this.options[option] = options[option];\n\t }\n\t }\n\t return this;\n\t }\n\n\t /**\n\t * Sets the label that is printed when there are no search results.\n\t *\n\t * @param {string} noSearchResultsLabel The label text.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t withNoSearchResultsLabel(noSearchResultsLabel) {\n\t this.options.noSearchResultsLabel = noSearchResultsLabel;\n\t return this;\n\t }\n\n\t /* ===================================================================================================================\n\t * Private methods\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Sets the label that is printed when there are too many search results.\n\t *\n\t * @param {string} tooManySearchResultsLabel The label text.\n\t * @returns {Searcher} This Searcher.\n\t */\n\t withTooManySearchResultsLabel(tooManySearchResultsLabel) {\n\t this.options.tooManySearchResultsLabel = tooManySearchResultsLabel;\n\t return this;\n\t }\n\n\t /**\n\t * Handles the blur event when the input goes out of focus.\n\t *\n\t * @private\n\t */\n\t _handleBlurEvent() {\n\t window.setTimeout((function() {\n\t if (document.activeElement !== this.inputElement.domElement) {\n\t this.closeSearchResults();\n\t }\n\t }).bind(this), 300);\n\t }\n\n\t /**\n\t * Handles all click events sent to the Searcher.\n\t *\n\t * @param {Event} event The mouse event.\n\t * @private\n\t */\n\t _handleClickEvent(event) {\n\t const target = new PrimeElement(event.currentTarget);\n\t if (target.hasClass('custom-add') || target.hasClass('search-result')) {\n\t this.selectHighlightedSearchResult();\n\t } else if (target.domElement === this.inputElement.domElement) {\n\t this.search();\n\t } else {\n\t console.log('Clicked something else target=[' + event.target + '] currentTarget=[' + event.currentTarget + ']');\n\t }\n\t }\n\n\t /**\n\t * Handles when the input field is focused by opening the search results.\n\t *\n\t * @private\n\t */\n\t _handleFocusEvent() {\n\t this.search();\n\t }\n\n\t /**\n\t * Handles the key down events that should not be propagated.\n\t *\n\t * @param {KeyboardEvent} event The keyboard event object.\n\t * @private\n\t */\n\t _handleKeyDownEvent(event) {\n\t const key = event.keyCode;\n\t if (key === Events.Keys.BACKSPACE) {\n\t this.previousSearchString = this.inputElement.getValue();\n\t } else if (key === Events.Keys.UP_ARROW) {\n\t Utils.stopEvent(event);\n\t this.highlightPreviousSearchResult();\n\t } else if (key === Events.Keys.DOWN_ARROW) {\n\t Utils.stopEvent(event);\n\t if (this.isSearchResultsVisible()) {\n\t this.highlightNextSearchResult();\n\t } else {\n\t this.search();\n\t }\n\t } else if (key === Events.Keys.ENTER) {\n\t Utils.stopEvent(event); // Don't bubble enter otherwise the form submits\n\t }\n\t }\n\n\t /**\n\t * Handles all key up events sent to the search results container.\n\t *\n\t * @param {KeyboardEvent} event The keyboard event object.\n\t * @private\n\t */\n\t _handleKeyUpEvent(event) {\n\t const key = event.keyCode;\n\t const value = this.inputElement.getValue();\n\n\t if (key === Events.Keys.BACKSPACE) {\n\t if (value === '' && this.previousSearchString === '') {\n\t this.options.callbackObject.deletedBeyondSearchInput();\n\t } else {\n\t this.search();\n\t }\n\t } else if (key === Events.Keys.ENTER) {\n\t Utils.stopEvent(event);\n\t // If a search result is highlighted, add it\n\t if (this.getHighlightedSearchResult() !== null) {\n\t this.selectHighlightedSearchResult();\n\t }\n\t } else if (key === Events.Keys.ESCAPE) {\n\t this.closeSearchResults();\n\t } else if (key === Events.Keys.SPACE || key === Events.Keys.DELETE ||\n\t (key >= 48 && key <= 90) || (key >= 96 && key <= 111) || (key >= 186 && key <= 192) || (key >= 219 && key <= 222)) {\n\t this.search();\n\t }\n\t }\n\n\t /**\n\t * Handles mouseover events for the search results (only) by highlighting the event target.\n\t *\n\t * @param {Event} event The mouseover event.\n\t * @private\n\t */\n\t _handleMouseOverEvent(event) {\n\t const target = new PrimeElement(event.currentTarget);\n\t this.highlightSearchResult(target);\n\t }\n\n\t /**\n\t * Removes all of the search results.\n\t *\n\t * @private\n\t */\n\t _removeAllSearchResults() {\n\t this.searchResults.query('li').removeAllFromDOM();\n\t }\n\n\t /* ===================================================================================================================\n\t * Search function implementations.\n\t * ===================================================================================================================*/\n\n\t /**\n\t * Set the initial options for this widget.\n\t * @private\n\t */\n\t _setInitialOptions(callbackObject) {\n\t // Defaults\n\t this.options = {\n\t callbackObject: callbackObject,\n\t closeTimeout: 200,\n\t customAddEnabled: true,\n\t 'customAddCallback'() {\n\t return true;\n\t },\n\t customAddLabel: 'Add Custom: ',\n\t noSearchResultsLabel: 'No Matches For: ',\n\t tooManySearchResultsLabel: 'Too Many Matches For: ',\n\t };\n\n\t const userOptions = Utils.dataSetToOptions(this.inputElement);\n\t for (let option in userOptions) {\n\t if (userOptions.hasOwnProperty(option)) {\n\t this.options[option] = userOptions[option];\n\t }\n\t }\n\t }\n\t}\n\n\t/*\n\t * Copyright (c) 2017, Inversoft Inc., All Rights Reserved\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\");\n\t * you may not use this file except in compliance with the License.\n\t * You may obtain a copy of the License at\n\t *\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing,\n\t * software distributed under the License is distributed on an\n\t * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n\t * either express or implied. See the License for the specific\n\t * language governing permissions and limitations under the License.\n\t */\n\n\tlet count = 1;\n\tlet AddOptionEvent = 'MultipleSelect:addOption';\n\tlet DeselectOptionEvent = 'MultipleSelect:deselectOption';\n\tlet SelectOptionEvent = 'MultipleSelect:selectOption';\n\n\tclass MultipleSelect {\n\t /**\n\t * Constructs a MultipleSelect object for the given element.\n\t *\n\t * The MultipleSelect generates a number of different HTML elements directly after the SELECT element you pass to the\n\t * constructor. A fully rendered MultipleSelect might look something like this:\n\t *\n\t *
\n\t * <select id=\"foo\">\n\t * <option value=\"one\">One</option>\n\t * <option value=\"two\">Two</option>\n\t * <option value=\"three\">Three</option>\n\t * </select>\n\t * <div id=\"foo-display\" class=\"prime-multiple-select\">\n\t * <ul id=\"foo-option-list\" class=\"option-list\">\n\t * <li id=\"foo-option-one\"><span>One</span><a href=\"#\">X</a></li>\n\t * <li id=\"foo-option-two\"><span>Two</span><a href=\"#\">X</a></li>\n\t * <li id=\"foo-option-three\"><span>Three</span><a href=\"#\">X</a></li>\n\t * <li><input type=\"text\" value=\"aaa\"/></li>\n\t * </ul>\n\t * <ul class=\"search-results\">\n\t * <li>One</li>\n\t * <li>Two</li>\n\t * <li>Three</li>\n\t * <li>Add Custom Entry: aaa/li>\n\t * </ul>\n\t * </div>\n\t * \n\t *\n\t * The with* methods can be used to setup the configuration for this MultipleSelect, but here are some defaults:\n\t *\n\t *
\n\t * <div class=\"split-button\">\n\t * <a href=\"#\">Loading... </a>\n\t * <button type=\"button\"></button>\n\t * <div type=\"menu\">\n\t * <a class=\"item\" href=\"/admin/foo/add/\">Add</a>\n\t * <a class=\"item\" href=\"/admin/foo/delete/\">Delete</a>\n\t * </div>\n\t * </ul>\n\t *\n\t *\n\t * Also, it is important to understand how to attach event listeners to the SplitButton. You cannot attach them to\n\t * the individual menu items since those will never be clicked. Instead, you must attach them to the div at the top\n\t * and handle all the events from inside. This is due to how the split button changes the main button based on the\n\t * action the user took last.\n\t *\n\t * @param element {PrimeElement|Element|EventTarget} The element to transform into a split button.\n\t * @constructor\n\t */\n\t constructor(element) {\n\t Utils.bindAll(this);\n\n\t this.element = PrimeElement.wrap(element);\n\t this.currentAction = this.element.queryFirst('a');\n\t if (this.currentAction === null) {\n\t throw new TypeError('The SplitButton element must contain an that is the currently selected action.');\n\t }\n\t this.loading = this.currentAction;\n\n\t this.button = this.element.queryFirst('button');\n\t if (this.button === null) {\n\t throw new TypeError('The SplitButton element must contain a