diff --git a/ajax/libs/topcoat-icons/0.1.0/LICENSE b/ajax/libs/topcoat-icons/0.1.0/LICENSE new file mode 100644 index 000000000..242fd8a60 --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/LICENSE @@ -0,0 +1,203 @@ +Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. + + 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 [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/ajax/libs/topcoat-icons/0.1.0/README.md b/ajax/libs/topcoat-icons/0.1.0/README.md new file mode 100644 index 000000000..86a009410 --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/README.md @@ -0,0 +1,117 @@ +TopCoat Icons +============ + +Open Source Icons designed for TopCoat + + + + + +common icons: +(done: 13px,18px,24px,40px size) + +1.share +2.user +3.favorite +4.attachment +5.checkmark +6.remove +7.add +8.cancel +9.lock +10.unlock +11.photo +12.image +13.back +14.next +15.settings +16.wifi +17.search +18.right arrow +19.left arrow +20.up arrow +21.down arrow +22.call +23.phone +24.tablet +25.laptop +26.location +27.expand +28.collapse +29.list view +30.tile view +31.text +32.home +33.brush +34.pencil +35.eye/visible + + + +to do: +35.eye/visible off +36.clock/time +37.video camera +38.alert +39.email +40.calendar +41.print +42.cart +43.save +44.cloud +45.page +46.user group +47.battery full +48.battery low +49.battery empty +50.bookmark +51.chat +52.upload +53.download +54.audio +55.audio off +56.comment/note +57.address book +58.map +59.credit card +60.news +61.graph +62.question mark +63.scissors +64.new +65.CC creative commons +66.video +67.retweet +68.refresh +69.error +70.delete + +social icons: +(done: 40px size) +1.facebook +2.twitter +3.pinterest +4.github +5.dribble +6.behance +7.instagramm +8.linkedin +9.google-plus +10.youtube +11.vimeo +12.flickr +13.picasa +14.tumblr +15.wordpress +16.blogger +17.github-text +18.path + +to do: +19.css +20.stackoverflow +21.html 5 +22.reddit +23.Skype + + diff --git a/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconSet_overview.png b/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconSet_overview.png new file mode 100644 index 000000000..77bd35ed2 Binary files /dev/null and b/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconSet_overview.png differ diff --git a/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconStyle_Guidelines.png b/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconStyle_Guidelines.png new file mode 100644 index 000000000..2f063001c Binary files /dev/null and b/ajax/libs/topcoat-icons/0.1.0/docs/_Topcoat_IconStyle_Guidelines.png differ diff --git a/ajax/libs/topcoat-icons/0.1.0/font/icomatic.css b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.css new file mode 100755 index 000000000..d307b4e40 --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.css @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Icomatic'; + src: url('icomatic.svg#icomatic') format('svg'); + } + .icomatic { + font-family: 'Icomatic','sans-serif'; + line-height: 1; + text-rendering: optimizeLegibility; + -webkit-font-feature-settings: "liga", "dlig"; + -ms-font-feature-settings: "liga", "dlig"; + -moz-font-feature-settings: "liga", "dlig"; + -o-font-feature-settings: "liga", "dlig"; + font-feature-settings: "liga", "dlig"; + -webkit-font-smoothing: antialiased; + } + .icomatic-alt { + margin: -1px; + border:0; + padding: 0; + width: 1px; height: 1px; + clip: rect(0 0 0 0); + position: absolute; + overflow: hidden; + } \ No newline at end of file diff --git a/ajax/libs/topcoat-icons/0.1.0/font/icomatic.js b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.js new file mode 100755 index 000000000..fd6ef43bc --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.js @@ -0,0 +1,43 @@ +var IcomaticUtils = (function() { +return { +fallbacks: [{ from: 'laptop', 'to': '' },{ from: 'phone', 'to': '' }], +substitute: function(el) { + var curr = el.firstChild; + var next, alt; + var content; + while (curr) { + next = curr.nextSibling; + if (curr.nodeType === Node.TEXT_NODE) { + content = curr.nodeValue; + for (var i = 0; i < IcomaticUtils.fallbacks.length; i++) { + content = content.replace( IcomaticUtils.fallbacks[i].from, function(match) { + alt = document.createElement('span'); + alt.setAttribute('class', 'icomatic-alt'); + alt.innerHTML = match; + el.insertBefore(alt, curr); + return IcomaticUtils.fallbacks[i].to; + }); + } + alt = document.createTextNode(content); + el.replaceChild(alt, curr); + } + curr = next; + } +}, +run: function(force) { + force = typeof force !== 'undefined' ? force : false; + var s = getComputedStyle(document.body); + if (s.hasOwnProperty('webkitFontFeatureSettings') + || s.hasOwnProperty('mozFontFeatureSettings') + || s.hasOwnProperty('msFontFeatureSettings') + || s.hasOwnProperty('oFontFeatureSettings') + || s.hasOwnProperty('fontFeatureSettings')) + if (!force) + return; + var els = document.querySelectorAll('.icomatic'); + for (var i = 0; i < els.length; i++) + IcomaticUtils.substitute(els[i]); +} +} // end of object +} // end of fn +)() \ No newline at end of file diff --git a/ajax/libs/topcoat-icons/0.1.0/font/icomatic.svg b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.svg new file mode 100755 index 000000000..d62bdb2ee --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/font/icomatic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ajax/libs/topcoat-icons/0.1.0/font/index.html b/ajax/libs/topcoat-icons/0.1.0/font/index.html new file mode 100755 index 000000000..005168328 --- /dev/null +++ b/ajax/libs/topcoat-icons/0.1.0/font/index.html @@ -0,0 +1,207 @@ + +
+ + + + + + + +
+<link rel='stylesheet' type='text/css' href='icomatic.css'>
+<!-- Include the script for fallback support -->
+<script type='text/javascript' src='icomatic.js'></script>
+...
+<span class='icomatic' style='color:blue'>laptop</span>
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ajax/libs/topcoat-icons/0.1.0/font/js/dat.color.js b/ajax/libs/topcoat-icons/0.1.0/font/js/dat.color.js
new file mode 100755
index 000000000..42ad20c89
--- /dev/null
+++ b/ajax/libs/topcoat-icons/0.1.0/font/js/dat.color.js
@@ -0,0 +1,755 @@
+/**
+ * dat-gui JavaScript Controller Library
+ * http://code.google.com/p/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
+ */
+
+/** @namespace */
+var dat = dat || {};
+
+/** @namespace */
+dat.color = dat.color || {};
+
+/** @namespace */
+dat.utils = dat.utils || {};
+
+dat.utils.common = (function () {
+
+ var ARR_EACH = Array.prototype.forEach;
+ var 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/
+ */
+
+ return {
+
+ BREAK: {},
+
+ extend: function(target) {
+
+ this.each(ARR_SLICE.call(arguments, 1), function(obj) {
+
+ for (var key in obj)
+ if (!this.isUndefined(obj[key]))
+ target[key] = obj[key];
+
+ }, this);
+
+ return target;
+
+ },
+
+ defaults: function(target) {
+
+ this.each(ARR_SLICE.call(arguments, 1), function(obj) {
+
+ for (var key in obj)
+ if (this.isUndefined(target[key]))
+ target[key] = obj[key];
+
+ }, this);
+
+ return target;
+
+ },
+
+ compose: function() {
+ 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(obj, itr, scope) {
+
+
+ if (ARR_EACH && obj.forEach === ARR_EACH) {
+
+ obj.forEach(itr, scope);
+
+ } else if (obj.length === obj.length + 0) { // Is number but not NaN
+
+ for (var 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(fnc) {
+ setTimeout(fnc, 0);
+ },
+
+ 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 obj !== 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 Object.prototype.toString.call(obj) === '[object Function]';
+ }
+
+ };
+
+})();
+
+
+dat.color.toString = (function (common) {
+
+ return function(color) {
+
+ if (color.a == 1 || common.isUndefined(color.a)) {
+
+ var s = color.hex.toString(16);
+ while (s.length < 6) {
+ s = '0' + s;
+ }
+
+ return '#' + s;
+
+ } else {
+
+ return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';
+
+ }
+
+ }
+
+})(dat.utils.common);
+
+
+dat.Color = dat.color.Color = (function (interpret, math, toString, common) {
+
+ var Color = function() {
+
+ this.__state = interpret.apply(this, arguments);
+
+ if (this.__state === false) {
+ throw 'Failed to interpret color arguments';
+ }
+
+ this.__state.a = this.__state.a || 1;
+
+
+ };
+
+ Color.COMPONENTS = ['r','g','b','h','s','v','hex','a'];
+
+ common.extend(Color.prototype, {
+
+ toString: function() {
+ return toString(this);
+ },
+
+ toOriginal: function() {
+ return this.__state.conversion.write(this);
+ }
+
+ });
+
+ 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);
+ }
+
+ return this.__state.hex;
+
+ },
+
+ set: function(v) {
+
+ this.__state.space = 'HEX';
+ this.__state.hex = v;
+
+ }
+
+ });
+
+ function defineRGBComponent(target, component, componentHexIndex) {
+
+ Object.defineProperty(target, component, {
+
+ get: function() {
+
+ if (this.__state.space === 'RGB') {
+ return this.__state[component];
+ }
+
+ recalculateRGB(this, component, componentHexIndex);
+
+ return this.__state[component];
+
+ },
+
+ set: function(v) {
+
+ if (this.__state.space !== 'RGB') {
+ 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];
+
+ recalculateHSV(this);
+
+ return this.__state[component];
+
+ },
+
+ set: function(v) {
+
+ if (this.__state.space !== 'HSV') {
+ recalculateHSV(this);
+ this.__state.space = 'HSV';
+ }
+
+ this.__state[component] = v;
+
+ }
+
+ });
+
+ }
+
+ function recalculateRGB(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 'Corrupted color state';
+
+ }
+
+ }
+
+ function recalculateHSV(color) {
+
+ var 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;
+ }
+
+ }
+
+ return Color;
+
+})(dat.color.interpret = (function (toString, common) {
+
+ var result, toReturn;
+
+ var interpret = function() {
+
+ 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 INTERPRETATIONS = [
+
+ // Strings
+ {
+
+ litmus: common.isString,
+
+ conversions: {
+
+ THREE_CHAR_HEX: {
+
+ read: function(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())
+ };
+
+ },
+
+ write: toString
+
+ },
+
+ SIX_CHAR_HEX: {
+
+ read: function(original) {
+
+ var test = original.match(/^#([A-F0-9]{6})$/i);
+ if (test === null) return false;
+
+ return {
+ space: 'HEX',
+ hex: parseInt('0x' + test[1].toString())
+ };
+
+ },
+
+ write: toString
+
+ },
+
+ CSS_RGB: {
+
+ read: function(original) {
+
+ var test = original.match(/^rgb\(\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) {
+
+ var test = original.match(/^rgba\(\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
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+
+ ];
+
+ return interpret;
+
+
+})(dat.color.toString,
+dat.utils.common),
+dat.color.math = (function () {
+
+ var tmpComponent;
+
+ return {
+
+ hsv_to_rgb: function(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(r, g, b) {
+
+ var min = Math.min(r, g, b),
+ max = Math.max(r, g, b),
+ delta = max - min,
+ h, 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) {
+ 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(hex, componentIndex) {
+ return (hex >> (componentIndex * 8)) & 0xFF;
+ },
+
+ hex_with_component: function(hex, componentIndex, value) {
+ return value << (tmpComponent = componentIndex * 8) | (hex & ~ (0xFF << tmpComponent));
+ }
+
+ }
+
+})(),
+dat.color.toString,
+dat.utils.common);
\ No newline at end of file
diff --git a/ajax/libs/topcoat-icons/0.1.0/font/js/dat.gui.js b/ajax/libs/topcoat-icons/0.1.0/font/js/dat.gui.js
new file mode 100755
index 000000000..152b7ec61
--- /dev/null
+++ b/ajax/libs/topcoat-icons/0.1.0/font/js/dat.gui.js
@@ -0,0 +1,3661 @@
+/**
+ * dat-gui JavaScript Controller Library
+ * http://code.google.com/p/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
+ */
+
+/** @namespace */
+var dat = dat || {};
+
+/** @namespace */
+dat.gui = dat.gui || {};
+
+/** @namespace */
+dat.utils = dat.utils || {};
+
+/** @namespace */
+dat.controllers = dat.controllers || {};
+
+/** @namespace */
+dat.dom = dat.dom || {};
+
+/** @namespace */
+dat.color = dat.color || {};
+
+dat.utils.css = (function () {
+ return {
+ load: function (url, doc) {
+ doc = doc || document;
+ var link = doc.createElement('link');
+ link.type = 'text/css';
+ link.rel = 'stylesheet';
+ link.href = url;
+ doc.getElementsByTagName('head')[0].appendChild(link);
+ },
+ inject: function(css, doc) {
+ doc = doc || document;
+ var injected = document.createElement('style');
+ injected.type = 'text/css';
+ injected.innerHTML = css;
+ doc.getElementsByTagName('head')[0].appendChild(injected);
+ }
+ }
+})();
+
+
+dat.utils.common = (function () {
+
+ var ARR_EACH = Array.prototype.forEach;
+ var 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/
+ */
+
+ return {
+
+ BREAK: {},
+
+ extend: function(target) {
+
+ this.each(ARR_SLICE.call(arguments, 1), function(obj) {
+
+ for (var key in obj)
+ if (!this.isUndefined(obj[key]))
+ target[key] = obj[key];
+
+ }, this);
+
+ return target;
+
+ },
+
+ defaults: function(target) {
+
+ this.each(ARR_SLICE.call(arguments, 1), function(obj) {
+
+ for (var key in obj)
+ if (this.isUndefined(target[key]))
+ target[key] = obj[key];
+
+ }, this);
+
+ return target;
+
+ },
+
+ compose: function() {
+ 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(obj, itr, scope) {
+
+
+ if (ARR_EACH && obj.forEach === ARR_EACH) {
+
+ obj.forEach(itr, scope);
+
+ } else if (obj.length === obj.length + 0) { // Is number but not NaN
+
+ for (var 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(fnc) {
+ setTimeout(fnc, 0);
+ },
+
+ 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 obj !== 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 Object.prototype.toString.call(obj) === '[object Function]';
+ }
+
+ };
+
+})();
+
+
+dat.controllers.Controller = (function (common) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var Controller = function(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;
+
+ };
+
+ common.extend(
+
+ Controller.prototype,
+
+ /** @lends dat.controllers.Controller.prototype */
+ {
+
+ /**
+ * 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 {dat.controllers.Controller} this
+ */
+ onChange: function(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 {dat.controllers.Controller} this
+ */
+ onFinishChange: function(fnc) {
+ this.__onFinishChange = fnc;
+ return this;
+ },
+
+ /**
+ * Change the value of object[property]
+ *
+ * @param {Object} newValue The new value of object[property]
+ */
+ setValue: function(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: function() {
+ return this.object[this.property];
+ },
+
+ /**
+ * Refreshes the visual display of a Controller in order to keep sync
+ * with the object's current value.
+ * @returns {dat.controllers.Controller} this
+ */
+ updateDisplay: function() {
+ return this;
+ },
+
+ /**
+ * @returns {Boolean} true if the value has deviated from initialValue
+ */
+ isModified: function() {
+ return this.initialValue !== this.getValue()
+ }
+
+ }
+
+ );
+
+ return Controller;
+
+
+})(dat.utils.common);
+
+
+dat.dom.dom = (function (common) {
+
+ 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]);
+ }
+
+ // TODO ...ems? %?
+
+ return 0;
+
+ }
+
+ /**
+ * @namespace
+ * @member dat.dom
+ */
+ var 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 vertical
+ */
+ makeFullscreen: function(elem, horizontal, vertical) {
+
+ 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, params, aux) {
+ params = params || {};
+ 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, //screen X
+ 0, //screen Y
+ clientX, //client X
+ clientY, //client Y
+ false, false, false, false, 0, null);
+ break;
+ case 'KeyboardEvents':
+ var 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, bool) {
+ bool = bool || 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, bool) {
+ bool = bool || 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) {
+ var 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 === undefined) {
+ // elem.className = className;
+ } else 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(elem, className) {
+ return new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)').test(elem.className) || false;
+ },
+
+ /**
+ *
+ * @param elem
+ */
+ getWidth: function(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']);
+ },
+
+ /**
+ *
+ * @param elem
+ */
+ getHeight: function(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']);
+ },
+
+ /**
+ *
+ * @param elem
+ */
+ getOffset: function(elem) {
+ var offset = {left: 0, top:0};
+ if (elem.offsetParent) {
+ do {
+ offset.left += elem.offsetLeft;
+ offset.top += elem.offsetTop;
+ } while (elem = elem.offsetParent);
+ }
+ return offset;
+ },
+
+ // http://stackoverflow.com/posts/2684561/revisions
+ /**
+ *
+ * @param elem
+ */
+ isActive: function(elem) {
+ return elem === document.activeElement && ( elem.type || elem.href );
+ }
+
+ };
+
+ return dom;
+
+})(dat.utils.common);
+
+
+dat.controllers.OptionController = (function (Controller, dom, 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.
+ *
+ * @member dat.controllers
+ */
+ var OptionController = function(object, property, options) {
+
+ OptionController.superclass.call(this, object, property);
+
+ var _this = this;
+
+ /**
+ * The drop down menu
+ * @ignore
+ */
+ this.__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);
+
+ });
+
+ // Acknowledge original value
+ this.updateDisplay();
+
+ dom.bind(this.__select, 'change', function() {
+ var desiredValue = this.options[this.selectedIndex].value;
+ _this.setValue(desiredValue);
+ });
+
+ this.domElement.appendChild(this.__select);
+
+ };
+
+ OptionController.superclass = Controller;
+
+ common.extend(
+
+ OptionController.prototype,
+ Controller.prototype,
+
+ {
+
+ setValue: function(v) {
+ var toReturn = OptionController.superclass.prototype.setValue.call(this, v);
+ if (this.__onFinishChange) {
+ this.__onFinishChange.call(this, this.getValue());
+ }
+ return toReturn;
+ },
+
+ updateDisplay: function() {
+ this.__select.value = this.getValue();
+ return OptionController.superclass.prototype.updateDisplay.call(this);
+ }
+
+ }
+
+ );
+
+ return OptionController;
+
+})(dat.controllers.Controller,
+dat.dom.dom,
+dat.utils.common);
+
+
+dat.controllers.NumberController = (function (Controller, common) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var NumberController = function(object, property, params) {
+
+ NumberController.superclass.call(this, object, property);
+
+ 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(this.initialValue)/Math.LN10))/10;
+ }
+
+ } else {
+
+ this.__impliedStep = this.__step;
+
+ }
+
+ this.__precision = numDecimals(this.__impliedStep);
+
+
+ };
+
+ NumberController.superclass = Controller;
+
+ common.extend(
+
+ NumberController.prototype,
+ Controller.prototype,
+
+ /** @lends dat.controllers.NumberController.prototype */
+ {
+
+ setValue: function(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 NumberController.superclass.prototype.setValue.call(this, v);
+
+ },
+
+ /**
+ * Specify a minimum value for object[property].
+ *
+ * @param {Number} minValue The minimum value for
+ * object[property]
+ * @returns {dat.controllers.NumberController} this
+ */
+ min: function(v) {
+ this.__min = v;
+ return this;
+ },
+
+ /**
+ * Specify a maximum value for object[property].
+ *
+ * @param {Number} maxValue The maximum value for
+ * object[property]
+ * @returns {dat.controllers.NumberController} this
+ */
+ max: function(v) {
+ this.__max = v;
+ 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: function(v) {
+ this.__step = v;
+ return this;
+ }
+
+ }
+
+ );
+
+ function numDecimals(x) {
+ x = x.toString();
+ if (x.indexOf('.') > -1) {
+ return x.length - x.indexOf('.') - 1;
+ } else {
+ return 0;
+ }
+ }
+
+ return NumberController;
+
+})(dat.controllers.Controller,
+dat.utils.common);
+
+
+dat.controllers.NumberControllerBox = (function (NumberController, dom, common) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var NumberControllerBox = function(object, property, params) {
+
+ this.__truncationSuspended = false;
+
+ NumberControllerBox.superclass.call(this, object, property, params);
+
+ var _this = this;
+
+ /**
+ * {Number} Previous mouse y position
+ * @ignore
+ */
+ var prev_y;
+
+ 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 entire, you can be as precise as you want.
+ if (e.keyCode === 13) {
+ _this.__truncationSuspended = true;
+ this.blur();
+ _this.__truncationSuspended = false;
+ }
+
+ });
+
+ function onChange() {
+ var attempted = parseFloat(_this.__input.value);
+ if (!common.isNaN(attempted)) _this.setValue(attempted);
+ }
+
+ function onBlur() {
+ onChange();
+ if (_this.__onFinishChange) {
+ _this.__onFinishChange.call(_this, _this.getValue());
+ }
+ }
+
+ function onMouseDown(e) {
+ dom.bind(window, 'mousemove', onMouseDrag);
+ dom.bind(window, 'mouseup', onMouseUp);
+ prev_y = e.clientY;
+ }
+
+ function onMouseDrag(e) {
+
+ var diff = prev_y - e.clientY;
+ _this.setValue(_this.getValue() + diff * _this.__impliedStep);
+
+ prev_y = e.clientY;
+
+ }
+
+ function onMouseUp() {
+ dom.unbind(window, 'mousemove', onMouseDrag);
+ dom.unbind(window, 'mouseup', onMouseUp);
+ }
+
+ this.updateDisplay();
+
+ this.domElement.appendChild(this.__input);
+
+ };
+
+ NumberControllerBox.superclass = NumberController;
+
+ common.extend(
+
+ NumberControllerBox.prototype,
+ NumberController.prototype,
+
+ {
+
+ updateDisplay: function() {
+
+ this.__input.value = this.__truncationSuspended ? this.getValue() : roundToDecimal(this.getValue(), this.__precision);
+ return NumberControllerBox.superclass.prototype.updateDisplay.call(this);
+ }
+
+ }
+
+ );
+
+ function roundToDecimal(value, decimals) {
+ var tenTo = Math.pow(10, decimals);
+ return Math.round(value * tenTo) / tenTo;
+ }
+
+ return NumberControllerBox;
+
+})(dat.controllers.NumberController,
+dat.dom.dom,
+dat.utils.common);
+
+
+dat.controllers.NumberControllerSlider = (function (NumberController, dom, css, common, styleSheet) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var NumberControllerSlider = function(object, property, min, max, step) {
+
+ NumberControllerSlider.superclass.call(this, object, property, { min: min, max: max, step: step });
+
+ var _this = this;
+
+ this.__background = document.createElement('div');
+ this.__foreground = document.createElement('div');
+
+
+
+ dom.bind(this.__background, 'mousedown', onMouseDown);
+
+ dom.addClass(this.__background, 'slider');
+ dom.addClass(this.__foreground, 'slider-fg');
+
+ function onMouseDown(e) {
+
+ dom.bind(window, 'mousemove', onMouseDrag);
+ dom.bind(window, 'mouseup', onMouseUp);
+
+ onMouseDrag(e);
+ }
+
+ function onMouseDrag(e) {
+
+ e.preventDefault();
+
+ var offset = dom.getOffset(_this.__background);
+ var width = dom.getWidth(_this.__background);
+
+ _this.setValue(
+ map(e.clientX, offset.left, offset.left + width, _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());
+ }
+ }
+
+ this.updateDisplay();
+
+ this.__background.appendChild(this.__foreground);
+ this.domElement.appendChild(this.__background);
+
+ };
+
+ NumberControllerSlider.superclass = NumberController;
+
+ /**
+ * Injects default stylesheet for slider elements.
+ */
+ NumberControllerSlider.useDefaultStyles = function() {
+ css.inject(styleSheet);
+ };
+
+ common.extend(
+
+ NumberControllerSlider.prototype,
+ NumberController.prototype,
+
+ {
+
+ updateDisplay: function() {
+ var pct = (this.getValue() - this.__min)/(this.__max - this.__min);
+ this.__foreground.style.width = pct*100+'%';
+ return NumberControllerSlider.superclass.prototype.updateDisplay.call(this);
+ }
+
+ }
+
+
+
+ );
+
+ function map(v, i1, i2, o1, o2) {
+ return o1 + (o2 - o1) * ((v - i1) / (i2 - i1));
+ }
+
+ return NumberControllerSlider;
+
+})(dat.controllers.NumberController,
+dat.dom.dom,
+dat.utils.css,
+dat.utils.common,
+".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
+
+
+dat.controllers.FunctionController = (function (Controller, dom, common) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var FunctionController = function(object, property, text) {
+
+ FunctionController.superclass.call(this, object, property);
+
+ var _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);
+
+
+ };
+
+ FunctionController.superclass = Controller;
+
+ common.extend(
+
+ FunctionController.prototype,
+ Controller.prototype,
+ {
+
+ fire: function() {
+ if (this.__onChange) {
+ this.__onChange.call(this);
+ }
+ if (this.__onFinishChange) {
+ this.__onFinishChange.call(this, this.getValue());
+ }
+ this.getValue().call(this.object);
+ }
+ }
+
+ );
+
+ return FunctionController;
+
+})(dat.controllers.Controller,
+dat.dom.dom,
+dat.utils.common);
+
+
+dat.controllers.BooleanController = (function (Controller, dom, common) {
+
+ /**
+ * @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
+ *
+ * @member dat.controllers
+ */
+ var BooleanController = function(object, property) {
+
+ BooleanController.superclass.call(this, object, property);
+
+ var _this = this;
+ this.__prev = this.getValue();
+
+ this.__checkbox = document.createElement('input');
+ this.__checkbox.setAttribute('type', 'checkbox');
+
+
+ dom.bind(this.__checkbox, 'change', onChange, false);
+
+ this.domElement.appendChild(this.__checkbox);
+
+ // Match original value
+ this.updateDisplay();
+
+ function onChange() {
+ _this.setValue(!_this.__prev);
+ }
+
+ };
+
+ BooleanController.superclass = Controller;
+
+ common.extend(
+
+ BooleanController.prototype,
+ Controller.prototype,
+
+ {
+
+ setValue: function(v) {
+ var toReturn = BooleanController.superclass.prototype.setValue.call(this, v);
+ if (this.__onFinishChange) {
+ this.__onFinishChange.call(this, this.getValue());
+ }
+ this.__prev = this.getValue();
+ return toReturn;
+ },
+
+ updateDisplay: function() {
+
+ if (this.getValue() === true) {
+ this.__checkbox.setAttribute('checked', 'checked');
+ this.__checkbox.checked = true;
+ } else {
+ this.__checkbox.checked = false;
+ }
+
+ return BooleanController.superclass.prototype.updateDisplay.call(this);
+
+ }
+
+
+ }
+
+ );
+
+ return BooleanController;
+
+})(dat.controllers.Controller,
+dat.dom.dom,
+dat.utils.common);
+
+
+dat.color.toString = (function (common) {
+
+ return function(color) {
+
+ if (color.a == 1 || common.isUndefined(color.a)) {
+
+ var s = color.hex.toString(16);
+ while (s.length < 6) {
+ s = '0' + s;
+ }
+
+ return '#' + s;
+
+ } else {
+
+ return 'rgba(' + Math.round(color.r) + ',' + Math.round(color.g) + ',' + Math.round(color.b) + ',' + color.a + ')';
+
+ }
+
+ }
+
+})(dat.utils.common);
+
+
+dat.color.interpret = (function (toString, common) {
+
+ var result, toReturn;
+
+ var interpret = function() {
+
+ 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 INTERPRETATIONS = [
+
+ // Strings
+ {
+
+ litmus: common.isString,
+
+ conversions: {
+
+ THREE_CHAR_HEX: {
+
+ read: function(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())
+ };
+
+ },
+
+ write: toString
+
+ },
+
+ SIX_CHAR_HEX: {
+
+ read: function(original) {
+
+ var test = original.match(/^#([A-F0-9]{6})$/i);
+ if (test === null) return false;
+
+ return {
+ space: 'HEX',
+ hex: parseInt('0x' + test[1].toString())
+ };
+
+ },
+
+ write: toString
+
+ },
+
+ CSS_RGB: {
+
+ read: function(original) {
+
+ var test = original.match(/^rgb\(\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) {
+
+ var test = original.match(/^rgba\(\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
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+
+ ];
+
+ return interpret;
+
+
+})(dat.color.toString,
+dat.utils.common);
+
+
+dat.GUI = dat.gui.GUI = (function (css, saveDialogueContents, styleSheet, controllerFactory, Controller, BooleanController, FunctionController, NumberControllerBox, NumberControllerSlider, OptionController, ColorController, requestAnimationFrame, CenteredDiv, dom, common) {
+
+ css.inject(styleSheet);
+
+ /** Outer-most className for GUI's */
+ var CSS_NAMESPACE = 'dg';
+
+ var HIDE_KEY_CODE = 72;
+
+ /** The only value shared between the JS and SCSS. Use caution. */
+ var CLOSE_BUTTON_HEIGHT = 20;
+
+ var DEFAULT_DEFAULT_PRESET_NAME = 'Default';
+
+ var SUPPORTS_LOCAL_STORAGE = (function() {
+ try {
+ return 'localStorage' in window && window['localStorage'] !== null;
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ var SAVE_DIALOGUE;
+
+ /** Have we yet to create an autoPlace GUI? */
+ var auto_place_virgin = true;
+
+ /** Fixed position div that auto place GUI's go inside */
+ var auto_place_container;
+
+ /** Are we hiding the GUI's ? */
+ var hide = false;
+
+ /** GUI's which should be hidden */
+ var hideable_guis = [];
+
+ /**
+ * A lightweight controller library for JavaScript. It allows you to easily
+ * manipulate variables and fire functions on the fly.
+ * @class
+ *
+ * @member dat.gui
+ *
+ * @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 {Boolean} [params.auto=true]
+ * @param {dat.gui.GUI} [params.parent] The GUI I'm nested in.
+ * @param {Boolean} [params.closed] If true, starts closed
+ */
+ var GUI = function(params) {
+
+ var _this = this;
+
+ /**
+ * 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 = [];
+
+ params = params || {};
+
+ // Default parameters
+ params = common.defaults(params, {
+ 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) {
+ hideable_guis.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.
+ var use_local_storage =
+ SUPPORTS_LOCAL_STORAGE &&
+ localStorage.getItem(getLocalStorageHash(this, 'isLocal')) === 'true';
+
+ Object.defineProperties(this,
+
+ /** @lends dat.gui.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;
+ }
+ },
+
+ /**
+ * The identifier for a set of saved values
+ * @type String
+ */
+ preset: {
+
+ get: function() {
+ if (_this.parent) {
+ return _this.getRoot().preset;
+ } else {
+ 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 (title_row_name) {
+ title_row_name.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 use_local_storage;
+ },
+ set: function(bool) {
+ if (SUPPORTS_LOCAL_STORAGE) {
+ use_local_storage = 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)) {
+
+ 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 (use_local_storage) {
+
+ _this.useLocalStorage = true;
+
+ var saved_gui = localStorage.getItem(getLocalStorageHash(this, 'gui'));
+
+ if (saved_gui) {
+ params.load = JSON.parse(saved_gui);
+ }
+
+ }
+
+ }
+
+ this.__closeButton = document.createElement('div');
+ this.__closeButton.innerHTML = GUI.TEXT_CLOSED;
+ dom.addClass(this.__closeButton, GUI.CLASS_CLOSE_BUTTON);
+ 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;
+ }
+
+ var title_row_name = document.createTextNode(params.name);
+ dom.addClass(title_row_name, 'controller-name');
+
+ var title_row = addRow(_this, title_row_name);
+
+ var on_click_title = function(e) {
+ e.preventDefault();
+ _this.closed = !_this.closed;
+ return false;
+ };
+
+ dom.addClass(this.__ul, GUI.CLASS_CLOSED);
+
+ dom.addClass(title_row, 'title');
+ dom.bind(title_row, 'click', on_click_title);
+
+ if (!params.closed) {
+ this.closed = false;
+ }
+
+ }
+
+ if (params.autoPlace) {
+
+ if (common.isUndefined(params.parent)) {
+
+ if (auto_place_virgin) {
+ auto_place_container = document.createElement('div');
+ dom.addClass(auto_place_container, CSS_NAMESPACE);
+ dom.addClass(auto_place_container, GUI.CLASS_AUTO_PLACE_CONTAINER);
+ document.body.appendChild(auto_place_container);
+ auto_place_virgin = false;
+ }
+
+ // Put it in the dom for you.
+ auto_place_container.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);
+
+ }
+
+ dom.bind(window, 'resize', function() { _this.onResize() });
+ dom.bind(this.__ul, 'webkitTransitionEnd', function() { _this.onResize(); });
+ dom.bind(this.__ul, 'transitionend', function() { _this.onResize() });
+ dom.bind(this.__ul, 'oTransitionEnd', function() { _this.onResize() });
+ this.onResize();
+
+
+ if (params.resizable) {
+ addResizeHandle(this);
+ }
+
+ function saveToLocalStorage() {
+ localStorage.setItem(getLocalStorageHash(_this, 'gui'), JSON.stringify(_this.getSaveObject()));
+ }
+
+ var root = _this.getRoot();
+ 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(hideable_guis, function(gui) {
+ gui.domElement.style.zIndex = hide ? -999 : 999;
+ gui.domElement.style.opacity = hide ? 0 : 1;
+ });
+ };
+
+ 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_DRAG = 'drag';
+
+ GUI.DEFAULT_WIDTH = 245;
+ GUI.TEXT_CLOSED = 'Close Controls';
+ GUI.TEXT_OPEN = 'Open Controls';
+
+ dom.bind(window, 'keydown', function(e) {
+
+ if (document.activeElement.type !== 'text' &&
+ (e.which === HIDE_KEY_CODE || e.keyCode == HIDE_KEY_CODE)) {
+ GUI.toggleHide();
+ }
+
+ }, false);
+
+ common.extend(
+
+ GUI.prototype,
+
+ /** @lends dat.gui.GUI */
+ {
+
+ /**
+ * @param object
+ * @param property
+ * @returns {dat.controllers.Controller} The new controller that was added.
+ * @instance
+ */
+ add: function(object, property) {
+
+ return add(
+ this,
+ object,
+ property,
+ {
+ factoryArgs: Array.prototype.slice.call(arguments, 2)
+ }
+ );
+
+ },
+
+ /**
+ * @param object
+ * @param property
+ * @returns {dat.controllers.ColorController} The new controller that was added.
+ * @instance
+ */
+ addColor: function(object, property) {
+
+ return add(
+ this,
+ object,
+ property,
+ {
+ color: true
+ }
+ );
+
+ },
+
+ /**
+ * @param controller
+ * @instance
+ */
+ remove: function(controller) {
+
+ // TODO listening?
+ this.__ul.removeChild(controller.__li);
+ this.__controllers.slice(this.__controllers.indexOf(controller), 1);
+ var _this = this;
+ common.defer(function() {
+ _this.onResize();
+ });
+
+ },
+
+ destroy: function() {
+
+ if (this.autoPlace) {
+ auto_place_container.removeChild(this.domElement);
+ }
+
+ },
+
+ /**
+ * @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 + '"');
+ }
+
+ var new_gui_params = { 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.
+ new_gui_params.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
+ new_gui_params.closed = this.load.folders[name].closed;
+
+ // Pass down the loaded data
+ new_gui_params.load = this.load.folders[name];
+
+ }
+
+ var gui = new GUI(new_gui_params);
+ this.__folders[name] = gui;
+
+ var li = addRow(this, gui.domElement);
+ dom.addClass(li, 'folder');
+ return gui;
+
+ },
+
+ open: function() {
+ this.closed = false;
+ },
+
+ close: function() {
+ this.closed = true;
+ },
+
+ onResize: function() {
+
+ 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';
+ }
+
+ },
+
+ /**
+ * 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
+ */
+ 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.");
+ }
+
+ 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) {
+ // Set save row width
+ setWidth(this, this.width);
+ }
+
+ },
+
+ /**
+ * @returns {dat.gui.GUI} the topmost parent GUI of a nested GUI.
+ * @instance
+ */
+ getRoot: function() {
+ var 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() {
+
+ var 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);
+
+ },
+
+ 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);
+
+ },
+
+ 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);
+ }
+ }, this);
+
+ common.each(this.__folders, function(folder) {
+ folder.revert(folder);
+ });
+
+ if (!gui) {
+ markPresetModified(this.getRoot(), false);
+ }
+
+
+ },
+
+ listen: function(controller) {
+
+ var init = this.__listening.length == 0;
+ this.__listening.push(controller);
+ if (init) updateDisplays(this.__listening);
+
+ }
+
+ }
+
+ );
+
+ function add(gui, object, property, params) {
+
+ if (object[property] === undefined) {
+ throw new Error("Object " + object + " has no property \"" + property + "\"");
+ }
+
+ var controller;
+
+ 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);
+ dom.addClass(li, typeof controller.getValue());
+
+ augmentController(gui, li, controller);
+
+ gui.__controllers.push(controller);
+
+ return controller;
+
+ }
+
+ /**
+ * Add a row to the end of the GUI or before another row.
+ *
+ * @param gui
+ * @param [dom] If specified, inserts the dom content in the new row
+ * @param [liBefore] If specified, places the new row before another row
+ */
+ function addRow(gui, dom, liBefore) {
+ var li = document.createElement('li');
+ if (dom) li.appendChild(dom);
+ if (liBefore) {
+ gui.__ul.insertBefore(li, params.before);
+ } else {
+ gui.__ul.appendChild(li);
+ }
+ gui.onResize();
+ return li;
+ }
+
+ function augmentController(gui, li, controller) {
+
+ controller.__li = li;
+ controller.__gui = gui;
+
+ common.extend(controller, {
+
+ options: function(options) {
+
+ if (arguments.length > 1) {
+ controller.remove();
+
+ return add(
+ gui,
+ controller.object,
+ controller.property,
+ {
+ before: controller.__li.nextElementSibling,
+ factoryArgs: [common.toArray(arguments)]
+ }
+ );
+
+ }
+
+ if (common.isArray(options) || common.isObject(options)) {
+ controller.remove();
+
+ return add(
+ gui,
+ controller.object,
+ controller.property,
+ {
+ before: controller.__li.nextElementSibling,
+ factoryArgs: [options]
+ }
+ );
+
+ }
+
+ },
+
+ name: function(v) {
+ controller.__li.firstElementChild.firstElementChild.innerHTML = v;
+ return controller;
+ },
+
+ listen: function() {
+ controller.__gui.listen(controller);
+ return controller;
+ },
+
+ remove: function() {
+ controller.__gui.remove(controller);
+ return controller;
+ }
+
+ });
+
+ // All sliders should be accompanied by a box.
+ 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'], function(method) {
+ var pc = controller[method];
+ var pb = box[method];
+ controller[method] = box[method] = function() {
+ var args = Array.prototype.slice.call(arguments);
+ pc.apply(controller, args);
+ return pb.apply(box, args);
+ }
+ });
+
+ dom.addClass(li, 'has-slider');
+ controller.domElement.insertBefore(box.domElement, controller.domElement.firstElementChild);
+
+ }
+ else if (controller instanceof NumberControllerBox) {
+
+ var 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.
+ controller.remove();
+ return add(
+ gui,
+ controller.object,
+ controller.property,
+ {
+ before: controller.__li.nextElementSibling,
+ factoryArgs: [controller.__min, controller.__max, controller.__step]
+ });
+
+ }
+
+ 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(r) {
+ li.style.borderLeftColor = controller.__color.toString();
+ return r;
+ }, controller.updateDisplay);
+
+ controller.updateDisplay();
+
+ }
+
+ controller.setValue = common.compose(function(r) {
+ if (gui.getRoot().__preset_select && controller.isModified()) {
+ markPresetModified(gui.getRoot(), true);
+ }
+ return r;
+ }, controller.setValue);
+
+ }
+
+ function recallSavedValue(gui, controller) {
+
+ // Find the topmost GUI, that's where remembered objects live.
+ var root = gui.getRoot();
+
+ // Does the object we're controlling match anything we've been told to
+ // remember?
+ var matched_index = root.__rememberedObjects.indexOf(controller.object);
+
+ // Why yes, it does!
+ if (matched_index != -1) {
+
+ // Let me fetch a map of controllers for thcommon.isObject.
+ var controller_map =
+ root.__rememberedObjectIndecesToControllers[matched_index];
+
+ // Ohp, I believe this is the first controller we've created for this
+ // object. Lets make the map fresh.
+ if (controller_map === undefined) {
+ controller_map = {};
+ root.__rememberedObjectIndecesToControllers[matched_index] =
+ controller_map;
+ }
+
+ // Keep track of this controller
+ controller_map[controller.property] = controller;
+
+ // Okay, now have we saved any values for this controller?
+ if (root.load && root.load.remembered) {
+
+ var preset_map = root.load.remembered;
+
+ // Which preset are we trying to load?
+ var preset;
+
+ if (preset_map[gui.preset]) {
+
+ preset = preset_map[gui.preset];
+
+ } else if (preset_map[DEFAULT_DEFAULT_PRESET_NAME]) {
+
+ // Uhh, you can have the default instead?
+ preset = preset_map[DEFAULT_DEFAULT_PRESET_NAME];
+
+ } else {
+
+ // Nada.
+
+ return;
+
+ }
+
+
+ // Did the loaded object remember thcommon.isObject?
+ if (preset[matched_index] &&
+
+ // Did we remember this particular property?
+ preset[matched_index][controller.property] !== undefined) {
+
+ // We did remember something for this guy ...
+ var value = preset[matched_index][controller.property];
+
+ // And that's what it is.
+ controller.initialValue = value;
+ controller.setValue(value);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ function getLocalStorageHash(gui, key) {
+ // TODO how does this deal with multiple GUI's?
+ return document.location.href + '.' + key;
+
+ }
+
+ 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');
+
+ // TODO replace with FunctionController
+ 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 saveLocally = document.getElementById('dg-save-locally');
+ var explain = document.getElementById('dg-local-explain');
+
+ saveLocally.style.display = 'block';
+
+ var localStorageCheckBox = document.getElementById('dg-local-storage');
+
+ if (localStorage.getItem(getLocalStorageHash(gui, 'isLocal')) === 'true') {
+ localStorageCheckBox.setAttribute('checked', 'checked');
+ }
+
+ function showHideExplain() {
+ explain.style.display = gui.useLocalStorage ? 'block' : 'none';
+ }
+
+ showHideExplain();
+
+ // TODO: Use a boolean controller, fool!
+ dom.bind(localStorageCheckBox, 'change', function() {
+ gui.useLocalStorage = !gui.useLocalStorage;
+ showHideExplain();
+ });
+
+ }
+
+ 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();
+ });
+
+// div.appendChild(button2);
+
+ }
+
+ function addResizeHandle(gui) {
+
+ 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'
+
+ });
+
+ var pmouseX;
+
+ dom.bind(gui.__resize_handle, 'mousedown', dragStart);
+ dom.bind(gui.__closeButton, 'mousedown', dragStart);
+
+ gui.domElement.insertBefore(gui.__resize_handle, gui.domElement.firstElementChild);
+
+ 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;
+
+ }
+
+ 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 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) {
+
+ var toReturn = {};
+
+ // For each object I'm remembering
+ common.each(gui.__rememberedObjects, function(val, index) {
+
+ var saved_values = {};
+
+ // The controllers I've made for thcommon.isObject by property
+ var controller_map =
+ gui.__rememberedObjectIndecesToControllers[index];
+
+ // Remember each value for each property
+ common.each(controller_map, function(controller, property) {
+ saved_values[property] = useInitialValues ? controller.initialValue : controller.getValue();
+ });
+
+ // Save the values for thcommon.isObject
+ toReturn[index] = saved_values;
+
+ });
+
+ return toReturn;
+
+ }
+
+ 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 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 markPresetModified(gui, modified) {
+ var opt = gui.__preset_select[gui.__preset_select.selectedIndex];
+// console.log('mark', modified, opt);
+ if (modified) {
+ opt.innerHTML = opt.value + "*";
+ } else {
+ opt.innerHTML = opt.value;
+ }
+ }
+
+ function updateDisplays(controllerArray) {
+
+
+ if (controllerArray.length != 0) {
+
+ requestAnimationFrame(function() {
+ updateDisplays(controllerArray);
+ });
+
+ }
+
+ common.each(controllerArray, function(c) {
+ c.updateDisplay();
+ });
+
+ }
+
+ return GUI;
+
+})(dat.utils.css,
+"GUI's constructor:\n\n \n\n localStorage on exit.\n\n 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