1 // Copyright (c) 2011 Google, Inc.
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * @fileoverview Dygraphs options palette.
24 * @author konigsberg@google.com (Robert Konigsberg)
29 * scope is either "global", "series", "x", "y" or "y2".
31 function Palette(scope
) {
32 // Contains pair of "input" (the input object) and "row" (the parent row)
33 // Also contains functionString.
35 // This is meant to be overridden by a palette host.
36 this.onchange
= function() {};
41 Palette
.prototype.create
= function(parentElement
) {
44 var table
= $("<div>")
47 .appendTo(parentElement
);
50 this.tooltip
= new Tooltip();
52 // One row per option.
53 $.each(opts
, function(opt
, optEntry
) {
55 var scope
= optEntry
.scope
|| [ "global" ]; // Scope can be empty, infer "global" only.
56 var valid
= scope
[0] == "*" || $.inArray(palette
.scope
, scope
) >= 0;
61 var type
= optEntry
.type
;
62 var isFunction
= type
.indexOf("function(") == 0;
67 .click(function(opt
, palette
) {
68 return function(event
) {
69 var entry
= palette
.model
[opt
];
70 var inputValue
= entry
.functionString
;
71 var type
= opts
[opt
].type
;
72 if (inputValue
== null || inputValue
.length
== 0) {
73 inputValue
= type
+ "{\n\n}";
75 var textarea
= new TextArea();
76 textarea
.show(opt
, inputValue
);
77 textarea
.okCallback
= function(value
) {
78 if (value
!= inputValue
) {
79 entry
.functionString
= value
;
80 entry
.input
.textContent
= value
? "defined" : "not defined";
85 } (opt
, palette
) // Instantiating this inner function.
87 } else if (type
== "boolean") {
89 .click(function(event
) {
90 var btn
= event
.target
;
91 if (btn
.value
== "none") {
92 Palette
.populateBooleanButton(btn
, "true");
93 } else if (btn
.value
== "true") {
94 Palette
.populateBooleanButton(btn
, "false");
96 Palette
.populateBooleanButton(btn
, "none");
101 input
= $("<input>", { type
: "text" })
102 .addClass("textInput")
103 .keypress(function(event
) {
104 var keycode
= event
.which
;
105 if (keycode
== 13 || keycode
== 8) {
112 .append($("<span>").addClass("name").text(opt
))
113 .append($("<span>").addClass("option")
116 row
.mouseover(function(source
, title
, type
, body
) {
118 // source[0] is un-jquerying.
119 // TODO(konigsberg): when tooltip is jquery, dump this.
120 palette
.tooltip
.show(source
[0], title
, type
, body
);
122 } (row
, opt
, type
, Dygraph
.OPTIONS_REFERENCE
[opt
].description
))
123 .mouseout(function() { palette
.tooltip
.hide(); })
127 palette
.model
[opt
] = { input
: input
, row
: row
};
129 throw "For option " + opt
+ ":" + err
;
136 // TODO: replace semicolon parsing with comma parsing, and supporting quotes.
137 Palette
.parseStringArray
= function(value
) {
138 if (value
== null || value
.length
== 0) {
141 return value
.split(";");
144 Palette
.parseBooleanArray
= function(value
) {
145 if (value
== null || value
.length
== 0) {
148 return value
.split(',').map(function(x
) {
149 return x
.trim() == "true";
153 Palette
.parseFloatArray
= function(value
) {
154 if (value
== null || value
.length
== 0) {
157 return value
.split(',').map(function(x
) {
158 return parseFloat(x
);
162 Palette
.parseIntArray
= function(value
) {
163 if (value
== null || value
.length
== 0) {
167 return value
.split(',').map(function(x
) {
172 Palette
.prototype.read
= function() {
174 for (var opt
in this.model
) {
175 if (this.model
.hasOwnProperty(opt
)) {
176 var type
= opts
[opt
].type
;
177 var isFunction
= type
.indexOf("function(") == 0;
178 var input
= this.model
[opt
].input
[0]; // jquery dereference.
179 var value
= isFunction
? this.model
[opt
].functionString
: input
.value
;
180 if (value
&& value
.length
!= 0) {
181 if (type
== "boolean") {
182 if (value
== "false") {
183 results
[opt
] = false;
185 if (value
== "true") {
188 // Ignore value == "none"
189 } else if (type
== "int") {
190 results
[opt
] = parseInt(value
);
191 } else if (type
== "float") {
192 results
[opt
] = parseFloat(value
);
193 } else if (type
== "array<string>") {
194 results
[opt
] = Palette
.parseStringArray(value
);
195 } else if (type
== "array<float>") {
196 results
[opt
] = Palette
.parseFloatArray(value
);
197 } else if (type
== "array<boolean>") {
198 results
[opt
] = Palette
.parseBooleanArray(value
);
199 } else if (type
== "array<int>") {
200 results
[opt
] = Palette
.parseIntArray(value
);
201 } else if (type
== "array<Date>") {
202 results
[opt
] = Palette
.parseIntArray(value
);
203 } else if (isFunction
) {
204 var localVariable
= null;
205 eval("localVariable = " + value
);
206 results
[opt
] = localVariable
;
208 results
[opt
] = value
;
217 * Write to input elements.
219 Palette
.prototype.write
= function(hash
) {
221 for (var opt
in this.model
) {
222 if (this.model
.hasOwnProperty(opt
)) {
223 var input
= this.model
[opt
].input
[0]; // jquery dereference
224 var type
= opts
[opt
].type
;
225 var value
= hash
[opt
];
226 if (type
== "boolean") {
227 var text
= value
== true ? "true" : (value
== false ? "false" : "none");
228 Palette
.populateBooleanButton(input
, text
);
229 } else if (type
== "array<string>") {
231 input
.value
= value
.join("; ");
233 } else if (type
.indexOf("array") == 0) {
235 input
.value
= value
.join(", ");
237 } else if (type
.indexOf("function(") == 0) {
238 input
.textContent
= value
? "defined" : "not defined";
239 this.model
[opt
].functionString
= value
? value
.toString() : null;
241 if (value
!= undefined
) {
249 Palette
.populateBooleanButton
= function(button
, value
) {
250 button
.innerHTML
= value
;
251 button
.value
= value
;
254 Palette
.prototype.filter
= function(pattern
) {
255 pattern
= pattern
.toLowerCase();
257 for (var opt
in this.model
) {
258 if (this.model
.hasOwnProperty(opt
)) {
259 var row
= this.model
[opt
].row
;
260 var matches
= opt
.toLowerCase().indexOf(pattern
) >= 0;
263 row
.attr("class", even
? "even" : "odd");