*/
"use strict";
-function Palette() {
+/**
+ * scope is either "global", "series", "x", "y" or "y2".
+ */
+function Palette(scope) {
+ // Contains pair of "input" (the input object) and "row" (the parent row)
+ // Also contains functionString.
this.model = {};
+ // This is meant to be overridden by a palette host.
this.onchange = function() {};
- this.filterBar = null;
+ this.scope = scope;
+ this.root = null;
}
-Palette.prototype.create = function(document, parentElement) {
+Palette.prototype.create = function(parentElement) {
var palette = this;
- var createChild = function(type, parentElement) {
- var element = document.createElement(type);
- parentElement.appendChild(element);
- return element;
- };
-
- var table = createChild("table", parentElement);
- table.class = "palette";
-
- var row = createChild("tr", table);
- row.style.display = "block";
-
- createChild("td", row).innerText = "Filter:";
- this.filterBar = createChild("input", createChild("td", row));
- this.filterBar.onkeyup = function() {
- palette.filter(palette.filterBar.value)
- };
- var go = document.createElement("button");
- createChild("td", row).appendChild(go);
- go.innerText = "Redraw"
- go.onclick = function() {
- palette.onchange();
- };
-
- for (var opt in opts) {
+
+ var table = $("<div>")
+ .addClass("palette")
+ .width(300)
+ .appendTo(parentElement);
+
+ this.root = table;
+ this.tooltip = new Tooltip();
+
+ // One row per option.
+ $.each(opts, function(opt, optEntry) {
try {
- if (opts.hasOwnProperty(opt)) {
- var type = opts[opt].type;
- var isFunction = type.indexOf("function(") == 0;
- var row = createChild("tr", table);
- var div = createChild("div", createChild("td", row));
- var a = createChild("a", div);
- a.innerText = opt;
- a.href = "http://dygraphs.com/options.html#" + opt;
- a.title = Dygraph.OPTIONS_REFERENCE[opt].description;
- a.target="_blank";
-
- if (isFunction) {
- var input = createChild("button", createChild("td", row));
- input.onclick = function(opt, palette) {
- return function(event) {
- var entry = palette.model[opt];
- var inputValue = entry.functionString;
- if (inputValue == null || inputValue.length == 0) {
- inputValue = type + "{ }";
- }
- var value = prompt("enter function", inputValue);
- if (value != null) {
- if (value.length == 0) {
- value = null;
- }
- if (value != inputValue) {
- entry.functionString = value;
- entry.input.innerText = value ? "defined" : "not defined";
- palette.onchange();
+ var scope = optEntry.scope || [ "global" ]; // Scope can be empty, infer "global" only.
+ var valid = scope[0] == "*" || $.inArray(palette.scope, scope) >= 0;
+ if (!valid) {
+ return;
+ }
+
+ var type = optEntry.type;
+ var isFunction = type.indexOf("function(") == 0;
+
+ var input;
+ if (isFunction) {
+ input = $("<button>")
+ .click(function(opt, palette) {
+ return function(event) {
+ var entry = palette.model[opt];
+ var inputValue = entry.functionString;
+ var type = opts[opt].type;
+ if (inputValue == null || inputValue.length == 0) {
+ inputValue = type + "{\n\n}";
}
- }
- }
- }(opt, this);
- } else {
- var input = createChild("input", createChild("td", row));
- input.onkeypress = function(event) {
- var keycode = event.which;
- if (keycode == 13 || keycode == 8) {
+ var textarea = new TextArea();
+ textarea.show(opt, inputValue);
+ textarea.okCallback = function(value) {
+ if (value != inputValue) {
+ entry.functionString = value;
+ entry.input.textContent = value ? "defined" : "not defined";
+ palette.onchange();
+ }
+ };
+ };
+ } (opt, palette) // Instantiating this inner function.
+ );
+ } else if (type == "boolean") {
+ input = $("<button>")
+ .click(function(event) {
+ var btn = event.target;
+ if (btn.value == "none") {
+ Palette.populateBooleanButton(btn, "true");
+ } else if (btn.value == "true") {
+ Palette.populateBooleanButton(btn, "false");
+ } else {
+ Palette.populateBooleanButton(btn, "none");
+ }
palette.onchange();
- }
- }
-
- input.type="text";
- }
- this.model[opt] = { input: input, row: row };
+ });
+ } else {
+ input = $("<input>", { type: "text" })
+ .addClass("textInput")
+ .keypress(function(event) {
+ var keycode = event.which;
+ if (keycode == 13 || keycode == 8) {
+ palette.onchange();
+ }
+ });
}
+
+ var row = $("<div>")
+ .append($("<span>").addClass("name").text(opt))
+ .append($("<span>").addClass("option")
+ .append(input));
+
+ row.mouseover(function(source, title, type, body) {
+ return function() {
+ palette.tooltip.show(source, title, type, body);
+ };
+ } (row, opt, type, Dygraph.OPTIONS_REFERENCE[opt].description))
+ .mouseout(function() { palette.tooltip.hide(); })
+
+ row.appendTo(table);
+
+ palette.model[opt] = { input: input, row: row };
} catch(err) {
throw "For option " + opt + ":" + err;
}
- }
+ });
+
this.filter("");
}
if (value == null || value.length == 0) {
return null;
}
- return value.split(',').map(function(x) { return x.trim() == "true"; });
+ return value.split(',').map(function(x) {
+ return x.trim() == "true";
+ });
}
Palette.parseFloatArray = function(value) {
if (value == null || value.length == 0) {
return null;
}
- return value.split(',').map(function(x) { return parseFloat(x); });
+ return value.split(',').map(function(x) {
+ return parseFloat(x);
+ });
}
Palette.parseIntArray = function(value) {
if (value == null || value.length == 0) {
return null;
}
- return value.split(',').map(function(x) { return parseInt(x); });
+
+ return value.split(',').map(function(x) {
+ return parseInt(x);
+ });
}
Palette.prototype.read = function() {
if (this.model.hasOwnProperty(opt)) {
var type = opts[opt].type;
var isFunction = type.indexOf("function(") == 0;
- var input = this.model[opt].input;
+ var input = this.model[opt].input[0]; // jquery dereference.
var value = isFunction ? this.model[opt].functionString : input.value;
if (value && value.length != 0) {
if (type == "boolean") {
- results[opt] = value == "true";
+ if (value == "false") {
+ results[opt] = false;
+ }
+ if (value == "true") {
+ results[opt] = true;
+ }
+ // Ignore value == "none"
} else if (type == "int") {
results[opt] = parseInt(value);
} else if (type == "float") {
results[opt] = Palette.parseFloatArray(value);
} else if (type == "array<boolean>") {
results[opt] = Palette.parseBooleanArray(value);
+ } else if (type == "array<int>") {
+ results[opt] = Palette.parseIntArray(value);
} else if (type == "array<Date>") {
results[opt] = Palette.parseIntArray(value);
} else if (isFunction) {
* Write to input elements.
*/
Palette.prototype.write = function(hash) {
+ if (!hash) {
+ return;
+ }
var results = {};
for (var opt in this.model) {
- // && hash.hasOwnProperty(opt)
if (this.model.hasOwnProperty(opt)) {
- var input = this.model[opt].input;
+ var input = this.model[opt].input[0]; // jquery dereference
var type = opts[opt].type;
var value = hash[opt];
- if (type == "array<string>") {
+ if (type == "boolean") {
+ var text = value == true ? "true" : (value == false ? "false" : "none");
+ Palette.populateBooleanButton(input, text);
+ } else if (type == "array<string>") {
if (value) {
input.value = value.join("; ");
}
input.value = value.join(", ");
}
} else if (type.indexOf("function(") == 0) {
- input.innerText = value ? "defined" : "not defined";
+ input.textContent = value ? "defined" : "not defined";
this.model[opt].functionString = value ? value.toString() : null;
} else {
- if (value) {
+ if (value != undefined) {
input.value = value;
}
}
}
}
+Palette.populateBooleanButton = function(button, value) {
+ button.innerHTML = value;
+ button.value = value;
+}
+
Palette.prototype.filter = function(pattern) {
pattern = pattern.toLowerCase();
+ var even = true;
for (var opt in this.model) {
if (this.model.hasOwnProperty(opt)) {
var row = this.model[opt].row;
- row.style.display = (opt.toLowerCase().indexOf(pattern) >= 0) ? "block" : "none";
+ var matches = opt.toLowerCase().indexOf(pattern) >= 0;
+ row.toggle(matches);
+ if (matches) {
+ row.attr("class", even ? "even" : "odd");
+ even = !even;
+ }
}
}
}