Repository: dataarts/dat.gui Branch: master Commit: 19c4725d0345 Files: 41 Total size: 630.1 KB Directory structure: gitextract_jimbhtoj/ ├── .babelrc ├── .gitignore ├── API.md ├── LICENSE ├── README.md ├── bower.json ├── build/ │ ├── dat.gui.css │ ├── dat.gui.js │ └── dat.gui.module.js ├── example.html ├── licenseBanner.txt ├── package.json ├── rollup.config.js ├── src/ │ └── dat/ │ ├── color/ │ │ ├── Color.js │ │ ├── interpret.js │ │ ├── math.js │ │ └── toString.js │ ├── controllers/ │ │ ├── BooleanController.js │ │ ├── ColorController.js │ │ ├── Controller.js │ │ ├── ControllerFactory.js │ │ ├── FunctionController.js │ │ ├── NumberController.js │ │ ├── NumberControllerBox.js │ │ ├── NumberControllerSlider.js │ │ ├── OptionController.js │ │ └── StringController.js │ ├── dom/ │ │ ├── CenteredDiv.js │ │ └── dom.js │ ├── gui/ │ │ ├── GUI.js │ │ ├── _structure.scss │ │ ├── saveDialogue.html.js │ │ └── style.scss │ ├── index.js │ └── utils/ │ ├── common.js │ ├── css.js │ └── requestAnimationFrame.js └── tests/ ├── index.html ├── jquery.js ├── qunit.css └── qunit.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [ ["env", { "modules": false }] ] } ================================================ FILE: .gitignore ================================================ .DS_Store .sass-cache .idea/ node_modules/ tmp/ ================================================ FILE: API.md ================================================ # dat.GUI API Details about the classes, methods, and properties provided by dat.GUI. For more hands-on examples, see the dat.GUI [tutorial](http://workshop.chromeexperiments.com/examples/gui). ## Classes
GUI

A lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly.

Controller

An "abstract" class that represents a given property of an object.

NumberControllerdat.controllers.Controller

Represents a given property of an object that is a number.

## GUI A lightweight controller library for JavaScript. It allows you to easily manipulate variables and fire functions on the fly. **Kind**: global class * [GUI](#GUI) * [new GUI([params])](#new_GUI_new) * [.domElement](#GUI+domElement) : DOMElement * [.parent](#GUI+parent) : dat.gui.GUI * [.autoPlace](#GUI+autoPlace) : Boolean * [.closeOnTop](#GUI+closeOnTop) : Boolean * [.preset](#GUI+preset) : String * [.width](#GUI+width) : Number * [.name](#GUI+name) : String * [.closed](#GUI+closed) : Boolean * [.load](#GUI+load) : Object * [.useLocalStorage](#GUI+useLocalStorage) : Boolean * [.add(object, property, [min], [max], [step])](#GUI+add) ⇒ [Controller](#Controller) * [.addColor(object, property)](#GUI+addColor) ⇒ [Controller](#Controller) * [.remove(controller)](#GUI+remove) * [.destroy()](#GUI+destroy) * [.addFolder(name)](#GUI+addFolder) ⇒ dat.gui.GUI * [.removeFolder(folder)](#GUI+removeFolder) * [.open()](#GUI+open) * [.close()](#GUI+close) * [.hide()](#GUI+hide) * [.show()](#GUI+show) * [.getRoot()](#GUI+getRoot) ⇒ dat.gui.GUI * [.getSaveObject()](#GUI+getSaveObject) ⇒ Object ### new GUI([params]) | Param | Type | Default | Description | | --- | --- | --- | --- | | [params] | Object | | | | [params.name] | String | | The name of this GUI. | | [params.load] | Object | | JSON object representing the saved state of this GUI. | | [params.parent] | dat.gui.GUI | | The GUI I'm nested in. | | [params.autoPlace] | Boolean | true | | | [params.hideable] | Boolean | true | If true, GUI is shown/hidden by h keypress. | | [params.closed] | Boolean | false | If true, starts closed | | [params.closeOnTop] | Boolean | false | If true, close/open button shows on top of the GUI | **Example** ```js // Creating a GUI with options. var gui = new dat.GUI({name: 'My GUI'}); ``` **Example** ```js // Creating a GUI and a subfolder. var gui = new dat.GUI(); var folder1 = gui.addFolder('Flow Field'); ``` ### gui.domElement : DOMElement Outermost DOM Element **Kind**: instance property of [GUI](#GUI) ### gui.parent : dat.gui.GUI The parent GUI **Kind**: instance property of [GUI](#GUI) ### gui.autoPlace : Boolean Handles GUI's element placement for you **Kind**: instance property of [GUI](#GUI) ### gui.closeOnTop : Boolean Handles GUI's position of open/close button **Kind**: instance property of [GUI](#GUI) ### gui.preset : String The identifier for a set of saved values **Kind**: instance property of [GUI](#GUI) ### gui.width : Number The width of GUI element **Kind**: instance property of [GUI](#GUI) ### gui.name : String The name of GUI. Used for folders. i.e a folder's name **Kind**: instance property of [GUI](#GUI) ### gui.closed : Boolean Whether the GUI is collapsed or not **Kind**: instance property of [GUI](#GUI) ### gui.load : Object Contains all presets **Kind**: instance property of [GUI](#GUI) ### gui.useLocalStorage : Boolean Determines whether or not to use localStorage as the means for remembering **Kind**: instance property of [GUI](#GUI) ### gui.add(object, property, [min], [max], [step]) ⇒ [Controller](#Controller) Adds a new [Controller](#Controller) to the GUI. The type of controller created is inferred from the initial value of object[property]. For color properties, see [addColor](addColor). **Kind**: instance method of [GUI](#GUI) **Returns**: [Controller](#Controller) - The controller that was added to the GUI. | Param | Type | Description | | --- | --- | --- | | object | Object | The object to be manipulated | | property | String | The name of the property to be manipulated | | [min] | Number | Minimum allowed value | | [max] | Number | Maximum allowed value | | [step] | Number | Increment by which to change value | **Example** ```js // Add a string controller. var person = {name: 'Sam'}; gui.add(person, 'name'); ``` **Example** ```js // Add a number controller slider. var person = {age: 45}; gui.add(person, 'age', 0, 100); ``` ### gui.addColor(object, property) ⇒ [Controller](#Controller) Adds a new color controller to the GUI. **Kind**: instance method of [GUI](#GUI) **Returns**: [Controller](#Controller) - The controller that was added to the GUI. | Param | | --- | | object | | property | **Example** ```js var palette = { color1: '#FF0000', // CSS string color2: [ 0, 128, 255 ], // RGB array color3: [ 0, 128, 255, 0.3 ], // RGB with alpha color4: { h: 350, s: 0.9, v: 0.3 } // Hue, saturation, value }; gui.addColor(palette, 'color1'); gui.addColor(palette, 'color2'); gui.addColor(palette, 'color3'); gui.addColor(palette, 'color4'); ``` ### gui.remove(controller) Removes the given controller from the GUI. **Kind**: instance method of [GUI](#GUI) | Param | Type | | --- | --- | | controller | [Controller](#Controller) | ### gui.destroy() Removes the root GUI from the document and unbinds all event listeners. For subfolders, use `gui.removeFolder(folder)` instead. **Kind**: instance method of [GUI](#GUI) ### gui.addFolder(name) ⇒ dat.gui.GUI Creates a new subfolder GUI instance. **Kind**: instance method of [GUI](#GUI) **Returns**: dat.gui.GUI - The new folder. **Throws**: - Error if this GUI already has a folder by the specified name | Param | | --- | | name | ### gui.removeFolder(folder) Removes a subfolder GUI instance. **Kind**: instance method of [GUI](#GUI) | Param | Type | Description | | --- | --- | --- | | folder | dat.gui.GUI | The folder to remove. | ### gui.open() Opens the GUI. **Kind**: instance method of [GUI](#GUI) ### gui.close() Closes the GUI. **Kind**: instance method of [GUI](#GUI) ### gui.hide() Hides the GUI. **Kind**: instance method of [GUI](#GUI) ### gui.show() Shows the GUI. **Kind**: instance method of [GUI](#GUI) ### gui.getRoot() ⇒ dat.gui.GUI **Kind**: instance method of [GUI](#GUI) **Returns**: dat.gui.GUI - the topmost parent GUI of a nested GUI. ### gui.getSaveObject() ⇒ Object **Kind**: instance method of [GUI](#GUI) **Returns**: Object - a JSON object representing the current state of this GUI as well as its remembered properties. ## Controller An "abstract" class that represents a given property of an object. **Kind**: global class * [Controller](#Controller) * [new Controller(object, property)](#new_Controller_new) * [.domElement](#Controller+domElement) : DOMElement * [.object](#Controller+object) : Object * [.property](#Controller+property) : String * [.options(options)](#Controller+options) ⇒ [Controller](#Controller) * [.name(name)](#Controller+name) ⇒ [Controller](#Controller) * [.listen()](#Controller+listen) ⇒ [Controller](#Controller) * [.remove()](#Controller+remove) ⇒ [Controller](#Controller) * [.onChange(fnc)](#Controller+onChange) ⇒ [Controller](#Controller) * [.onFinishChange(fnc)](#Controller+onFinishChange) ⇒ [Controller](#Controller) * [.setValue(newValue)](#Controller+setValue) * [.getValue()](#Controller+getValue) ⇒ Object * [.updateDisplay()](#Controller+updateDisplay) ⇒ [Controller](#Controller) * [.isModified()](#Controller+isModified) ⇒ Boolean ### new Controller(object, property) | Param | Type | Description | | --- | --- | --- | | object | Object | The object to be manipulated | | property | string | The name of the property to be manipulated | ### controller.domElement : DOMElement Those who extend this class will put their DOM elements in here. **Kind**: instance property of [Controller](#Controller) ### controller.object : Object The object to manipulate **Kind**: instance property of [Controller](#Controller) ### controller.property : String The name of the property to manipulate **Kind**: instance property of [Controller](#Controller) ### controller.options(options) ⇒ [Controller](#Controller) **Kind**: instance method of [Controller](#Controller) | Param | Type | | --- | --- | | options | Array \| Object | ### controller.name(name) ⇒ [Controller](#Controller) Sets the name of the controller. **Kind**: instance method of [Controller](#Controller) | Param | Type | | --- | --- | | name | string | ### controller.listen() ⇒ [Controller](#Controller) Sets controller to listen for changes on its underlying object. **Kind**: instance method of [Controller](#Controller) ### controller.remove() ⇒ [Controller](#Controller) Removes the controller from its parent GUI. **Kind**: instance method of [Controller](#Controller) ### controller.onChange(fnc) ⇒ [Controller](#Controller) Specify that a function fire every time someone changes the value with this Controller. **Kind**: instance method of [Controller](#Controller) **Returns**: [Controller](#Controller) - this | Param | Type | Description | | --- | --- | --- | | fnc | function | This function will be called whenever the value is modified via this Controller. | ### controller.onFinishChange(fnc) ⇒ [Controller](#Controller) Specify that a function fire every time someone "finishes" changing the value wih this Controller. Useful for values that change incrementally like numbers or strings. **Kind**: instance method of [Controller](#Controller) **Returns**: [Controller](#Controller) - this | Param | Type | Description | | --- | --- | --- | | fnc | function | This function will be called whenever someone "finishes" changing the value via this Controller. | ### controller.setValue(newValue) Change the value of object[property] **Kind**: instance method of [Controller](#Controller) | Param | Type | Description | | --- | --- | --- | | newValue | Object | The new value of object[property] | ### controller.getValue() ⇒ Object Gets the value of object[property] **Kind**: instance method of [Controller](#Controller) **Returns**: Object - The current value of object[property] ### controller.updateDisplay() ⇒ [Controller](#Controller) Refreshes the visual display of a Controller in order to keep sync with the object's current value. **Kind**: instance method of [Controller](#Controller) **Returns**: [Controller](#Controller) - this ### controller.isModified() ⇒ Boolean **Kind**: instance method of [Controller](#Controller) **Returns**: Boolean - true if the value has deviated from initialValue ## NumberController ⇐ dat.controllers.Controller Represents a given property of an object that is a number. **Kind**: global class **Extends**: dat.controllers.Controller * [NumberController](#NumberController) ⇐ dat.controllers.Controller * [new NumberController(object, property, [params])](#new_NumberController_new) * [.min(minValue)](#NumberController+min) ⇒ dat.controllers.NumberController * [.max(maxValue)](#NumberController+max) ⇒ dat.controllers.NumberController * [.step(stepValue)](#NumberController+step) ⇒ dat.controllers.NumberController ### new NumberController(object, property, [params]) | Param | Type | Description | | --- | --- | --- | | object | Object | The object to be manipulated | | property | string | The name of the property to be manipulated | | [params] | Object | Optional parameters | | [params.min] | Number | Minimum allowed value | | [params.max] | Number | Maximum allowed value | | [params.step] | Number | Increment by which to change value | ### numberController.min(minValue) ⇒ dat.controllers.NumberController Specify a minimum value for object[property]. **Kind**: instance method of [NumberController](#NumberController) **Returns**: dat.controllers.NumberController - this | Param | Type | Description | | --- | --- | --- | | minValue | Number | The minimum value for object[property] | ### numberController.max(maxValue) ⇒ dat.controllers.NumberController Specify a maximum value for object[property]. **Kind**: instance method of [NumberController](#NumberController) **Returns**: dat.controllers.NumberController - this | Param | Type | Description | | --- | --- | --- | | maxValue | Number | The maximum value for object[property] | ### numberController.step(stepValue) ⇒ dat.controllers.NumberController Specify a step value that dat.controllers.NumberController increments by. **Kind**: instance method of [NumberController](#NumberController) **Default**: if minimum and maximum specified increment is 1% of the difference otherwise stepValue is 1 **Returns**: dat.controllers.NumberController - this | Param | Type | Description | | --- | --- | --- | | stepValue | Number | The step value for dat.controllers.NumberController | ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014, Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ # dat.GUI A lightweight graphical user interface for changing variables in JavaScript. Get started with dat.GUI by reading the [API documentation](API.md). ## Packaged Builds The easiest way to use dat.GUI in your code is by using the built source at `build/dat.gui.min.js`. These built JavaScript files bundle all the necessary dependencies to run dat.GUI. In your `head` tag, include the following code: ```html ``` ## Installing from npm ```bash $ npm install --save dat.gui ``` ```js // CommonJS: const dat = require('dat.gui'); // ES6: import * as dat from 'dat.gui'; const gui = new dat.GUI(); ``` ## Directory Contents ``` ├── build - Compiled source code. ├── src - Source files. └── tests - Tests. ``` ## Building your own dat.GUI In the terminal, enter the following: ``` $ npm install $ npm run build ``` ## npm scripts - npm run build - Build development and production version of scripts. - npm run dev - Build development version of script and watch for changes. ## Working with Content Security Policy If you're using a server with a Content Security Policy in place that blocks 'unsafe-inline', you will have problems when dat.gui.js tries to inject style information. To get around this, load 'build/dat.gui.css' as an external style sheet. ## Changes View the [Change Log](https://github.com/dataarts/dat.gui) ## Thanks The following libraries / open-source projects were used in the development of dat.GUI: * [Rollup](https://rollupjs.org) * [Sass](http://sass-lang.com/) * [Node.js](http://nodejs.org/) * [QUnit](https://github.com/jquery/qunit) / [jquery](http://jquery.com/) ================================================ FILE: bower.json ================================================ { "name": "dat.gui", "homepage": "https://github.com/dataarts/dat.gui.git", "authors": [ "Google Data Arts Team " ], "description": "dat.gui is a lightweight controller library for JavaScript.", "main": "build/dat.gui.js", "keywords": [ "controller", "javascript", "gui", "slider" ], "license": "Apache License, Version 2.0", "ignore": [ "**/.*", "node_modules", "bower_components", "app/bower_components", "test", "tests" ] } ================================================ FILE: build/dat.gui.css ================================================ .dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .cr.function .property-name{width:100%}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda} ================================================ FILE: build/dat.gui.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (factory((global.dat = {}))); }(this, (function (exports) { 'use strict'; function ___$insertStyle(css) { if (!css) { return; } if (typeof window === 'undefined') { return; } var style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.innerHTML = css; document.head.appendChild(style); return css; } function colorToString (color, forceCSSHex) { var colorFormat = color.__state.conversionName.toString(); var r = Math.round(color.r); var g = Math.round(color.g); var b = Math.round(color.b); var a = color.a; var h = Math.round(color.h); var s = color.s.toFixed(1); var v = color.v.toFixed(1); if (forceCSSHex || colorFormat === 'THREE_CHAR_HEX' || colorFormat === 'SIX_CHAR_HEX') { var str = color.hex.toString(16); while (str.length < 6) { str = '0' + str; } return '#' + str; } else if (colorFormat === 'CSS_RGB') { return 'rgb(' + r + ',' + g + ',' + b + ')'; } else if (colorFormat === 'CSS_RGBA') { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; } else if (colorFormat === 'HEX') { return '0x' + color.hex.toString(16); } else if (colorFormat === 'RGB_ARRAY') { return '[' + r + ',' + g + ',' + b + ']'; } else if (colorFormat === 'RGBA_ARRAY') { return '[' + r + ',' + g + ',' + b + ',' + a + ']'; } else if (colorFormat === 'RGB_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + '}'; } else if (colorFormat === 'RGBA_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + ',a:' + a + '}'; } else if (colorFormat === 'HSV_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + '}'; } else if (colorFormat === 'HSVA_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + ',a:' + a + '}'; } return 'unknown format'; } var ARR_EACH = Array.prototype.forEach; var ARR_SLICE = Array.prototype.slice; var Common = { BREAK: {}, extend: function extend(target) { this.each(ARR_SLICE.call(arguments, 1), function (obj) { var keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function (key) { if (!this.isUndefined(obj[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, defaults: function defaults(target) { this.each(ARR_SLICE.call(arguments, 1), function (obj) { var keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function (key) { if (this.isUndefined(target[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, compose: function compose() { var toCall = ARR_SLICE.call(arguments); return function () { var args = ARR_SLICE.call(arguments); for (var i = toCall.length - 1; i >= 0; i--) { args = [toCall[i].apply(this, args)]; } return args[0]; }; }, each: function each(obj, itr, scope) { if (!obj) { return; } if (ARR_EACH && obj.forEach && obj.forEach === ARR_EACH) { obj.forEach(itr, scope); } else if (obj.length === obj.length + 0) { var key = void 0; var l = void 0; for (key = 0, l = obj.length; key < l; key++) { if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) { return; } } } else { for (var _key in obj) { if (itr.call(scope, obj[_key], _key) === this.BREAK) { return; } } } }, defer: function defer(fnc) { setTimeout(fnc, 0); }, debounce: function debounce(func, threshold, callImmediately) { var timeout = void 0; return function () { var obj = this; var args = arguments; function delayed() { timeout = null; if (!callImmediately) func.apply(obj, args); } var callNow = callImmediately || !timeout; clearTimeout(timeout); timeout = setTimeout(delayed, threshold); if (callNow) { func.apply(obj, args); } }; }, toArray: function toArray(obj) { if (obj.toArray) return obj.toArray(); return ARR_SLICE.call(obj); }, isUndefined: function isUndefined(obj) { return obj === undefined; }, isNull: function isNull(obj) { return obj === null; }, isNaN: function (_isNaN) { function isNaN(_x) { return _isNaN.apply(this, arguments); } isNaN.toString = function () { return _isNaN.toString(); }; return isNaN; }(function (obj) { return isNaN(obj); }), isArray: Array.isArray || function (obj) { return obj.constructor === Array; }, isObject: function isObject(obj) { return obj === Object(obj); }, isNumber: function isNumber(obj) { return obj === obj + 0; }, isString: function isString(obj) { return obj === obj + ''; }, isBoolean: function isBoolean(obj) { return obj === false || obj === true; }, isFunction: function isFunction(obj) { return obj instanceof Function; } }; var INTERPRETATIONS = [ { litmus: Common.isString, conversions: { THREE_CHAR_HEX: { read: function read(original) { var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt('0x' + test[1].toString() + test[1].toString() + test[2].toString() + test[2].toString() + test[3].toString() + test[3].toString(), 0) }; }, write: colorToString }, SIX_CHAR_HEX: { read: function read(original) { var test = original.match(/^#([A-F0-9]{6})$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt('0x' + test[1].toString(), 0) }; }, write: colorToString }, CSS_RGB: { read: function read(original) { var test = original.match(/^rgb\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]) }; }, write: colorToString }, CSS_RGBA: { read: function read(original) { var test = original.match(/^rgba\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]), a: parseFloat(test[4]) }; }, write: colorToString } } }, { litmus: Common.isNumber, conversions: { HEX: { read: function read(original) { return { space: 'HEX', hex: original, conversionName: 'HEX' }; }, write: function write(color) { return color.hex; } } } }, { litmus: Common.isArray, conversions: { RGB_ARRAY: { read: function read(original) { if (original.length !== 3) { return false; } return { space: 'RGB', r: original[0], g: original[1], b: original[2] }; }, write: function write(color) { return [color.r, color.g, color.b]; } }, RGBA_ARRAY: { read: function read(original) { if (original.length !== 4) return false; return { space: 'RGB', r: original[0], g: original[1], b: original[2], a: original[3] }; }, write: function write(color) { return [color.r, color.g, color.b, color.a]; } } } }, { litmus: Common.isObject, conversions: { RGBA_OBJ: { read: function read(original) { if (Common.isNumber(original.r) && Common.isNumber(original.g) && Common.isNumber(original.b) && Common.isNumber(original.a)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b, a: original.a }; } return false; }, write: function write(color) { return { r: color.r, g: color.g, b: color.b, a: color.a }; } }, RGB_OBJ: { read: function read(original) { if (Common.isNumber(original.r) && Common.isNumber(original.g) && Common.isNumber(original.b)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b }; } return false; }, write: function write(color) { return { r: color.r, g: color.g, b: color.b }; } }, HSVA_OBJ: { read: function read(original) { if (Common.isNumber(original.h) && Common.isNumber(original.s) && Common.isNumber(original.v) && Common.isNumber(original.a)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v, a: original.a }; } return false; }, write: function write(color) { return { h: color.h, s: color.s, v: color.v, a: color.a }; } }, HSV_OBJ: { read: function read(original) { if (Common.isNumber(original.h) && Common.isNumber(original.s) && Common.isNumber(original.v)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v }; } return false; }, write: function write(color) { return { h: color.h, s: color.s, v: color.v }; } } } }]; var result = void 0; var toReturn = void 0; var interpret = function interpret() { toReturn = false; var original = arguments.length > 1 ? Common.toArray(arguments) : arguments[0]; Common.each(INTERPRETATIONS, function (family) { if (family.litmus(original)) { Common.each(family.conversions, function (conversion, conversionName) { result = conversion.read(original); if (toReturn === false && result !== false) { toReturn = result; result.conversionName = conversionName; result.conversion = conversion; return Common.BREAK; } }); return Common.BREAK; } }); return toReturn; }; var tmpComponent = void 0; var ColorMath = { hsv_to_rgb: function hsv_to_rgb(h, s, v) { var hi = Math.floor(h / 60) % 6; var f = h / 60 - Math.floor(h / 60); var p = v * (1.0 - s); var q = v * (1.0 - f * s); var t = v * (1.0 - (1.0 - f) * s); var c = [[v, t, p], [q, v, p], [p, v, t], [p, q, v], [t, p, v], [v, p, q]][hi]; return { r: c[0] * 255, g: c[1] * 255, b: c[2] * 255 }; }, rgb_to_hsv: function rgb_to_hsv(r, g, b) { var min = Math.min(r, g, b); var max = Math.max(r, g, b); var delta = max - min; var h = void 0; var s = void 0; if (max !== 0) { s = delta / max; } else { return { h: NaN, s: 0, v: 0 }; } if (r === max) { h = (g - b) / delta; } else if (g === max) { h = 2 + (b - r) / delta; } else { h = 4 + (r - g) / delta; } h /= 6; if (h < 0) { h += 1; } return { h: h * 360, s: s, v: max / 255 }; }, rgb_to_hex: function rgb_to_hex(r, g, b) { var hex = this.hex_with_component(0, 2, r); hex = this.hex_with_component(hex, 1, g); hex = this.hex_with_component(hex, 0, b); return hex; }, component_from_hex: function component_from_hex(hex, componentIndex) { return hex >> componentIndex * 8 & 0xFF; }, hex_with_component: function hex_with_component(hex, componentIndex, value) { return value << (tmpComponent = componentIndex * 8) | hex & ~(0xFF << tmpComponent); } }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var Color = function () { function Color() { classCallCheck(this, Color); this.__state = interpret.apply(this, arguments); if (this.__state === false) { throw new Error('Failed to interpret color arguments'); } this.__state.a = this.__state.a || 1; } createClass(Color, [{ key: 'toString', value: function toString() { return colorToString(this); } }, { key: 'toHexString', value: function toHexString() { return colorToString(this, true); } }, { key: 'toOriginal', value: function toOriginal() { return this.__state.conversion.write(this); } }]); return Color; }(); function defineRGBComponent(target, component, componentHexIndex) { Object.defineProperty(target, component, { get: function get$$1() { if (this.__state.space === 'RGB') { return this.__state[component]; } Color.recalculateRGB(this, component, componentHexIndex); return this.__state[component]; }, set: function set$$1(v) { if (this.__state.space !== 'RGB') { Color.recalculateRGB(this, component, componentHexIndex); this.__state.space = 'RGB'; } this.__state[component] = v; } }); } function defineHSVComponent(target, component) { Object.defineProperty(target, component, { get: function get$$1() { if (this.__state.space === 'HSV') { return this.__state[component]; } Color.recalculateHSV(this); return this.__state[component]; }, set: function set$$1(v) { if (this.__state.space !== 'HSV') { Color.recalculateHSV(this); this.__state.space = 'HSV'; } this.__state[component] = v; } }); } Color.recalculateRGB = function (color, component, componentHexIndex) { if (color.__state.space === 'HEX') { color.__state[component] = ColorMath.component_from_hex(color.__state.hex, componentHexIndex); } else if (color.__state.space === 'HSV') { Common.extend(color.__state, ColorMath.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); } else { throw new Error('Corrupted color state'); } }; Color.recalculateHSV = function (color) { var result = ColorMath.rgb_to_hsv(color.r, color.g, color.b); Common.extend(color.__state, { s: result.s, v: result.v }); if (!Common.isNaN(result.h)) { color.__state.h = result.h; } else if (Common.isUndefined(color.__state.h)) { color.__state.h = 0; } }; Color.COMPONENTS = ['r', 'g', 'b', 'h', 's', 'v', 'hex', 'a']; defineRGBComponent(Color.prototype, 'r', 2); defineRGBComponent(Color.prototype, 'g', 1); defineRGBComponent(Color.prototype, 'b', 0); defineHSVComponent(Color.prototype, 'h'); defineHSVComponent(Color.prototype, 's'); defineHSVComponent(Color.prototype, 'v'); Object.defineProperty(Color.prototype, 'a', { get: function get$$1() { return this.__state.a; }, set: function set$$1(v) { this.__state.a = v; } }); Object.defineProperty(Color.prototype, 'hex', { get: function get$$1() { if (this.__state.space !== 'HEX') { this.__state.hex = ColorMath.rgb_to_hex(this.r, this.g, this.b); this.__state.space = 'HEX'; } return this.__state.hex; }, set: function set$$1(v) { this.__state.space = 'HEX'; this.__state.hex = v; } }); var Controller = function () { function Controller(object, property) { classCallCheck(this, Controller); this.initialValue = object[property]; this.domElement = document.createElement('div'); this.object = object; this.property = property; this.__onChange = undefined; this.__onFinishChange = undefined; } createClass(Controller, [{ key: 'onChange', value: function onChange(fnc) { this.__onChange = fnc; return this; } }, { key: 'onFinishChange', value: function onFinishChange(fnc) { this.__onFinishChange = fnc; return this; } }, { key: 'setValue', value: function setValue(newValue) { this.object[this.property] = newValue; if (this.__onChange) { this.__onChange.call(this, newValue); } this.updateDisplay(); return this; } }, { key: 'getValue', value: function getValue() { return this.object[this.property]; } }, { key: 'updateDisplay', value: function updateDisplay() { return this; } }, { key: 'isModified', value: function isModified() { return this.initialValue !== this.getValue(); } }]); return Controller; }(); var EVENT_MAP = { HTMLEvents: ['change'], MouseEvents: ['click', 'mousemove', 'mousedown', 'mouseup', 'mouseover'], KeyboardEvents: ['keydown'] }; var EVENT_MAP_INV = {}; Common.each(EVENT_MAP, function (v, k) { Common.each(v, function (e) { EVENT_MAP_INV[e] = k; }); }); var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; function cssValueToPixels(val) { if (val === '0' || Common.isUndefined(val)) { return 0; } var match = val.match(CSS_VALUE_PIXELS); if (!Common.isNull(match)) { return parseFloat(match[1]); } return 0; } var dom = { makeSelectable: function makeSelectable(elem, selectable) { if (elem === undefined || elem.style === undefined) return; elem.onselectstart = selectable ? function () { return false; } : function () {}; elem.style.MozUserSelect = selectable ? 'auto' : 'none'; elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none'; elem.unselectable = selectable ? 'on' : 'off'; }, makeFullscreen: function makeFullscreen(elem, hor, vert) { var vertical = vert; var horizontal = hor; if (Common.isUndefined(horizontal)) { horizontal = true; } if (Common.isUndefined(vertical)) { vertical = true; } elem.style.position = 'absolute'; if (horizontal) { elem.style.left = 0; elem.style.right = 0; } if (vertical) { elem.style.top = 0; elem.style.bottom = 0; } }, fakeEvent: function fakeEvent(elem, eventType, pars, aux) { var params = pars || {}; var className = EVENT_MAP_INV[eventType]; if (!className) { throw new Error('Event type ' + eventType + ' not supported.'); } var evt = document.createEvent(className); switch (className) { case 'MouseEvents': { var clientX = params.x || params.clientX || 0; var clientY = params.y || params.clientY || 0; evt.initMouseEvent(eventType, params.bubbles || false, params.cancelable || true, window, params.clickCount || 1, 0, 0, clientX, clientY, false, false, false, false, 0, null); break; } case 'KeyboardEvents': { var init = evt.initKeyboardEvent || evt.initKeyEvent; Common.defaults(params, { cancelable: true, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: undefined, charCode: undefined }); init(eventType, params.bubbles || false, params.cancelable, window, params.ctrlKey, params.altKey, params.shiftKey, params.metaKey, params.keyCode, params.charCode); break; } default: { evt.initEvent(eventType, params.bubbles || false, params.cancelable || true); break; } } Common.defaults(evt, aux); elem.dispatchEvent(evt); }, bind: function bind(elem, event, func, newBool) { var bool = newBool || false; if (elem.addEventListener) { elem.addEventListener(event, func, bool); } else if (elem.attachEvent) { elem.attachEvent('on' + event, func); } return dom; }, unbind: function unbind(elem, event, func, newBool) { var bool = newBool || false; if (elem.removeEventListener) { elem.removeEventListener(event, func, bool); } else if (elem.detachEvent) { elem.detachEvent('on' + event, func); } return dom; }, addClass: function addClass(elem, className) { if (elem.className === undefined) { elem.className = className; } else if (elem.className !== className) { var classes = elem.className.split(/ +/); if (classes.indexOf(className) === -1) { classes.push(className); elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, ''); } } return dom; }, removeClass: function removeClass(elem, className) { if (className) { if (elem.className === className) { elem.removeAttribute('class'); } else { var classes = elem.className.split(/ +/); var index = classes.indexOf(className); if (index !== -1) { classes.splice(index, 1); elem.className = classes.join(' '); } } } else { elem.className = undefined; } return dom; }, hasClass: function hasClass(elem, className) { return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false; }, getWidth: function getWidth(elem) { var style = getComputedStyle(elem); return cssValueToPixels(style['border-left-width']) + cssValueToPixels(style['border-right-width']) + cssValueToPixels(style['padding-left']) + cssValueToPixels(style['padding-right']) + cssValueToPixels(style.width); }, getHeight: function getHeight(elem) { var style = getComputedStyle(elem); return cssValueToPixels(style['border-top-width']) + cssValueToPixels(style['border-bottom-width']) + cssValueToPixels(style['padding-top']) + cssValueToPixels(style['padding-bottom']) + cssValueToPixels(style.height); }, getOffset: function getOffset(el) { var elem = el; var offset = { left: 0, top: 0 }; if (elem.offsetParent) { do { offset.left += elem.offsetLeft; offset.top += elem.offsetTop; elem = elem.offsetParent; } while (elem); } return offset; }, isActive: function isActive(elem) { return elem === document.activeElement && (elem.type || elem.href); } }; var BooleanController = function (_Controller) { inherits(BooleanController, _Controller); function BooleanController(object, property) { classCallCheck(this, BooleanController); var _this2 = possibleConstructorReturn(this, (BooleanController.__proto__ || Object.getPrototypeOf(BooleanController)).call(this, object, property)); var _this = _this2; _this2.__prev = _this2.getValue(); _this2.__checkbox = document.createElement('input'); _this2.__checkbox.setAttribute('type', 'checkbox'); function onChange() { _this.setValue(!_this.__prev); } dom.bind(_this2.__checkbox, 'change', onChange, false); _this2.domElement.appendChild(_this2.__checkbox); _this2.updateDisplay(); return _this2; } createClass(BooleanController, [{ key: 'setValue', value: function setValue(v) { var toReturn = get(BooleanController.prototype.__proto__ || Object.getPrototypeOf(BooleanController.prototype), 'setValue', this).call(this, v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } this.__prev = this.getValue(); return toReturn; } }, { key: 'updateDisplay', value: function updateDisplay() { if (this.getValue() === true) { this.__checkbox.setAttribute('checked', 'checked'); this.__checkbox.checked = true; this.__prev = true; } else { this.__checkbox.checked = false; this.__prev = false; } return get(BooleanController.prototype.__proto__ || Object.getPrototypeOf(BooleanController.prototype), 'updateDisplay', this).call(this); } }]); return BooleanController; }(Controller); var OptionController = function (_Controller) { inherits(OptionController, _Controller); function OptionController(object, property, opts) { classCallCheck(this, OptionController); var _this2 = possibleConstructorReturn(this, (OptionController.__proto__ || Object.getPrototypeOf(OptionController)).call(this, object, property)); var options = opts; var _this = _this2; _this2.__select = document.createElement('select'); if (Common.isArray(options)) { var map = {}; Common.each(options, function (element) { map[element] = element; }); options = map; } Common.each(options, function (value, key) { var opt = document.createElement('option'); opt.innerHTML = key; opt.setAttribute('value', value); _this.__select.appendChild(opt); }); _this2.updateDisplay(); dom.bind(_this2.__select, 'change', function () { var desiredValue = this.options[this.selectedIndex].value; _this.setValue(desiredValue); }); _this2.domElement.appendChild(_this2.__select); return _this2; } createClass(OptionController, [{ key: 'setValue', value: function setValue(v) { var toReturn = get(OptionController.prototype.__proto__ || Object.getPrototypeOf(OptionController.prototype), 'setValue', this).call(this, v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } return toReturn; } }, { key: 'updateDisplay', value: function updateDisplay() { if (dom.isActive(this.__select)) return this; this.__select.value = this.getValue(); return get(OptionController.prototype.__proto__ || Object.getPrototypeOf(OptionController.prototype), 'updateDisplay', this).call(this); } }]); return OptionController; }(Controller); var StringController = function (_Controller) { inherits(StringController, _Controller); function StringController(object, property) { classCallCheck(this, StringController); var _this2 = possibleConstructorReturn(this, (StringController.__proto__ || Object.getPrototypeOf(StringController)).call(this, object, property)); var _this = _this2; function onChange() { _this.setValue(_this.__input.value); } function onBlur() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } _this2.__input = document.createElement('input'); _this2.__input.setAttribute('type', 'text'); dom.bind(_this2.__input, 'keyup', onChange); dom.bind(_this2.__input, 'change', onChange); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { this.blur(); } }); _this2.updateDisplay(); _this2.domElement.appendChild(_this2.__input); return _this2; } createClass(StringController, [{ key: 'updateDisplay', value: function updateDisplay() { if (!dom.isActive(this.__input)) { this.__input.value = this.getValue(); } return get(StringController.prototype.__proto__ || Object.getPrototypeOf(StringController.prototype), 'updateDisplay', this).call(this); } }]); return StringController; }(Controller); function numDecimals(x) { var _x = x.toString(); if (_x.indexOf('.') > -1) { return _x.length - _x.indexOf('.') - 1; } return 0; } var NumberController = function (_Controller) { inherits(NumberController, _Controller); function NumberController(object, property, params) { classCallCheck(this, NumberController); var _this = possibleConstructorReturn(this, (NumberController.__proto__ || Object.getPrototypeOf(NumberController)).call(this, object, property)); var _params = params || {}; _this.__min = _params.min; _this.__max = _params.max; _this.__step = _params.step; if (Common.isUndefined(_this.__step)) { if (_this.initialValue === 0) { _this.__impliedStep = 1; } else { _this.__impliedStep = Math.pow(10, Math.floor(Math.log(Math.abs(_this.initialValue)) / Math.LN10)) / 10; } } else { _this.__impliedStep = _this.__step; } _this.__precision = numDecimals(_this.__impliedStep); return _this; } createClass(NumberController, [{ key: 'setValue', value: function setValue(v) { var _v = v; if (this.__min !== undefined && _v < this.__min) { _v = this.__min; } else if (this.__max !== undefined && _v > this.__max) { _v = this.__max; } if (this.__step !== undefined && _v % this.__step !== 0) { _v = Math.round(_v / this.__step) * this.__step; } return get(NumberController.prototype.__proto__ || Object.getPrototypeOf(NumberController.prototype), 'setValue', this).call(this, _v); } }, { key: 'min', value: function min(minValue) { this.__min = minValue; return this; } }, { key: 'max', value: function max(maxValue) { this.__max = maxValue; return this; } }, { key: 'step', value: function step(stepValue) { this.__step = stepValue; this.__impliedStep = stepValue; this.__precision = numDecimals(stepValue); return this; } }]); return NumberController; }(Controller); function roundToDecimal(value, decimals) { var tenTo = Math.pow(10, decimals); return Math.round(value * tenTo) / tenTo; } var NumberControllerBox = function (_NumberController) { inherits(NumberControllerBox, _NumberController); function NumberControllerBox(object, property, params) { classCallCheck(this, NumberControllerBox); var _this2 = possibleConstructorReturn(this, (NumberControllerBox.__proto__ || Object.getPrototypeOf(NumberControllerBox)).call(this, object, property, params)); _this2.__truncationSuspended = false; var _this = _this2; var prevY = void 0; function onChange() { var attempted = parseFloat(_this.__input.value); if (!Common.isNaN(attempted)) { _this.setValue(attempted); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onBlur() { onFinish(); } function onMouseDrag(e) { var diff = prevY - e.clientY; _this.setValue(_this.getValue() + diff * _this.__impliedStep); prevY = e.clientY; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); onFinish(); } function onMouseDown(e) { dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); prevY = e.clientY; } _this2.__input = document.createElement('input'); _this2.__input.setAttribute('type', 'text'); dom.bind(_this2.__input, 'change', onChange); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__input, 'mousedown', onMouseDown); dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { _this.__truncationSuspended = true; this.blur(); _this.__truncationSuspended = false; onFinish(); } }); _this2.updateDisplay(); _this2.domElement.appendChild(_this2.__input); return _this2; } createClass(NumberControllerBox, [{ key: 'updateDisplay', value: function updateDisplay() { this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision); return get(NumberControllerBox.prototype.__proto__ || Object.getPrototypeOf(NumberControllerBox.prototype), 'updateDisplay', this).call(this); } }]); return NumberControllerBox; }(NumberController); function map(v, i1, i2, o1, o2) { return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); } var NumberControllerSlider = function (_NumberController) { inherits(NumberControllerSlider, _NumberController); function NumberControllerSlider(object, property, min, max, step) { classCallCheck(this, NumberControllerSlider); var _this2 = possibleConstructorReturn(this, (NumberControllerSlider.__proto__ || Object.getPrototypeOf(NumberControllerSlider)).call(this, object, property, { min: min, max: max, step: step })); var _this = _this2; _this2.__background = document.createElement('div'); _this2.__foreground = document.createElement('div'); dom.bind(_this2.__background, 'mousedown', onMouseDown); dom.bind(_this2.__background, 'touchstart', onTouchStart); dom.addClass(_this2.__background, 'slider'); dom.addClass(_this2.__foreground, 'slider-fg'); function onMouseDown(e) { document.activeElement.blur(); dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); onMouseDrag(e); } function onMouseDrag(e) { e.preventDefault(); var bgRect = _this.__background.getBoundingClientRect(); _this.setValue(map(e.clientX, bgRect.left, bgRect.right, _this.__min, _this.__max)); return false; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onTouchStart(e) { if (e.touches.length !== 1) { return; } dom.bind(window, 'touchmove', onTouchMove); dom.bind(window, 'touchend', onTouchEnd); onTouchMove(e); } function onTouchMove(e) { var clientX = e.touches[0].clientX; var bgRect = _this.__background.getBoundingClientRect(); _this.setValue(map(clientX, bgRect.left, bgRect.right, _this.__min, _this.__max)); } function onTouchEnd() { dom.unbind(window, 'touchmove', onTouchMove); dom.unbind(window, 'touchend', onTouchEnd); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } _this2.updateDisplay(); _this2.__background.appendChild(_this2.__foreground); _this2.domElement.appendChild(_this2.__background); return _this2; } createClass(NumberControllerSlider, [{ key: 'updateDisplay', value: function updateDisplay() { var pct = (this.getValue() - this.__min) / (this.__max - this.__min); this.__foreground.style.width = pct * 100 + '%'; return get(NumberControllerSlider.prototype.__proto__ || Object.getPrototypeOf(NumberControllerSlider.prototype), 'updateDisplay', this).call(this); } }]); return NumberControllerSlider; }(NumberController); var FunctionController = function (_Controller) { inherits(FunctionController, _Controller); function FunctionController(object, property, text) { classCallCheck(this, FunctionController); var _this2 = possibleConstructorReturn(this, (FunctionController.__proto__ || Object.getPrototypeOf(FunctionController)).call(this, object, property)); var _this = _this2; _this2.__button = document.createElement('div'); _this2.__button.innerHTML = text === undefined ? 'Fire' : text; dom.bind(_this2.__button, 'click', function (e) { e.preventDefault(); _this.fire(); return false; }); dom.addClass(_this2.__button, 'button'); _this2.domElement.appendChild(_this2.__button); return _this2; } createClass(FunctionController, [{ key: 'fire', value: function fire() { if (this.__onChange) { this.__onChange.call(this); } this.getValue().call(this.object); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } } }]); return FunctionController; }(Controller); var ColorController = function (_Controller) { inherits(ColorController, _Controller); function ColorController(object, property) { classCallCheck(this, ColorController); var _this2 = possibleConstructorReturn(this, (ColorController.__proto__ || Object.getPrototypeOf(ColorController)).call(this, object, property)); _this2.__color = new Color(_this2.getValue()); _this2.__temp = new Color(0); var _this = _this2; _this2.domElement = document.createElement('div'); dom.makeSelectable(_this2.domElement, false); _this2.__selector = document.createElement('div'); _this2.__selector.className = 'selector'; _this2.__saturation_field = document.createElement('div'); _this2.__saturation_field.className = 'saturation-field'; _this2.__field_knob = document.createElement('div'); _this2.__field_knob.className = 'field-knob'; _this2.__field_knob_border = '2px solid '; _this2.__hue_knob = document.createElement('div'); _this2.__hue_knob.className = 'hue-knob'; _this2.__hue_field = document.createElement('div'); _this2.__hue_field.className = 'hue-field'; _this2.__input = document.createElement('input'); _this2.__input.type = 'text'; _this2.__input_textShadow = '0 1px 1px '; dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { onBlur.call(this); } }); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__selector, 'mousedown', function () { dom.addClass(this, 'drag').bind(window, 'mouseup', function () { dom.removeClass(_this.__selector, 'drag'); }); }); dom.bind(_this2.__selector, 'touchstart', function () { dom.addClass(this, 'drag').bind(window, 'touchend', function () { dom.removeClass(_this.__selector, 'drag'); }); }); var valueField = document.createElement('div'); Common.extend(_this2.__selector.style, { width: '122px', height: '102px', padding: '3px', backgroundColor: '#222', boxShadow: '0px 1px 3px rgba(0,0,0,0.3)' }); Common.extend(_this2.__field_knob.style, { position: 'absolute', width: '12px', height: '12px', border: _this2.__field_knob_border + (_this2.__color.v < 0.5 ? '#fff' : '#000'), boxShadow: '0px 1px 3px rgba(0,0,0,0.5)', borderRadius: '12px', zIndex: 1 }); Common.extend(_this2.__hue_knob.style, { position: 'absolute', width: '15px', height: '2px', borderRight: '4px solid #fff', zIndex: 1 }); Common.extend(_this2.__saturation_field.style, { width: '100px', height: '100px', border: '1px solid #555', marginRight: '3px', display: 'inline-block', cursor: 'pointer' }); Common.extend(valueField.style, { width: '100%', height: '100%', background: 'none' }); linearGradient(valueField, 'top', 'rgba(0,0,0,0)', '#000'); Common.extend(_this2.__hue_field.style, { width: '15px', height: '100px', border: '1px solid #555', cursor: 'ns-resize', position: 'absolute', top: '3px', right: '3px' }); hueGradient(_this2.__hue_field); Common.extend(_this2.__input.style, { outline: 'none', textAlign: 'center', color: '#fff', border: 0, fontWeight: 'bold', textShadow: _this2.__input_textShadow + 'rgba(0,0,0,0.7)' }); dom.bind(_this2.__saturation_field, 'mousedown', fieldDown); dom.bind(_this2.__saturation_field, 'touchstart', fieldDown); dom.bind(_this2.__field_knob, 'mousedown', fieldDown); dom.bind(_this2.__field_knob, 'touchstart', fieldDown); dom.bind(_this2.__hue_field, 'mousedown', fieldDownH); dom.bind(_this2.__hue_field, 'touchstart', fieldDownH); function fieldDown(e) { setSV(e); dom.bind(window, 'mousemove', setSV); dom.bind(window, 'touchmove', setSV); dom.bind(window, 'mouseup', fieldUpSV); dom.bind(window, 'touchend', fieldUpSV); } function fieldDownH(e) { setH(e); dom.bind(window, 'mousemove', setH); dom.bind(window, 'touchmove', setH); dom.bind(window, 'mouseup', fieldUpH); dom.bind(window, 'touchend', fieldUpH); } function fieldUpSV() { dom.unbind(window, 'mousemove', setSV); dom.unbind(window, 'touchmove', setSV); dom.unbind(window, 'mouseup', fieldUpSV); dom.unbind(window, 'touchend', fieldUpSV); onFinish(); } function fieldUpH() { dom.unbind(window, 'mousemove', setH); dom.unbind(window, 'touchmove', setH); dom.unbind(window, 'mouseup', fieldUpH); dom.unbind(window, 'touchend', fieldUpH); onFinish(); } function onBlur() { var i = interpret(this.value); if (i !== false) { _this.__color.__state = i; _this.setValue(_this.__color.toOriginal()); } else { this.value = _this.__color.toString(); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.__color.toOriginal()); } } _this2.__saturation_field.appendChild(valueField); _this2.__selector.appendChild(_this2.__field_knob); _this2.__selector.appendChild(_this2.__saturation_field); _this2.__selector.appendChild(_this2.__hue_field); _this2.__hue_field.appendChild(_this2.__hue_knob); _this2.domElement.appendChild(_this2.__input); _this2.domElement.appendChild(_this2.__selector); _this2.updateDisplay(); function setSV(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } var fieldRect = _this.__saturation_field.getBoundingClientRect(); var _ref = e.touches && e.touches[0] || e, clientX = _ref.clientX, clientY = _ref.clientY; var s = (clientX - fieldRect.left) / (fieldRect.right - fieldRect.left); var v = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (v > 1) { v = 1; } else if (v < 0) { v = 0; } if (s > 1) { s = 1; } else if (s < 0) { s = 0; } _this.__color.v = v; _this.__color.s = s; _this.setValue(_this.__color.toOriginal()); return false; } function setH(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } var fieldRect = _this.__hue_field.getBoundingClientRect(); var _ref2 = e.touches && e.touches[0] || e, clientY = _ref2.clientY; var h = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (h > 1) { h = 1; } else if (h < 0) { h = 0; } _this.__color.h = h * 360; _this.setValue(_this.__color.toOriginal()); return false; } return _this2; } createClass(ColorController, [{ key: 'updateDisplay', value: function updateDisplay() { var i = interpret(this.getValue()); if (i !== false) { var mismatch = false; Common.each(Color.COMPONENTS, function (component) { if (!Common.isUndefined(i[component]) && !Common.isUndefined(this.__color.__state[component]) && i[component] !== this.__color.__state[component]) { mismatch = true; return {}; } }, this); if (mismatch) { Common.extend(this.__color.__state, i); } } Common.extend(this.__temp.__state, this.__color.__state); this.__temp.a = 1; var flip = this.__color.v < 0.5 || this.__color.s > 0.5 ? 255 : 0; var _flip = 255 - flip; Common.extend(this.__field_knob.style, { marginLeft: 100 * this.__color.s - 7 + 'px', marginTop: 100 * (1 - this.__color.v) - 7 + 'px', backgroundColor: this.__temp.toHexString(), border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip + ')' }); this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px'; this.__temp.s = 1; this.__temp.v = 1; linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toHexString()); this.__input.value = this.__color.toString(); Common.extend(this.__input.style, { backgroundColor: this.__color.toHexString(), color: 'rgb(' + flip + ',' + flip + ',' + flip + ')', textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip + ',.7)' }); } }]); return ColorController; }(Controller); var vendors = ['-moz-', '-o-', '-webkit-', '-ms-', '']; function linearGradient(elem, x, a, b) { elem.style.background = ''; Common.each(vendors, function (vendor) { elem.style.cssText += 'background: ' + vendor + 'linear-gradient(' + x + ', ' + a + ' 0%, ' + b + ' 100%); '; }); } function hueGradient(elem) { elem.style.background = ''; elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'; elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; } var css = { load: function load(url, indoc) { var doc = indoc || document; var link = doc.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = url; doc.getElementsByTagName('head')[0].appendChild(link); }, inject: function inject(cssContent, indoc) { var doc = indoc || document; var injected = document.createElement('style'); injected.type = 'text/css'; injected.innerHTML = cssContent; var head = doc.getElementsByTagName('head')[0]; try { head.appendChild(injected); } catch (e) { } } }; var saveDialogContents = "
\n\n Here's the new load parameter for your GUI's constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI's constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n
"; var ControllerFactory = function ControllerFactory(object, property) { var initialValue = object[property]; if (Common.isArray(arguments[2]) || Common.isObject(arguments[2])) { return new OptionController(object, property, arguments[2]); } if (Common.isNumber(initialValue)) { if (Common.isNumber(arguments[2]) && Common.isNumber(arguments[3])) { if (Common.isNumber(arguments[4])) { return new NumberControllerSlider(object, property, arguments[2], arguments[3], arguments[4]); } return new NumberControllerSlider(object, property, arguments[2], arguments[3]); } if (Common.isNumber(arguments[4])) { return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3], step: arguments[4] }); } return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] }); } if (Common.isString(initialValue)) { return new StringController(object, property); } if (Common.isFunction(initialValue)) { return new FunctionController(object, property, ''); } if (Common.isBoolean(initialValue)) { return new BooleanController(object, property); } return null; }; function requestAnimationFrame(callback) { setTimeout(callback, 1000 / 60); } var requestAnimationFrame$1 = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || requestAnimationFrame; var CenteredDiv = function () { function CenteredDiv() { classCallCheck(this, CenteredDiv); this.backgroundElement = document.createElement('div'); Common.extend(this.backgroundElement.style, { backgroundColor: 'rgba(0,0,0,0.8)', top: 0, left: 0, display: 'none', zIndex: '1000', opacity: 0, WebkitTransition: 'opacity 0.2s linear', transition: 'opacity 0.2s linear' }); dom.makeFullscreen(this.backgroundElement); this.backgroundElement.style.position = 'fixed'; this.domElement = document.createElement('div'); Common.extend(this.domElement.style, { position: 'fixed', display: 'none', zIndex: '1001', opacity: 0, WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear', transition: 'transform 0.2s ease-out, opacity 0.2s linear' }); document.body.appendChild(this.backgroundElement); document.body.appendChild(this.domElement); var _this = this; dom.bind(this.backgroundElement, 'click', function () { _this.hide(); }); } createClass(CenteredDiv, [{ key: 'show', value: function show() { var _this = this; this.backgroundElement.style.display = 'block'; this.domElement.style.display = 'block'; this.domElement.style.opacity = 0; this.domElement.style.webkitTransform = 'scale(1.1)'; this.layout(); Common.defer(function () { _this.backgroundElement.style.opacity = 1; _this.domElement.style.opacity = 1; _this.domElement.style.webkitTransform = 'scale(1)'; }); } }, { key: 'hide', value: function hide() { var _this = this; var hide = function hide() { _this.domElement.style.display = 'none'; _this.backgroundElement.style.display = 'none'; dom.unbind(_this.domElement, 'webkitTransitionEnd', hide); dom.unbind(_this.domElement, 'transitionend', hide); dom.unbind(_this.domElement, 'oTransitionEnd', hide); }; dom.bind(this.domElement, 'webkitTransitionEnd', hide); dom.bind(this.domElement, 'transitionend', hide); dom.bind(this.domElement, 'oTransitionEnd', hide); this.backgroundElement.style.opacity = 0; this.domElement.style.opacity = 0; this.domElement.style.webkitTransform = 'scale(1.1)'; } }, { key: 'layout', value: function layout() { this.domElement.style.left = window.innerWidth / 2 - dom.getWidth(this.domElement) / 2 + 'px'; this.domElement.style.top = window.innerHeight / 2 - dom.getHeight(this.domElement) / 2 + 'px'; } }]); return CenteredDiv; }(); var styleSheet = ___$insertStyle(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .cr.function .property-name{width:100%}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n"); css.inject(styleSheet); var CSS_NAMESPACE = 'dg'; var HIDE_KEY_CODE = 72; var CLOSE_BUTTON_HEIGHT = 20; var DEFAULT_DEFAULT_PRESET_NAME = 'Default'; var SUPPORTS_LOCAL_STORAGE = function () { try { return !!window.localStorage; } catch (e) { return false; } }(); var SAVE_DIALOGUE = void 0; var autoPlaceVirgin = true; var autoPlaceContainer = void 0; var hide = false; var hideableGuis = []; var GUI = function GUI(pars) { var _this = this; var params = pars || {}; this.domElement = document.createElement('div'); this.__ul = document.createElement('ul'); this.domElement.appendChild(this.__ul); dom.addClass(this.domElement, CSS_NAMESPACE); this.__folders = {}; this.__controllers = []; this.__rememberedObjects = []; this.__rememberedObjectIndecesToControllers = []; this.__listening = []; params = Common.defaults(params, { closeOnTop: false, autoPlace: true, width: GUI.DEFAULT_WIDTH }); params = Common.defaults(params, { resizable: params.autoPlace, hideable: params.autoPlace }); if (!Common.isUndefined(params.load)) { if (params.preset) { params.load.preset = params.preset; } } else { params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME }; } if (Common.isUndefined(params.parent) && params.hideable) { hideableGuis.push(this); } params.resizable = Common.isUndefined(params.parent) && params.resizable; if (params.autoPlace && Common.isUndefined(params.scrollable)) { params.scrollable = true; } var useLocalStorage = SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true'; var saveToLocalStorage = void 0; var titleRow = void 0; Object.defineProperties(this, { parent: { get: function get$$1() { return params.parent; } }, scrollable: { get: function get$$1() { return params.scrollable; } }, autoPlace: { get: function get$$1() { return params.autoPlace; } }, closeOnTop: { get: function get$$1() { return params.closeOnTop; } }, preset: { get: function get$$1() { if (_this.parent) { return _this.getRoot().preset; } return params.load.preset; }, set: function set$$1(v) { if (_this.parent) { _this.getRoot().preset = v; } else { params.load.preset = v; } setPresetSelectIndex(this); _this.revert(); } }, width: { get: function get$$1() { return params.width; }, set: function set$$1(v) { params.width = v; setWidth(_this, v); } }, name: { get: function get$$1() { return params.name; }, set: function set$$1(v) { params.name = v; if (titleRow) { titleRow.innerHTML = params.name; } } }, closed: { get: function get$$1() { return params.closed; }, set: function set$$1(v) { params.closed = v; if (params.closed) { dom.addClass(_this.__ul, GUI.CLASS_CLOSED); } else { dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); } this.onResize(); if (_this.__closeButton) { _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED; } } }, load: { get: function get$$1() { return params.load; } }, useLocalStorage: { get: function get$$1() { return useLocalStorage; }, set: function set$$1(bool) { if (SUPPORTS_LOCAL_STORAGE) { useLocalStorage = bool; if (bool) { dom.bind(window, 'unload', saveToLocalStorage); } else { dom.unbind(window, 'unload', saveToLocalStorage); } localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool); } } } }); if (Common.isUndefined(params.parent)) { this.closed = params.closed || false; dom.addClass(this.domElement, GUI.CLASS_MAIN); dom.makeSelectable(this.domElement, false); if (SUPPORTS_LOCAL_STORAGE) { if (useLocalStorage) { _this.useLocalStorage = true; var savedGui = localStorage.getItem(getLocalStorageHash(this, 'gui')); if (savedGui) { params.load = JSON.parse(savedGui); } } } this.__closeButton = document.createElement('div'); this.__closeButton.innerHTML = GUI.TEXT_CLOSED; dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); if (params.closeOnTop) { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_TOP); this.domElement.insertBefore(this.__closeButton, this.domElement.childNodes[0]); } else { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BOTTOM); this.domElement.appendChild(this.__closeButton); } dom.bind(this.__closeButton, 'click', function () { _this.closed = !_this.closed; }); } else { if (params.closed === undefined) { params.closed = true; } var titleRowName = document.createTextNode(params.name); dom.addClass(titleRowName, 'controller-name'); titleRow = addRow(_this, titleRowName); var onClickTitle = function onClickTitle(e) { e.preventDefault(); _this.closed = !_this.closed; return false; }; dom.addClass(this.__ul, GUI.CLASS_CLOSED); dom.addClass(titleRow, 'title'); dom.bind(titleRow, 'click', onClickTitle); if (!params.closed) { this.closed = false; } } if (params.autoPlace) { if (Common.isUndefined(params.parent)) { if (autoPlaceVirgin) { autoPlaceContainer = document.createElement('div'); dom.addClass(autoPlaceContainer, CSS_NAMESPACE); dom.addClass(autoPlaceContainer, GUI.CLASS_AUTO_PLACE_CONTAINER); document.body.appendChild(autoPlaceContainer); autoPlaceVirgin = false; } autoPlaceContainer.appendChild(this.domElement); dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); } if (!this.parent) { setWidth(_this, params.width); } } this.__resizeHandler = function () { _this.onResizeDebounced(); }; dom.bind(window, 'resize', this.__resizeHandler); dom.bind(this.__ul, 'webkitTransitionEnd', this.__resizeHandler); dom.bind(this.__ul, 'transitionend', this.__resizeHandler); dom.bind(this.__ul, 'oTransitionEnd', this.__resizeHandler); this.onResize(); if (params.resizable) { addResizeHandle(this); } saveToLocalStorage = function saveToLocalStorage() { if (SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(_this, 'isLocal')) === 'true') { localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject())); } }; this.saveToLocalStorageIfPossible = saveToLocalStorage; function resetWidth() { var root = _this.getRoot(); root.width += 1; Common.defer(function () { root.width -= 1; }); } if (!params.parent) { resetWidth(); } }; GUI.toggleHide = function () { hide = !hide; Common.each(hideableGuis, function (gui) { gui.domElement.style.display = hide ? 'none' : ''; }); }; GUI.CLASS_AUTO_PLACE = 'a'; GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac'; GUI.CLASS_MAIN = 'main'; GUI.CLASS_CONTROLLER_ROW = 'cr'; GUI.CLASS_TOO_TALL = 'taller-than-window'; GUI.CLASS_CLOSED = 'closed'; GUI.CLASS_CLOSE_BUTTON = 'close-button'; GUI.CLASS_CLOSE_TOP = 'close-top'; GUI.CLASS_CLOSE_BOTTOM = 'close-bottom'; GUI.CLASS_DRAG = 'drag'; GUI.DEFAULT_WIDTH = 245; GUI.TEXT_CLOSED = 'Close Controls'; GUI.TEXT_OPEN = 'Open Controls'; GUI._keydownHandler = function (e) { if (document.activeElement.type !== 'text' && (e.which === HIDE_KEY_CODE || e.keyCode === HIDE_KEY_CODE)) { GUI.toggleHide(); } }; dom.bind(window, 'keydown', GUI._keydownHandler, false); Common.extend(GUI.prototype, { add: function add(object, property) { return _add(this, object, property, { factoryArgs: Array.prototype.slice.call(arguments, 2) }); }, addColor: function addColor(object, property) { return _add(this, object, property, { color: true }); }, remove: function remove(controller) { this.__ul.removeChild(controller.__li); this.__controllers.splice(this.__controllers.indexOf(controller), 1); var _this = this; Common.defer(function () { _this.onResize(); }); }, destroy: function destroy() { if (this.parent) { throw new Error('Only the root GUI should be removed with .destroy(). ' + 'For subfolders, use gui.removeFolder(folder) instead.'); } if (this.autoPlace) { autoPlaceContainer.removeChild(this.domElement); } var _this = this; Common.each(this.__folders, function (subfolder) { _this.removeFolder(subfolder); }); dom.unbind(window, 'keydown', GUI._keydownHandler, false); removeListeners(this); }, addFolder: function addFolder(name) { if (this.__folders[name] !== undefined) { throw new Error('You already have a folder in this GUI by the' + ' name "' + name + '"'); } var newGuiParams = { name: name, parent: this }; newGuiParams.autoPlace = this.autoPlace; if (this.load && this.load.folders && this.load.folders[name]) { newGuiParams.closed = this.load.folders[name].closed; newGuiParams.load = this.load.folders[name]; } var gui = new GUI(newGuiParams); this.__folders[name] = gui; var li = addRow(this, gui.domElement); dom.addClass(li, 'folder'); return gui; }, removeFolder: function removeFolder(folder) { this.__ul.removeChild(folder.domElement.parentElement); delete this.__folders[folder.name]; if (this.load && this.load.folders && this.load.folders[folder.name]) { delete this.load.folders[folder.name]; } removeListeners(folder); var _this = this; Common.each(folder.__folders, function (subfolder) { folder.removeFolder(subfolder); }); Common.defer(function () { _this.onResize(); }); }, open: function open() { this.closed = false; }, close: function close() { this.closed = true; }, hide: function hide() { this.domElement.style.display = 'none'; }, show: function show() { this.domElement.style.display = ''; }, onResize: function onResize() { var root = this.getRoot(); if (root.scrollable) { var top = dom.getOffset(root.__ul).top; var h = 0; Common.each(root.__ul.childNodes, function (node) { if (!(root.autoPlace && node === root.__save_row)) { h += dom.getHeight(node); } }); if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px'; } else { dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = 'auto'; } } if (root.__resize_handle) { Common.defer(function () { root.__resize_handle.style.height = root.__ul.offsetHeight + 'px'; }); } if (root.__closeButton) { root.__closeButton.style.width = root.width + 'px'; } }, onResizeDebounced: Common.debounce(function () { this.onResize(); }, 50), remember: function remember() { if (Common.isUndefined(SAVE_DIALOGUE)) { SAVE_DIALOGUE = new CenteredDiv(); SAVE_DIALOGUE.domElement.innerHTML = saveDialogContents; } if (this.parent) { throw new Error('You can only call remember on a top level GUI.'); } var _this = this; Common.each(Array.prototype.slice.call(arguments), function (object) { if (_this.__rememberedObjects.length === 0) { addSaveMenu(_this); } if (_this.__rememberedObjects.indexOf(object) === -1) { _this.__rememberedObjects.push(object); } }); if (this.autoPlace) { setWidth(this, this.width); } }, getRoot: function getRoot() { var gui = this; while (gui.parent) { gui = gui.parent; } return gui; }, getSaveObject: function getSaveObject() { var toReturn = this.load; toReturn.closed = this.closed; if (this.__rememberedObjects.length > 0) { toReturn.preset = this.preset; if (!toReturn.remembered) { toReturn.remembered = {}; } toReturn.remembered[this.preset] = getCurrentPreset(this); } toReturn.folders = {}; Common.each(this.__folders, function (element, key) { toReturn.folders[key] = element.getSaveObject(); }); return toReturn; }, save: function save() { if (!this.load.remembered) { this.load.remembered = {}; } this.load.remembered[this.preset] = getCurrentPreset(this); markPresetModified(this, false); this.saveToLocalStorageIfPossible(); }, saveAs: function saveAs(presetName) { if (!this.load.remembered) { this.load.remembered = {}; this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); } this.load.remembered[presetName] = getCurrentPreset(this); this.preset = presetName; addPresetOption(this, presetName, true); this.saveToLocalStorageIfPossible(); }, revert: function revert(gui) { Common.each(this.__controllers, function (controller) { if (!this.getRoot().load.remembered) { controller.setValue(controller.initialValue); } else { recallSavedValue(gui || this.getRoot(), controller); } if (controller.__onFinishChange) { controller.__onFinishChange.call(controller, controller.getValue()); } }, this); Common.each(this.__folders, function (folder) { folder.revert(folder); }); if (!gui) { markPresetModified(this.getRoot(), false); } }, listen: function listen(controller) { var init = this.__listening.length === 0; this.__listening.push(controller); if (init) { updateDisplays(this.__listening); } }, updateDisplay: function updateDisplay() { Common.each(this.__controllers, function (controller) { controller.updateDisplay(); }); Common.each(this.__folders, function (folder) { folder.updateDisplay(); }); } }); function addRow(gui, newDom, liBefore) { var li = document.createElement('li'); if (newDom) { li.appendChild(newDom); } if (liBefore) { gui.__ul.insertBefore(li, liBefore); } else { gui.__ul.appendChild(li); } gui.onResize(); return li; } function removeListeners(gui) { dom.unbind(window, 'resize', gui.__resizeHandler); if (gui.saveToLocalStorageIfPossible) { dom.unbind(window, 'unload', gui.saveToLocalStorageIfPossible); } } function markPresetModified(gui, modified) { var opt = gui.__preset_select[gui.__preset_select.selectedIndex]; if (modified) { opt.innerHTML = opt.value + '*'; } else { opt.innerHTML = opt.value; } } function augmentController(gui, li, controller) { controller.__li = li; controller.__gui = gui; Common.extend(controller, { options: function options(_options) { if (arguments.length > 1) { var nextSibling = controller.__li.nextElementSibling; controller.remove(); return _add(gui, controller.object, controller.property, { before: nextSibling, factoryArgs: [Common.toArray(arguments)] }); } if (Common.isArray(_options) || Common.isObject(_options)) { var _nextSibling = controller.__li.nextElementSibling; controller.remove(); return _add(gui, controller.object, controller.property, { before: _nextSibling, factoryArgs: [_options] }); } }, name: function name(_name) { controller.__li.firstElementChild.firstElementChild.innerHTML = _name; return controller; }, listen: function listen() { controller.__gui.listen(controller); return controller; }, remove: function remove() { controller.__gui.remove(controller); return controller; } }); if (controller instanceof NumberControllerSlider) { var box = new NumberControllerBox(controller.object, controller.property, { min: controller.__min, max: controller.__max, step: controller.__step }); Common.each(['updateDisplay', 'onChange', 'onFinishChange', 'step', 'min', 'max'], function (method) { var pc = controller[method]; var pb = box[method]; controller[method] = box[method] = function () { var args = Array.prototype.slice.call(arguments); pb.apply(box, args); return pc.apply(controller, args); }; }); dom.addClass(li, 'has-slider'); controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); } else if (controller instanceof NumberControllerBox) { var r = function r(returned) { if (Common.isNumber(controller.__min) && Common.isNumber(controller.__max)) { var oldName = controller.__li.firstElementChild.firstElementChild.innerHTML; var wasListening = controller.__gui.__listening.indexOf(controller) > -1; controller.remove(); var newController = _add(gui, controller.object, controller.property, { before: controller.__li.nextElementSibling, factoryArgs: [controller.__min, controller.__max, controller.__step] }); newController.name(oldName); if (wasListening) newController.listen(); return newController; } return returned; }; controller.min = Common.compose(r, controller.min); controller.max = Common.compose(r, controller.max); } else if (controller instanceof BooleanController) { dom.bind(li, 'click', function () { dom.fakeEvent(controller.__checkbox, 'click'); }); dom.bind(controller.__checkbox, 'click', function (e) { e.stopPropagation(); }); } else if (controller instanceof FunctionController) { dom.bind(li, 'click', function () { dom.fakeEvent(controller.__button, 'click'); }); dom.bind(li, 'mouseover', function () { dom.addClass(controller.__button, 'hover'); }); dom.bind(li, 'mouseout', function () { dom.removeClass(controller.__button, 'hover'); }); } else if (controller instanceof ColorController) { dom.addClass(li, 'color'); controller.updateDisplay = Common.compose(function (val) { li.style.borderLeftColor = controller.__color.toString(); return val; }, controller.updateDisplay); controller.updateDisplay(); } controller.setValue = Common.compose(function (val) { if (gui.getRoot().__preset_select && controller.isModified()) { markPresetModified(gui.getRoot(), true); } return val; }, controller.setValue); } function recallSavedValue(gui, controller) { var root = gui.getRoot(); var matchedIndex = root.__rememberedObjects.indexOf(controller.object); if (matchedIndex !== -1) { var controllerMap = root.__rememberedObjectIndecesToControllers[matchedIndex]; if (controllerMap === undefined) { controllerMap = {}; root.__rememberedObjectIndecesToControllers[matchedIndex] = controllerMap; } controllerMap[controller.property] = controller; if (root.load && root.load.remembered) { var presetMap = root.load.remembered; var preset = void 0; if (presetMap[gui.preset]) { preset = presetMap[gui.preset]; } else if (presetMap[DEFAULT_DEFAULT_PRESET_NAME]) { preset = presetMap[DEFAULT_DEFAULT_PRESET_NAME]; } else { return; } if (preset[matchedIndex] && preset[matchedIndex][controller.property] !== undefined) { var value = preset[matchedIndex][controller.property]; controller.initialValue = value; controller.setValue(value); } } } } function _add(gui, object, property, params) { if (object[property] === undefined) { throw new Error('Object "' + object + '" has no property "' + property + '"'); } var controller = void 0; if (params.color) { controller = new ColorController(object, property); } else { var factoryArgs = [object, property].concat(params.factoryArgs); controller = ControllerFactory.apply(gui, factoryArgs); } if (params.before instanceof Controller) { params.before = params.before.__li; } recallSavedValue(gui, controller); dom.addClass(controller.domElement, 'c'); var name = document.createElement('span'); dom.addClass(name, 'property-name'); name.innerHTML = controller.property; var container = document.createElement('div'); container.appendChild(name); container.appendChild(controller.domElement); var li = addRow(gui, container, params.before); dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); if (controller instanceof ColorController) { dom.addClass(li, 'color'); } else { dom.addClass(li, _typeof(controller.getValue())); } augmentController(gui, li, controller); gui.__controllers.push(controller); return controller; } function getLocalStorageHash(gui, key) { return document.location.href + '.' + key; } function addPresetOption(gui, name, setSelected) { var opt = document.createElement('option'); opt.innerHTML = name; opt.value = name; gui.__preset_select.appendChild(opt); if (setSelected) { gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; } } function showHideExplain(gui, explain) { explain.style.display = gui.useLocalStorage ? 'block' : 'none'; } function addSaveMenu(gui) { var div = gui.__save_row = document.createElement('li'); dom.addClass(gui.domElement, 'has-save'); gui.__ul.insertBefore(div, gui.__ul.firstChild); dom.addClass(div, 'save-row'); var gears = document.createElement('span'); gears.innerHTML = ' '; dom.addClass(gears, 'button gears'); var button = document.createElement('span'); button.innerHTML = 'Save'; dom.addClass(button, 'button'); dom.addClass(button, 'save'); var button2 = document.createElement('span'); button2.innerHTML = 'New'; dom.addClass(button2, 'button'); dom.addClass(button2, 'save-as'); var button3 = document.createElement('span'); button3.innerHTML = 'Revert'; dom.addClass(button3, 'button'); dom.addClass(button3, 'revert'); var select = gui.__preset_select = document.createElement('select'); if (gui.load && gui.load.remembered) { Common.each(gui.load.remembered, function (value, key) { addPresetOption(gui, key, key === gui.preset); }); } else { addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); } dom.bind(select, 'change', function () { for (var index = 0; index < gui.__preset_select.length; index++) { gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; } gui.preset = this.value; }); div.appendChild(select); div.appendChild(gears); div.appendChild(button); div.appendChild(button2); div.appendChild(button3); if (SUPPORTS_LOCAL_STORAGE) { var explain = document.getElementById('dg-local-explain'); var localStorageCheckBox = document.getElementById('dg-local-storage'); var saveLocally = document.getElementById('dg-save-locally'); saveLocally.style.display = 'block'; if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') { localStorageCheckBox.setAttribute('checked', 'checked'); } showHideExplain(gui, explain); dom.bind(localStorageCheckBox, 'change', function () { gui.useLocalStorage = !gui.useLocalStorage; showHideExplain(gui, explain); }); } var newConstructorTextArea = document.getElementById('dg-new-constructor'); dom.bind(newConstructorTextArea, 'keydown', function (e) { if (e.metaKey && (e.which === 67 || e.keyCode === 67)) { SAVE_DIALOGUE.hide(); } }); dom.bind(gears, 'click', function () { newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); SAVE_DIALOGUE.show(); newConstructorTextArea.focus(); newConstructorTextArea.select(); }); dom.bind(button, 'click', function () { gui.save(); }); dom.bind(button2, 'click', function () { var presetName = prompt('Enter a new preset name.'); if (presetName) { gui.saveAs(presetName); } }); dom.bind(button3, 'click', function () { gui.revert(); }); } function addResizeHandle(gui) { var pmouseX = void 0; gui.__resize_handle = document.createElement('div'); Common.extend(gui.__resize_handle.style, { width: '6px', marginLeft: '-3px', height: '200px', cursor: 'ew-resize', position: 'absolute' }); function drag(e) { e.preventDefault(); gui.width += pmouseX - e.clientX; gui.onResize(); pmouseX = e.clientX; return false; } function dragStop() { dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); dom.unbind(window, 'mousemove', drag); dom.unbind(window, 'mouseup', dragStop); } function dragStart(e) { e.preventDefault(); pmouseX = e.clientX; dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); dom.bind(window, 'mousemove', drag); dom.bind(window, 'mouseup', dragStop); return false; } dom.bind(gui.__resize_handle, 'mousedown', dragStart); dom.bind(gui.__closeButton, 'mousedown', dragStart); gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); } function setWidth(gui, w) { gui.domElement.style.width = w + 'px'; if (gui.__save_row && gui.autoPlace) { gui.__save_row.style.width = w + 'px'; } if (gui.__closeButton) { gui.__closeButton.style.width = w + 'px'; } } function getCurrentPreset(gui, useInitialValues) { var toReturn = {}; Common.each(gui.__rememberedObjects, function (val, index) { var savedValues = {}; var controllerMap = gui.__rememberedObjectIndecesToControllers[index]; Common.each(controllerMap, function (controller, property) { savedValues[property] = useInitialValues ? controller.initialValue : controller.getValue(); }); toReturn[index] = savedValues; }); return toReturn; } function setPresetSelectIndex(gui) { for (var index = 0; index < gui.__preset_select.length; index++) { if (gui.__preset_select[index].value === gui.preset) { gui.__preset_select.selectedIndex = index; } } } function updateDisplays(controllerArray) { if (controllerArray.length !== 0) { requestAnimationFrame$1.call(window, function () { updateDisplays(controllerArray); }); } Common.each(controllerArray, function (c) { c.updateDisplay(); }); } var color = { Color: Color, math: ColorMath, interpret: interpret }; var controllers = { Controller: Controller, BooleanController: BooleanController, OptionController: OptionController, StringController: StringController, NumberController: NumberController, NumberControllerBox: NumberControllerBox, NumberControllerSlider: NumberControllerSlider, FunctionController: FunctionController, ColorController: ColorController }; var dom$1 = { dom: dom }; var gui = { GUI: GUI }; var GUI$1 = GUI; var index = { color: color, controllers: controllers, dom: dom$1, gui: gui, GUI: GUI$1 }; exports.color = color; exports.controllers = controllers; exports.dom = dom$1; exports.gui = gui; exports.GUI = GUI$1; exports['default'] = index; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=dat.gui.js.map ================================================ FILE: build/dat.gui.module.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ function ___$insertStyle(css) { if (!css) { return; } if (typeof window === 'undefined') { return; } var style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.innerHTML = css; document.head.appendChild(style); return css; } function colorToString (color, forceCSSHex) { var colorFormat = color.__state.conversionName.toString(); var r = Math.round(color.r); var g = Math.round(color.g); var b = Math.round(color.b); var a = color.a; var h = Math.round(color.h); var s = color.s.toFixed(1); var v = color.v.toFixed(1); if (forceCSSHex || colorFormat === 'THREE_CHAR_HEX' || colorFormat === 'SIX_CHAR_HEX') { var str = color.hex.toString(16); while (str.length < 6) { str = '0' + str; } return '#' + str; } else if (colorFormat === 'CSS_RGB') { return 'rgb(' + r + ',' + g + ',' + b + ')'; } else if (colorFormat === 'CSS_RGBA') { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; } else if (colorFormat === 'HEX') { return '0x' + color.hex.toString(16); } else if (colorFormat === 'RGB_ARRAY') { return '[' + r + ',' + g + ',' + b + ']'; } else if (colorFormat === 'RGBA_ARRAY') { return '[' + r + ',' + g + ',' + b + ',' + a + ']'; } else if (colorFormat === 'RGB_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + '}'; } else if (colorFormat === 'RGBA_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + ',a:' + a + '}'; } else if (colorFormat === 'HSV_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + '}'; } else if (colorFormat === 'HSVA_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + ',a:' + a + '}'; } return 'unknown format'; } var ARR_EACH = Array.prototype.forEach; var ARR_SLICE = Array.prototype.slice; var Common = { BREAK: {}, extend: function extend(target) { this.each(ARR_SLICE.call(arguments, 1), function (obj) { var keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function (key) { if (!this.isUndefined(obj[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, defaults: function defaults(target) { this.each(ARR_SLICE.call(arguments, 1), function (obj) { var keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function (key) { if (this.isUndefined(target[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, compose: function compose() { var toCall = ARR_SLICE.call(arguments); return function () { var args = ARR_SLICE.call(arguments); for (var i = toCall.length - 1; i >= 0; i--) { args = [toCall[i].apply(this, args)]; } return args[0]; }; }, each: function each(obj, itr, scope) { if (!obj) { return; } if (ARR_EACH && obj.forEach && obj.forEach === ARR_EACH) { obj.forEach(itr, scope); } else if (obj.length === obj.length + 0) { var key = void 0; var l = void 0; for (key = 0, l = obj.length; key < l; key++) { if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) { return; } } } else { for (var _key in obj) { if (itr.call(scope, obj[_key], _key) === this.BREAK) { return; } } } }, defer: function defer(fnc) { setTimeout(fnc, 0); }, debounce: function debounce(func, threshold, callImmediately) { var timeout = void 0; return function () { var obj = this; var args = arguments; function delayed() { timeout = null; if (!callImmediately) func.apply(obj, args); } var callNow = callImmediately || !timeout; clearTimeout(timeout); timeout = setTimeout(delayed, threshold); if (callNow) { func.apply(obj, args); } }; }, toArray: function toArray(obj) { if (obj.toArray) return obj.toArray(); return ARR_SLICE.call(obj); }, isUndefined: function isUndefined(obj) { return obj === undefined; }, isNull: function isNull(obj) { return obj === null; }, isNaN: function (_isNaN) { function isNaN(_x) { return _isNaN.apply(this, arguments); } isNaN.toString = function () { return _isNaN.toString(); }; return isNaN; }(function (obj) { return isNaN(obj); }), isArray: Array.isArray || function (obj) { return obj.constructor === Array; }, isObject: function isObject(obj) { return obj === Object(obj); }, isNumber: function isNumber(obj) { return obj === obj + 0; }, isString: function isString(obj) { return obj === obj + ''; }, isBoolean: function isBoolean(obj) { return obj === false || obj === true; }, isFunction: function isFunction(obj) { return obj instanceof Function; } }; var INTERPRETATIONS = [ { litmus: Common.isString, conversions: { THREE_CHAR_HEX: { read: function read(original) { var test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt('0x' + test[1].toString() + test[1].toString() + test[2].toString() + test[2].toString() + test[3].toString() + test[3].toString(), 0) }; }, write: colorToString }, SIX_CHAR_HEX: { read: function read(original) { var test = original.match(/^#([A-F0-9]{6})$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt('0x' + test[1].toString(), 0) }; }, write: colorToString }, CSS_RGB: { read: function read(original) { var test = original.match(/^rgb\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]) }; }, write: colorToString }, CSS_RGBA: { read: function read(original) { var test = original.match(/^rgba\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]), a: parseFloat(test[4]) }; }, write: colorToString } } }, { litmus: Common.isNumber, conversions: { HEX: { read: function read(original) { return { space: 'HEX', hex: original, conversionName: 'HEX' }; }, write: function write(color) { return color.hex; } } } }, { litmus: Common.isArray, conversions: { RGB_ARRAY: { read: function read(original) { if (original.length !== 3) { return false; } return { space: 'RGB', r: original[0], g: original[1], b: original[2] }; }, write: function write(color) { return [color.r, color.g, color.b]; } }, RGBA_ARRAY: { read: function read(original) { if (original.length !== 4) return false; return { space: 'RGB', r: original[0], g: original[1], b: original[2], a: original[3] }; }, write: function write(color) { return [color.r, color.g, color.b, color.a]; } } } }, { litmus: Common.isObject, conversions: { RGBA_OBJ: { read: function read(original) { if (Common.isNumber(original.r) && Common.isNumber(original.g) && Common.isNumber(original.b) && Common.isNumber(original.a)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b, a: original.a }; } return false; }, write: function write(color) { return { r: color.r, g: color.g, b: color.b, a: color.a }; } }, RGB_OBJ: { read: function read(original) { if (Common.isNumber(original.r) && Common.isNumber(original.g) && Common.isNumber(original.b)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b }; } return false; }, write: function write(color) { return { r: color.r, g: color.g, b: color.b }; } }, HSVA_OBJ: { read: function read(original) { if (Common.isNumber(original.h) && Common.isNumber(original.s) && Common.isNumber(original.v) && Common.isNumber(original.a)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v, a: original.a }; } return false; }, write: function write(color) { return { h: color.h, s: color.s, v: color.v, a: color.a }; } }, HSV_OBJ: { read: function read(original) { if (Common.isNumber(original.h) && Common.isNumber(original.s) && Common.isNumber(original.v)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v }; } return false; }, write: function write(color) { return { h: color.h, s: color.s, v: color.v }; } } } }]; var result = void 0; var toReturn = void 0; var interpret = function interpret() { toReturn = false; var original = arguments.length > 1 ? Common.toArray(arguments) : arguments[0]; Common.each(INTERPRETATIONS, function (family) { if (family.litmus(original)) { Common.each(family.conversions, function (conversion, conversionName) { result = conversion.read(original); if (toReturn === false && result !== false) { toReturn = result; result.conversionName = conversionName; result.conversion = conversion; return Common.BREAK; } }); return Common.BREAK; } }); return toReturn; }; var tmpComponent = void 0; var ColorMath = { hsv_to_rgb: function hsv_to_rgb(h, s, v) { var hi = Math.floor(h / 60) % 6; var f = h / 60 - Math.floor(h / 60); var p = v * (1.0 - s); var q = v * (1.0 - f * s); var t = v * (1.0 - (1.0 - f) * s); var c = [[v, t, p], [q, v, p], [p, v, t], [p, q, v], [t, p, v], [v, p, q]][hi]; return { r: c[0] * 255, g: c[1] * 255, b: c[2] * 255 }; }, rgb_to_hsv: function rgb_to_hsv(r, g, b) { var min = Math.min(r, g, b); var max = Math.max(r, g, b); var delta = max - min; var h = void 0; var s = void 0; if (max !== 0) { s = delta / max; } else { return { h: NaN, s: 0, v: 0 }; } if (r === max) { h = (g - b) / delta; } else if (g === max) { h = 2 + (b - r) / delta; } else { h = 4 + (r - g) / delta; } h /= 6; if (h < 0) { h += 1; } return { h: h * 360, s: s, v: max / 255 }; }, rgb_to_hex: function rgb_to_hex(r, g, b) { var hex = this.hex_with_component(0, 2, r); hex = this.hex_with_component(hex, 1, g); hex = this.hex_with_component(hex, 0, b); return hex; }, component_from_hex: function component_from_hex(hex, componentIndex) { return hex >> componentIndex * 8 & 0xFF; }, hex_with_component: function hex_with_component(hex, componentIndex, value) { return value << (tmpComponent = componentIndex * 8) | hex & ~(0xFF << tmpComponent); } }; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; var inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }; var possibleConstructorReturn = function (self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var Color = function () { function Color() { classCallCheck(this, Color); this.__state = interpret.apply(this, arguments); if (this.__state === false) { throw new Error('Failed to interpret color arguments'); } this.__state.a = this.__state.a || 1; } createClass(Color, [{ key: 'toString', value: function toString() { return colorToString(this); } }, { key: 'toHexString', value: function toHexString() { return colorToString(this, true); } }, { key: 'toOriginal', value: function toOriginal() { return this.__state.conversion.write(this); } }]); return Color; }(); function defineRGBComponent(target, component, componentHexIndex) { Object.defineProperty(target, component, { get: function get$$1() { if (this.__state.space === 'RGB') { return this.__state[component]; } Color.recalculateRGB(this, component, componentHexIndex); return this.__state[component]; }, set: function set$$1(v) { if (this.__state.space !== 'RGB') { Color.recalculateRGB(this, component, componentHexIndex); this.__state.space = 'RGB'; } this.__state[component] = v; } }); } function defineHSVComponent(target, component) { Object.defineProperty(target, component, { get: function get$$1() { if (this.__state.space === 'HSV') { return this.__state[component]; } Color.recalculateHSV(this); return this.__state[component]; }, set: function set$$1(v) { if (this.__state.space !== 'HSV') { Color.recalculateHSV(this); this.__state.space = 'HSV'; } this.__state[component] = v; } }); } Color.recalculateRGB = function (color, component, componentHexIndex) { if (color.__state.space === 'HEX') { color.__state[component] = ColorMath.component_from_hex(color.__state.hex, componentHexIndex); } else if (color.__state.space === 'HSV') { Common.extend(color.__state, ColorMath.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); } else { throw new Error('Corrupted color state'); } }; Color.recalculateHSV = function (color) { var result = ColorMath.rgb_to_hsv(color.r, color.g, color.b); Common.extend(color.__state, { s: result.s, v: result.v }); if (!Common.isNaN(result.h)) { color.__state.h = result.h; } else if (Common.isUndefined(color.__state.h)) { color.__state.h = 0; } }; Color.COMPONENTS = ['r', 'g', 'b', 'h', 's', 'v', 'hex', 'a']; defineRGBComponent(Color.prototype, 'r', 2); defineRGBComponent(Color.prototype, 'g', 1); defineRGBComponent(Color.prototype, 'b', 0); defineHSVComponent(Color.prototype, 'h'); defineHSVComponent(Color.prototype, 's'); defineHSVComponent(Color.prototype, 'v'); Object.defineProperty(Color.prototype, 'a', { get: function get$$1() { return this.__state.a; }, set: function set$$1(v) { this.__state.a = v; } }); Object.defineProperty(Color.prototype, 'hex', { get: function get$$1() { if (this.__state.space !== 'HEX') { this.__state.hex = ColorMath.rgb_to_hex(this.r, this.g, this.b); this.__state.space = 'HEX'; } return this.__state.hex; }, set: function set$$1(v) { this.__state.space = 'HEX'; this.__state.hex = v; } }); var Controller = function () { function Controller(object, property) { classCallCheck(this, Controller); this.initialValue = object[property]; this.domElement = document.createElement('div'); this.object = object; this.property = property; this.__onChange = undefined; this.__onFinishChange = undefined; } createClass(Controller, [{ key: 'onChange', value: function onChange(fnc) { this.__onChange = fnc; return this; } }, { key: 'onFinishChange', value: function onFinishChange(fnc) { this.__onFinishChange = fnc; return this; } }, { key: 'setValue', value: function setValue(newValue) { this.object[this.property] = newValue; if (this.__onChange) { this.__onChange.call(this, newValue); } this.updateDisplay(); return this; } }, { key: 'getValue', value: function getValue() { return this.object[this.property]; } }, { key: 'updateDisplay', value: function updateDisplay() { return this; } }, { key: 'isModified', value: function isModified() { return this.initialValue !== this.getValue(); } }]); return Controller; }(); var EVENT_MAP = { HTMLEvents: ['change'], MouseEvents: ['click', 'mousemove', 'mousedown', 'mouseup', 'mouseover'], KeyboardEvents: ['keydown'] }; var EVENT_MAP_INV = {}; Common.each(EVENT_MAP, function (v, k) { Common.each(v, function (e) { EVENT_MAP_INV[e] = k; }); }); var CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; function cssValueToPixels(val) { if (val === '0' || Common.isUndefined(val)) { return 0; } var match = val.match(CSS_VALUE_PIXELS); if (!Common.isNull(match)) { return parseFloat(match[1]); } return 0; } var dom = { makeSelectable: function makeSelectable(elem, selectable) { if (elem === undefined || elem.style === undefined) return; elem.onselectstart = selectable ? function () { return false; } : function () {}; elem.style.MozUserSelect = selectable ? 'auto' : 'none'; elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none'; elem.unselectable = selectable ? 'on' : 'off'; }, makeFullscreen: function makeFullscreen(elem, hor, vert) { var vertical = vert; var horizontal = hor; if (Common.isUndefined(horizontal)) { horizontal = true; } if (Common.isUndefined(vertical)) { vertical = true; } elem.style.position = 'absolute'; if (horizontal) { elem.style.left = 0; elem.style.right = 0; } if (vertical) { elem.style.top = 0; elem.style.bottom = 0; } }, fakeEvent: function fakeEvent(elem, eventType, pars, aux) { var params = pars || {}; var className = EVENT_MAP_INV[eventType]; if (!className) { throw new Error('Event type ' + eventType + ' not supported.'); } var evt = document.createEvent(className); switch (className) { case 'MouseEvents': { var clientX = params.x || params.clientX || 0; var clientY = params.y || params.clientY || 0; evt.initMouseEvent(eventType, params.bubbles || false, params.cancelable || true, window, params.clickCount || 1, 0, 0, clientX, clientY, false, false, false, false, 0, null); break; } case 'KeyboardEvents': { var init = evt.initKeyboardEvent || evt.initKeyEvent; Common.defaults(params, { cancelable: true, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: undefined, charCode: undefined }); init(eventType, params.bubbles || false, params.cancelable, window, params.ctrlKey, params.altKey, params.shiftKey, params.metaKey, params.keyCode, params.charCode); break; } default: { evt.initEvent(eventType, params.bubbles || false, params.cancelable || true); break; } } Common.defaults(evt, aux); elem.dispatchEvent(evt); }, bind: function bind(elem, event, func, newBool) { var bool = newBool || false; if (elem.addEventListener) { elem.addEventListener(event, func, bool); } else if (elem.attachEvent) { elem.attachEvent('on' + event, func); } return dom; }, unbind: function unbind(elem, event, func, newBool) { var bool = newBool || false; if (elem.removeEventListener) { elem.removeEventListener(event, func, bool); } else if (elem.detachEvent) { elem.detachEvent('on' + event, func); } return dom; }, addClass: function addClass(elem, className) { if (elem.className === undefined) { elem.className = className; } else if (elem.className !== className) { var classes = elem.className.split(/ +/); if (classes.indexOf(className) === -1) { classes.push(className); elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, ''); } } return dom; }, removeClass: function removeClass(elem, className) { if (className) { if (elem.className === className) { elem.removeAttribute('class'); } else { var classes = elem.className.split(/ +/); var index = classes.indexOf(className); if (index !== -1) { classes.splice(index, 1); elem.className = classes.join(' '); } } } else { elem.className = undefined; } return dom; }, hasClass: function hasClass(elem, className) { return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false; }, getWidth: function getWidth(elem) { var style = getComputedStyle(elem); return cssValueToPixels(style['border-left-width']) + cssValueToPixels(style['border-right-width']) + cssValueToPixels(style['padding-left']) + cssValueToPixels(style['padding-right']) + cssValueToPixels(style.width); }, getHeight: function getHeight(elem) { var style = getComputedStyle(elem); return cssValueToPixels(style['border-top-width']) + cssValueToPixels(style['border-bottom-width']) + cssValueToPixels(style['padding-top']) + cssValueToPixels(style['padding-bottom']) + cssValueToPixels(style.height); }, getOffset: function getOffset(el) { var elem = el; var offset = { left: 0, top: 0 }; if (elem.offsetParent) { do { offset.left += elem.offsetLeft; offset.top += elem.offsetTop; elem = elem.offsetParent; } while (elem); } return offset; }, isActive: function isActive(elem) { return elem === document.activeElement && (elem.type || elem.href); } }; var BooleanController = function (_Controller) { inherits(BooleanController, _Controller); function BooleanController(object, property) { classCallCheck(this, BooleanController); var _this2 = possibleConstructorReturn(this, (BooleanController.__proto__ || Object.getPrototypeOf(BooleanController)).call(this, object, property)); var _this = _this2; _this2.__prev = _this2.getValue(); _this2.__checkbox = document.createElement('input'); _this2.__checkbox.setAttribute('type', 'checkbox'); function onChange() { _this.setValue(!_this.__prev); } dom.bind(_this2.__checkbox, 'change', onChange, false); _this2.domElement.appendChild(_this2.__checkbox); _this2.updateDisplay(); return _this2; } createClass(BooleanController, [{ key: 'setValue', value: function setValue(v) { var toReturn = get(BooleanController.prototype.__proto__ || Object.getPrototypeOf(BooleanController.prototype), 'setValue', this).call(this, v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } this.__prev = this.getValue(); return toReturn; } }, { key: 'updateDisplay', value: function updateDisplay() { if (this.getValue() === true) { this.__checkbox.setAttribute('checked', 'checked'); this.__checkbox.checked = true; this.__prev = true; } else { this.__checkbox.checked = false; this.__prev = false; } return get(BooleanController.prototype.__proto__ || Object.getPrototypeOf(BooleanController.prototype), 'updateDisplay', this).call(this); } }]); return BooleanController; }(Controller); var OptionController = function (_Controller) { inherits(OptionController, _Controller); function OptionController(object, property, opts) { classCallCheck(this, OptionController); var _this2 = possibleConstructorReturn(this, (OptionController.__proto__ || Object.getPrototypeOf(OptionController)).call(this, object, property)); var options = opts; var _this = _this2; _this2.__select = document.createElement('select'); if (Common.isArray(options)) { var map = {}; Common.each(options, function (element) { map[element] = element; }); options = map; } Common.each(options, function (value, key) { var opt = document.createElement('option'); opt.innerHTML = key; opt.setAttribute('value', value); _this.__select.appendChild(opt); }); _this2.updateDisplay(); dom.bind(_this2.__select, 'change', function () { var desiredValue = this.options[this.selectedIndex].value; _this.setValue(desiredValue); }); _this2.domElement.appendChild(_this2.__select); return _this2; } createClass(OptionController, [{ key: 'setValue', value: function setValue(v) { var toReturn = get(OptionController.prototype.__proto__ || Object.getPrototypeOf(OptionController.prototype), 'setValue', this).call(this, v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } return toReturn; } }, { key: 'updateDisplay', value: function updateDisplay() { if (dom.isActive(this.__select)) return this; this.__select.value = this.getValue(); return get(OptionController.prototype.__proto__ || Object.getPrototypeOf(OptionController.prototype), 'updateDisplay', this).call(this); } }]); return OptionController; }(Controller); var StringController = function (_Controller) { inherits(StringController, _Controller); function StringController(object, property) { classCallCheck(this, StringController); var _this2 = possibleConstructorReturn(this, (StringController.__proto__ || Object.getPrototypeOf(StringController)).call(this, object, property)); var _this = _this2; function onChange() { _this.setValue(_this.__input.value); } function onBlur() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } _this2.__input = document.createElement('input'); _this2.__input.setAttribute('type', 'text'); dom.bind(_this2.__input, 'keyup', onChange); dom.bind(_this2.__input, 'change', onChange); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { this.blur(); } }); _this2.updateDisplay(); _this2.domElement.appendChild(_this2.__input); return _this2; } createClass(StringController, [{ key: 'updateDisplay', value: function updateDisplay() { if (!dom.isActive(this.__input)) { this.__input.value = this.getValue(); } return get(StringController.prototype.__proto__ || Object.getPrototypeOf(StringController.prototype), 'updateDisplay', this).call(this); } }]); return StringController; }(Controller); function numDecimals(x) { var _x = x.toString(); if (_x.indexOf('.') > -1) { return _x.length - _x.indexOf('.') - 1; } return 0; } var NumberController = function (_Controller) { inherits(NumberController, _Controller); function NumberController(object, property, params) { classCallCheck(this, NumberController); var _this = possibleConstructorReturn(this, (NumberController.__proto__ || Object.getPrototypeOf(NumberController)).call(this, object, property)); var _params = params || {}; _this.__min = _params.min; _this.__max = _params.max; _this.__step = _params.step; if (Common.isUndefined(_this.__step)) { if (_this.initialValue === 0) { _this.__impliedStep = 1; } else { _this.__impliedStep = Math.pow(10, Math.floor(Math.log(Math.abs(_this.initialValue)) / Math.LN10)) / 10; } } else { _this.__impliedStep = _this.__step; } _this.__precision = numDecimals(_this.__impliedStep); return _this; } createClass(NumberController, [{ key: 'setValue', value: function setValue(v) { var _v = v; if (this.__min !== undefined && _v < this.__min) { _v = this.__min; } else if (this.__max !== undefined && _v > this.__max) { _v = this.__max; } if (this.__step !== undefined && _v % this.__step !== 0) { _v = Math.round(_v / this.__step) * this.__step; } return get(NumberController.prototype.__proto__ || Object.getPrototypeOf(NumberController.prototype), 'setValue', this).call(this, _v); } }, { key: 'min', value: function min(minValue) { this.__min = minValue; return this; } }, { key: 'max', value: function max(maxValue) { this.__max = maxValue; return this; } }, { key: 'step', value: function step(stepValue) { this.__step = stepValue; this.__impliedStep = stepValue; this.__precision = numDecimals(stepValue); return this; } }]); return NumberController; }(Controller); function roundToDecimal(value, decimals) { var tenTo = Math.pow(10, decimals); return Math.round(value * tenTo) / tenTo; } var NumberControllerBox = function (_NumberController) { inherits(NumberControllerBox, _NumberController); function NumberControllerBox(object, property, params) { classCallCheck(this, NumberControllerBox); var _this2 = possibleConstructorReturn(this, (NumberControllerBox.__proto__ || Object.getPrototypeOf(NumberControllerBox)).call(this, object, property, params)); _this2.__truncationSuspended = false; var _this = _this2; var prevY = void 0; function onChange() { var attempted = parseFloat(_this.__input.value); if (!Common.isNaN(attempted)) { _this.setValue(attempted); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onBlur() { onFinish(); } function onMouseDrag(e) { var diff = prevY - e.clientY; _this.setValue(_this.getValue() + diff * _this.__impliedStep); prevY = e.clientY; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); onFinish(); } function onMouseDown(e) { dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); prevY = e.clientY; } _this2.__input = document.createElement('input'); _this2.__input.setAttribute('type', 'text'); dom.bind(_this2.__input, 'change', onChange); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__input, 'mousedown', onMouseDown); dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { _this.__truncationSuspended = true; this.blur(); _this.__truncationSuspended = false; onFinish(); } }); _this2.updateDisplay(); _this2.domElement.appendChild(_this2.__input); return _this2; } createClass(NumberControllerBox, [{ key: 'updateDisplay', value: function updateDisplay() { this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision); return get(NumberControllerBox.prototype.__proto__ || Object.getPrototypeOf(NumberControllerBox.prototype), 'updateDisplay', this).call(this); } }]); return NumberControllerBox; }(NumberController); function map(v, i1, i2, o1, o2) { return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); } var NumberControllerSlider = function (_NumberController) { inherits(NumberControllerSlider, _NumberController); function NumberControllerSlider(object, property, min, max, step) { classCallCheck(this, NumberControllerSlider); var _this2 = possibleConstructorReturn(this, (NumberControllerSlider.__proto__ || Object.getPrototypeOf(NumberControllerSlider)).call(this, object, property, { min: min, max: max, step: step })); var _this = _this2; _this2.__background = document.createElement('div'); _this2.__foreground = document.createElement('div'); dom.bind(_this2.__background, 'mousedown', onMouseDown); dom.bind(_this2.__background, 'touchstart', onTouchStart); dom.addClass(_this2.__background, 'slider'); dom.addClass(_this2.__foreground, 'slider-fg'); function onMouseDown(e) { document.activeElement.blur(); dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); onMouseDrag(e); } function onMouseDrag(e) { e.preventDefault(); var bgRect = _this.__background.getBoundingClientRect(); _this.setValue(map(e.clientX, bgRect.left, bgRect.right, _this.__min, _this.__max)); return false; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onTouchStart(e) { if (e.touches.length !== 1) { return; } dom.bind(window, 'touchmove', onTouchMove); dom.bind(window, 'touchend', onTouchEnd); onTouchMove(e); } function onTouchMove(e) { var clientX = e.touches[0].clientX; var bgRect = _this.__background.getBoundingClientRect(); _this.setValue(map(clientX, bgRect.left, bgRect.right, _this.__min, _this.__max)); } function onTouchEnd() { dom.unbind(window, 'touchmove', onTouchMove); dom.unbind(window, 'touchend', onTouchEnd); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } _this2.updateDisplay(); _this2.__background.appendChild(_this2.__foreground); _this2.domElement.appendChild(_this2.__background); return _this2; } createClass(NumberControllerSlider, [{ key: 'updateDisplay', value: function updateDisplay() { var pct = (this.getValue() - this.__min) / (this.__max - this.__min); this.__foreground.style.width = pct * 100 + '%'; return get(NumberControllerSlider.prototype.__proto__ || Object.getPrototypeOf(NumberControllerSlider.prototype), 'updateDisplay', this).call(this); } }]); return NumberControllerSlider; }(NumberController); var FunctionController = function (_Controller) { inherits(FunctionController, _Controller); function FunctionController(object, property, text) { classCallCheck(this, FunctionController); var _this2 = possibleConstructorReturn(this, (FunctionController.__proto__ || Object.getPrototypeOf(FunctionController)).call(this, object, property)); var _this = _this2; _this2.__button = document.createElement('div'); _this2.__button.innerHTML = text === undefined ? 'Fire' : text; dom.bind(_this2.__button, 'click', function (e) { e.preventDefault(); _this.fire(); return false; }); dom.addClass(_this2.__button, 'button'); _this2.domElement.appendChild(_this2.__button); return _this2; } createClass(FunctionController, [{ key: 'fire', value: function fire() { if (this.__onChange) { this.__onChange.call(this); } this.getValue().call(this.object); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } } }]); return FunctionController; }(Controller); var ColorController = function (_Controller) { inherits(ColorController, _Controller); function ColorController(object, property) { classCallCheck(this, ColorController); var _this2 = possibleConstructorReturn(this, (ColorController.__proto__ || Object.getPrototypeOf(ColorController)).call(this, object, property)); _this2.__color = new Color(_this2.getValue()); _this2.__temp = new Color(0); var _this = _this2; _this2.domElement = document.createElement('div'); dom.makeSelectable(_this2.domElement, false); _this2.__selector = document.createElement('div'); _this2.__selector.className = 'selector'; _this2.__saturation_field = document.createElement('div'); _this2.__saturation_field.className = 'saturation-field'; _this2.__field_knob = document.createElement('div'); _this2.__field_knob.className = 'field-knob'; _this2.__field_knob_border = '2px solid '; _this2.__hue_knob = document.createElement('div'); _this2.__hue_knob.className = 'hue-knob'; _this2.__hue_field = document.createElement('div'); _this2.__hue_field.className = 'hue-field'; _this2.__input = document.createElement('input'); _this2.__input.type = 'text'; _this2.__input_textShadow = '0 1px 1px '; dom.bind(_this2.__input, 'keydown', function (e) { if (e.keyCode === 13) { onBlur.call(this); } }); dom.bind(_this2.__input, 'blur', onBlur); dom.bind(_this2.__selector, 'mousedown', function () { dom.addClass(this, 'drag').bind(window, 'mouseup', function () { dom.removeClass(_this.__selector, 'drag'); }); }); dom.bind(_this2.__selector, 'touchstart', function () { dom.addClass(this, 'drag').bind(window, 'touchend', function () { dom.removeClass(_this.__selector, 'drag'); }); }); var valueField = document.createElement('div'); Common.extend(_this2.__selector.style, { width: '122px', height: '102px', padding: '3px', backgroundColor: '#222', boxShadow: '0px 1px 3px rgba(0,0,0,0.3)' }); Common.extend(_this2.__field_knob.style, { position: 'absolute', width: '12px', height: '12px', border: _this2.__field_knob_border + (_this2.__color.v < 0.5 ? '#fff' : '#000'), boxShadow: '0px 1px 3px rgba(0,0,0,0.5)', borderRadius: '12px', zIndex: 1 }); Common.extend(_this2.__hue_knob.style, { position: 'absolute', width: '15px', height: '2px', borderRight: '4px solid #fff', zIndex: 1 }); Common.extend(_this2.__saturation_field.style, { width: '100px', height: '100px', border: '1px solid #555', marginRight: '3px', display: 'inline-block', cursor: 'pointer' }); Common.extend(valueField.style, { width: '100%', height: '100%', background: 'none' }); linearGradient(valueField, 'top', 'rgba(0,0,0,0)', '#000'); Common.extend(_this2.__hue_field.style, { width: '15px', height: '100px', border: '1px solid #555', cursor: 'ns-resize', position: 'absolute', top: '3px', right: '3px' }); hueGradient(_this2.__hue_field); Common.extend(_this2.__input.style, { outline: 'none', textAlign: 'center', color: '#fff', border: 0, fontWeight: 'bold', textShadow: _this2.__input_textShadow + 'rgba(0,0,0,0.7)' }); dom.bind(_this2.__saturation_field, 'mousedown', fieldDown); dom.bind(_this2.__saturation_field, 'touchstart', fieldDown); dom.bind(_this2.__field_knob, 'mousedown', fieldDown); dom.bind(_this2.__field_knob, 'touchstart', fieldDown); dom.bind(_this2.__hue_field, 'mousedown', fieldDownH); dom.bind(_this2.__hue_field, 'touchstart', fieldDownH); function fieldDown(e) { setSV(e); dom.bind(window, 'mousemove', setSV); dom.bind(window, 'touchmove', setSV); dom.bind(window, 'mouseup', fieldUpSV); dom.bind(window, 'touchend', fieldUpSV); } function fieldDownH(e) { setH(e); dom.bind(window, 'mousemove', setH); dom.bind(window, 'touchmove', setH); dom.bind(window, 'mouseup', fieldUpH); dom.bind(window, 'touchend', fieldUpH); } function fieldUpSV() { dom.unbind(window, 'mousemove', setSV); dom.unbind(window, 'touchmove', setSV); dom.unbind(window, 'mouseup', fieldUpSV); dom.unbind(window, 'touchend', fieldUpSV); onFinish(); } function fieldUpH() { dom.unbind(window, 'mousemove', setH); dom.unbind(window, 'touchmove', setH); dom.unbind(window, 'mouseup', fieldUpH); dom.unbind(window, 'touchend', fieldUpH); onFinish(); } function onBlur() { var i = interpret(this.value); if (i !== false) { _this.__color.__state = i; _this.setValue(_this.__color.toOriginal()); } else { this.value = _this.__color.toString(); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.__color.toOriginal()); } } _this2.__saturation_field.appendChild(valueField); _this2.__selector.appendChild(_this2.__field_knob); _this2.__selector.appendChild(_this2.__saturation_field); _this2.__selector.appendChild(_this2.__hue_field); _this2.__hue_field.appendChild(_this2.__hue_knob); _this2.domElement.appendChild(_this2.__input); _this2.domElement.appendChild(_this2.__selector); _this2.updateDisplay(); function setSV(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } var fieldRect = _this.__saturation_field.getBoundingClientRect(); var _ref = e.touches && e.touches[0] || e, clientX = _ref.clientX, clientY = _ref.clientY; var s = (clientX - fieldRect.left) / (fieldRect.right - fieldRect.left); var v = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (v > 1) { v = 1; } else if (v < 0) { v = 0; } if (s > 1) { s = 1; } else if (s < 0) { s = 0; } _this.__color.v = v; _this.__color.s = s; _this.setValue(_this.__color.toOriginal()); return false; } function setH(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } var fieldRect = _this.__hue_field.getBoundingClientRect(); var _ref2 = e.touches && e.touches[0] || e, clientY = _ref2.clientY; var h = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (h > 1) { h = 1; } else if (h < 0) { h = 0; } _this.__color.h = h * 360; _this.setValue(_this.__color.toOriginal()); return false; } return _this2; } createClass(ColorController, [{ key: 'updateDisplay', value: function updateDisplay() { var i = interpret(this.getValue()); if (i !== false) { var mismatch = false; Common.each(Color.COMPONENTS, function (component) { if (!Common.isUndefined(i[component]) && !Common.isUndefined(this.__color.__state[component]) && i[component] !== this.__color.__state[component]) { mismatch = true; return {}; } }, this); if (mismatch) { Common.extend(this.__color.__state, i); } } Common.extend(this.__temp.__state, this.__color.__state); this.__temp.a = 1; var flip = this.__color.v < 0.5 || this.__color.s > 0.5 ? 255 : 0; var _flip = 255 - flip; Common.extend(this.__field_knob.style, { marginLeft: 100 * this.__color.s - 7 + 'px', marginTop: 100 * (1 - this.__color.v) - 7 + 'px', backgroundColor: this.__temp.toHexString(), border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip + ')' }); this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px'; this.__temp.s = 1; this.__temp.v = 1; linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toHexString()); this.__input.value = this.__color.toString(); Common.extend(this.__input.style, { backgroundColor: this.__color.toHexString(), color: 'rgb(' + flip + ',' + flip + ',' + flip + ')', textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip + ',.7)' }); } }]); return ColorController; }(Controller); var vendors = ['-moz-', '-o-', '-webkit-', '-ms-', '']; function linearGradient(elem, x, a, b) { elem.style.background = ''; Common.each(vendors, function (vendor) { elem.style.cssText += 'background: ' + vendor + 'linear-gradient(' + x + ', ' + a + ' 0%, ' + b + ' 100%); '; }); } function hueGradient(elem) { elem.style.background = ''; elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'; elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; } var css = { load: function load(url, indoc) { var doc = indoc || document; var link = doc.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = url; doc.getElementsByTagName('head')[0].appendChild(link); }, inject: function inject(cssContent, indoc) { var doc = indoc || document; var injected = document.createElement('style'); injected.type = 'text/css'; injected.innerHTML = cssContent; var head = doc.getElementsByTagName('head')[0]; try { head.appendChild(injected); } catch (e) { } } }; var saveDialogContents = "
\n\n Here's the new load parameter for your GUI's constructor:\n\n \n\n
\n\n Automatically save\n values to localStorage on exit.\n\n
The values saved to localStorage will\n override those passed to dat.GUI's constructor. This makes it\n easier to work incrementally, but localStorage is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n
"; var ControllerFactory = function ControllerFactory(object, property) { var initialValue = object[property]; if (Common.isArray(arguments[2]) || Common.isObject(arguments[2])) { return new OptionController(object, property, arguments[2]); } if (Common.isNumber(initialValue)) { if (Common.isNumber(arguments[2]) && Common.isNumber(arguments[3])) { if (Common.isNumber(arguments[4])) { return new NumberControllerSlider(object, property, arguments[2], arguments[3], arguments[4]); } return new NumberControllerSlider(object, property, arguments[2], arguments[3]); } if (Common.isNumber(arguments[4])) { return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3], step: arguments[4] }); } return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] }); } if (Common.isString(initialValue)) { return new StringController(object, property); } if (Common.isFunction(initialValue)) { return new FunctionController(object, property, ''); } if (Common.isBoolean(initialValue)) { return new BooleanController(object, property); } return null; }; function requestAnimationFrame(callback) { setTimeout(callback, 1000 / 60); } var requestAnimationFrame$1 = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || requestAnimationFrame; var CenteredDiv = function () { function CenteredDiv() { classCallCheck(this, CenteredDiv); this.backgroundElement = document.createElement('div'); Common.extend(this.backgroundElement.style, { backgroundColor: 'rgba(0,0,0,0.8)', top: 0, left: 0, display: 'none', zIndex: '1000', opacity: 0, WebkitTransition: 'opacity 0.2s linear', transition: 'opacity 0.2s linear' }); dom.makeFullscreen(this.backgroundElement); this.backgroundElement.style.position = 'fixed'; this.domElement = document.createElement('div'); Common.extend(this.domElement.style, { position: 'fixed', display: 'none', zIndex: '1001', opacity: 0, WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear', transition: 'transform 0.2s ease-out, opacity 0.2s linear' }); document.body.appendChild(this.backgroundElement); document.body.appendChild(this.domElement); var _this = this; dom.bind(this.backgroundElement, 'click', function () { _this.hide(); }); } createClass(CenteredDiv, [{ key: 'show', value: function show() { var _this = this; this.backgroundElement.style.display = 'block'; this.domElement.style.display = 'block'; this.domElement.style.opacity = 0; this.domElement.style.webkitTransform = 'scale(1.1)'; this.layout(); Common.defer(function () { _this.backgroundElement.style.opacity = 1; _this.domElement.style.opacity = 1; _this.domElement.style.webkitTransform = 'scale(1)'; }); } }, { key: 'hide', value: function hide() { var _this = this; var hide = function hide() { _this.domElement.style.display = 'none'; _this.backgroundElement.style.display = 'none'; dom.unbind(_this.domElement, 'webkitTransitionEnd', hide); dom.unbind(_this.domElement, 'transitionend', hide); dom.unbind(_this.domElement, 'oTransitionEnd', hide); }; dom.bind(this.domElement, 'webkitTransitionEnd', hide); dom.bind(this.domElement, 'transitionend', hide); dom.bind(this.domElement, 'oTransitionEnd', hide); this.backgroundElement.style.opacity = 0; this.domElement.style.opacity = 0; this.domElement.style.webkitTransform = 'scale(1.1)'; } }, { key: 'layout', value: function layout() { this.domElement.style.left = window.innerWidth / 2 - dom.getWidth(this.domElement) / 2 + 'px'; this.domElement.style.top = window.innerHeight / 2 - dom.getHeight(this.domElement) / 2 + 'px'; } }]); return CenteredDiv; }(); var styleSheet = ___$insertStyle(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .cr.function .property-name{width:100%}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n"); css.inject(styleSheet); var CSS_NAMESPACE = 'dg'; var HIDE_KEY_CODE = 72; var CLOSE_BUTTON_HEIGHT = 20; var DEFAULT_DEFAULT_PRESET_NAME = 'Default'; var SUPPORTS_LOCAL_STORAGE = function () { try { return !!window.localStorage; } catch (e) { return false; } }(); var SAVE_DIALOGUE = void 0; var autoPlaceVirgin = true; var autoPlaceContainer = void 0; var hide = false; var hideableGuis = []; var GUI = function GUI(pars) { var _this = this; var params = pars || {}; this.domElement = document.createElement('div'); this.__ul = document.createElement('ul'); this.domElement.appendChild(this.__ul); dom.addClass(this.domElement, CSS_NAMESPACE); this.__folders = {}; this.__controllers = []; this.__rememberedObjects = []; this.__rememberedObjectIndecesToControllers = []; this.__listening = []; params = Common.defaults(params, { closeOnTop: false, autoPlace: true, width: GUI.DEFAULT_WIDTH }); params = Common.defaults(params, { resizable: params.autoPlace, hideable: params.autoPlace }); if (!Common.isUndefined(params.load)) { if (params.preset) { params.load.preset = params.preset; } } else { params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME }; } if (Common.isUndefined(params.parent) && params.hideable) { hideableGuis.push(this); } params.resizable = Common.isUndefined(params.parent) && params.resizable; if (params.autoPlace && Common.isUndefined(params.scrollable)) { params.scrollable = true; } var useLocalStorage = SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true'; var saveToLocalStorage = void 0; var titleRow = void 0; Object.defineProperties(this, { parent: { get: function get$$1() { return params.parent; } }, scrollable: { get: function get$$1() { return params.scrollable; } }, autoPlace: { get: function get$$1() { return params.autoPlace; } }, closeOnTop: { get: function get$$1() { return params.closeOnTop; } }, preset: { get: function get$$1() { if (_this.parent) { return _this.getRoot().preset; } return params.load.preset; }, set: function set$$1(v) { if (_this.parent) { _this.getRoot().preset = v; } else { params.load.preset = v; } setPresetSelectIndex(this); _this.revert(); } }, width: { get: function get$$1() { return params.width; }, set: function set$$1(v) { params.width = v; setWidth(_this, v); } }, name: { get: function get$$1() { return params.name; }, set: function set$$1(v) { params.name = v; if (titleRow) { titleRow.innerHTML = params.name; } } }, closed: { get: function get$$1() { return params.closed; }, set: function set$$1(v) { params.closed = v; if (params.closed) { dom.addClass(_this.__ul, GUI.CLASS_CLOSED); } else { dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); } this.onResize(); if (_this.__closeButton) { _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED; } } }, load: { get: function get$$1() { return params.load; } }, useLocalStorage: { get: function get$$1() { return useLocalStorage; }, set: function set$$1(bool) { if (SUPPORTS_LOCAL_STORAGE) { useLocalStorage = bool; if (bool) { dom.bind(window, 'unload', saveToLocalStorage); } else { dom.unbind(window, 'unload', saveToLocalStorage); } localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool); } } } }); if (Common.isUndefined(params.parent)) { this.closed = params.closed || false; dom.addClass(this.domElement, GUI.CLASS_MAIN); dom.makeSelectable(this.domElement, false); if (SUPPORTS_LOCAL_STORAGE) { if (useLocalStorage) { _this.useLocalStorage = true; var savedGui = localStorage.getItem(getLocalStorageHash(this, 'gui')); if (savedGui) { params.load = JSON.parse(savedGui); } } } this.__closeButton = document.createElement('div'); this.__closeButton.innerHTML = GUI.TEXT_CLOSED; dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); if (params.closeOnTop) { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_TOP); this.domElement.insertBefore(this.__closeButton, this.domElement.childNodes[0]); } else { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BOTTOM); this.domElement.appendChild(this.__closeButton); } dom.bind(this.__closeButton, 'click', function () { _this.closed = !_this.closed; }); } else { if (params.closed === undefined) { params.closed = true; } var titleRowName = document.createTextNode(params.name); dom.addClass(titleRowName, 'controller-name'); titleRow = addRow(_this, titleRowName); var onClickTitle = function onClickTitle(e) { e.preventDefault(); _this.closed = !_this.closed; return false; }; dom.addClass(this.__ul, GUI.CLASS_CLOSED); dom.addClass(titleRow, 'title'); dom.bind(titleRow, 'click', onClickTitle); if (!params.closed) { this.closed = false; } } if (params.autoPlace) { if (Common.isUndefined(params.parent)) { if (autoPlaceVirgin) { autoPlaceContainer = document.createElement('div'); dom.addClass(autoPlaceContainer, CSS_NAMESPACE); dom.addClass(autoPlaceContainer, GUI.CLASS_AUTO_PLACE_CONTAINER); document.body.appendChild(autoPlaceContainer); autoPlaceVirgin = false; } autoPlaceContainer.appendChild(this.domElement); dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); } if (!this.parent) { setWidth(_this, params.width); } } this.__resizeHandler = function () { _this.onResizeDebounced(); }; dom.bind(window, 'resize', this.__resizeHandler); dom.bind(this.__ul, 'webkitTransitionEnd', this.__resizeHandler); dom.bind(this.__ul, 'transitionend', this.__resizeHandler); dom.bind(this.__ul, 'oTransitionEnd', this.__resizeHandler); this.onResize(); if (params.resizable) { addResizeHandle(this); } saveToLocalStorage = function saveToLocalStorage() { if (SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(_this, 'isLocal')) === 'true') { localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject())); } }; this.saveToLocalStorageIfPossible = saveToLocalStorage; function resetWidth() { var root = _this.getRoot(); root.width += 1; Common.defer(function () { root.width -= 1; }); } if (!params.parent) { resetWidth(); } }; GUI.toggleHide = function () { hide = !hide; Common.each(hideableGuis, function (gui) { gui.domElement.style.display = hide ? 'none' : ''; }); }; GUI.CLASS_AUTO_PLACE = 'a'; GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac'; GUI.CLASS_MAIN = 'main'; GUI.CLASS_CONTROLLER_ROW = 'cr'; GUI.CLASS_TOO_TALL = 'taller-than-window'; GUI.CLASS_CLOSED = 'closed'; GUI.CLASS_CLOSE_BUTTON = 'close-button'; GUI.CLASS_CLOSE_TOP = 'close-top'; GUI.CLASS_CLOSE_BOTTOM = 'close-bottom'; GUI.CLASS_DRAG = 'drag'; GUI.DEFAULT_WIDTH = 245; GUI.TEXT_CLOSED = 'Close Controls'; GUI.TEXT_OPEN = 'Open Controls'; GUI._keydownHandler = function (e) { if (document.activeElement.type !== 'text' && (e.which === HIDE_KEY_CODE || e.keyCode === HIDE_KEY_CODE)) { GUI.toggleHide(); } }; dom.bind(window, 'keydown', GUI._keydownHandler, false); Common.extend(GUI.prototype, { add: function add(object, property) { return _add(this, object, property, { factoryArgs: Array.prototype.slice.call(arguments, 2) }); }, addColor: function addColor(object, property) { return _add(this, object, property, { color: true }); }, remove: function remove(controller) { this.__ul.removeChild(controller.__li); this.__controllers.splice(this.__controllers.indexOf(controller), 1); var _this = this; Common.defer(function () { _this.onResize(); }); }, destroy: function destroy() { if (this.parent) { throw new Error('Only the root GUI should be removed with .destroy(). ' + 'For subfolders, use gui.removeFolder(folder) instead.'); } if (this.autoPlace) { autoPlaceContainer.removeChild(this.domElement); } var _this = this; Common.each(this.__folders, function (subfolder) { _this.removeFolder(subfolder); }); dom.unbind(window, 'keydown', GUI._keydownHandler, false); removeListeners(this); }, addFolder: function addFolder(name) { if (this.__folders[name] !== undefined) { throw new Error('You already have a folder in this GUI by the' + ' name "' + name + '"'); } var newGuiParams = { name: name, parent: this }; newGuiParams.autoPlace = this.autoPlace; if (this.load && this.load.folders && this.load.folders[name]) { newGuiParams.closed = this.load.folders[name].closed; newGuiParams.load = this.load.folders[name]; } var gui = new GUI(newGuiParams); this.__folders[name] = gui; var li = addRow(this, gui.domElement); dom.addClass(li, 'folder'); return gui; }, removeFolder: function removeFolder(folder) { this.__ul.removeChild(folder.domElement.parentElement); delete this.__folders[folder.name]; if (this.load && this.load.folders && this.load.folders[folder.name]) { delete this.load.folders[folder.name]; } removeListeners(folder); var _this = this; Common.each(folder.__folders, function (subfolder) { folder.removeFolder(subfolder); }); Common.defer(function () { _this.onResize(); }); }, open: function open() { this.closed = false; }, close: function close() { this.closed = true; }, hide: function hide() { this.domElement.style.display = 'none'; }, show: function show() { this.domElement.style.display = ''; }, onResize: function onResize() { var root = this.getRoot(); if (root.scrollable) { var top = dom.getOffset(root.__ul).top; var h = 0; Common.each(root.__ul.childNodes, function (node) { if (!(root.autoPlace && node === root.__save_row)) { h += dom.getHeight(node); } }); if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px'; } else { dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = 'auto'; } } if (root.__resize_handle) { Common.defer(function () { root.__resize_handle.style.height = root.__ul.offsetHeight + 'px'; }); } if (root.__closeButton) { root.__closeButton.style.width = root.width + 'px'; } }, onResizeDebounced: Common.debounce(function () { this.onResize(); }, 50), remember: function remember() { if (Common.isUndefined(SAVE_DIALOGUE)) { SAVE_DIALOGUE = new CenteredDiv(); SAVE_DIALOGUE.domElement.innerHTML = saveDialogContents; } if (this.parent) { throw new Error('You can only call remember on a top level GUI.'); } var _this = this; Common.each(Array.prototype.slice.call(arguments), function (object) { if (_this.__rememberedObjects.length === 0) { addSaveMenu(_this); } if (_this.__rememberedObjects.indexOf(object) === -1) { _this.__rememberedObjects.push(object); } }); if (this.autoPlace) { setWidth(this, this.width); } }, getRoot: function getRoot() { var gui = this; while (gui.parent) { gui = gui.parent; } return gui; }, getSaveObject: function getSaveObject() { var toReturn = this.load; toReturn.closed = this.closed; if (this.__rememberedObjects.length > 0) { toReturn.preset = this.preset; if (!toReturn.remembered) { toReturn.remembered = {}; } toReturn.remembered[this.preset] = getCurrentPreset(this); } toReturn.folders = {}; Common.each(this.__folders, function (element, key) { toReturn.folders[key] = element.getSaveObject(); }); return toReturn; }, save: function save() { if (!this.load.remembered) { this.load.remembered = {}; } this.load.remembered[this.preset] = getCurrentPreset(this); markPresetModified(this, false); this.saveToLocalStorageIfPossible(); }, saveAs: function saveAs(presetName) { if (!this.load.remembered) { this.load.remembered = {}; this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); } this.load.remembered[presetName] = getCurrentPreset(this); this.preset = presetName; addPresetOption(this, presetName, true); this.saveToLocalStorageIfPossible(); }, revert: function revert(gui) { Common.each(this.__controllers, function (controller) { if (!this.getRoot().load.remembered) { controller.setValue(controller.initialValue); } else { recallSavedValue(gui || this.getRoot(), controller); } if (controller.__onFinishChange) { controller.__onFinishChange.call(controller, controller.getValue()); } }, this); Common.each(this.__folders, function (folder) { folder.revert(folder); }); if (!gui) { markPresetModified(this.getRoot(), false); } }, listen: function listen(controller) { var init = this.__listening.length === 0; this.__listening.push(controller); if (init) { updateDisplays(this.__listening); } }, updateDisplay: function updateDisplay() { Common.each(this.__controllers, function (controller) { controller.updateDisplay(); }); Common.each(this.__folders, function (folder) { folder.updateDisplay(); }); } }); function addRow(gui, newDom, liBefore) { var li = document.createElement('li'); if (newDom) { li.appendChild(newDom); } if (liBefore) { gui.__ul.insertBefore(li, liBefore); } else { gui.__ul.appendChild(li); } gui.onResize(); return li; } function removeListeners(gui) { dom.unbind(window, 'resize', gui.__resizeHandler); if (gui.saveToLocalStorageIfPossible) { dom.unbind(window, 'unload', gui.saveToLocalStorageIfPossible); } } function markPresetModified(gui, modified) { var opt = gui.__preset_select[gui.__preset_select.selectedIndex]; if (modified) { opt.innerHTML = opt.value + '*'; } else { opt.innerHTML = opt.value; } } function augmentController(gui, li, controller) { controller.__li = li; controller.__gui = gui; Common.extend(controller, { options: function options(_options) { if (arguments.length > 1) { var nextSibling = controller.__li.nextElementSibling; controller.remove(); return _add(gui, controller.object, controller.property, { before: nextSibling, factoryArgs: [Common.toArray(arguments)] }); } if (Common.isArray(_options) || Common.isObject(_options)) { var _nextSibling = controller.__li.nextElementSibling; controller.remove(); return _add(gui, controller.object, controller.property, { before: _nextSibling, factoryArgs: [_options] }); } }, name: function name(_name) { controller.__li.firstElementChild.firstElementChild.innerHTML = _name; return controller; }, listen: function listen() { controller.__gui.listen(controller); return controller; }, remove: function remove() { controller.__gui.remove(controller); return controller; } }); if (controller instanceof NumberControllerSlider) { var box = new NumberControllerBox(controller.object, controller.property, { min: controller.__min, max: controller.__max, step: controller.__step }); Common.each(['updateDisplay', 'onChange', 'onFinishChange', 'step', 'min', 'max'], function (method) { var pc = controller[method]; var pb = box[method]; controller[method] = box[method] = function () { var args = Array.prototype.slice.call(arguments); pb.apply(box, args); return pc.apply(controller, args); }; }); dom.addClass(li, 'has-slider'); controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); } else if (controller instanceof NumberControllerBox) { var r = function r(returned) { if (Common.isNumber(controller.__min) && Common.isNumber(controller.__max)) { var oldName = controller.__li.firstElementChild.firstElementChild.innerHTML; var wasListening = controller.__gui.__listening.indexOf(controller) > -1; controller.remove(); var newController = _add(gui, controller.object, controller.property, { before: controller.__li.nextElementSibling, factoryArgs: [controller.__min, controller.__max, controller.__step] }); newController.name(oldName); if (wasListening) newController.listen(); return newController; } return returned; }; controller.min = Common.compose(r, controller.min); controller.max = Common.compose(r, controller.max); } else if (controller instanceof BooleanController) { dom.bind(li, 'click', function () { dom.fakeEvent(controller.__checkbox, 'click'); }); dom.bind(controller.__checkbox, 'click', function (e) { e.stopPropagation(); }); } else if (controller instanceof FunctionController) { dom.bind(li, 'click', function () { dom.fakeEvent(controller.__button, 'click'); }); dom.bind(li, 'mouseover', function () { dom.addClass(controller.__button, 'hover'); }); dom.bind(li, 'mouseout', function () { dom.removeClass(controller.__button, 'hover'); }); } else if (controller instanceof ColorController) { dom.addClass(li, 'color'); controller.updateDisplay = Common.compose(function (val) { li.style.borderLeftColor = controller.__color.toString(); return val; }, controller.updateDisplay); controller.updateDisplay(); } controller.setValue = Common.compose(function (val) { if (gui.getRoot().__preset_select && controller.isModified()) { markPresetModified(gui.getRoot(), true); } return val; }, controller.setValue); } function recallSavedValue(gui, controller) { var root = gui.getRoot(); var matchedIndex = root.__rememberedObjects.indexOf(controller.object); if (matchedIndex !== -1) { var controllerMap = root.__rememberedObjectIndecesToControllers[matchedIndex]; if (controllerMap === undefined) { controllerMap = {}; root.__rememberedObjectIndecesToControllers[matchedIndex] = controllerMap; } controllerMap[controller.property] = controller; if (root.load && root.load.remembered) { var presetMap = root.load.remembered; var preset = void 0; if (presetMap[gui.preset]) { preset = presetMap[gui.preset]; } else if (presetMap[DEFAULT_DEFAULT_PRESET_NAME]) { preset = presetMap[DEFAULT_DEFAULT_PRESET_NAME]; } else { return; } if (preset[matchedIndex] && preset[matchedIndex][controller.property] !== undefined) { var value = preset[matchedIndex][controller.property]; controller.initialValue = value; controller.setValue(value); } } } } function _add(gui, object, property, params) { if (object[property] === undefined) { throw new Error('Object "' + object + '" has no property "' + property + '"'); } var controller = void 0; if (params.color) { controller = new ColorController(object, property); } else { var factoryArgs = [object, property].concat(params.factoryArgs); controller = ControllerFactory.apply(gui, factoryArgs); } if (params.before instanceof Controller) { params.before = params.before.__li; } recallSavedValue(gui, controller); dom.addClass(controller.domElement, 'c'); var name = document.createElement('span'); dom.addClass(name, 'property-name'); name.innerHTML = controller.property; var container = document.createElement('div'); container.appendChild(name); container.appendChild(controller.domElement); var li = addRow(gui, container, params.before); dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); if (controller instanceof ColorController) { dom.addClass(li, 'color'); } else { dom.addClass(li, _typeof(controller.getValue())); } augmentController(gui, li, controller); gui.__controllers.push(controller); return controller; } function getLocalStorageHash(gui, key) { return document.location.href + '.' + key; } function addPresetOption(gui, name, setSelected) { var opt = document.createElement('option'); opt.innerHTML = name; opt.value = name; gui.__preset_select.appendChild(opt); if (setSelected) { gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; } } function showHideExplain(gui, explain) { explain.style.display = gui.useLocalStorage ? 'block' : 'none'; } function addSaveMenu(gui) { var div = gui.__save_row = document.createElement('li'); dom.addClass(gui.domElement, 'has-save'); gui.__ul.insertBefore(div, gui.__ul.firstChild); dom.addClass(div, 'save-row'); var gears = document.createElement('span'); gears.innerHTML = ' '; dom.addClass(gears, 'button gears'); var button = document.createElement('span'); button.innerHTML = 'Save'; dom.addClass(button, 'button'); dom.addClass(button, 'save'); var button2 = document.createElement('span'); button2.innerHTML = 'New'; dom.addClass(button2, 'button'); dom.addClass(button2, 'save-as'); var button3 = document.createElement('span'); button3.innerHTML = 'Revert'; dom.addClass(button3, 'button'); dom.addClass(button3, 'revert'); var select = gui.__preset_select = document.createElement('select'); if (gui.load && gui.load.remembered) { Common.each(gui.load.remembered, function (value, key) { addPresetOption(gui, key, key === gui.preset); }); } else { addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); } dom.bind(select, 'change', function () { for (var index = 0; index < gui.__preset_select.length; index++) { gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; } gui.preset = this.value; }); div.appendChild(select); div.appendChild(gears); div.appendChild(button); div.appendChild(button2); div.appendChild(button3); if (SUPPORTS_LOCAL_STORAGE) { var explain = document.getElementById('dg-local-explain'); var localStorageCheckBox = document.getElementById('dg-local-storage'); var saveLocally = document.getElementById('dg-save-locally'); saveLocally.style.display = 'block'; if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') { localStorageCheckBox.setAttribute('checked', 'checked'); } showHideExplain(gui, explain); dom.bind(localStorageCheckBox, 'change', function () { gui.useLocalStorage = !gui.useLocalStorage; showHideExplain(gui, explain); }); } var newConstructorTextArea = document.getElementById('dg-new-constructor'); dom.bind(newConstructorTextArea, 'keydown', function (e) { if (e.metaKey && (e.which === 67 || e.keyCode === 67)) { SAVE_DIALOGUE.hide(); } }); dom.bind(gears, 'click', function () { newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); SAVE_DIALOGUE.show(); newConstructorTextArea.focus(); newConstructorTextArea.select(); }); dom.bind(button, 'click', function () { gui.save(); }); dom.bind(button2, 'click', function () { var presetName = prompt('Enter a new preset name.'); if (presetName) { gui.saveAs(presetName); } }); dom.bind(button3, 'click', function () { gui.revert(); }); } function addResizeHandle(gui) { var pmouseX = void 0; gui.__resize_handle = document.createElement('div'); Common.extend(gui.__resize_handle.style, { width: '6px', marginLeft: '-3px', height: '200px', cursor: 'ew-resize', position: 'absolute' }); function drag(e) { e.preventDefault(); gui.width += pmouseX - e.clientX; gui.onResize(); pmouseX = e.clientX; return false; } function dragStop() { dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); dom.unbind(window, 'mousemove', drag); dom.unbind(window, 'mouseup', dragStop); } function dragStart(e) { e.preventDefault(); pmouseX = e.clientX; dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); dom.bind(window, 'mousemove', drag); dom.bind(window, 'mouseup', dragStop); return false; } dom.bind(gui.__resize_handle, 'mousedown', dragStart); dom.bind(gui.__closeButton, 'mousedown', dragStart); gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); } function setWidth(gui, w) { gui.domElement.style.width = w + 'px'; if (gui.__save_row && gui.autoPlace) { gui.__save_row.style.width = w + 'px'; } if (gui.__closeButton) { gui.__closeButton.style.width = w + 'px'; } } function getCurrentPreset(gui, useInitialValues) { var toReturn = {}; Common.each(gui.__rememberedObjects, function (val, index) { var savedValues = {}; var controllerMap = gui.__rememberedObjectIndecesToControllers[index]; Common.each(controllerMap, function (controller, property) { savedValues[property] = useInitialValues ? controller.initialValue : controller.getValue(); }); toReturn[index] = savedValues; }); return toReturn; } function setPresetSelectIndex(gui) { for (var index = 0; index < gui.__preset_select.length; index++) { if (gui.__preset_select[index].value === gui.preset) { gui.__preset_select.selectedIndex = index; } } } function updateDisplays(controllerArray) { if (controllerArray.length !== 0) { requestAnimationFrame$1.call(window, function () { updateDisplays(controllerArray); }); } Common.each(controllerArray, function (c) { c.updateDisplay(); }); } var color = { Color: Color, math: ColorMath, interpret: interpret }; var controllers = { Controller: Controller, BooleanController: BooleanController, OptionController: OptionController, StringController: StringController, NumberController: NumberController, NumberControllerBox: NumberControllerBox, NumberControllerSlider: NumberControllerSlider, FunctionController: FunctionController, ColorController: ColorController }; var dom$1 = { dom: dom }; var gui = { GUI: GUI }; var GUI$1 = GUI; var index = { color: color, controllers: controllers, dom: dom$1, gui: gui, GUI: GUI$1 }; export { color, controllers, dom$1 as dom, gui, GUI$1 as GUI }; export default index; //# sourceMappingURL=dat.gui.module.js.map ================================================ FILE: example.html ================================================ ================================================ FILE: licenseBanner.txt ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ ================================================ FILE: package.json ================================================ { "name": "dat.gui", "version": "0.7.9", "description": "A lightweight graphical user interface for changing variables in JavaScript.", "main": "build/dat.gui.js", "module": "build/dat.gui.module.js", "directories": { "test": "tests" }, "scripts": { "dev": "concurrently --names \"ROLLUP,HTTP\" -c \"bgBlue.bold,bgGreen.bold\" \"rollup -c -w -m inline\" \"serve --listen 8080\"", "build": "rollup -c && rollup -c rollup.config.min.js", "build-docs": "jsdoc2md -f src/dat/gui/GUI.js src/dat/controllers/Controller.js src/dat/controllers/NumberController.js | replace-between --target API.md --token API", "lint": "eslint src", "preversion": "npm run lint", "version": "npm run build && git add -A build", "postversion": "git push && git push --tags && npm publish" }, "repository": { "type": "git", "url": "git+https://github.com/dataarts/dat.gui.git" }, "author": "Data Arts Team, Google", "license": "Apache-2.0", "bugs": { "url": "https://github.com/dataarts/dat.gui/issues" }, "homepage": "https://github.com/dataarts/dat.gui#readme", "devDependencies": { "babel-core": "^6.26.3", "babel-plugin-external-helpers": "^6.22.0", "babel-preset-env": "^1.7.0", "concurrently": "^3.5.1", "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.1.0", "eslint-loader": "^4.0.0", "eslint-plugin-import": "^2.20.2", "extend": "^3.0.2", "jsdoc-to-markdown": "^5.0.3", "replace-between": "0.0.8", "rollup": "^0.54.1", "rollup-plugin-babel": "^3.0.4", "rollup-plugin-cleanup": "^3.1.1", "rollup-plugin-node-resolve": "^3.3.0", "rollup-plugin-sass": "^0.6.1", "rollup-plugin-uglify": "^2.0.1", "serve": "^11.3.0" }, "eslintConfig": { "extends": "airbnb-base", "rules": { "comma-dangle": 0, "func-names": 0, "no-alert": 0, "no-console": 1, "no-use-before-define": 0, "prefer-rest-params": 0, "prefer-template": 0, "no-mixed-operators": 0, "no-undef": 0, "no-underscore-dangle": 0, "prefer-arrow-callback": 0, "space-before-function-paren": 0, "global-require": 0, "object-shorthand": 0, "max-len": 0, "no-param-reassign": 0, "consistent-return": 0, "no-restricted-syntax": 0, "no-bitwise": 0, "no-plusplus": 0, "operator-linebreak": 0, "no-else-return": 0, "prefer-destructuring": 0, "no-multi-assign": 0, "no-restricted-properties": 0, "no-return-assign": 0, "no-restricted-globals": 0 } } } ================================================ FILE: rollup.config.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import fs from 'fs'; import path from 'path'; import resolve from 'rollup-plugin-node-resolve'; import cleanup from 'rollup-plugin-cleanup'; import babel from 'rollup-plugin-babel'; import sass from 'rollup-plugin-sass'; const banner = fs.readFileSync(path.join(__dirname, 'licenseBanner.txt')); export default { input: 'src/dat/index.js', output: [{ // TODO: Remove default exports, and this line, in v0.8.0. exports: 'named', file: './build/dat.gui.js', format: 'umd', name: 'dat', sourcemap: true, banner: banner }, { file: './build/dat.gui.module.js', format: 'es', sourcemap: true, banner: banner }], watch: { include: 'src/**' }, plugins: [ resolve(), sass({ insert: true, output: 'build/dat.gui.css', options: {outputStyle: 'compressed'} }), babel({ plugins: ['external-helpers'], exclude: 'node_modules/**' }), cleanup() ] }; ================================================ FILE: src/dat/color/Color.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import interpret from './interpret'; import math from './math'; import colorToString from './toString'; import common from '../utils/common'; class Color { constructor() { this.__state = interpret.apply(this, arguments); if (this.__state === false) { throw new Error('Failed to interpret color arguments'); } this.__state.a = this.__state.a || 1; } toString() { return colorToString(this); } toHexString() { return colorToString(this, true); } toOriginal() { return this.__state.conversion.write(this); } } function defineRGBComponent(target, component, componentHexIndex) { Object.defineProperty(target, component, { get: function() { if (this.__state.space === 'RGB') { return this.__state[component]; } Color.recalculateRGB(this, component, componentHexIndex); return this.__state[component]; }, set: function(v) { if (this.__state.space !== 'RGB') { Color.recalculateRGB(this, component, componentHexIndex); this.__state.space = 'RGB'; } this.__state[component] = v; } }); } function defineHSVComponent(target, component) { Object.defineProperty(target, component, { get: function() { if (this.__state.space === 'HSV') { return this.__state[component]; } Color.recalculateHSV(this); return this.__state[component]; }, set: function(v) { if (this.__state.space !== 'HSV') { Color.recalculateHSV(this); this.__state.space = 'HSV'; } this.__state[component] = v; } }); } Color.recalculateRGB = function(color, component, componentHexIndex) { if (color.__state.space === 'HEX') { color.__state[component] = math.component_from_hex(color.__state.hex, componentHexIndex); } else if (color.__state.space === 'HSV') { common.extend(color.__state, math.hsv_to_rgb(color.__state.h, color.__state.s, color.__state.v)); } else { throw new Error('Corrupted color state'); } }; Color.recalculateHSV = function(color) { const result = math.rgb_to_hsv(color.r, color.g, color.b); common.extend(color.__state, { s: result.s, v: result.v }); if (!common.isNaN(result.h)) { color.__state.h = result.h; } else if (common.isUndefined(color.__state.h)) { color.__state.h = 0; } }; Color.COMPONENTS = ['r', 'g', 'b', 'h', 's', 'v', 'hex', 'a']; defineRGBComponent(Color.prototype, 'r', 2); defineRGBComponent(Color.prototype, 'g', 1); defineRGBComponent(Color.prototype, 'b', 0); defineHSVComponent(Color.prototype, 'h'); defineHSVComponent(Color.prototype, 's'); defineHSVComponent(Color.prototype, 'v'); Object.defineProperty(Color.prototype, 'a', { get: function() { return this.__state.a; }, set: function(v) { this.__state.a = v; } }); Object.defineProperty(Color.prototype, 'hex', { get: function() { if (this.__state.space !== 'HEX') { this.__state.hex = math.rgb_to_hex(this.r, this.g, this.b); this.__state.space = 'HEX'; } return this.__state.hex; }, set: function(v) { this.__state.space = 'HEX'; this.__state.hex = v; } }); export default Color; ================================================ FILE: src/dat/color/interpret.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import toString from './toString'; import common from '../utils/common'; const INTERPRETATIONS = [ // Strings { litmus: common.isString, conversions: { THREE_CHAR_HEX: { read: function(original) { const test = original.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt( '0x' + test[1].toString() + test[1].toString() + test[2].toString() + test[2].toString() + test[3].toString() + test[3].toString(), 0 ) }; }, write: toString }, SIX_CHAR_HEX: { read: function(original) { const test = original.match(/^#([A-F0-9]{6})$/i); if (test === null) { return false; } return { space: 'HEX', hex: parseInt('0x' + test[1].toString(), 0) }; }, write: toString }, CSS_RGB: { read: function(original) { const test = original.match(/^rgb\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]) }; }, write: toString }, CSS_RGBA: { read: function(original) { const test = original.match(/^rgba\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/); if (test === null) { return false; } return { space: 'RGB', r: parseFloat(test[1]), g: parseFloat(test[2]), b: parseFloat(test[3]), a: parseFloat(test[4]) }; }, write: toString } } }, // Numbers { litmus: common.isNumber, conversions: { HEX: { read: function(original) { return { space: 'HEX', hex: original, conversionName: 'HEX' }; }, write: function(color) { return color.hex; } } } }, // Arrays { litmus: common.isArray, conversions: { RGB_ARRAY: { read: function(original) { if (original.length !== 3) { return false; } return { space: 'RGB', r: original[0], g: original[1], b: original[2] }; }, write: function(color) { return [color.r, color.g, color.b]; } }, RGBA_ARRAY: { read: function(original) { if (original.length !== 4) return false; return { space: 'RGB', r: original[0], g: original[1], b: original[2], a: original[3] }; }, write: function(color) { return [color.r, color.g, color.b, color.a]; } } } }, // Objects { litmus: common.isObject, conversions: { RGBA_OBJ: { read: function(original) { if (common.isNumber(original.r) && common.isNumber(original.g) && common.isNumber(original.b) && common.isNumber(original.a)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b, a: original.a }; } return false; }, write: function(color) { return { r: color.r, g: color.g, b: color.b, a: color.a }; } }, RGB_OBJ: { read: function(original) { if (common.isNumber(original.r) && common.isNumber(original.g) && common.isNumber(original.b)) { return { space: 'RGB', r: original.r, g: original.g, b: original.b }; } return false; }, write: function(color) { return { r: color.r, g: color.g, b: color.b }; } }, HSVA_OBJ: { read: function(original) { if (common.isNumber(original.h) && common.isNumber(original.s) && common.isNumber(original.v) && common.isNumber(original.a)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v, a: original.a }; } return false; }, write: function(color) { return { h: color.h, s: color.s, v: color.v, a: color.a }; } }, HSV_OBJ: { read: function(original) { if (common.isNumber(original.h) && common.isNumber(original.s) && common.isNumber(original.v)) { return { space: 'HSV', h: original.h, s: original.s, v: original.v }; } return false; }, write: function(color) { return { h: color.h, s: color.s, v: color.v }; } } } } ]; let result; let toReturn; const interpret = function() { toReturn = false; const original = arguments.length > 1 ? common.toArray(arguments) : arguments[0]; common.each(INTERPRETATIONS, function(family) { if (family.litmus(original)) { common.each(family.conversions, function(conversion, conversionName) { result = conversion.read(original); if (toReturn === false && result !== false) { toReturn = result; result.conversionName = conversionName; result.conversion = conversion; return common.BREAK; } }); return common.BREAK; } }); return toReturn; }; export default interpret; ================================================ FILE: src/dat/color/math.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ let tmpComponent; const ColorMath = { hsv_to_rgb: function(h, s, v) { const hi = Math.floor(h / 60) % 6; const f = h / 60 - Math.floor(h / 60); const p = v * (1.0 - s); const q = v * (1.0 - (f * s)); const t = v * (1.0 - ((1.0 - f) * s)); const c = [ [v, t, p], [q, v, p], [p, v, t], [p, q, v], [t, p, v], [v, p, q] ][hi]; return { r: c[0] * 255, g: c[1] * 255, b: c[2] * 255 }; }, rgb_to_hsv: function(r, g, b) { const min = Math.min(r, g, b); const max = Math.max(r, g, b); const delta = max - min; let h; let s; if (max !== 0) { s = delta / max; } else { return { h: NaN, s: 0, v: 0 }; } if (r === max) { h = (g - b) / delta; } else if (g === max) { h = 2 + (b - r) / delta; } else { h = 4 + (r - g) / delta; } h /= 6; if (h < 0) { h += 1; } return { h: h * 360, s: s, v: max / 255 }; }, rgb_to_hex: function(r, g, b) { let hex = this.hex_with_component(0, 2, r); hex = this.hex_with_component(hex, 1, g); hex = this.hex_with_component(hex, 0, b); return hex; }, component_from_hex: function(hex, componentIndex) { return (hex >> (componentIndex * 8)) & 0xFF; }, hex_with_component: function(hex, componentIndex, value) { return value << (tmpComponent = componentIndex * 8) | (hex & ~(0xFF << tmpComponent)); } }; export default ColorMath; ================================================ FILE: src/dat/color/toString.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ export default function(color, forceCSSHex) { const colorFormat = color.__state.conversionName.toString(); const r = Math.round(color.r); const g = Math.round(color.g); const b = Math.round(color.b); const a = color.a; const h = Math.round(color.h); const s = color.s.toFixed(1); const v = color.v.toFixed(1); if (forceCSSHex || (colorFormat === 'THREE_CHAR_HEX') || (colorFormat === 'SIX_CHAR_HEX')) { let str = color.hex.toString(16); while (str.length < 6) { str = '0' + str; } return '#' + str; } else if (colorFormat === 'CSS_RGB') { return 'rgb(' + r + ',' + g + ',' + b + ')'; } else if (colorFormat === 'CSS_RGBA') { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; } else if (colorFormat === 'HEX') { return '0x' + color.hex.toString(16); } else if (colorFormat === 'RGB_ARRAY') { return '[' + r + ',' + g + ',' + b + ']'; } else if (colorFormat === 'RGBA_ARRAY') { return '[' + r + ',' + g + ',' + b + ',' + a + ']'; } else if (colorFormat === 'RGB_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + '}'; } else if (colorFormat === 'RGBA_OBJ') { return '{r:' + r + ',g:' + g + ',b:' + b + ',a:' + a + '}'; } else if (colorFormat === 'HSV_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + '}'; } else if (colorFormat === 'HSVA_OBJ') { return '{h:' + h + ',s:' + s + ',v:' + v + ',a:' + a + '}'; } return 'unknown format'; } ================================================ FILE: src/dat/controllers/BooleanController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import dom from '../dom/dom'; /** * @class Provides a checkbox input to alter the boolean property of an object. * * @extends dat.controllers.Controller * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated */ class BooleanController extends Controller { constructor(object, property) { super(object, property); const _this = this; this.__prev = this.getValue(); this.__checkbox = document.createElement('input'); this.__checkbox.setAttribute('type', 'checkbox'); function onChange() { _this.setValue(!_this.__prev); } dom.bind(this.__checkbox, 'change', onChange, false); this.domElement.appendChild(this.__checkbox); // Match original value this.updateDisplay(); } setValue(v) { const toReturn = super.setValue(v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } this.__prev = this.getValue(); return toReturn; } updateDisplay() { if (this.getValue() === true) { this.__checkbox.setAttribute('checked', 'checked'); this.__checkbox.checked = true; this.__prev = true; } else { this.__checkbox.checked = false; this.__prev = false; } return super.updateDisplay(); } } export default BooleanController; ================================================ FILE: src/dat/controllers/ColorController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import dom from '../dom/dom'; import Color from '../color/Color'; import interpret from '../color/interpret'; import common from '../utils/common'; /** * @class Represents a given property of an object that is a color. * @param {Object} object * @param {string} property */ class ColorController extends Controller { constructor(object, property) { super(object, property); this.__color = new Color(this.getValue()); this.__temp = new Color(0); const _this = this; this.domElement = document.createElement('div'); dom.makeSelectable(this.domElement, false); this.__selector = document.createElement('div'); this.__selector.className = 'selector'; this.__saturation_field = document.createElement('div'); this.__saturation_field.className = 'saturation-field'; this.__field_knob = document.createElement('div'); this.__field_knob.className = 'field-knob'; this.__field_knob_border = '2px solid '; this.__hue_knob = document.createElement('div'); this.__hue_knob.className = 'hue-knob'; this.__hue_field = document.createElement('div'); this.__hue_field.className = 'hue-field'; this.__input = document.createElement('input'); this.__input.type = 'text'; this.__input_textShadow = '0 1px 1px '; dom.bind(this.__input, 'keydown', function(e) { if (e.keyCode === 13) { // on enter onBlur.call(this); } }); dom.bind(this.__input, 'blur', onBlur); dom.bind(this.__selector, 'mousedown', function(/* e */) { dom .addClass(this, 'drag') .bind(window, 'mouseup', function(/* e */) { dom.removeClass(_this.__selector, 'drag'); }); }); dom.bind(this.__selector, 'touchstart', function(/* e */) { dom .addClass(this, 'drag') .bind(window, 'touchend', function(/* e */) { dom.removeClass(_this.__selector, 'drag'); }); }); const valueField = document.createElement('div'); common.extend(this.__selector.style, { width: '122px', height: '102px', padding: '3px', backgroundColor: '#222', boxShadow: '0px 1px 3px rgba(0,0,0,0.3)' }); common.extend(this.__field_knob.style, { position: 'absolute', width: '12px', height: '12px', border: this.__field_knob_border + (this.__color.v < 0.5 ? '#fff' : '#000'), boxShadow: '0px 1px 3px rgba(0,0,0,0.5)', borderRadius: '12px', zIndex: 1 }); common.extend(this.__hue_knob.style, { position: 'absolute', width: '15px', height: '2px', borderRight: '4px solid #fff', zIndex: 1 }); common.extend(this.__saturation_field.style, { width: '100px', height: '100px', border: '1px solid #555', marginRight: '3px', display: 'inline-block', cursor: 'pointer' }); common.extend(valueField.style, { width: '100%', height: '100%', background: 'none' }); linearGradient(valueField, 'top', 'rgba(0,0,0,0)', '#000'); common.extend(this.__hue_field.style, { width: '15px', height: '100px', border: '1px solid #555', cursor: 'ns-resize', position: 'absolute', top: '3px', right: '3px' }); hueGradient(this.__hue_field); common.extend(this.__input.style, { outline: 'none', // width: '120px', textAlign: 'center', // padding: '4px', // marginBottom: '6px', color: '#fff', border: 0, fontWeight: 'bold', textShadow: this.__input_textShadow + 'rgba(0,0,0,0.7)' }); dom.bind(this.__saturation_field, 'mousedown', fieldDown); dom.bind(this.__saturation_field, 'touchstart', fieldDown); dom.bind(this.__field_knob, 'mousedown', fieldDown); dom.bind(this.__field_knob, 'touchstart', fieldDown); dom.bind(this.__hue_field, 'mousedown', fieldDownH); dom.bind(this.__hue_field, 'touchstart', fieldDownH); function fieldDown(e) { setSV(e); dom.bind(window, 'mousemove', setSV); dom.bind(window, 'touchmove', setSV); dom.bind(window, 'mouseup', fieldUpSV); dom.bind(window, 'touchend', fieldUpSV); } function fieldDownH(e) { setH(e); dom.bind(window, 'mousemove', setH); dom.bind(window, 'touchmove', setH); dom.bind(window, 'mouseup', fieldUpH); dom.bind(window, 'touchend', fieldUpH); } function fieldUpSV() { dom.unbind(window, 'mousemove', setSV); dom.unbind(window, 'touchmove', setSV); dom.unbind(window, 'mouseup', fieldUpSV); dom.unbind(window, 'touchend', fieldUpSV); onFinish(); } function fieldUpH() { dom.unbind(window, 'mousemove', setH); dom.unbind(window, 'touchmove', setH); dom.unbind(window, 'mouseup', fieldUpH); dom.unbind(window, 'touchend', fieldUpH); onFinish(); } function onBlur() { const i = interpret(this.value); if (i !== false) { _this.__color.__state = i; _this.setValue(_this.__color.toOriginal()); } else { this.value = _this.__color.toString(); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.__color.toOriginal()); } } this.__saturation_field.appendChild(valueField); this.__selector.appendChild(this.__field_knob); this.__selector.appendChild(this.__saturation_field); this.__selector.appendChild(this.__hue_field); this.__hue_field.appendChild(this.__hue_knob); this.domElement.appendChild(this.__input); this.domElement.appendChild(this.__selector); this.updateDisplay(); function setSV(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } const fieldRect = _this.__saturation_field.getBoundingClientRect(); const { clientX, clientY } = (e.touches && e.touches[0]) || e; let s = (clientX - fieldRect.left) / (fieldRect.right - fieldRect.left); let v = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (v > 1) { v = 1; } else if (v < 0) { v = 0; } if (s > 1) { s = 1; } else if (s < 0) { s = 0; } _this.__color.v = v; _this.__color.s = s; _this.setValue(_this.__color.toOriginal()); return false; } function setH(e) { if (e.type.indexOf('touch') === -1) { e.preventDefault(); } const fieldRect = _this.__hue_field.getBoundingClientRect(); const { clientY } = (e.touches && e.touches[0]) || e; let h = 1 - (clientY - fieldRect.top) / (fieldRect.bottom - fieldRect.top); if (h > 1) { h = 1; } else if (h < 0) { h = 0; } _this.__color.h = h * 360; _this.setValue(_this.__color.toOriginal()); return false; } } updateDisplay() { const i = interpret(this.getValue()); if (i !== false) { let mismatch = false; // Check for mismatch on the interpreted value. common.each(Color.COMPONENTS, function(component) { if (!common.isUndefined(i[component]) && !common.isUndefined(this.__color.__state[component]) && i[component] !== this.__color.__state[component]) { mismatch = true; return {}; // break } }, this); // If nothing diverges, we keep our previous values // for statefulness, otherwise we recalculate fresh if (mismatch) { common.extend(this.__color.__state, i); } } common.extend(this.__temp.__state, this.__color.__state); this.__temp.a = 1; const flip = (this.__color.v < 0.5 || this.__color.s > 0.5) ? 255 : 0; const _flip = 255 - flip; common.extend(this.__field_knob.style, { marginLeft: 100 * this.__color.s - 7 + 'px', marginTop: 100 * (1 - this.__color.v) - 7 + 'px', backgroundColor: this.__temp.toHexString(), border: this.__field_knob_border + 'rgb(' + flip + ',' + flip + ',' + flip + ')' }); this.__hue_knob.style.marginTop = (1 - this.__color.h / 360) * 100 + 'px'; this.__temp.s = 1; this.__temp.v = 1; linearGradient(this.__saturation_field, 'left', '#fff', this.__temp.toHexString()); this.__input.value = this.__color.toString(); common.extend(this.__input.style, { backgroundColor: this.__color.toHexString(), color: 'rgb(' + flip + ',' + flip + ',' + flip + ')', textShadow: this.__input_textShadow + 'rgba(' + _flip + ',' + _flip + ',' + _flip + ',.7)' }); } } const vendors = ['-moz-', '-o-', '-webkit-', '-ms-', '']; function linearGradient(elem, x, a, b) { elem.style.background = ''; common.each(vendors, function(vendor) { elem.style.cssText += 'background: ' + vendor + 'linear-gradient(' + x + ', ' + a + ' 0%, ' + b + ' 100%); '; }); } function hueGradient(elem) { elem.style.background = ''; elem.style.cssText += 'background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);'; elem.style.cssText += 'background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; elem.style.cssText += 'background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);'; } export default ColorController; ================================================ FILE: src/dat/controllers/Controller.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ /** * @class An "abstract" class that represents a given property of an object. * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated */ class Controller { constructor(object, property) { this.initialValue = object[property]; /** * Those who extend this class will put their DOM elements in here. * @type {DOMElement} */ this.domElement = document.createElement('div'); /** * The object to manipulate * @type {Object} */ this.object = object; /** * The name of the property to manipulate * @type {String} */ this.property = property; /** * The function to be called on change. * @type {Function} * @ignore */ this.__onChange = undefined; /** * The function to be called on finishing change. * @type {Function} * @ignore */ this.__onFinishChange = undefined; } /** * Specify that a function fire every time someone changes the value with * this Controller. * * @param {Function} fnc This function will be called whenever the value * is modified via this Controller. * @returns {Controller} this */ onChange(fnc) { this.__onChange = fnc; return this; } /** * Specify that a function fire every time someone "finishes" changing * the value wih this Controller. Useful for values that change * incrementally like numbers or strings. * * @param {Function} fnc This function will be called whenever * someone "finishes" changing the value via this Controller. * @returns {Controller} this */ onFinishChange(fnc) { this.__onFinishChange = fnc; return this; } /** * Change the value of object[property] * * @param {Object} newValue The new value of object[property] */ setValue(newValue) { this.object[this.property] = newValue; if (this.__onChange) { this.__onChange.call(this, newValue); } this.updateDisplay(); return this; } /** * Gets the value of object[property] * * @returns {Object} The current value of object[property] */ getValue() { return this.object[this.property]; } /** * Refreshes the visual display of a Controller in order to keep sync * with the object's current value. * @returns {Controller} this */ updateDisplay() { return this; } /** * @returns {boolean} true if the value has deviated from initialValue */ isModified() { return this.initialValue !== this.getValue(); } } export default Controller; ================================================ FILE: src/dat/controllers/ControllerFactory.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import OptionController from './OptionController'; import NumberControllerBox from './NumberControllerBox'; import NumberControllerSlider from './NumberControllerSlider'; import StringController from './StringController'; import FunctionController from './FunctionController'; import BooleanController from './BooleanController'; import common from '../utils/common'; const ControllerFactory = function(object, property) { const initialValue = object[property]; // Providing options? if (common.isArray(arguments[2]) || common.isObject(arguments[2])) { return new OptionController(object, property, arguments[2]); } // Providing a map? if (common.isNumber(initialValue)) { // Has min and max? (slider) if (common.isNumber(arguments[2]) && common.isNumber(arguments[3])) { // has step? if (common.isNumber(arguments[4])) { return new NumberControllerSlider(object, property, arguments[2], arguments[3], arguments[4]); } return new NumberControllerSlider(object, property, arguments[2], arguments[3]); } // number box if (common.isNumber(arguments[4])) { // has step return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3], step: arguments[4] }); } return new NumberControllerBox(object, property, { min: arguments[2], max: arguments[3] }); } if (common.isString(initialValue)) { return new StringController(object, property); } if (common.isFunction(initialValue)) { return new FunctionController(object, property, ''); } if (common.isBoolean(initialValue)) { return new BooleanController(object, property); } return null; }; export default ControllerFactory; ================================================ FILE: src/dat/controllers/FunctionController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import dom from '../dom/dom'; /** * @class Provides a GUI interface to fire a specified method, a property of an object. * * @extends dat.controllers.Controller * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated */ class FunctionController extends Controller { constructor(object, property, text) { super(object, property); const _this = this; this.__button = document.createElement('div'); this.__button.innerHTML = text === undefined ? 'Fire' : text; dom.bind(this.__button, 'click', function(e) { e.preventDefault(); _this.fire(); return false; }); dom.addClass(this.__button, 'button'); this.domElement.appendChild(this.__button); } fire() { if (this.__onChange) { this.__onChange.call(this); } this.getValue().call(this.object); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } } } export default FunctionController; ================================================ FILE: src/dat/controllers/NumberController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import common from '../utils/common'; function numDecimals(x) { const _x = x.toString(); if (_x.indexOf('.') > -1) { return _x.length - _x.indexOf('.') - 1; } return 0; } /** * @class Represents a given property of an object that is a number. * * @extends dat.controllers.Controller * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated * @param {Object} [params] Optional parameters * @param {Number} [params.min] Minimum allowed value * @param {Number} [params.max] Maximum allowed value * @param {Number} [params.step] Increment by which to change value */ class NumberController extends Controller { constructor(object, property, params) { super(object, property); const _params = params || {}; this.__min = _params.min; this.__max = _params.max; this.__step = _params.step; if (common.isUndefined(this.__step)) { if (this.initialValue === 0) { this.__impliedStep = 1; // What are we, psychics? } else { // Hey Doug, check this out. this.__impliedStep = Math.pow(10, Math.floor(Math.log(Math.abs(this.initialValue)) / Math.LN10)) / 10; } } else { this.__impliedStep = this.__step; } this.__precision = numDecimals(this.__impliedStep); } setValue(v) { let _v = v; if (this.__min !== undefined && _v < this.__min) { _v = this.__min; } else if (this.__max !== undefined && _v > this.__max) { _v = this.__max; } if (this.__step !== undefined && _v % this.__step !== 0) { _v = Math.round(_v / this.__step) * this.__step; } return super.setValue(_v); } /** * Specify a minimum value for object[property]. * * @param {Number} minValue The minimum value for * object[property] * @returns {dat.controllers.NumberController} this */ min(minValue) { this.__min = minValue; return this; } /** * Specify a maximum value for object[property]. * * @param {Number} maxValue The maximum value for * object[property] * @returns {dat.controllers.NumberController} this */ max(maxValue) { this.__max = maxValue; return this; } /** * Specify a step value that dat.controllers.NumberController * increments by. * * @param {Number} stepValue The step value for * dat.controllers.NumberController * @default if minimum and maximum specified increment is 1% of the * difference otherwise stepValue is 1 * @returns {dat.controllers.NumberController} this */ step(stepValue) { this.__step = stepValue; this.__impliedStep = stepValue; this.__precision = numDecimals(stepValue); return this; } } export default NumberController; ================================================ FILE: src/dat/controllers/NumberControllerBox.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import NumberController from './NumberController'; import dom from '../dom/dom'; import common from '../utils/common'; function roundToDecimal(value, decimals) { const tenTo = Math.pow(10, decimals); return Math.round(value * tenTo) / tenTo; } /** * @class Represents a given property of an object that is a number and * provides an input element with which to manipulate it. * * @extends dat.controllers.Controller * @extends dat.controllers.NumberController * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated * @param {Object} [params] Optional parameters * @param {Number} [params.min] Minimum allowed value * @param {Number} [params.max] Maximum allowed value * @param {Number} [params.step] Increment by which to change value */ class NumberControllerBox extends NumberController { constructor(object, property, params) { super(object, property, params); this.__truncationSuspended = false; const _this = this; /** * {Number} Previous mouse y position * @ignore */ let prevY; function onChange() { const attempted = parseFloat(_this.__input.value); if (!common.isNaN(attempted)) { _this.setValue(attempted); } } function onFinish() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onBlur() { onFinish(); } function onMouseDrag(e) { const diff = prevY - e.clientY; _this.setValue(_this.getValue() + diff * _this.__impliedStep); prevY = e.clientY; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); onFinish(); } function onMouseDown(e) { dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); prevY = e.clientY; } this.__input = document.createElement('input'); this.__input.setAttribute('type', 'text'); // Makes it so manually specified values are not truncated. dom.bind(this.__input, 'change', onChange); dom.bind(this.__input, 'blur', onBlur); dom.bind(this.__input, 'mousedown', onMouseDown); dom.bind(this.__input, 'keydown', function(e) { // When pressing enter, you can be as precise as you want. if (e.keyCode === 13) { _this.__truncationSuspended = true; this.blur(); _this.__truncationSuspended = false; onFinish(); } }); this.updateDisplay(); this.domElement.appendChild(this.__input); } updateDisplay() { this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision); return super.updateDisplay(); } } export default NumberControllerBox; ================================================ FILE: src/dat/controllers/NumberControllerSlider.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import NumberController from './NumberController'; import dom from '../dom/dom'; function map(v, i1, i2, o1, o2) { return o1 + (o2 - o1) * ((v - i1) / (i2 - i1)); } /** * @class Represents a given property of an object that is a number, contains * a minimum and maximum, and provides a slider element with which to * manipulate it. It should be noted that the slider element is made up of * <div> tags, not the html5 * <slider> element. * * @extends dat.controllers.Controller * @extends dat.controllers.NumberController * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated * @param {Number} minValue Minimum allowed value * @param {Number} maxValue Maximum allowed value * @param {Number} stepValue Increment by which to change value */ class NumberControllerSlider extends NumberController { constructor(object, property, min, max, step) { super(object, property, { min: min, max: max, step: step }); const _this = this; this.__background = document.createElement('div'); this.__foreground = document.createElement('div'); dom.bind(this.__background, 'mousedown', onMouseDown); dom.bind(this.__background, 'touchstart', onTouchStart); dom.addClass(this.__background, 'slider'); dom.addClass(this.__foreground, 'slider-fg'); function onMouseDown(e) { document.activeElement.blur(); dom.bind(window, 'mousemove', onMouseDrag); dom.bind(window, 'mouseup', onMouseUp); onMouseDrag(e); } function onMouseDrag(e) { e.preventDefault(); const bgRect = _this.__background.getBoundingClientRect(); _this.setValue( map(e.clientX, bgRect.left, bgRect.right, _this.__min, _this.__max) ); return false; } function onMouseUp() { dom.unbind(window, 'mousemove', onMouseDrag); dom.unbind(window, 'mouseup', onMouseUp); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } function onTouchStart(e) { if (e.touches.length !== 1) { return; } dom.bind(window, 'touchmove', onTouchMove); dom.bind(window, 'touchend', onTouchEnd); onTouchMove(e); } function onTouchMove(e) { const clientX = e.touches[0].clientX; const bgRect = _this.__background.getBoundingClientRect(); _this.setValue( map(clientX, bgRect.left, bgRect.right, _this.__min, _this.__max) ); } function onTouchEnd() { dom.unbind(window, 'touchmove', onTouchMove); dom.unbind(window, 'touchend', onTouchEnd); if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } this.updateDisplay(); this.__background.appendChild(this.__foreground); this.domElement.appendChild(this.__background); } updateDisplay() { const pct = (this.getValue() - this.__min) / (this.__max - this.__min); this.__foreground.style.width = pct * 100 + '%'; return super.updateDisplay(); } } export default NumberControllerSlider; ================================================ FILE: src/dat/controllers/OptionController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import dom from '../dom/dom'; import common from '../utils/common'; /** * @class Provides a select input to alter the property of an object, using a * list of accepted values. * * @extends dat.controllers.Controller * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated * @param {Object|string[]} options A map of labels to acceptable values, or * a list of acceptable string values. */ class OptionController extends Controller { constructor(object, property, opts) { super(object, property); let options = opts; const _this = this; /** * The drop down menu * @ignore */ this.__select = document.createElement('select'); if (common.isArray(options)) { const map = {}; common.each(options, function(element) { map[element] = element; }); options = map; } common.each(options, function(value, key) { const opt = document.createElement('option'); opt.innerHTML = key; opt.setAttribute('value', value); _this.__select.appendChild(opt); }); // Acknowledge original value this.updateDisplay(); dom.bind(this.__select, 'change', function() { const desiredValue = this.options[this.selectedIndex].value; _this.setValue(desiredValue); }); this.domElement.appendChild(this.__select); } setValue(v) { const toReturn = super.setValue(v); if (this.__onFinishChange) { this.__onFinishChange.call(this, this.getValue()); } return toReturn; } updateDisplay() { if (dom.isActive(this.__select)) return this; // prevent number from updating if user is trying to manually update this.__select.value = this.getValue(); return super.updateDisplay(); } } export default OptionController; ================================================ FILE: src/dat/controllers/StringController.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Controller from './Controller'; import dom from '../dom/dom'; /** * @class Provides a text input to alter the string property of an object. * * @extends dat.controllers.Controller * * @param {Object} object The object to be manipulated * @param {string} property The name of the property to be manipulated */ class StringController extends Controller { constructor(object, property) { super(object, property); const _this = this; function onChange() { _this.setValue(_this.__input.value); } function onBlur() { if (_this.__onFinishChange) { _this.__onFinishChange.call(_this, _this.getValue()); } } this.__input = document.createElement('input'); this.__input.setAttribute('type', 'text'); dom.bind(this.__input, 'keyup', onChange); dom.bind(this.__input, 'change', onChange); dom.bind(this.__input, 'blur', onBlur); dom.bind(this.__input, 'keydown', function(e) { if (e.keyCode === 13) { this.blur(); } }); this.updateDisplay(); this.domElement.appendChild(this.__input); } updateDisplay() { // Stops the caret from moving on account of: // keyup -> setValue -> updateDisplay if (!dom.isActive(this.__input)) { this.__input.value = this.getValue(); } return super.updateDisplay(); } } export default StringController; ================================================ FILE: src/dat/dom/CenteredDiv.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import dom from './dom'; import common from '../utils/common'; class CenteredDiv { constructor() { this.backgroundElement = document.createElement('div'); common.extend(this.backgroundElement.style, { backgroundColor: 'rgba(0,0,0,0.8)', top: 0, left: 0, display: 'none', zIndex: '1000', opacity: 0, WebkitTransition: 'opacity 0.2s linear', transition: 'opacity 0.2s linear' }); dom.makeFullscreen(this.backgroundElement); this.backgroundElement.style.position = 'fixed'; this.domElement = document.createElement('div'); common.extend(this.domElement.style, { position: 'fixed', display: 'none', zIndex: '1001', opacity: 0, WebkitTransition: '-webkit-transform 0.2s ease-out, opacity 0.2s linear', transition: 'transform 0.2s ease-out, opacity 0.2s linear' }); document.body.appendChild(this.backgroundElement); document.body.appendChild(this.domElement); const _this = this; dom.bind(this.backgroundElement, 'click', function() { _this.hide(); }); } show() { const _this = this; this.backgroundElement.style.display = 'block'; this.domElement.style.display = 'block'; this.domElement.style.opacity = 0; // this.domElement.style.top = '52%'; this.domElement.style.webkitTransform = 'scale(1.1)'; this.layout(); common.defer(function() { _this.backgroundElement.style.opacity = 1; _this.domElement.style.opacity = 1; _this.domElement.style.webkitTransform = 'scale(1)'; }); } /** * Hide centered div */ hide() { const _this = this; const hide = function() { _this.domElement.style.display = 'none'; _this.backgroundElement.style.display = 'none'; dom.unbind(_this.domElement, 'webkitTransitionEnd', hide); dom.unbind(_this.domElement, 'transitionend', hide); dom.unbind(_this.domElement, 'oTransitionEnd', hide); }; dom.bind(this.domElement, 'webkitTransitionEnd', hide); dom.bind(this.domElement, 'transitionend', hide); dom.bind(this.domElement, 'oTransitionEnd', hide); this.backgroundElement.style.opacity = 0; // this.domElement.style.top = '48%'; this.domElement.style.opacity = 0; this.domElement.style.webkitTransform = 'scale(1.1)'; } layout() { this.domElement.style.left = window.innerWidth / 2 - dom.getWidth(this.domElement) / 2 + 'px'; this.domElement.style.top = window.innerHeight / 2 - dom.getHeight(this.domElement) / 2 + 'px'; } } export default CenteredDiv; ================================================ FILE: src/dat/dom/dom.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import common from '../utils/common'; const EVENT_MAP = { HTMLEvents: ['change'], MouseEvents: ['click', 'mousemove', 'mousedown', 'mouseup', 'mouseover'], KeyboardEvents: ['keydown'] }; const EVENT_MAP_INV = {}; common.each(EVENT_MAP, function(v, k) { common.each(v, function(e) { EVENT_MAP_INV[e] = k; }); }); const CSS_VALUE_PIXELS = /(\d+(\.\d+)?)px/; function cssValueToPixels(val) { if (val === '0' || common.isUndefined(val)) { return 0; } const match = val.match(CSS_VALUE_PIXELS); if (!common.isNull(match)) { return parseFloat(match[1]); } // TODO ...ems? %? return 0; } /** * @namespace * @member dat.dom */ const dom = { /** * * @param elem * @param selectable */ makeSelectable: function(elem, selectable) { if (elem === undefined || elem.style === undefined) return; elem.onselectstart = selectable ? function() { return false; } : function() { }; elem.style.MozUserSelect = selectable ? 'auto' : 'none'; elem.style.KhtmlUserSelect = selectable ? 'auto' : 'none'; elem.unselectable = selectable ? 'on' : 'off'; }, /** * * @param elem * @param horizontal * @param vert */ makeFullscreen: function(elem, hor, vert) { let vertical = vert; let horizontal = hor; if (common.isUndefined(horizontal)) { horizontal = true; } if (common.isUndefined(vertical)) { vertical = true; } elem.style.position = 'absolute'; if (horizontal) { elem.style.left = 0; elem.style.right = 0; } if (vertical) { elem.style.top = 0; elem.style.bottom = 0; } }, /** * * @param elem * @param eventType * @param params */ fakeEvent: function(elem, eventType, pars, aux) { const params = pars || {}; const className = EVENT_MAP_INV[eventType]; if (!className) { throw new Error('Event type ' + eventType + ' not supported.'); } const evt = document.createEvent(className); switch (className) { case 'MouseEvents': { const clientX = params.x || params.clientX || 0; const clientY = params.y || params.clientY || 0; evt.initMouseEvent(eventType, params.bubbles || false, params.cancelable || true, window, params.clickCount || 1, 0, // screen X 0, // screen Y clientX, // client X clientY, // client Y false, false, false, false, 0, null); break; } case 'KeyboardEvents': { const init = evt.initKeyboardEvent || evt.initKeyEvent; // webkit || moz common.defaults(params, { cancelable: true, ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, keyCode: undefined, charCode: undefined }); init(eventType, params.bubbles || false, params.cancelable, window, params.ctrlKey, params.altKey, params.shiftKey, params.metaKey, params.keyCode, params.charCode); break; } default: { evt.initEvent(eventType, params.bubbles || false, params.cancelable || true); break; } } common.defaults(evt, aux); elem.dispatchEvent(evt); }, /** * * @param elem * @param event * @param func * @param bool */ bind: function(elem, event, func, newBool) { const bool = newBool || false; if (elem.addEventListener) { elem.addEventListener(event, func, bool); } else if (elem.attachEvent) { elem.attachEvent('on' + event, func); } return dom; }, /** * * @param elem * @param event * @param func * @param bool */ unbind: function(elem, event, func, newBool) { const bool = newBool || false; if (elem.removeEventListener) { elem.removeEventListener(event, func, bool); } else if (elem.detachEvent) { elem.detachEvent('on' + event, func); } return dom; }, /** * * @param elem * @param className */ addClass: function(elem, className) { if (elem.className === undefined) { elem.className = className; } else if (elem.className !== className) { const classes = elem.className.split(/ +/); if (classes.indexOf(className) === -1) { classes.push(className); elem.className = classes.join(' ').replace(/^\s+/, '').replace(/\s+$/, ''); } } return dom; }, /** * * @param elem * @param className */ removeClass: function(elem, className) { if (className) { if (elem.className === className) { elem.removeAttribute('class'); } else { const classes = elem.className.split(/ +/); const index = classes.indexOf(className); if (index !== -1) { classes.splice(index, 1); elem.className = classes.join(' '); } } } else { elem.className = undefined; } return dom; }, hasClass: function(elem, className) { return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false; }, /** * * @param elem */ getWidth: function(elem) { const style = getComputedStyle(elem); return cssValueToPixels(style['border-left-width']) + cssValueToPixels(style['border-right-width']) + cssValueToPixels(style['padding-left']) + cssValueToPixels(style['padding-right']) + cssValueToPixels(style.width); }, /** * * @param elem */ getHeight: function(elem) { const style = getComputedStyle(elem); return cssValueToPixels(style['border-top-width']) + cssValueToPixels(style['border-bottom-width']) + cssValueToPixels(style['padding-top']) + cssValueToPixels(style['padding-bottom']) + cssValueToPixels(style.height); }, /** * * @param el */ getOffset: function(el) { let elem = el; const offset = { left: 0, top: 0 }; if (elem.offsetParent) { do { offset.left += elem.offsetLeft; offset.top += elem.offsetTop; elem = elem.offsetParent; } while (elem); } return offset; }, // http://stackoverflow.com/posts/2684561/revisions /** * * @param elem */ isActive: function(elem) { return elem === document.activeElement && (elem.type || elem.href); } }; export default dom; ================================================ FILE: src/dat/gui/GUI.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import css from '../utils/css'; import saveDialogueContents from './saveDialogue.html'; import ControllerFactory from '../controllers/ControllerFactory'; import Controller from '../controllers/Controller'; import BooleanController from '../controllers/BooleanController'; import FunctionController from '../controllers/FunctionController'; import NumberControllerBox from '../controllers/NumberControllerBox'; import NumberControllerSlider from '../controllers/NumberControllerSlider'; import ColorController from '../controllers/ColorController'; import requestAnimationFrame from '../utils/requestAnimationFrame'; import CenteredDiv from '../dom/CenteredDiv'; import dom from '../dom/dom'; import common from '../utils/common'; import styleSheet from './style.scss'; // CSS to embed in build css.inject(styleSheet); /** @ignore Outer-most className for GUI's */ const CSS_NAMESPACE = 'dg'; const HIDE_KEY_CODE = 72; /** @ignore The only value shared between the JS and SCSS. Use caution. */ const CLOSE_BUTTON_HEIGHT = 20; const DEFAULT_DEFAULT_PRESET_NAME = 'Default'; const SUPPORTS_LOCAL_STORAGE = (function() { try { return !!window.localStorage; } catch (e) { return false; } }()); let SAVE_DIALOGUE; /** @ignore Have we yet to create an autoPlace GUI? */ let autoPlaceVirgin = true; /** @ignore Fixed position div that auto place GUI's go inside */ let autoPlaceContainer; /** @ignore Are we hiding the GUI's ? */ let hide = false; /** @private GUI's which should be hidden */ const hideableGuis = []; /** * @class A lightweight controller library for JavaScript. It allows you to easily * manipulate variables and fire functions on the fly. * * @typicalname gui * * @example * // Creating a GUI with options. * var gui = new dat.GUI({name: 'My GUI'}); * * @example * // Creating a GUI and a subfolder. * var gui = new dat.GUI(); * var folder1 = gui.addFolder('Flow Field'); * * @param {Object} [params] * @param {String} [params.name] The name of this GUI. * @param {Object} [params.load] JSON object representing the saved state of * this GUI. * @param {dat.gui.GUI} [params.parent] The GUI I'm nested in. * @param {Boolean} [params.autoPlace=true] * @param {Boolean} [params.hideable=true] If true, GUI is shown/hidden by h keypress. * @param {Boolean} [params.closed=false] If true, starts closed * @param {Boolean} [params.closeOnTop=false] If true, close/open button shows on top of the GUI */ const GUI = function(pars) { const _this = this; let params = pars || {}; /** * Outermost DOM Element * @type {DOMElement} */ this.domElement = document.createElement('div'); this.__ul = document.createElement('ul'); this.domElement.appendChild(this.__ul); dom.addClass(this.domElement, CSS_NAMESPACE); /** * Nested GUI's by name * @ignore */ this.__folders = {}; this.__controllers = []; /** * List of objects I'm remembering for save, only used in top level GUI * @ignore */ this.__rememberedObjects = []; /** * Maps the index of remembered objects to a map of controllers, only used * in top level GUI. * * @private * @ignore * * @example * [ * { * propertyName: Controller, * anotherPropertyName: Controller * }, * { * propertyName: Controller * } * ] */ this.__rememberedObjectIndecesToControllers = []; this.__listening = []; // Default parameters params = common.defaults(params, { closeOnTop: false, autoPlace: true, width: GUI.DEFAULT_WIDTH }); params = common.defaults(params, { resizable: params.autoPlace, hideable: params.autoPlace }); if (!common.isUndefined(params.load)) { // Explicit preset if (params.preset) { params.load.preset = params.preset; } } else { params.load = { preset: DEFAULT_DEFAULT_PRESET_NAME }; } if (common.isUndefined(params.parent) && params.hideable) { hideableGuis.push(this); } // Only root level GUI's are resizable. params.resizable = common.isUndefined(params.parent) && params.resizable; if (params.autoPlace && common.isUndefined(params.scrollable)) { params.scrollable = true; } // params.scrollable = common.isUndefined(params.parent) && params.scrollable === true; // Not part of params because I don't want people passing this in via // constructor. Should be a 'remembered' value. let useLocalStorage = SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true'; let saveToLocalStorage; let titleRow; Object.defineProperties(this, /** @lends GUI.prototype */ { /** * The parent GUI * @type dat.gui.GUI */ parent: { get: function() { return params.parent; } }, scrollable: { get: function() { return params.scrollable; } }, /** * Handles GUI's element placement for you * @type Boolean */ autoPlace: { get: function() { return params.autoPlace; } }, /** * Handles GUI's position of open/close button * @type Boolean */ closeOnTop: { get: function() { return params.closeOnTop; } }, /** * The identifier for a set of saved values * @type String */ preset: { get: function() { if (_this.parent) { return _this.getRoot().preset; } return params.load.preset; }, set: function(v) { if (_this.parent) { _this.getRoot().preset = v; } else { params.load.preset = v; } setPresetSelectIndex(this); _this.revert(); } }, /** * The width of GUI element * @type Number */ width: { get: function() { return params.width; }, set: function(v) { params.width = v; setWidth(_this, v); } }, /** * The name of GUI. Used for folders. i.e * a folder's name * @type String */ name: { get: function() { return params.name; }, set: function(v) { // TODO Check for collisions among sibling folders params.name = v; if (titleRow) { titleRow.innerHTML = params.name; } } }, /** * Whether the GUI is collapsed or not * @type Boolean */ closed: { get: function() { return params.closed; }, set: function(v) { params.closed = v; if (params.closed) { dom.addClass(_this.__ul, GUI.CLASS_CLOSED); } else { dom.removeClass(_this.__ul, GUI.CLASS_CLOSED); } // For browsers that aren't going to respect the CSS transition, // Lets just check our height against the window height right off // the bat. this.onResize(); if (_this.__closeButton) { _this.__closeButton.innerHTML = v ? GUI.TEXT_OPEN : GUI.TEXT_CLOSED; } } }, /** * Contains all presets * @type Object */ load: { get: function() { return params.load; } }, /** * Determines whether or not to use localStorage as the means for * remembering * @type Boolean */ useLocalStorage: { get: function() { return useLocalStorage; }, set: function(bool) { if (SUPPORTS_LOCAL_STORAGE) { useLocalStorage = bool; if (bool) { dom.bind(window, 'unload', saveToLocalStorage); } else { dom.unbind(window, 'unload', saveToLocalStorage); } localStorage.setItem(getLocalStorageHash(_this, 'isLocal'), bool); } } } }); // Are we a root level GUI? if (common.isUndefined(params.parent)) { this.closed = params.closed || false; dom.addClass(this.domElement, GUI.CLASS_MAIN); dom.makeSelectable(this.domElement, false); // Are we supposed to be loading locally? if (SUPPORTS_LOCAL_STORAGE) { if (useLocalStorage) { _this.useLocalStorage = true; const savedGui = localStorage.getItem(getLocalStorageHash(this, 'gui')); if (savedGui) { params.load = JSON.parse(savedGui); } } } this.__closeButton = document.createElement('div'); this.__closeButton.innerHTML = GUI.TEXT_CLOSED; dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON); if (params.closeOnTop) { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_TOP); this.domElement.insertBefore(this.__closeButton, this.domElement.childNodes[0]); } else { dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BOTTOM); this.domElement.appendChild(this.__closeButton); } dom.bind(this.__closeButton, 'click', function() { _this.closed = !_this.closed; }); // Oh, you're a nested GUI! } else { if (params.closed === undefined) { params.closed = true; } const titleRowName = document.createTextNode(params.name); dom.addClass(titleRowName, 'controller-name'); titleRow = addRow(_this, titleRowName); const onClickTitle = function(e) { e.preventDefault(); _this.closed = !_this.closed; return false; }; dom.addClass(this.__ul, GUI.CLASS_CLOSED); dom.addClass(titleRow, 'title'); dom.bind(titleRow, 'click', onClickTitle); if (!params.closed) { this.closed = false; } } if (params.autoPlace) { if (common.isUndefined(params.parent)) { if (autoPlaceVirgin) { autoPlaceContainer = document.createElement('div'); dom.addClass(autoPlaceContainer, CSS_NAMESPACE); dom.addClass(autoPlaceContainer, GUI.CLASS_AUTO_PLACE_CONTAINER); document.body.appendChild(autoPlaceContainer); autoPlaceVirgin = false; } // Put it in the dom for you. autoPlaceContainer.appendChild(this.domElement); // Apply the auto styles dom.addClass(this.domElement, GUI.CLASS_AUTO_PLACE); } // Make it not elastic. if (!this.parent) { setWidth(_this, params.width); } } this.__resizeHandler = function() { _this.onResizeDebounced(); }; dom.bind(window, 'resize', this.__resizeHandler); dom.bind(this.__ul, 'webkitTransitionEnd', this.__resizeHandler); dom.bind(this.__ul, 'transitionend', this.__resizeHandler); dom.bind(this.__ul, 'oTransitionEnd', this.__resizeHandler); this.onResize(); if (params.resizable) { addResizeHandle(this); } saveToLocalStorage = function() { if (SUPPORTS_LOCAL_STORAGE && localStorage.getItem(getLocalStorageHash(_this, 'isLocal')) === 'true') { localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject())); } }; // expose this method publicly this.saveToLocalStorageIfPossible = saveToLocalStorage; function resetWidth() { const root = _this.getRoot(); root.width += 1; common.defer(function() { root.width -= 1; }); } if (!params.parent) { resetWidth(); } }; GUI.toggleHide = function() { hide = !hide; common.each(hideableGuis, function(gui) { gui.domElement.style.display = hide ? 'none' : ''; }); }; GUI.CLASS_AUTO_PLACE = 'a'; GUI.CLASS_AUTO_PLACE_CONTAINER = 'ac'; GUI.CLASS_MAIN = 'main'; GUI.CLASS_CONTROLLER_ROW = 'cr'; GUI.CLASS_TOO_TALL = 'taller-than-window'; GUI.CLASS_CLOSED = 'closed'; GUI.CLASS_CLOSE_BUTTON = 'close-button'; GUI.CLASS_CLOSE_TOP = 'close-top'; GUI.CLASS_CLOSE_BOTTOM = 'close-bottom'; GUI.CLASS_DRAG = 'drag'; GUI.DEFAULT_WIDTH = 245; GUI.TEXT_CLOSED = 'Close Controls'; GUI.TEXT_OPEN = 'Open Controls'; GUI._keydownHandler = function(e) { if (document.activeElement.type !== 'text' && (e.which === HIDE_KEY_CODE || e.keyCode === HIDE_KEY_CODE)) { GUI.toggleHide(); } }; dom.bind(window, 'keydown', GUI._keydownHandler, false); common.extend( GUI.prototype, /** @lends GUI.prototype */ { /** * Adds a new {@link Controller} to the GUI. The type of controller created * is inferred from the initial value of object[property]. For * color properties, see {@link addColor}. * * @param {Object} object The object to be manipulated * @param {String} property The name of the property to be manipulated * @param {Number} [min] Minimum allowed value * @param {Number} [max] Maximum allowed value * @param {Number} [step] Increment by which to change value * @returns {Controller} The controller that was added to the GUI. * @instance * * @example * // Add a string controller. * var person = {name: 'Sam'}; * gui.add(person, 'name'); * * @example * // Add a number controller slider. * var person = {age: 45}; * gui.add(person, 'age', 0, 100); */ add: function(object, property) { return add( this, object, property, { factoryArgs: Array.prototype.slice.call(arguments, 2) } ); }, /** * Adds a new color controller to the GUI. * * @param object * @param property * @returns {Controller} The controller that was added to the GUI. * @instance * * @example * var palette = { * color1: '#FF0000', // CSS string * color2: [ 0, 128, 255 ], // RGB array * color3: [ 0, 128, 255, 0.3 ], // RGB with alpha * color4: { h: 350, s: 0.9, v: 0.3 } // Hue, saturation, value * }; * gui.addColor(palette, 'color1'); * gui.addColor(palette, 'color2'); * gui.addColor(palette, 'color3'); * gui.addColor(palette, 'color4'); */ addColor: function(object, property) { return add( this, object, property, { color: true } ); }, /** * Removes the given controller from the GUI. * @param {Controller} controller * @instance */ remove: function(controller) { // TODO listening? this.__ul.removeChild(controller.__li); this.__controllers.splice(this.__controllers.indexOf(controller), 1); const _this = this; common.defer(function() { _this.onResize(); }); }, /** * Removes the root GUI from the document and unbinds all event listeners. * For subfolders, use `gui.removeFolder(folder)` instead. * @instance */ destroy: function() { if (this.parent) { throw new Error( 'Only the root GUI should be removed with .destroy(). ' + 'For subfolders, use gui.removeFolder(folder) instead.' ); } if (this.autoPlace) { autoPlaceContainer.removeChild(this.domElement); } const _this = this; common.each(this.__folders, function(subfolder) { _this.removeFolder(subfolder); }); dom.unbind(window, 'keydown', GUI._keydownHandler, false); removeListeners(this); }, /** * Creates a new subfolder GUI instance. * @param name * @returns {dat.gui.GUI} The new folder. * @throws {Error} if this GUI already has a folder by the specified * name * @instance */ addFolder: function(name) { // We have to prevent collisions on names in order to have a key // by which to remember saved values if (this.__folders[name] !== undefined) { throw new Error('You already have a folder in this GUI by the' + ' name "' + name + '"'); } const newGuiParams = { name: name, parent: this }; // We need to pass down the autoPlace trait so that we can // attach event listeners to open/close folder actions to // ensure that a scrollbar appears if the window is too short. newGuiParams.autoPlace = this.autoPlace; // Do we have saved appearance data for this folder? if (this.load && // Anything loaded? this.load.folders && // Was my parent a dead-end? this.load.folders[name]) { // Did daddy remember me? // Start me closed if I was closed newGuiParams.closed = this.load.folders[name].closed; // Pass down the loaded data newGuiParams.load = this.load.folders[name]; } const gui = new GUI(newGuiParams); this.__folders[name] = gui; const li = addRow(this, gui.domElement); dom.addClass(li, 'folder'); return gui; }, /** * Removes a subfolder GUI instance. * @param {dat.gui.GUI} folder The folder to remove. * @instance */ removeFolder: function(folder) { this.__ul.removeChild(folder.domElement.parentElement); delete this.__folders[folder.name]; // Do we have saved appearance data for this folder? if (this.load && // Anything loaded? this.load.folders && // Was my parent a dead-end? this.load.folders[folder.name]) { delete this.load.folders[folder.name]; } removeListeners(folder); const _this = this; common.each(folder.__folders, function(subfolder) { folder.removeFolder(subfolder); }); common.defer(function() { _this.onResize(); }); }, /** * Opens the GUI. */ open: function() { this.closed = false; }, /** * Closes the GUI. */ close: function() { this.closed = true; }, /** * Hides the GUI. */ hide: function() { this.domElement.style.display = 'none'; }, /** * Shows the GUI. */ show: function() { this.domElement.style.display = ''; }, onResize: function() { // we debounce this function to prevent performance issues when rotating on tablet/mobile const root = this.getRoot(); if (root.scrollable) { const top = dom.getOffset(root.__ul).top; let h = 0; common.each(root.__ul.childNodes, function(node) { if (!(root.autoPlace && node === root.__save_row)) { h += dom.getHeight(node); } }); if (window.innerHeight - top - CLOSE_BUTTON_HEIGHT < h) { dom.addClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = window.innerHeight - top - CLOSE_BUTTON_HEIGHT + 'px'; } else { dom.removeClass(root.domElement, GUI.CLASS_TOO_TALL); root.__ul.style.height = 'auto'; } } if (root.__resize_handle) { common.defer(function() { root.__resize_handle.style.height = root.__ul.offsetHeight + 'px'; }); } if (root.__closeButton) { root.__closeButton.style.width = root.width + 'px'; } }, onResizeDebounced: common.debounce(function() { this.onResize(); }, 50), /** * Mark objects for saving. The order of these objects cannot change as * the GUI grows. When remembering new objects, append them to the end * of the list. * * @param {...Object} objects * @throws {Error} if not called on a top level GUI. * @instance * @ignore */ remember: function() { if (common.isUndefined(SAVE_DIALOGUE)) { SAVE_DIALOGUE = new CenteredDiv(); SAVE_DIALOGUE.domElement.innerHTML = saveDialogueContents; } if (this.parent) { throw new Error('You can only call remember on a top level GUI.'); } const _this = this; common.each(Array.prototype.slice.call(arguments), function(object) { if (_this.__rememberedObjects.length === 0) { addSaveMenu(_this); } if (_this.__rememberedObjects.indexOf(object) === -1) { _this.__rememberedObjects.push(object); } }); if (this.autoPlace) { // Set save row width setWidth(this, this.width); } }, /** * @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI. * @instance */ getRoot: function() { let gui = this; while (gui.parent) { gui = gui.parent; } return gui; }, /** * @returns {Object} a JSON object representing the current state of * this GUI as well as its remembered properties. * @instance */ getSaveObject: function() { const toReturn = this.load; toReturn.closed = this.closed; // Am I remembering any values? if (this.__rememberedObjects.length > 0) { toReturn.preset = this.preset; if (!toReturn.remembered) { toReturn.remembered = {}; } toReturn.remembered[this.preset] = getCurrentPreset(this); } toReturn.folders = {}; common.each(this.__folders, function(element, key) { toReturn.folders[key] = element.getSaveObject(); }); return toReturn; }, save: function() { if (!this.load.remembered) { this.load.remembered = {}; } this.load.remembered[this.preset] = getCurrentPreset(this); markPresetModified(this, false); this.saveToLocalStorageIfPossible(); }, saveAs: function(presetName) { if (!this.load.remembered) { // Retain default values upon first save this.load.remembered = {}; this.load.remembered[DEFAULT_DEFAULT_PRESET_NAME] = getCurrentPreset(this, true); } this.load.remembered[presetName] = getCurrentPreset(this); this.preset = presetName; addPresetOption(this, presetName, true); this.saveToLocalStorageIfPossible(); }, revert: function(gui) { common.each(this.__controllers, function(controller) { // Make revert work on Default. if (!this.getRoot().load.remembered) { controller.setValue(controller.initialValue); } else { recallSavedValue(gui || this.getRoot(), controller); } // fire onFinishChange callback if (controller.__onFinishChange) { controller.__onFinishChange.call(controller, controller.getValue()); } }, this); common.each(this.__folders, function(folder) { folder.revert(folder); }); if (!gui) { markPresetModified(this.getRoot(), false); } }, listen: function(controller) { const init = this.__listening.length === 0; this.__listening.push(controller); if (init) { updateDisplays(this.__listening); } }, updateDisplay: function() { common.each(this.__controllers, function(controller) { controller.updateDisplay(); }); common.each(this.__folders, function(folder) { folder.updateDisplay(); }); } } ); /** * Add a row to the end of the GUI or before another row. * * @param gui * @param [newDom] If specified, inserts the dom content in the new row * @param [liBefore] If specified, places the new row before another row * * @ignore */ function addRow(gui, newDom, liBefore) { const li = document.createElement('li'); if (newDom) { li.appendChild(newDom); } if (liBefore) { gui.__ul.insertBefore(li, liBefore); } else { gui.__ul.appendChild(li); } gui.onResize(); return li; } function removeListeners(gui) { dom.unbind(window, 'resize', gui.__resizeHandler); if (gui.saveToLocalStorageIfPossible) { dom.unbind(window, 'unload', gui.saveToLocalStorageIfPossible); } } function markPresetModified(gui, modified) { const opt = gui.__preset_select[gui.__preset_select.selectedIndex]; if (modified) { opt.innerHTML = opt.value + '*'; } else { opt.innerHTML = opt.value; } } function augmentController(gui, li, controller) { controller.__li = li; controller.__gui = gui; common.extend(controller, /** @lends Controller.prototype */ { /** * @param {Array|Object} options * @return {Controller} */ options: function(options) { if (arguments.length > 1) { const nextSibling = controller.__li.nextElementSibling; controller.remove(); return add( gui, controller.object, controller.property, { before: nextSibling, factoryArgs: [common.toArray(arguments)] } ); } if (common.isArray(options) || common.isObject(options)) { const nextSibling = controller.__li.nextElementSibling; controller.remove(); return add( gui, controller.object, controller.property, { before: nextSibling, factoryArgs: [options] } ); } }, /** * Sets the name of the controller. * @param {string} name * @return {Controller} */ name: function(name) { controller.__li.firstElementChild.firstElementChild.innerHTML = name; return controller; }, /** * Sets controller to listen for changes on its underlying object. * @return {Controller} */ listen: function() { controller.__gui.listen(controller); return controller; }, /** * Removes the controller from its parent GUI. * @return {Controller} */ remove: function() { controller.__gui.remove(controller); return controller; } }); // All sliders should be accompanied by a box. if (controller instanceof NumberControllerSlider) { const box = new NumberControllerBox(controller.object, controller.property, { min: controller.__min, max: controller.__max, step: controller.__step }); common.each(['updateDisplay', 'onChange', 'onFinishChange', 'step', 'min', 'max'], function(method) { const pc = controller[method]; const pb = box[method]; controller[method] = box[method] = function() { const args = Array.prototype.slice.call(arguments); pb.apply(box, args); return pc.apply(controller, args); }; }); dom.addClass(li, 'has-slider'); controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild); } else if (controller instanceof NumberControllerBox) { const r = function(returned) { // Have we defined both boundaries? if (common.isNumber(controller.__min) && common.isNumber(controller.__max)) { // Well, then lets just replace this with a slider. // lets remember if the old controller had a specific name or was listening const oldName = controller.__li.firstElementChild.firstElementChild.innerHTML; const wasListening = controller.__gui.__listening.indexOf(controller) > -1; controller.remove(); const newController = add( gui, controller.object, controller.property, { before: controller.__li.nextElementSibling, factoryArgs: [controller.__min, controller.__max, controller.__step] } ); newController.name(oldName); if (wasListening) newController.listen(); return newController; } return returned; }; controller.min = common.compose(r, controller.min); controller.max = common.compose(r, controller.max); } else if (controller instanceof BooleanController) { dom.bind(li, 'click', function() { dom.fakeEvent(controller.__checkbox, 'click'); }); dom.bind(controller.__checkbox, 'click', function(e) { e.stopPropagation(); // Prevents double-toggle }); } else if (controller instanceof FunctionController) { dom.bind(li, 'click', function() { dom.fakeEvent(controller.__button, 'click'); }); dom.bind(li, 'mouseover', function() { dom.addClass(controller.__button, 'hover'); }); dom.bind(li, 'mouseout', function() { dom.removeClass(controller.__button, 'hover'); }); } else if (controller instanceof ColorController) { dom.addClass(li, 'color'); controller.updateDisplay = common.compose(function(val) { li.style.borderLeftColor = controller.__color.toString(); return val; }, controller.updateDisplay); controller.updateDisplay(); } controller.setValue = common.compose(function(val) { if (gui.getRoot().__preset_select && controller.isModified()) { markPresetModified(gui.getRoot(), true); } return val; }, controller.setValue); } function recallSavedValue(gui, controller) { // Find the topmost GUI, that's where remembered objects live. const root = gui.getRoot(); // Does the object we're controlling match anything we've been told to // remember? const matchedIndex = root.__rememberedObjects.indexOf(controller.object); // Why yes, it does! if (matchedIndex !== -1) { // Let me fetch a map of controllers for thcommon.isObject. let controllerMap = root.__rememberedObjectIndecesToControllers[matchedIndex]; // Ohp, I believe this is the first controller we've created for this // object. Lets make the map fresh. if (controllerMap === undefined) { controllerMap = {}; root.__rememberedObjectIndecesToControllers[matchedIndex] = controllerMap; } // Keep track of this controller controllerMap[controller.property] = controller; // Okay, now have we saved any values for this controller? if (root.load && root.load.remembered) { const presetMap = root.load.remembered; // Which preset are we trying to load? let preset; if (presetMap[gui.preset]) { preset = presetMap[gui.preset]; } else if (presetMap[DEFAULT_DEFAULT_PRESET_NAME]) { // Uhh, you can have the default instead? preset = presetMap[DEFAULT_DEFAULT_PRESET_NAME]; } else { // Nada. return; } // Did the loaded object remember thcommon.isObject? && Did we remember this particular property? if (preset[matchedIndex] && preset[matchedIndex][controller.property] !== undefined) { // We did remember something for this guy ... const value = preset[matchedIndex][controller.property]; // And that's what it is. controller.initialValue = value; controller.setValue(value); } } } } function add(gui, object, property, params) { if (object[property] === undefined) { throw new Error(`Object "${object}" has no property "${property}"`); } let controller; if (params.color) { controller = new ColorController(object, property); } else { const factoryArgs = [object, property].concat(params.factoryArgs); controller = ControllerFactory.apply(gui, factoryArgs); } if (params.before instanceof Controller) { params.before = params.before.__li; } recallSavedValue(gui, controller); dom.addClass(controller.domElement, 'c'); const name = document.createElement('span'); dom.addClass(name, 'property-name'); name.innerHTML = controller.property; const container = document.createElement('div'); container.appendChild(name); container.appendChild(controller.domElement); const li = addRow(gui, container, params.before); dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); if (controller instanceof ColorController) { dom.addClass(li, 'color'); } else { dom.addClass(li, typeof controller.getValue()); } augmentController(gui, li, controller); gui.__controllers.push(controller); return controller; } function getLocalStorageHash(gui, key) { // TODO how does this deal with multiple GUI's? return document.location.href + '.' + key; } function addPresetOption(gui, name, setSelected) { const opt = document.createElement('option'); opt.innerHTML = name; opt.value = name; gui.__preset_select.appendChild(opt); if (setSelected) { gui.__preset_select.selectedIndex = gui.__preset_select.length - 1; } } function showHideExplain(gui, explain) { explain.style.display = gui.useLocalStorage ? 'block' : 'none'; } function addSaveMenu(gui) { const div = gui.__save_row = document.createElement('li'); dom.addClass(gui.domElement, 'has-save'); gui.__ul.insertBefore(div, gui.__ul.firstChild); dom.addClass(div, 'save-row'); const gears = document.createElement('span'); gears.innerHTML = ' '; dom.addClass(gears, 'button gears'); // TODO replace with FunctionController const button = document.createElement('span'); button.innerHTML = 'Save'; dom.addClass(button, 'button'); dom.addClass(button, 'save'); const button2 = document.createElement('span'); button2.innerHTML = 'New'; dom.addClass(button2, 'button'); dom.addClass(button2, 'save-as'); const button3 = document.createElement('span'); button3.innerHTML = 'Revert'; dom.addClass(button3, 'button'); dom.addClass(button3, 'revert'); const select = gui.__preset_select = document.createElement('select'); if (gui.load && gui.load.remembered) { common.each(gui.load.remembered, function(value, key) { addPresetOption(gui, key, key === gui.preset); }); } else { addPresetOption(gui, DEFAULT_DEFAULT_PRESET_NAME, false); } dom.bind(select, 'change', function() { for (let index = 0; index < gui.__preset_select.length; index++) { gui.__preset_select[index].innerHTML = gui.__preset_select[index].value; } gui.preset = this.value; }); div.appendChild(select); div.appendChild(gears); div.appendChild(button); div.appendChild(button2); div.appendChild(button3); if (SUPPORTS_LOCAL_STORAGE) { const explain = document.getElementById('dg-local-explain'); const localStorageCheckBox = document.getElementById('dg-local-storage'); const saveLocally = document.getElementById('dg-save-locally'); saveLocally.style.display = 'block'; if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') { localStorageCheckBox.setAttribute('checked', 'checked'); } showHideExplain(gui, explain); // TODO: Use a boolean controller, fool! dom.bind(localStorageCheckBox, 'change', function() { gui.useLocalStorage = !gui.useLocalStorage; showHideExplain(gui, explain); }); } const newConstructorTextArea = document.getElementById('dg-new-constructor'); dom.bind(newConstructorTextArea, 'keydown', function(e) { if (e.metaKey && (e.which === 67 || e.keyCode === 67)) { SAVE_DIALOGUE.hide(); } }); dom.bind(gears, 'click', function() { newConstructorTextArea.innerHTML = JSON.stringify(gui.getSaveObject(), undefined, 2); SAVE_DIALOGUE.show(); newConstructorTextArea.focus(); newConstructorTextArea.select(); }); dom.bind(button, 'click', function() { gui.save(); }); dom.bind(button2, 'click', function() { const presetName = prompt('Enter a new preset name.'); if (presetName) { gui.saveAs(presetName); } }); dom.bind(button3, 'click', function() { gui.revert(); }); // div.appendChild(button2); } function addResizeHandle(gui) { let pmouseX; gui.__resize_handle = document.createElement('div'); common.extend(gui.__resize_handle.style, { width: '6px', marginLeft: '-3px', height: '200px', cursor: 'ew-resize', position: 'absolute' // border: '1px solid blue' }); function drag(e) { e.preventDefault(); gui.width += pmouseX - e.clientX; gui.onResize(); pmouseX = e.clientX; return false; } function dragStop() { dom.removeClass(gui.__closeButton, GUI.CLASS_DRAG); dom.unbind(window, 'mousemove', drag); dom.unbind(window, 'mouseup', dragStop); } function dragStart(e) { e.preventDefault(); pmouseX = e.clientX; dom.addClass(gui.__closeButton, GUI.CLASS_DRAG); dom.bind(window, 'mousemove', drag); dom.bind(window, 'mouseup', dragStop); return false; } dom.bind(gui.__resize_handle, 'mousedown', dragStart); dom.bind(gui.__closeButton, 'mousedown', dragStart); gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild); } function setWidth(gui, w) { gui.domElement.style.width = w + 'px'; // Auto placed save-rows are position fixed, so we have to // set the width manually if we want it to bleed to the edge if (gui.__save_row && gui.autoPlace) { gui.__save_row.style.width = w + 'px'; } if (gui.__closeButton) { gui.__closeButton.style.width = w + 'px'; } } function getCurrentPreset(gui, useInitialValues) { const toReturn = {}; // For each object I'm remembering common.each(gui.__rememberedObjects, function(val, index) { const savedValues = {}; // The controllers I've made for thcommon.isObject by property const controllerMap = gui.__rememberedObjectIndecesToControllers[index]; // Remember each value for each property common.each(controllerMap, function(controller, property) { savedValues[property] = useInitialValues ? controller.initialValue : controller.getValue(); }); // Save the values for thcommon.isObject toReturn[index] = savedValues; }); return toReturn; } function setPresetSelectIndex(gui) { for (let index = 0; index < gui.__preset_select.length; index++) { if (gui.__preset_select[index].value === gui.preset) { gui.__preset_select.selectedIndex = index; } } } function updateDisplays(controllerArray) { if (controllerArray.length !== 0) { requestAnimationFrame.call(window, function() { updateDisplays(controllerArray); }); } common.each(controllerArray, function(c) { c.updateDisplay(); }); } export default GUI; ================================================ FILE: src/dat/gui/_structure.scss ================================================ $nest-margin: 4px; $row-height: 27px; $button-height: 20px; .dg { /** Clear list styles */ ul { list-style: none; margin: 0; padding: 0; width: 100%; clear: both; } /* Auto-place container */ &.ac { position: fixed; top: 0; left: 0; right: 0; height: 0; z-index: 0; } &:not(.ac) .main { /** Exclude mains in ac so that we don't hide close button */ overflow: hidden; } &.main { @include transition(opacity, 0.1s, linear); &.taller-than-window { overflow-y: auto; .close-button { opacity: 1; /* TODO, these are style notes */ margin-top: -1px; border-top: 1px solid $border-color; } } ul.closed .close-button { opacity: 1 !important; } &:hover .close-button, .close-button.drag { opacity: 1; } .close-button { /*opacity: 0;*/ @include transition(opacity, 0.1s, linear); border: 0; line-height: $button-height - 1; height: $button-height; /* TODO, these are style notes */ cursor: pointer; text-align: center; background-color: #000; &.close-top { position: relative; } &.close-bottom { position: absolute; } &:hover { background-color: #111; } } } /* Auto-placed GUI's */ &.a { float: right; margin-right: 15px; overflow-y:visible; &.has-save > ul { &.close-top { margin-top: 0; } &.close-bottom { margin-top: $row-height; } &.closed { margin-top: 0; } } .save-row { top: 0; z-index: 1002; &.close-top { position: relative; } &.close-bottom { position: fixed; } } } li { @include transition(height, 0.1s, ease-out); @include transition(overflow, 0.1s, linear); } /* Line items that don't contain folders. */ li:not(.folder) { cursor: auto; height: $row-height; line-height: $row-height; padding: 0 4px 0 5px; } li.folder { padding: 0; border-left: $nest-margin solid rgba(0, 0, 0, 0); } /** Folder names */ li.title { cursor: pointer; margin-left: -$nest-margin; } /** Hides closed items */ .closed li:not(.title), .closed ul li, .closed ul li > * { height: 0; overflow: hidden; border: 0; } /** Controller row */ .cr { clear: both; padding-left: 3px; height: $row-height; overflow: hidden; } /** Name-half (left) */ .property-name { cursor: default; float: left; clear: left; width: 40%; overflow: hidden; text-overflow: ellipsis; } /** Function controllers can use the entire width */ .cr.function .property-name { width: 100%; } /** Controller-half (right) */ .c { float: left; width: 60%; position: relative; } /** Controller placement */ .c input[type=text] { border: 0; margin-top: 4px; padding: 3px; width: 100%; float: right; } /** Shorter number boxes when slider is present. */ .has-slider input[type=text] { width: 30%; /*display: none;*/ margin-left: 0; } .slider { float: left; width: 66%; margin-left: -5px; margin-right: 0; height: 19px; margin-top: 4px; } .slider-fg { height: 100%; } .c input[type=checkbox] { margin-top: 7px; } .c select { margin-top: 5px; } /** Ensure the entire boolean and function row shows a hand */ .cr.function, .cr.function .property-name, /* Don't know why I need to be this explicit */ .cr.function *, .cr.boolean, .cr.boolean * { cursor: pointer; } /** allow overflow for color selector */ .cr.color { overflow: visible; } .selector { display: none; position: absolute; margin-left: -9px; margin-top: 23px; z-index: 10; } .c:hover .selector, .selector.drag { display: block; } li.save-row { padding: 0; .button { display: inline-block; padding: 0px 6px; } } &.dialogue { background-color: #222; width: 460px; padding: 15px; font-size: 13px; line-height: 15px; } } /* TODO Separate style and structure */ #dg-new-constructor { padding: 10px; color: #222; font-family: Monaco, monospace; font-size: 10px; border: 0; resize: none; box-shadow: inset 1px 1px 1px #888; word-wrap: break-word; margin: 12px 0; display: block; width: 440px; overflow-y: scroll; height: 100px; position: relative; } #dg-local-explain { display: none; font-size: 11px; line-height: 17px; border-radius: 3px; background-color: #333; padding: 8px; margin-top: 10px; code { font-size: 10px; } } #dat-gui-save-locally { display: none; } ================================================ FILE: src/dat/gui/saveDialogue.html.js ================================================ const saveDialogContents = `
Here's the new load parameter for your GUI's constructor:
Automatically save values to localStorage on exit.
The values saved to localStorage will override those passed to dat.GUI's constructor. This makes it easier to work incrementally, but localStorage is fragile, and your friends may not see the same values you do.
`; export default saveDialogContents; ================================================ FILE: src/dat/gui/style.scss ================================================ $background-color: #1a1a1a; $hover-lighten: 5%; $border-lighten: 7%; $active-lighten: 10%; $number-color: #2FA1D6; $boolean-color: #806787; $string-color: #1ed36f; $function-color: #e61d5f; $save-row-color: #dad5cb; $button-color: darken($save-row-color, 10%); $border-color: lighten($background-color, $border-lighten); $input-color: lighten($background-color, 8.5%); @mixin transition($prop, $time, $curve) { -webkit-transition: $prop $time $curve; -o-transition: $prop $time $curve; -moz-transition: $prop $time $curve; transition: $prop $time $curve; } @mixin gradient($a, $b) { background: -webkit-gradient(linear, 0% 0%, 0% 100%, from($a), to($b)); background: -o-gradient(linear, 0% 0%, 0% 100%, from($a), to($b)); background: -moz-gradient(linear, 0% 0%, 0% 100%, from($a), to($b)); } @mixin button() { margin-left: 5px; margin-top: 1px; border-radius: 2px; font-size: 9px; line-height: 7px; padding: 4px 4px 5px 4px; background: $button-color; color: #fff; text-shadow: 0 1px 0 darken($button-color, 10%); box-shadow: 0 -1px 0 darken($button-color, 10%); cursor: pointer; } @mixin gears() { background: $button-color url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat; height: 7px; width: 8px; } @import "structure"; /** Main type */ .dg { color: #eee; font: 11px 'Lucida Grande', sans-serif; text-shadow: 0 -1px 0 #111; /** Auto place */ &.main { /** Scrollbar */ &::-webkit-scrollbar { width: 5px; background: $background-color; } &::-webkit-scrollbar-corner { height: 0; display: none; } &::-webkit-scrollbar-thumb { border-radius: 5px; background: lighten($background-color, 30%); } } li { &:not(.folder) { background: $background-color; border-bottom: 1px solid $border-color; } &.save-row { line-height: 25px; background: $save-row-color; border: 0; select { margin-left: 5px; width: 108px; } .button { &.gears { @include gears; } @include button; &:hover { background-color: darken($button-color, 5%); box-shadow: 0 -1px 0 darken($button-color, 10%); } } } &.folder { border-bottom: 0; } &.title { padding-left: 16px; background: #000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat; cursor: pointer; border-bottom: 1px solid rgba(255, 255, 255, 0.2); } } .closed li.title { background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); } /* Controller row,
  • */ .cr { &.boolean { border-left: 3px solid $boolean-color; } &.color { border-left: 3px solid; } &.function { border-left: 3px solid $function-color; } &.number { border-left: 3px solid $number-color; input[type=text] { color: $number-color; } } &.string { border-left: 3px solid $string-color; input[type=text] { color: $string-color; } } &.function:hover, &.boolean:hover { background: #111; } } /** Controllers */ .c { input[type=text] { background: $input-color; outline: none; &:hover { background: lighten($input-color, $hover-lighten); } &:focus { background: lighten($input-color, $active-lighten); color: #fff; } } .slider { background: $input-color; cursor: ew-resize; } .slider-fg { background: $number-color; max-width: 100%; } .slider:hover { background: lighten($input-color, $hover-lighten); .slider-fg { background: lighten($number-color, $hover-lighten); } } } } ================================================ FILE: src/dat/index.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ import Color from './color/Color'; import math from './color/math'; import interpret from './color/interpret'; import Controller from './controllers/Controller'; import BooleanController from './controllers/BooleanController'; import OptionController from './controllers/OptionController'; import StringController from './controllers/StringController'; import NumberController from './controllers/NumberController'; import NumberControllerBox from './controllers/NumberControllerBox'; import NumberControllerSlider from './controllers/NumberControllerSlider'; import FunctionController from './controllers/FunctionController'; import ColorController from './controllers/ColorController'; import domImport from './dom/dom'; import GUIImport from './gui/GUI'; export const color = { Color: Color, math: math, interpret: interpret }; export const controllers = { Controller: Controller, BooleanController: BooleanController, OptionController: OptionController, StringController: StringController, NumberController: NumberController, NumberControllerBox: NumberControllerBox, NumberControllerSlider: NumberControllerSlider, FunctionController: FunctionController, ColorController: ColorController }; export const dom = { dom: domImport }; export const gui = { GUI: GUIImport }; export const GUI = GUIImport; export default { color, controllers, dom, gui, GUI }; ================================================ FILE: src/dat/utils/common.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ const ARR_EACH = Array.prototype.forEach; const ARR_SLICE = Array.prototype.slice; /** * Band-aid methods for things that should be a lot easier in JavaScript. * Implementation and structure inspired by underscore.js * http://documentcloud.github.com/underscore/ */ const Common = { BREAK: {}, extend: function(target) { this.each(ARR_SLICE.call(arguments, 1), function(obj) { const keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function(key) { if (!this.isUndefined(obj[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, defaults: function(target) { this.each(ARR_SLICE.call(arguments, 1), function(obj) { const keys = this.isObject(obj) ? Object.keys(obj) : []; keys.forEach(function(key) { if (this.isUndefined(target[key])) { target[key] = obj[key]; } }.bind(this)); }, this); return target; }, compose: function() { const toCall = ARR_SLICE.call(arguments); return function() { let args = ARR_SLICE.call(arguments); for (let i = toCall.length - 1; i >= 0; i--) { args = [toCall[i].apply(this, args)]; } return args[0]; }; }, each: function(obj, itr, scope) { if (!obj) { return; } if (ARR_EACH && obj.forEach && obj.forEach === ARR_EACH) { obj.forEach(itr, scope); } else if (obj.length === obj.length + 0) { // Is number but not NaN let key; let l; for (key = 0, l = obj.length; key < l; key++) { if (key in obj && itr.call(scope, obj[key], key) === this.BREAK) { return; } } } else { for (const key in obj) { if (itr.call(scope, obj[key], key) === this.BREAK) { return; } } } }, defer: function(fnc) { setTimeout(fnc, 0); }, // if the function is called repeatedly, wait until threshold passes until we execute the function debounce: function(func, threshold, callImmediately) { let timeout; return function() { const obj = this; const args = arguments; function delayed() { timeout = null; if (!callImmediately) func.apply(obj, args); } const callNow = callImmediately || !timeout; clearTimeout(timeout); timeout = setTimeout(delayed, threshold); if (callNow) { func.apply(obj, args); } }; }, toArray: function(obj) { if (obj.toArray) return obj.toArray(); return ARR_SLICE.call(obj); }, isUndefined: function(obj) { return obj === undefined; }, isNull: function(obj) { return obj === null; }, isNaN: function(obj) { return isNaN(obj); }, isArray: Array.isArray || function(obj) { return obj.constructor === Array; }, isObject: function(obj) { return obj === Object(obj); }, isNumber: function(obj) { return obj === obj + 0; }, isString: function(obj) { return obj === obj + ''; }, isBoolean: function(obj) { return obj === false || obj === true; }, isFunction: function(obj) { return obj instanceof Function; } }; export default Common; ================================================ FILE: src/dat/utils/css.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ const css = { load: function(url, indoc) { const doc = indoc || document; const link = doc.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = url; doc.getElementsByTagName('head')[0].appendChild(link); }, inject: function(cssContent, indoc) { const doc = indoc || document; const injected = document.createElement('style'); injected.type = 'text/css'; injected.innerHTML = cssContent; const head = doc.getElementsByTagName('head')[0]; try { head.appendChild(injected); } catch (e) { // Unable to inject CSS, probably because of a Content Security Policy } } }; export default css; ================================================ FILE: src/dat/utils/requestAnimationFrame.js ================================================ /** * dat-gui JavaScript Controller Library * https://github.com/dataarts/dat.gui * * Copyright 2011 Data Arts Team, Google Creative Lab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 */ function requestAnimationFrame(callback) { setTimeout(callback, 1000 / 60); } export default window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || requestAnimationFrame; ================================================ FILE: tests/index.html ================================================

      test markup, will be hidden
      ================================================ FILE: tests/jquery.js ================================================ /*! * jQuery JavaScript Library v1.6.4 * http://jquery.com/ * * Copyright 2011, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Mon Sep 12 18:54:48 2011 -0400 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) var document = window.document, navigator = window.navigator, location = window.location; var jQuery = (function() { // Define a local copy of jQuery var jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // A central reference to the root jQuery(document) rootjQuery, // A simple way to check for HTML strings or ID strings // Prioritize #id over to avoid XSS via location.hash (#9521) quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace trimLeft = /^\s+/, trimRight = /\s+$/, // Check for digits rdigit = /\d/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // JSON RegExp rvalidchars = /^[\],:{}\s]*$/, rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, // Useragent RegExp rwebkit = /(webkit)[ \/]([\w.]+)/, ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, // Matches dashed string for camelizing rdashAlpha = /-([a-z]|[0-9])/ig, rmsPrefix = /^-ms-/, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return ( letter + "" ).toUpperCase(); }, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // The deferred used on DOM ready readyList, // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, trim = String.prototype.trim, indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs class2type = {}; jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // The body element only exists once, optimize finding it if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; this.selector = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = quickExpr.exec( selector ); } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; doc = (context ? context.ownerDocument || context : document); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; } return jQuery.merge( this, selector ); // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return (context || rootjQuery).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if (selector.selector !== undefined) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.6.4", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { // Build a new jQuery matched element set var ret = this.constructor(); if ( jQuery.isArray( elems ) ) { push.apply( ret, elems ); } else { jQuery.merge( ret, elems ); } // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + (this.selector ? " " : "") + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // Add the callback readyList.done( fn ); return this; }, eq: function( i ) { return i === -1 ? this.slice( i ) : this.slice( i, +i + 1 ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).unbind( "ready" ); } } }, bindReady: function() { if ( readyList ) { return; } readyList = jQuery._Deferred(); // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, // A crude way of determining if an object is a window isWindow: function( obj ) { return obj && typeof obj === "object" && "setInterval" in obj; }, isNaN: function( obj ) { return obj == null || !rdigit.test( obj ) || isNaN( obj ); }, type: function( obj ) { return obj == null ? String( obj ) : class2type[ toString.call(obj) ] || "object"; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw msg; }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return (new Function( "return " + data ))(); } jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing parseXML: function( data ) { var xml, tmp; try { if ( window.DOMParser ) { // Standard tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, noop: function() {}, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && rnotwhite.test( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { break; } } } } return object; }, // Use native String.trim function wherever possible trim: trim ? function( text ) { return text == null ? "" : trim.call( text ); } : // Otherwise use our own trimming functionality function( text ) { return text == null ? "" : text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); }, // results is for internal usage only makeArray: function( array, results ) { var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array ) { if ( !array ) { return -1; } if ( indexOf ) { return indexOf.call( array, elem ); } for ( var i = 0, length = array.length; i < length; i++ ) { if ( array[ i ] === elem ) { return i; } } return -1; }, merge: function( first, second ) { var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var ret = [], retVal; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, key, ret = [], i = 0, length = elems.length, // jquery objects are treated as arrays isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } // Go through every key on the object, } else { for ( key in elems ) { value = callback( elems[ key ], key, arg ); if ( value != null ) { ret[ ret.length ] = value; } } } // Flatten any nested arrays return ret.concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { if ( typeof context === "string" ) { var tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind var args = slice.call( arguments, 2 ), proxy = function() { return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; return proxy; }, // Mutifunctional method to get and set values to a collection // The value/s can optionally be executed if it's a function access: function( elems, key, value, exec, fn, pass ) { var length = elems.length; // Setting many attributes if ( typeof key === "object" ) { for ( var k in key ) { jQuery.access( elems, k, key[k], exec, fn, value ); } return elems; } // Setting one attribute if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = !pass && exec && jQuery.isFunction(value); for ( var i = 0; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } return elems; } // Getting an attribute return length ? fn( elems[0], key ) : undefined; }, now: function() { return (new Date()).getTime(); }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, sub: function() { function jQuerySub( selector, context ) { return new jQuerySub.fn.init( selector, context ); } jQuery.extend( true, jQuerySub, this ); jQuerySub.superclass = this; jQuerySub.fn = jQuerySub.prototype = this(); jQuerySub.fn.constructor = jQuerySub; jQuerySub.sub = this.sub; jQuerySub.fn.init = function init( selector, context ) { if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { context = jQuerySub( context ); } return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; jQuerySub.fn.init.prototype = jQuerySub.fn; var rootjQuerySub = jQuerySub(document); return jQuerySub; }, browser: {} }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); browserMatch = jQuery.uaMatch( userAgent ); if ( browserMatch.browser ) { jQuery.browser[ browserMatch.browser ] = true; jQuery.browser.version = browserMatch.version; } // Deprecated, use jQuery.browser.webkit instead if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } // All jQuery objects should point back to these rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }; } // The DOM ready check for Internet Explorer function doScrollCheck() { if ( jQuery.isReady ) { return; } try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch(e) { setTimeout( doScrollCheck, 1 ); return; } // and execute any waiting functions jQuery.ready(); } return jQuery; })(); var // Promise methods promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), // Static reference to slice sliceDeferred = [].slice; jQuery.extend({ // Create a simple deferred (one callbacks list) _Deferred: function() { var // callbacks list callbacks = [], // stored [ context , args ] fired, // to avoid firing when already doing so firing, // flag to know if the deferred has been cancelled cancelled, // the deferred itself deferred = { // done( f1, f2, ...) done: function() { if ( !cancelled ) { var args = arguments, i, length, elem, type, _fired; if ( fired ) { _fired = fired; fired = 0; } for ( i = 0, length = args.length; i < length; i++ ) { elem = args[ i ]; type = jQuery.type( elem ); if ( type === "array" ) { deferred.done.apply( deferred, elem ); } else if ( type === "function" ) { callbacks.push( elem ); } } if ( _fired ) { deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); } } return this; }, // resolve with given context and args resolveWith: function( context, args ) { if ( !cancelled && !fired && !firing ) { // make sure args are available (#8421) args = args || []; firing = 1; try { while( callbacks[ 0 ] ) { callbacks.shift().apply( context, args ); } } finally { fired = [ context, args ]; firing = 0; } } return this; }, // resolve with this as context and given arguments resolve: function() { deferred.resolveWith( this, arguments ); return this; }, // Has this deferred been resolved? isResolved: function() { return !!( firing || fired ); }, // Cancel cancel: function() { cancelled = 1; callbacks = []; return this; } }; return deferred; }, // Full fledged deferred (two callbacks list) Deferred: function( func ) { var deferred = jQuery._Deferred(), failDeferred = jQuery._Deferred(), promise; // Add errorDeferred methods, then and promise jQuery.extend( deferred, { then: function( doneCallbacks, failCallbacks ) { deferred.done( doneCallbacks ).fail( failCallbacks ); return this; }, always: function() { return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); }, fail: failDeferred.done, rejectWith: failDeferred.resolveWith, reject: failDeferred.resolve, isRejected: failDeferred.isResolved, pipe: function( fnDone, fnFail ) { return jQuery.Deferred(function( newDefer ) { jQuery.each( { done: [ fnDone, "resolve" ], fail: [ fnFail, "reject" ] }, function( handler, data ) { var fn = data[ 0 ], action = data[ 1 ], returned; if ( jQuery.isFunction( fn ) ) { deferred[ handler ](function() { returned = fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise().then( newDefer.resolve, newDefer.reject ); } else { newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); } }); } else { deferred[ handler ]( newDefer[ action ] ); } }); }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { if ( obj == null ) { if ( promise ) { return promise; } promise = obj = {}; } var i = promiseMethods.length; while( i-- ) { obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; } return obj; } }); // Make sure only one callback list will be used deferred.done( failDeferred.cancel ).fail( deferred.cancel ); // Unexpose cancel delete deferred.cancel; // Call given func if any if ( func ) { func.call( deferred, deferred ); } return deferred; }, // Deferred helper when: function( firstParam ) { var args = arguments, i = 0, length = args.length, count = length, deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? firstParam : jQuery.Deferred(); function resolveFunc( i ) { return function( value ) { args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; if ( !( --count ) ) { // Strange bug in FF4: // Values changed onto the arguments object sometimes end up as undefined values // outside the $.when method. Cloning the object into a fresh array solves the issue deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); } }; } if ( length > 1 ) { for( ; i < length; i++ ) { if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { args[ i ].promise().then( resolveFunc(i), deferred.reject ); } else { --count; } } if ( !count ) { deferred.resolveWith( deferred, args ); } } else if ( deferred !== firstParam ) { deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); } return deferred.promise(); } }); jQuery.support = (function() { var div = document.createElement( "div" ), documentElement = document.documentElement, all, a, select, opt, input, marginDiv, support, fragment, body, testElementParent, testElement, testElementStyle, tds, events, eventName, i, isSupported; // Preliminary tests div.setAttribute("className", "t"); div.innerHTML = "
      a"; all = div.getElementsByTagName( "*" ); a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { return {}; } // First batch of supports tests select = document.createElement( "select" ); opt = select.appendChild( document.createElement("option") ); input = div.getElementsByTagName( "input" )[ 0 ]; support = { // IE strips leading whitespace when .innerHTML is used leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName( "tbody" ).length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName( "link" ).length, // Get the style information from getAttribute // (IE uses .cssText instead) style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.55$/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // Will be defined later submitBubbles: true, changeBubbles: true, focusinBubbles: false, deleteExpando: true, noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, reliableMarginRight: true }; // Make sure checked status is properly cloned input.checked = true; support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled // (WebKit marks them as disabled) select.disabled = true; support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; } catch( e ) { support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) support.noCloneEvent = false; }); div.cloneNode( true ).fireEvent( "onclick" ); } // Check if a radio maintains it's value // after being appended to the DOM input = document.createElement("input"); input.value = "t"; input.setAttribute("type", "radio"); support.radioValue = input.value === "t"; input.setAttribute("checked", "checked"); div.appendChild( input ); fragment = document.createDocumentFragment(); fragment.appendChild( div.firstChild ); // WebKit doesn't clone checked state correctly in fragments support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; div.innerHTML = ""; // Figure out if the W3C box model works as expected div.style.width = div.style.paddingLeft = "1px"; body = document.getElementsByTagName( "body" )[ 0 ]; // We use our own, invisible, body unless the body is already present // in which case we use a div (#9239) testElement = document.createElement( body ? "div" : "body" ); testElementStyle = { visibility: "hidden", width: 0, height: 0, border: 0, margin: 0, background: "none" }; if ( body ) { jQuery.extend( testElementStyle, { position: "absolute", left: "-1000px", top: "-1000px" }); } for ( i in testElementStyle ) { testElement.style[ i ] = testElementStyle[ i ]; } testElement.appendChild( div ); testElementParent = body || documentElement; testElementParent.insertBefore( testElement, testElementParent.firstChild ); // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) support.appendChecked = input.checked; support.boxModel = div.offsetWidth === 2; if ( "zoom" in div.style ) { // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout // (IE < 8 does this) div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); // Check if elements with layout shrink-wrap their children // (IE 6 does this) div.style.display = ""; div.innerHTML = "
      "; support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); } div.innerHTML = "
      t
      "; tds = div.getElementsByTagName( "td" ); // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a // table row; if so, offsetWidth/Height are not reliable for use when // determining if an element has been hidden directly using // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). // (only IE 8 fails this test) isSupported = ( tds[ 0 ].offsetHeight === 0 ); tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; // Check if empty table cells still have offsetWidth/Height // (IE < 8 fail this test) support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); div.innerHTML = ""; // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. For more // info see bug #3333 // Fails in WebKit before Feb 2011 nightlies // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right if ( document.defaultView && document.defaultView.getComputedStyle ) { marginDiv = document.createElement( "div" ); marginDiv.style.width = "0"; marginDiv.style.marginRight = "0"; div.appendChild( marginDiv ); support.reliableMarginRight = ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; } // Remove the body element we added testElement.innerHTML = ""; testElementParent.removeChild( testElement ); // Technique from Juriy Zaytsev // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ // We only care about the case where non-standard event systems // are used, namely in IE. Short-circuiting here helps us to // avoid an eval call (in setAttribute) which can cause CSP // to go haywire. See: https://developer.mozilla.org/en/Security/CSP if ( div.attachEvent ) { for( i in { submit: 1, change: 1, focusin: 1 } ) { eventName = "on" + i; isSupported = ( eventName in div ); if ( !isSupported ) { div.setAttribute( eventName, "return;" ); isSupported = ( typeof div[ eventName ] === "function" ); } support[ i + "Bubbles" ] = isSupported; } } // Null connected elements to avoid leaks in IE testElement = fragment = select = opt = body = marginDiv = div = input = null; return support; })(); // Keep track of boxModel jQuery.boxModel = jQuery.support.boxModel; var rbrace = /^(?:\{.*\}|\[.*\])$/, rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, // Please use with caution uuid: 0, // Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, // Ban all objects except for Flash (which handle expandos) "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, ret, internalKey = jQuery.expando, getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || (pvt && id && (cache[ id ] && !cache[ id ][ internalKey ]))) && getByName && data === undefined ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { elem[ jQuery.expando ] = id = ++jQuery.uuid; } else { id = jQuery.expando; } } if ( !cache[ id ] ) { cache[ id ] = {}; // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery // metadata on plain JS objects when the object is serialized using // JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); } else { cache[ id ] = jQuery.extend(cache[ id ], name); } } thisCache = cache[ id ]; // Internal jQuery data is stored in a separate object inside the object's data // cache in order to avoid key collisions between internal data and user-defined // data if ( pvt ) { if ( !thisCache[ internalKey ] ) { thisCache[ internalKey ] = {}; } thisCache = thisCache[ internalKey ]; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should // not attempt to inspect the internal events object using jQuery.data, as this // internal data object is undocumented and subject to change. if ( name === "events" && !thisCache[name] ) { return thisCache[ internalKey ] && thisCache[ internalKey ].events; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( getByName ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, // Reference to internal data cache key internalKey = jQuery.expando, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, // See jQuery.data for more information id = isNode ? elem[ jQuery.expando ] : jQuery.expando; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; if ( thisCache ) { // Support interoperable removal of hyphenated or camelcased keys if ( !thisCache[ name ] ) { name = jQuery.camelCase( name ); } delete thisCache[ name ]; // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( !isEmptyDataObject(thisCache) ) { return; } } } // See jQuery.data for more information if ( pvt ) { delete cache[ id ][ internalKey ]; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject(cache[ id ]) ) { return; } } var internalCache = cache[ id ][ internalKey ]; // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care // Ensure that `cache` is not a window object #10080 if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } // We destroyed the entire user cache at once because it's faster than // iterating through each key, but we need to continue to persist internal // data if it existed if ( internalCache ) { cache[ id ] = {}; // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery // metadata on plain JS objects when the object is serialized using // JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } cache[ id ][ internalKey ] = internalCache; // Otherwise, we need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist } else if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( jQuery.support.deleteExpando ) { delete elem[ jQuery.expando ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( jQuery.expando ); } else { elem[ jQuery.expando ] = null; } } }, // For internal use only. _data: function( elem, name, data ) { return jQuery.data( elem, name, data, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { if ( elem.nodeName ) { var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; if ( match ) { return !(match === true || elem.getAttribute("classid") !== match); } } return true; } }); jQuery.fn.extend({ data: function( key, value ) { var data = null; if ( typeof key === "undefined" ) { if ( this.length ) { data = jQuery.data( this[0] ); if ( this[0].nodeType === 1 ) { var attr = this[0].attributes, name; for ( var i = 0, l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.substring(5) ); dataAttr( this[0], name, data[ name ] ); } } } } return data; } else if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } var parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; if ( value === undefined ) { data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); // Try to fetch any internally stored data first if ( data === undefined && this.length ) { data = jQuery.data( this[0], key ); data = dataAttr( this[0], key, data ); } return data === undefined && parts[1] ? this.data( parts[0] ) : data; } else { return this.each(function() { var $this = jQuery( this ), args = [ parts[0], value ]; $this.triggerHandler( "setData" + parts[1] + "!", args ); jQuery.data( this, key, value ); $this.triggerHandler( "changeData" + parts[1] + "!", args ); }); } }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : !jQuery.isNaN( data ) ? parseFloat( data ) : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON // property to be considered empty objects; this property always exists in // order to make sure JSON.stringify does not expose internal metadata function isEmptyDataObject( obj ) { for ( var name in obj ) { if ( name !== "toJSON" ) { return false; } } return true; } function handleQueueMarkDefer( elem, type, src ) { var deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", defer = jQuery.data( elem, deferDataKey, undefined, true ); if ( defer && ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { // Give room for hard-coded callbacks to fire first // and eventually mark/queue something else on the element setTimeout( function() { if ( !jQuery.data( elem, queueDataKey, undefined, true ) && !jQuery.data( elem, markDataKey, undefined, true ) ) { jQuery.removeData( elem, deferDataKey, true ); defer.resolve(); } }, 0 ); } } jQuery.extend({ _mark: function( elem, type ) { if ( elem ) { type = (type || "fx") + "mark"; jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); } }, _unmark: function( force, elem, type ) { if ( force !== true ) { type = elem; elem = force; force = false; } if ( elem ) { type = type || "fx"; var key = type + "mark", count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); if ( count ) { jQuery.data( elem, key, count, true ); } else { jQuery.removeData( elem, key, true ); handleQueueMarkDefer( elem, type, "mark" ); } } }, queue: function( elem, type, data ) { if ( elem ) { type = (type || "fx") + "queue"; var q = jQuery.data( elem, type, undefined, true ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !q || jQuery.isArray(data) ) { q = jQuery.data( elem, type, jQuery.makeArray(data), true ); } else { q.push( data ); } } return q || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), fn = queue.shift(), defer; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift("inprogress"); } fn.call(elem, function() { jQuery.dequeue(elem, type); }); } if ( !queue.length ) { jQuery.removeData( elem, type + "queue", true ); handleQueueMarkDefer( elem, type, "queue" ); } } }); jQuery.fn.extend({ queue: function( type, data ) { if ( typeof type !== "string" ) { data = type; type = "fx"; } if ( data === undefined ) { return jQuery.queue( this[0], type ); } return this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; type = type || "fx"; return this.queue( type, function() { var elem = this; setTimeout(function() { jQuery.dequeue( elem, type ); }, time ); }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, object ) { if ( typeof type !== "string" ) { object = type; type = undefined; } type = type || "fx"; var defer = jQuery.Deferred(), elements = this, i = elements.length, count = 1, deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", tmp; function resolve() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } } while( i-- ) { if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { count++; tmp.done( resolve ); } } resolve(); return defer.promise(); } }); var rclass = /[\n\t\r]/g, rspace = /\s+/, rreturn = /\r/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, nodeHook, boolHook; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }, prop: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.prop ); }, removeProp: function( name ) { name = jQuery.propFix[ name ] || name; return this.each(function() { // try/catch handles cases where IE balks (such as removing a property on window) try { this[ name ] = undefined; delete this[ name ]; } catch( e ) {} }); }, addClass: function( value ) { var classNames, i, l, elem, setClass, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { classNames = value.split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 ) { if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { setClass = " " + elem.className + " "; for ( c = 0, cl = classNames.length; c < cl; c++ ) { if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); } } } } return this; }, removeClass: function( value ) { var classNames, i, l, elem, className, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { classNames = (value || "").split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { className = (" " + elem.className + " ").replace( rclass, " " ); for ( c = 0, cl = classNames.length; c < cl; c++ ) { className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); } else { elem.className = ""; } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } } else if ( type === "undefined" || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); } // toggle whole className this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " "; for ( var i = 0, l = this.length; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } return false; }, val: function( value ) { var hooks, ret, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; } return undefined; } var isFunction = jQuery.isFunction( value ); return this.each(function( i ) { var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, self.val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( jQuery.isArray( val ) ) { val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); } }); jQuery.extend({ valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; // Nothing was selected if ( index < 0 ) { return null; } // Loop through all the selected options for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { var option = options[ i ]; // Don't return options that are disabled or in a disabled optgroup if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } // Fixes Bug #2551 -- select.val() broken in IE after form.reset() if ( one && !values.length && options.length ) { return jQuery( options[ index ] ).val(); } return values; }, set: function( elem, value ) { var values = jQuery.makeArray( value ); jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { elem.selectedIndex = -1; } return values; } } }, attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attrFix: { // Always normalize to ensure hook usage tabindex: "tabIndex" }, attr: function( elem, name, value, pass ) { var nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( !("getAttribute" in elem) ) { return jQuery.prop( elem, name, value ); } var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // Normalize the name if needed if ( notxml ) { name = jQuery.attrFix[ name ] || name; hooks = jQuery.attrHooks[ name ]; if ( !hooks ) { // Use boolHook for boolean attributes if ( rboolean.test( name ) ) { hooks = boolHook; // Use nodeHook if available( IE6/7 ) } else if ( nodeHook ) { hooks = nodeHook; } } } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return undefined; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, "" + value ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }, removeAttr: function( elem, name ) { var propName; if ( elem.nodeType === 1 ) { name = jQuery.attrFix[ name ] || name; jQuery.attr( elem, name, "" ); elem.removeAttribute( name ); // Set corresponding property to false for boolean attributes if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { elem[ propName ] = false; } } }, attrHooks: { type: { set: function( elem, value ) { // We can't allow the type property to be changed (since it causes problems in IE) if ( rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { // Setting the type on a radio button after the value resets the value in IE6-9 // Reset value to it's default in case type is set after value // This is for element creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } }, // Use the value property for back compat // Use the nodeHook for button elements in IE6/7 (#1954) value: { get: function( elem, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.get( elem, name ); } return name in elem ? elem.value : null; }, set: function( elem, value, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.set( elem, value, name ); } // Does not return so that setAttribute is also used elem.value = value; } } }, propFix: { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, prop: function( elem, name, value ) { var nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { return (elem[ name ] = value); } } else { if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { return elem[ name ]; } } }, propHooks: { tabIndex: { get: function( elem ) { // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ var attributeNode = elem.getAttributeNode("tabindex"); return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } } }); // Add the tabindex propHook to attrHooks for back-compat jQuery.attrHooks.tabIndex = jQuery.propHooks.tabIndex; // Hook for boolean attributes boolHook = { get: function( elem, name ) { // Align boolean attributes with corresponding properties // Fall back to attribute presence where some booleans are not supported var attrNode; return jQuery.prop( elem, name ) === true || ( attrNode = elem.getAttributeNode( name ) ) && attrNode.nodeValue !== false ? name.toLowerCase() : undefined; }, set: function( elem, value, name ) { var propName; if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { // value is true since we know at this point it's type boolean and not false // Set boolean attributes to the same name and set the DOM property propName = jQuery.propFix[ name ] || name; if ( propName in elem ) { // Only set the IDL specifically if it already exists on the element elem[ propName ] = true; } elem.setAttribute( name, name.toLowerCase() ); } return name; } }; // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !jQuery.support.getSetAttribute ) { // Use this for any attribute in IE6/7 // This fixes almost every IE6/7 issue nodeHook = jQuery.valHooks.button = { get: function( elem, name ) { var ret; ret = elem.getAttributeNode( name ); // Return undefined if nodeValue is empty string return ret && ret.nodeValue !== "" ? ret.nodeValue : undefined; }, set: function( elem, value, name ) { // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); if ( !ret ) { ret = document.createAttribute( name ); elem.setAttributeNode( ret ); } return (ret.nodeValue = value + ""); } }; // Set width and height to auto instead of 0 on empty string( Bug #8150 ) // This is for removals jQuery.each([ "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( value === "" ) { elem.setAttribute( name, "auto" ); return value; } } }); }); } // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { var ret = elem.getAttribute( name, 2 ); return ret === null ? undefined : ret; } }); }); } if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string // Normalize to lowercase since IE uppercases css property names return elem.style.cssText.toLowerCase() || undefined; }, set: function( elem, value ) { return (elem.style.cssText = "" + value); } }; } // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } return null; } }); } // Radios and checkboxes getter/setter if ( !jQuery.support.checkOn ) { jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { get: function( elem ) { // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; } }; }); } jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); } } }); }); var rnamespaces = /\.(.*)$/, rformElems = /^(?:textarea|input|select)$/i, rperiod = /\./g, rspaces = / /g, rescape = /[^\w\s.|`]/g, fcleanup = function( nm ) { return nm.replace(rescape, "\\$&"); }; /* * A number of helper functions used for managing events. * Many of the ideas behind this code originated from * Dean Edwards' addEvent library. */ jQuery.event = { // Bind an event to an element // Original by Dean Edwards add: function( elem, types, handler, data ) { if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } if ( handler === false ) { handler = returnFalse; } else if ( !handler ) { // Fixes bug #7229. Fix recommended by jdalton return; } var handleObjIn, handleObj; if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; } // Make sure that the function being executed has a unique ID if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure var elemData = jQuery._data( elem ); // If no elemData is found then we must be trying to bind to one of the // banned noData elements if ( !elemData ) { return; } var events = elemData.events, eventHandle = elemData.handle; if ( !events ) { elemData.events = events = {}; } if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; }; } // Add elem as a property of the handle function // This is to prevent a memory leak with non-native events in IE. eventHandle.elem = elem; // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = types.split(" "); var type, i = 0, namespaces; while ( (type = types[ i++ ]) ) { handleObj = handleObjIn ? jQuery.extend({}, handleObjIn) : { handler: handler, data: data }; // Namespaced event handlers if ( type.indexOf(".") > -1 ) { namespaces = type.split("."); type = namespaces.shift(); handleObj.namespace = namespaces.slice(0).sort().join("."); } else { namespaces = []; handleObj.namespace = ""; } handleObj.type = type; if ( !handleObj.guid ) { handleObj.guid = handler.guid; } // Get the current list of functions bound to this event var handlers = events[ type ], special = jQuery.event.special[ type ] || {}; // Init the event handler queue if ( !handlers ) { handlers = events[ type ] = []; // Check for a special event handler // Only use addEventListener/attachEvent if the special // events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add the function to the element's handler list handlers.push( handleObj ); // Keep track of which events have been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, global: {}, // Detach an event or set of events from an element remove: function( elem, types, handler, pos ) { // don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } if ( handler === false ) { handler = returnFalse; } var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ), events = elemData && elemData.events; if ( !elemData || !events ) { return; } // types is actually an event object here if ( types && types.type ) { handler = types.handler; types = types.type; } // Unbind all events for the element if ( !types || typeof types === "string" && types.charAt(0) === "." ) { types = types || ""; for ( type in events ) { jQuery.event.remove( elem, type + types ); } return; } // Handle multiple events separated by a space // jQuery(...).unbind("mouseover mouseout", fn); types = types.split(" "); while ( (type = types[ i++ ]) ) { origType = type; handleObj = null; all = type.indexOf(".") < 0; namespaces = []; if ( !all ) { // Namespaced event handlers namespaces = type.split("."); type = namespaces.shift(); namespace = new RegExp("(^|\\.)" + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); } eventType = events[ type ]; if ( !eventType ) { continue; } if ( !handler ) { for ( j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( all || namespace.test( handleObj.namespace ) ) { jQuery.event.remove( elem, origType, handleObj.handler, j ); eventType.splice( j--, 1 ); } } continue; } special = jQuery.event.special[ type ] || {}; for ( j = pos || 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( handler.guid === handleObj.guid ) { // remove the given handler for the given type if ( all || namespace.test( handleObj.namespace ) ) { if ( pos == null ) { eventType.splice( j--, 1 ); } if ( special.remove ) { special.remove.call( elem, handleObj ); } } if ( pos != null ) { break; } } } // remove generic event handler if no more handlers exist if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } ret = null; delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { var handle = elemData.handle; if ( handle ) { handle.elem = null; } delete elemData.events; delete elemData.handle; if ( jQuery.isEmptyObject( elemData ) ) { jQuery.removeData( elem, undefined, true ); } } }, // Events that are safe to short-circuit if no handlers are attached. // Native DOM events should not be added, they may have inline handlers. customEvent: { "getData": true, "setData": true, "changeData": true }, trigger: function( event, data, elem, onlyHandlers ) { // Event object or event type var type = event.type || event, namespaces = [], exclusive; if ( type.indexOf("!") >= 0 ) { // Exclusive events trigger only for the exact event (no namespaces) type = type.slice(0, -1); exclusive = true; } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { // No jQuery handlers for this event type, and it can't have inline handlers return; } // Caller can pass in an Event, Object, or just an event type string event = typeof event === "object" ? // jQuery.Event object event[ jQuery.expando ] ? event : // Object literal new jQuery.Event( type, event ) : // Just the event type (string) new jQuery.Event( type ); event.type = type; event.exclusive = exclusive; event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); // triggerHandler() and global events don't bubble or run the default action if ( onlyHandlers || !elem ) { event.preventDefault(); event.stopPropagation(); } // Handle a global trigger if ( !elem ) { // TODO: Stop taunting the data cache; remove global events and always attach to document jQuery.each( jQuery.cache, function() { // internalKey variable is just used to make it easier to find // and potentially change this stuff later; currently it just // points to jQuery.expando var internalKey = jQuery.expando, internalCache = this[ internalKey ]; if ( internalCache && internalCache.events && internalCache.events[ type ] ) { jQuery.event.trigger( event, data, internalCache.handle.elem ); } }); return; } // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // Clean up the event in case it is being reused event.result = undefined; event.target = elem; // Clone any incoming data and prepend the event, creating the handler arg list data = data != null ? jQuery.makeArray( data ) : []; data.unshift( event ); var cur = elem, // IE doesn't like method names with a colon (#3533, #8272) ontype = type.indexOf(":") < 0 ? "on" + type : ""; // Fire event on the current element, then bubble up the DOM tree do { var handle = jQuery._data( cur, "handle" ); event.currentTarget = cur; if ( handle ) { handle.apply( cur, data ); } // Trigger an inline bound script if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { event.result = false; event.preventDefault(); } // Bubble up to document, then to window cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; } while ( cur && !event.isPropagationStopped() ); // If nobody prevented the default action, do it now if ( !event.isDefaultPrevented() ) { var old, special = jQuery.event.special[ type ] || {}; if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction)() check here because IE6/7 fails that test. // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. try { if ( ontype && elem[ type ] ) { // Don't re-trigger an onFOO event when we call its FOO() method old = elem[ ontype ]; if ( old ) { elem[ ontype ] = null; } jQuery.event.triggered = type; elem[ type ](); } } catch ( ieError ) {} if ( old ) { elem[ ontype ] = old; } jQuery.event.triggered = undefined; } } return event.result; }, handle: function( event ) { event = jQuery.event.fix( event || window.event ); // Snapshot the handlers list since a called handler may add/remove events. var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), run_all = !event.exclusive && !event.namespace, args = Array.prototype.slice.call( arguments, 0 ); // Use the fix-ed Event rather than the (read-only) native event args[0] = event; event.currentTarget = this; for ( var j = 0, l = handlers.length; j < l; j++ ) { var handleObj = handlers[ j ]; // Triggered event must 1) be non-exclusive and have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event. if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { // Pass in a reference to the handler function itself // So that we can later remove it event.handler = handleObj.handler; event.data = handleObj.data; event.handleObj = handleObj; var ret = handleObj.handler.apply( this, args ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) { event.preventDefault(); event.stopPropagation(); } } if ( event.isImmediatePropagationStopped() ) { break; } } } return event.result; }, props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // store a copy of the original event object // and "clone" to set read-only properties var originalEvent = event; event = jQuery.Event( originalEvent ); for ( var i = this.props.length, prop; i; ) { prop = this.props[ --i ]; event[ prop ] = originalEvent[ prop ]; } // Fix target property, if necessary if ( !event.target ) { // Fixes #1925 where srcElement might not be defined either event.target = event.srcElement || document; } // check if target is a textnode (safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Add relatedTarget, if necessary if ( !event.relatedTarget && event.fromElement ) { event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; } // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { var eventDocument = event.target.ownerDocument || document, doc = eventDocument.documentElement, body = eventDocument.body; event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); } // Add which for key events if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { event.which = event.charCode != null ? event.charCode : event.keyCode; } // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) if ( !event.metaKey && event.ctrlKey ) { event.metaKey = event.ctrlKey; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && event.button !== undefined ) { event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); } return event; }, // Deprecated, use jQuery.guid instead guid: 1E8, // Deprecated, use jQuery.proxy instead proxy: jQuery.proxy, special: { ready: { // Make sure the ready event is setup setup: jQuery.bindReady, teardown: jQuery.noop }, live: { add: function( handleObj ) { jQuery.event.add( this, liveConvert( handleObj.origType, handleObj.selector ), jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); }, remove: function( handleObj ) { jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); } }, beforeunload: { setup: function( data, namespaces, eventHandle ) { // We only want to do this special case on windows if ( jQuery.isWindow( this ) ) { this.onbeforeunload = eventHandle; } }, teardown: function( namespaces, eventHandle ) { if ( this.onbeforeunload === eventHandle ) { this.onbeforeunload = null; } } } } }; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { if ( elem.detachEvent ) { elem.detachEvent( "on" + type, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !this.preventDefault ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // timeStamp is buggy for some events on Firefox(#3843) // So we won't rely on the native value this.timeStamp = jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; function returnFalse() { return false; } function returnTrue() { return true; } // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { preventDefault: function() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if preventDefault exists run it on the original event if ( e.preventDefault ) { e.preventDefault(); // otherwise set the returnValue property of the original event to false (IE) } else { e.returnValue = false; } }, stopPropagation: function() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if stopPropagation exists run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // otherwise set the cancelBubble property of the original event to true (IE) e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; // Checks if an event happened on an element within another element // Used in jQuery.event.special.mouseenter and mouseleave handlers var withinElement = function( event ) { // Check if mouse(over|out) are still within the same parent element var related = event.relatedTarget, inside = false, eventType = event.type; event.type = event.data; if ( related !== this ) { if ( related ) { inside = jQuery.contains( this, related ); } if ( !inside ) { jQuery.event.handle.apply( this, arguments ); event.type = eventType; } } }, // In case of event delegation, we only need to rename the event.type, // liveHandler will take care of the rest. delegate = function( event ) { event.type = event.data; jQuery.event.handle.apply( this, arguments ); }; // Create mouseenter and mouseleave events jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { setup: function( data ) { jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); }, teardown: function( data ) { jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); } }; }); // submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function( data, namespaces ) { if ( !jQuery.nodeName( this, "form" ) ) { jQuery.event.add(this, "click.specialSubmit", function( e ) { // Avoid triggering error on non-existent type attribute in IE VML (#7071) var elem = e.target, type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { trigger( "submit", this, arguments ); } }); jQuery.event.add(this, "keypress.specialSubmit", function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.type : ""; if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { trigger( "submit", this, arguments ); } }); } else { return false; } }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialSubmit" ); } }; } // change delegation, happens here so we have bind. if ( !jQuery.support.changeBubbles ) { var changeFilters, getVal = function( elem ) { var type = jQuery.nodeName( elem, "input" ) ? elem.type : "", val = elem.value; if ( type === "radio" || type === "checkbox" ) { val = elem.checked; } else if ( type === "select-multiple" ) { val = elem.selectedIndex > -1 ? jQuery.map( elem.options, function( elem ) { return elem.selected; }).join("-") : ""; } else if ( jQuery.nodeName( elem, "select" ) ) { val = elem.selectedIndex; } return val; }, testChange = function testChange( e ) { var elem = e.target, data, val; if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { return; } data = jQuery._data( elem, "_change_data" ); val = getVal(elem); // the current data will be also retrieved by beforeactivate if ( e.type !== "focusout" || elem.type !== "radio" ) { jQuery._data( elem, "_change_data", val ); } if ( data === undefined || val === data ) { return; } if ( data != null || val ) { e.type = "change"; e.liveFired = undefined; jQuery.event.trigger( e, arguments[1], elem ); } }; jQuery.event.special.change = { filters: { focusout: testChange, beforedeactivate: testChange, click: function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { testChange.call( this, e ); } }, // Change has to be called before submit // Keydown will be called before keypress, which is used in submit-event delegation keydown: function( e ) { var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || type === "select-multiple" ) { testChange.call( this, e ); } }, // Beforeactivate happens also before the previous element is blurred // with this event you can't trigger a change event, but you can store // information beforeactivate: function( e ) { var elem = e.target; jQuery._data( elem, "_change_data", getVal(elem) ); } }, setup: function( data, namespaces ) { if ( this.type === "file" ) { return false; } for ( var type in changeFilters ) { jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); } return rformElems.test( this.nodeName ); }, teardown: function( namespaces ) { jQuery.event.remove( this, ".specialChange" ); return rformElems.test( this.nodeName ); } }; changeFilters = jQuery.event.special.change.filters; // Handle when the input is .focus()'d changeFilters.focus = changeFilters.beforeactivate; } function trigger( type, elem, args ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. // Don't pass args or remember liveFired; they apply to the donor event. var event = jQuery.extend( {}, args[ 0 ] ); event.type = type; event.originalEvent = {}; event.liveFired = undefined; jQuery.event.handle.call( elem, event ); if ( event.isDefaultPrevented() ) { args[ 0 ].preventDefault(); } } // Create "bubbling" focus and blur events if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } }; function handler( donor ) { // Donor event is always a native one; fix it and switch its type. // Let focusin/out handler cancel the donor focus/blur event. var e = jQuery.event.fix( donor ); e.type = fix; e.originalEvent = {}; jQuery.event.trigger( e, null, e.target ); if ( e.isDefaultPrevented() ) { donor.preventDefault(); } } }); } jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { var handler; // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { this[ name ](key, data, type[key], fn); } return this; } if ( arguments.length === 2 || data === false ) { fn = data; data = undefined; } if ( name === "one" ) { handler = function( event ) { jQuery( this ).unbind( event, handler ); return fn.apply( this, arguments ); }; handler.guid = fn.guid || jQuery.guid++; } else { handler = fn; } if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.add( this[i], type, handler, data ); } } return this; }; }); jQuery.fn.extend({ unbind: function( type, fn ) { // Handle object literals if ( typeof type === "object" && !type.preventDefault ) { for ( var key in type ) { this.unbind(key, type[key]); } } else { for ( var i = 0, l = this.length; i < l; i++ ) { jQuery.event.remove( this[i], type, fn ); } } return this; }, delegate: function( selector, types, data, fn ) { return this.live( types, data, fn, selector ); }, undelegate: function( selector, types, fn ) { if ( arguments.length === 0 ) { return this.unbind( "live" ); } else { return this.die( types, null, fn, selector ); } }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { if ( this[0] ) { return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, guid = fn.guid || jQuery.guid++, i = 0, toggler = function( event ) { // Figure out which function to execute var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); // Make sure that clicks stop event.preventDefault(); // and execute the function return args[ lastToggle ].apply( this, arguments ) || false; }; // link all the functions, so any of them can unbind this click handler toggler.guid = guid; while ( i < args.length ) { args[ i++ ].guid = guid; } return this.click( toggler ); }, hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } }); var liveMap = { focus: "focusin", blur: "focusout", mouseenter: "mouseover", mouseleave: "mouseout" }; jQuery.each(["live", "die"], function( i, name ) { jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { var type, i = 0, match, namespaces, preType, selector = origSelector || this.selector, context = origSelector ? this : jQuery( this.context ); if ( typeof types === "object" && !types.preventDefault ) { for ( var key in types ) { context[ name ]( key, data, types[key], selector ); } return this; } if ( name === "die" && !types && origSelector && origSelector.charAt(0) === "." ) { context.unbind( origSelector ); return this; } if ( data === false || jQuery.isFunction( data ) ) { fn = data || returnFalse; data = undefined; } types = (types || "").split(" "); while ( (type = types[ i++ ]) != null ) { match = rnamespaces.exec( type ); namespaces = ""; if ( match ) { namespaces = match[0]; type = type.replace( rnamespaces, "" ); } if ( type === "hover" ) { types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); continue; } preType = type; if ( liveMap[ type ] ) { types.push( liveMap[ type ] + namespaces ); type = type + namespaces; } else { type = (liveMap[ type ] || type) + namespaces; } if ( name === "live" ) { // bind live handler for ( var j = 0, l = context.length; j < l; j++ ) { jQuery.event.add( context[j], "live." + liveConvert( type, selector ), { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); } } else { // unbind live handler context.unbind( "live." + liveConvert( type, selector ), fn ); } } return this; }; }); function liveHandler( event ) { var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, elems = [], selectors = [], events = jQuery._data( this, "events" ); // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { return; } if ( event.namespace ) { namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); } event.liveFired = this; var live = events.live.slice(0); for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { selectors.push( handleObj.selector ); } else { live.splice( j--, 1 ); } } match = jQuery( event.target ).closest( selectors, event.currentTarget ); for ( i = 0, l = match.length; i < l; i++ ) { close = match[i]; for ( j = 0; j < live.length; j++ ) { handleObj = live[j]; if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { elem = close.elem; related = null; // Those two events require additional checking if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { event.type = handleObj.preType; related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; // Make sure not to accidentally match a child element with the same selector if ( related && jQuery.contains( elem, related ) ) { related = elem; } } if ( !related || related !== elem ) { elems.push({ elem: elem, handleObj: handleObj, level: close.level }); } } } } for ( i = 0, l = elems.length; i < l; i++ ) { match = elems[i]; if ( maxLevel && match.level > maxLevel ) { break; } event.currentTarget = match.elem; event.data = match.handleObj.data; event.handleObj = match.handleObj; ret = match.handleObj.origHandler.apply( match.elem, arguments ); if ( ret === false || event.isPropagationStopped() ) { maxLevel = match.level; if ( ret === false ) { stop = false; } if ( event.isImmediatePropagationStopped() ) { break; } } } return stop; } function liveConvert( type, selector ) { return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { if ( fn == null ) { fn = data; data = null; } return arguments.length > 0 ? this.bind( name, data, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } }); /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function() { baseHasDuplicate = false; return 0; }); var Sizzle = function( selector, context, results, seed ) { results = results || []; context = context || document; var origContext = context; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var m, set, checkSet, extra, ret, cur, pop, i, prune = true, contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); m = chunker.exec( soFar ); if ( m ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray( set ); } else { prune = false; } while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function( results ) { if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort( sortOrder ); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[ i - 1 ] ) { results.splice( i--, 1 ); } } } } return results; }; Sizzle.matches = function( expr, set ) { return Sizzle( expr, null, null, set ); }; Sizzle.matchesSelector = function( node, expr ) { return Sizzle( expr, null, null, [node] ).length > 0; }; Sizzle.find = function( expr, context, isXML ) { var set; if ( !expr ) { return []; } for ( var i = 0, l = Expr.order.length; i < l; i++ ) { var match, type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { var left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace( rBackslash, "" ); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( "*" ) : []; } return { set: set, expr: expr }; }; Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { for ( var type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { var found, item, filter = Expr.filter[ type ], left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( var i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); var pass = not ^ !!found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw "Syntax error, unrecognized expression: " + msg; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function( elem ) { return elem.getAttribute( "href" ); }, type: function( elem ) { return elem.getAttribute( "type" ); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !rNonWord.test( part ), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function( checkSet, part ) { var elem, isPartStr = typeof part === "string", i = 0, l = checkSet.length; if ( isPartStr && !rNonWord.test( part ) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); }, "~": function( checkSet, part, isXML ) { var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); } }, find: { ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; } }, NAME: function( match, context ) { if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName( match[1] ); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function( match, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( match[1] ); } } }, preFilter: { CLASS: function( match, curLoop, inplace, result, not, isXML ) { match = " " + match[1].replace( rBackslash, "" ) + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function( match ) { return match[1].replace( rBackslash, "" ); }, TAG: function( match, curLoop ) { return match[1].replace( rBackslash, "" ).toLowerCase(); }, CHILD: function( match ) { if ( match[1] === "nth" ) { if ( !match[2] ) { Sizzle.error( match[0] ); } match[2] = match[2].replace(/^\+|\s*/g, ''); // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } else if ( match[2] ) { Sizzle.error( match[0] ); } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } // Handle if an un-quoted value was used match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function( match, curLoop, inplace, result, not ) { if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function( match ) { match.unshift( true ); return match; } }, filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; }, disabled: function( elem ) { return elem.disabled === true; }, checked: function( elem ) { return elem.checked === true; }, selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, parent: function( elem ) { return !!elem.firstChild; }, empty: function( elem ) { return !elem.firstChild; }, has: function( elem, i, match ) { return !!Sizzle( match[3], elem ).length; }, header: function( elem ) { return (/h\d/i).test( elem.nodeName ); }, text: function( elem ) { var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, radio: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, password: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); }, focus: function( elem ) { return elem === elem.ownerDocument.activeElement; } }, setFilters: { first: function( elem, i ) { return i === 0; }, last: function( elem, i, match, array ) { return i === array.length - 1; }, even: function( elem, i ) { return i % 2 === 0; }, odd: function( elem, i ) { return i % 2 === 1; }, lt: function( elem, i, match ) { return i < match[3] - 0; }, gt: function( elem, i, match ) { return i > match[3] - 0; }, nth: function( elem, i, match ) { return match[3] - 0 === i; }, eq: function( elem, i, match ) { return match[3] - 0 === i; } }, filter: { PSEUDO: function( elem, match, i, array ) { var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var j = 0, l = not.length; j < l; j++ ) { if ( not[j] === elem ) { return false; } } return true; } else { Sizzle.error( name ); } }, CHILD: function( elem, match ) { var type = match[1], node = elem; switch ( type ) { case "only": case "first": while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; case "last": while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case "nth": var first = match[2], last = match[3]; if ( first === 1 && last === 0 ) { return true; } var doneName = match[0], parent = elem.parentNode; if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { var count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent.sizcache = doneName; } var diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function( elem, match ) { return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; }, CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function( elem, match ) { var name = match[1], result = Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function( elem, match, i, array ) { var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS, fescape = function(all, num){ return "\\" + (num - 0 + 1); }; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch( e ) { makeArray = function( array, results ) { var i = 0, ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder, siblingCheck; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; return 0; } if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { return a.compareDocumentPosition ? -1 : 1; } return a.compareDocumentPosition(b) & 4 ? -1 : 1; }; } else { sortOrder = function( a, b ) { // The nodes are identical, we can exit early if ( a === b ) { hasDuplicate = true; return 0; // Fallback to using sourceIndex (in IE) if it's available on both nodes } else if ( a.sourceIndex && b.sourceIndex ) { return a.sourceIndex - b.sourceIndex; } var al, bl, ap = [], bp = [], aup = a.parentNode, bup = b.parentNode, cur = aup; // If the nodes are siblings (or identical) we can do a quick check if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected } else if ( !aup ) { return -1; } else if ( !bup ) { return 1; } // Otherwise they're somewhere else in the tree so we need // to build up a full list of the parentNodes for comparison while ( cur ) { ap.unshift( cur ); cur = cur.parentNode; } cur = bup; while ( cur ) { bp.unshift( cur ); cur = cur.parentNode; } al = ap.length; bl = bp.length; // Start walking down the tree looking for a discrepancy for ( var i = 0; i < al && i < bl; i++ ) { if ( ap[i] !== bp[i] ) { return siblingCheck( ap[i], bp[i] ); } } // We ended someplace up the tree so do a sibling check return i === al ? siblingCheck( a, bp[i], -1 ) : siblingCheck( ap[i], b, 1 ); }; siblingCheck = function( a, b, ret ) { if ( a === b ) { return ret; } var cur = a.nextSibling; while ( cur ) { if ( cur === b ) { return -1; } cur = cur.nextSibling; } return 1; }; } // Utility function for retreiving the text value of an array of DOM nodes Sizzle.getText = function( elems ) { var ret = "", elem; for ( var i = 0; elems[i]; i++ ) { elem = elems[i]; // Get the text from text nodes and CDATA nodes if ( elem.nodeType === 3 || elem.nodeType === 4 ) { ret += elem.nodeValue; // Traverse everything else, except comment nodes } else if ( elem.nodeType !== 8 ) { ret += Sizzle.getText( elem.childNodes ); } } return ret; }; // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date()).getTime(), root = document.documentElement; form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function( elem, match ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); // release memory in IE root = form = null; })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function( match, context ) { var results = context.getElementsByTagName( match[1] ); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function( elem ) { return elem.getAttribute( "href", 2 ); }; } // release memory in IE div = null; })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"), id = "__sizzle__"; div.innerHTML = "

      "; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function( query, context, extra, seed ) { context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } } else { return makeArray( [], extra ); } } try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { var oldContext = context, old = context.getAttribute( "id" ), nid = old || id, hasParent = context.parentNode, relativeHierarchySelector = /^\s*[+~]/.test( query ); if ( !old ) { context.setAttribute( "id", nid ); } else { nid = nid.replace( /'/g, "\\$&" ); } if ( relativeHierarchySelector && hasParent ) { context = context.parentNode; } try { if ( !relativeHierarchySelector || hasParent ) { return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); } } catch(pseudoError) { } finally { if ( !old ) { oldContext.removeAttribute( "id" ); } } } } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } // release memory in IE div = null; })(); } (function(){ var html = document.documentElement, matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9 fails this) var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), pseudoWorks = false; try { // This should fail with an exception // Gecko does not error, returns false instead matches.call( document.documentElement, "[test!='']:sizzle" ); } catch( pseudoError ) { pseudoWorks = true; } Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { var ret = matches.call( node, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || !disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9, so check for that node.document && node.document.nodeType !== 11 ) { return ret; } } } catch(e) {} } return Sizzle(expr, null, null, [node]).length > 0; }; } })(); (function(){ var div = document.createElement("div"); div.innerHTML = "
      "; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; // release memory in IE div = null; })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem.sizcache = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem.sizcache === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem.sizcache = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } if ( document.documentElement.contains ) { Sizzle.contains = function( a, b ) { return a !== b && (a.contains ? a.contains(b) : true); }; } else if ( document.documentElement.compareDocumentPosition ) { Sizzle.contains = function( a, b ) { return !!(a.compareDocumentPosition(b) & 16); }; } else { Sizzle.contains = function() { return false; }; } Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function( selector, context ) { var match, tmpSet = [], later = "", root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; })(); var runtil = /Until$/, rparentsprev = /^(?:parents|prevUntil|prevAll)/, // Note: This RegExp should be improved, or likely pulled from Sizzle rmultiselector = /,/, isSimple = /^.[^:#\[\.,]*$/, slice = Array.prototype.slice, POS = jQuery.expr.match.POS, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend({ find: function( selector ) { var self = this, i, l; if ( typeof selector !== "string" ) { return jQuery( selector ).filter(function() { for ( i = 0, l = self.length; i < l; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }); } var ret = this.pushStack( "", "find", selector ), length, n, r; for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique for ( n = length; n < ret.length; n++ ) { for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; } } } } } return ret; }, has: function( target ) { var targets = jQuery( target ); return this.filter(function() { for ( var i = 0, l = targets.length; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false), "not", selector); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true), "filter", selector ); }, is: function( selector ) { return !!selector && ( typeof selector === "string" ? jQuery.filter( selector, this ).length > 0 : this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; // Array if ( jQuery.isArray( selectors ) ) { var match, selector, matches = {}, level = 1; if ( cur && selectors.length ) { for ( i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; if ( !matches[ selector ] ) { matches[ selector ] = POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } } while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { match = matches[ selector ]; if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { ret.push({ selector: selector, elem: cur, level: level }); } } cur = cur.parentNode; level++; } } return ret; } // String var pos = POS.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; while ( cur ) { if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { ret.push( cur ); break; } else { cur = cur.parentNode; if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? all : jQuery.unique( all ) ); }, andSelf: function() { return this.add( this.prevObject ); } }); // A painfully simple check to see if an element is disconnected // from a document (should be improved, where feasible). function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return jQuery.nth( elem, 2, "nextSibling" ); }, prev: function( elem ) { return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( elem.parentNode.firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.makeArray( elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ), // The variable 'args' was introduced in // https://github.com/jquery/jquery/commit/52a0238 // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. // http://code.google.com/p/v8/issues/detail?id=1050 args = slice.call(arguments); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret, name, args.join(",") ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 ? jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, nth: function( cur, result, dir, elem ) { result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType === 1 && ++num === result ) { break; } } return cur; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { // Can't pass null or undefined to indexOf in Firefox 4 // Set to 0 to skip string check qualifier = qualifier || 0; if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); return retVal === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return (elem === qualifier) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem, i ) { return (jQuery.inArray( elem, qualifier ) >= 0) === keep; }); } var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /", "" ], legend: [ 1, "
      ", "
      " ], thead: [ 1, "", "
      " ], tr: [ 2, "", "
      " ], td: [ 3, "", "
      " ], col: [ 2, "", "
      " ], area: [ 1, "", "" ], _default: [ 0, "", "" ] }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // IE can't serialize and