var Query = Class.create(JSControl, {
initialize: function($super, element, children){
$super(element);
this.children = { "binop": [
{"class": "AButton", "label": "<", "id": this.ID() + ".Unindent", "css-class": "Unindent"}, //
{"class": "AButton", "label": ">", "id": this.ID() + ".Indent", "css-class": "Indent"}
],
"section": [] };
this.children_original_ = children;
for (var iii = 0; iii < children.length; ++iii){
var child = children[iii];
this.children[child["type"] == "AND_OR" ? "binop" : "section"].push(child);
}
this.children["section"].push({"class": "AButton", "label": "+", "id": this.ID() + ".AddRow", "css-class": "AddRowButton"});
this.children["section"].push({"class": "AButton", "label": "-", "id": this.ID() + ".RemoveRow", "css-class": "RemoveRowButton"});
this.children_by_id_ = {};
this.getChildDescrs().each(function(descr){
var localid = descr["id"]; if (!localid) return;
localid = localid.substr(localid.indexOf(".") + 1);
this.children_by_id_[localid] = descr;
}, this);
this.rownum = 0;
this.init_timer_ = function(){
var section = this.getSection();
this.appendRow(section);
new AEvent("WM_INIT", {}, this);
}.bind(this).defer();
this.shadow = new Element("div", {"style": "display: none"});
this.element.parentNode.appendChild(this.shadow);
this.resetShadow();
var wnd = AControl.GetParentWindow(this.element);
if (wnd){
wnd.Subscribe("CHANGE", this.onControlChange, this);
wnd.Subscribe("WM_INIT", this.onControlInit, this);
wnd.Subscribe("QUERY:REWIND", this.onrewind, this);
wnd.Subscribe("CLICK", this.onControlClick, this);
wnd.Subscribe("CALLBACK", this.callback, this);
this.awindow = wnd;
}
},
getChildDescrs: function(){ return this.children["binop"].concat(this.children["section"]); },
process_error: function(err){
alert(["QUERY [id=\"" + this.element.getAttribute("localid") + "\"] ERROR", //
"Error name: " + err.name, //
"Error message: " + err.message].join("\n"));
},
isButton: function(jscontrol){ return ["AddRow", "RemoveRow", "Indent", "Unindent"].include(this.getLocalID(jscontrol)); },
getChildControls: function(block, includeButtons){
var result = JSControl.GetChildControls(block);
if (includeButtons) return result;
else return result.reject(this.isButton, this);
},
getHTML: function(descrs, num){
var newdescrs = descrs.collect(function(attrs){
var result = Object.clone(attrs);
result["id"] = attrs["id"] + (typeof num != "undefined" ? "-" + num : "");
if (typeof attrs["htmlid"] == "undefined") attrs["htmlid"] = attrs["id"];
result["htmlid"] = attrs["htmlid"] + (typeof num != "undefined" ? "-" + num : "");
if (typeof attrs["acceptor"] != "undefined"){
var acceptor = String(attrs["acceptor"]);
var localid = this.element.getAttribute("localid");
if (!acceptor.startsWith(localid + ".")) acceptor = localid + "." + acceptor;
if (typeof num != "undefined") acceptor += "-" + num;
result["acceptor"] = acceptor;
}
return result;
}, this);
return JSControl.TransformElementsAndUnwrap(newdescrs, this.getTypeset());
},
merge_attrs: function(arr, extra_attrs){
if (!extra_attrs) return arr;
else return arr.collect(function(struct){
if (!("id" in struct)) return struct;
var localid = struct["id"];
localid = localid.substr(localid.indexOf(".") + 1);
if (!(localid in extra_attrs)) return struct;
else return Object.extend(Object.clone(struct), extra_attrs[localid]);
}, this);
},
getSection: function(extra_attrs){
var dd = new Element("dd");
dd.num = this.rownum++;
dd.innerHTML = " " + //
this.getHTML(this.merge_attrs(this.children["section"], extra_attrs), dd.num) + //
" ";
if (extra_attrs) dd.attrs_ = extra_attrs;
return dd;
},
getBinop: function(extra_attrs){
var dt = new Element("dt");
dt.num = this.rownum++;
dt.innerHTML = this.getHTML(this.merge_attrs(this.children["binop"], extra_attrs), dt.num);
if (extra_attrs) dt.attrs_ = extra_attrs;
return dt;
},
appendRow: function(row, ref, attrs){
var html = row.innerHTML;
row.innerHTML = html.stripScripts();
var parentNode = ref ? ref.parentNode : this.element;
if (!ref || !ref.nextSibling) parentNode.appendChild(row);
else parentNode.insertBefore(row, ref.nextSibling);
try{ html.evalScripts(); }catch(err){ this.process_error(err); }
if (!attrs) this.getChildControls(row, true).each(this.setAttrs, this);
else this.getChildControls(row, true).each(//
function(jscontrol){ this.setAttrs(jscontrol, attrs[this.getLocalID(jscontrol)]); }, this);
this.setButtonsVisibility(row);
if (row.tagName.toLowerCase() == "dt") this.setButtonsVisibility(row.previousSibling);
else if (typeof this.bracketWidth === "undefined"){
var elem = Element.down(row, ".lbrackets");
if (elem) this.bracketWidth = elem.offsetWidth;
}
},
setButtonsVisibility: function(row){
if (!row) return;
this.getChildControls(row, true).each(function(jscontrol){
if (!this.isButton(jscontrol)) return;
Element.setStyle(jscontrol.ID(), {"display": this.isDisabled() || //
(this.getLocalID(jscontrol) == "RemoveRow" && !row.previousSibling && !row.nextSibling) ? "none" : ""});
}, this);
},
getRow: function(ele){
for (ele = $(ele); ele && Element.descendantOf(ele, this.element); ele = ele.parentNode){
var locnam = Node.localName(ele).toLowerCase();
if (locnam == "dt" || locnam == "dd") return ele;
}
return null;
},
getLocalID: function(jscontrol){
var localid = jscontrol.ID().substr(this.ID().length + 1);
var dashindex = localid.lastIndexOf("-");
return dashindex == -1 ? localid : localid.substr(0, dashindex);
},
touchIndentFactor: function(force){
if (force || typeof this.indentFactor != "undefined") return;
var binop = this.getBinop();
Element.setStyle(binop, {"visibility": "hidden"});
this.appendRow(binop)
var child = binop.lastChild;
while (child && (child.nodeType != Node.ELEMENT_NODE || !child.JSControl)) child = child.previousSibling;
if (child) this.indentFactor = child.offsetLeft + child.offsetWidth;
this.binopPaddingLeft = parseInt(Element.getStyle(binop, "paddingLeft"), 10);
Element.remove(binop);
--this.rownum;
},
getIndentFactor: function(includeBracketWidth){
if (this.isDisabled()) return Query.indentFactor;
this.touchIndentFactor();
return (this.indentFactor || Query.indentFactor) + (includeBracketWidth || 0) * Query.bracketWidth;
},
getIndentLevel: function(block){ return Number(block ? block.indentLevel || 0 : 0); },
setIndentLevel: function(block, indentLevel){
if (!block || indentLevel < 0) return;
switch (block.tagName.toLowerCase()){
case "dt":
Element.setStyle(block, {"paddingLeft": (indentLevel > 0) ? //
((this.binopPaddingLeft || 0) + indentLevel * this.getIndentFactor(true)) + "px" : ""});
block.indentLevel = indentLevel;
this.refreshIndentLevel(block.previousSibling);
this.refreshIndentLevel(block.nextSibling);
break;
case "dd":
block.indentLevel = indentLevel;
this.refreshBrackets(block);
break;
}
},
refreshIndentLevel : function(block){
if (!block || block.tagName.toLowerCase() != "dd") return;
var previousSection = block.previousSibling;
var nextSection = block.nextSibling;
var indentLevel = 0;
[previousSection, nextSection].each(function(binopBlock){
indentLevel = Math.max(indentLevel, this.getIndentLevel(binopBlock));
}, this);
if (indentLevel != this.getIndentLevel(block)) this.setIndentLevel(block, indentLevel);
else this.refreshBrackets(block);
},
getBrackets: function(block, type){
if (!block || block.tagName.toLowerCase() != "dd") return null;
switch (type){
case "l":
if (!block.lbrackets) block.lbrackets = Element.down(block, ".lbrackets");
return block.lbrackets;
case "r":
if (!block.rbrackets) block.rbrackets = Element.down(block, ".rbrackets");
return block.rbrackets;
}
},
refreshBrackets: function(block){
if (!block || block.tagName.toLowerCase() != "dd") return;
var lbrackets = this.getBrackets(block, "l");
var rbrackets = this.getBrackets(block, "r");
var blockIndentLevel = this.getIndentLevel(block);
var disabled = this.isDisabled();
if (lbrackets){
var nlbrackets = blockIndentLevel - this.getIndentLevel(block.previousSibling);
Element.clear(lbrackets);
if (disabled){
lbrackets.appendChild(document.createTextNode("(".times(nlbrackets) + Query.NBSP));
Element.setStyle(lbrackets, { "width": blockIndentLevel * this.getIndentFactor() + "px", "marginRight": "" });
}else{
lbrackets.appendChild(document.createTextNode(nlbrackets > 0 ? "(".times(nlbrackets) : Query.NBSP));
var singleBlock = !block.previousSibling && !block.nextSibling;
Element.setStyle(lbrackets, {
"width": blockIndentLevel > 0 ? blockIndentLevel * this.getIndentFactor(true) + "px" : "",
"marginRight": singleBlock ? "" : this.getIndentFactor() + ((blockIndentLevel > 0) * this.bracketWidth || 0) + "px"
});
Element.setStyle(block, {"paddingLeft": singleBlock ? "0px" : ""});
}
}
if (rbrackets){
var nrbrackets = blockIndentLevel - this.getIndentLevel(block.nextSibling);
Element.clear(rbrackets);
if (nrbrackets > 0) rbrackets.appendChild(document.createTextNode(")".times(nrbrackets)));
Element.setStyle(rbrackets, {"width": disabled ? "auto" : nrbrackets + "ex"});
}
},
onControlClick: function(aevent){
var emitter = aevent.Emitter();
if (!this.isChildControl(emitter)) return;
var localid = this.getLocalID(emitter);
var row = this.getRow(emitter.ID());
switch (localid){
case "AddRow":
this.AddSection(row);
this.onchange();
break;
case "RemoveRow":
this.RemoveSection(row);
this.onchange();
break;
case "Indent": this.setIndentLevel(row, this.getIndentLevel(row) + 1); this.onchange(); break;
case "Unindent":
var indentLevel = this.getIndentLevel(row);
if (indentLevel == 0) break;
this.setIndentLevel(row, indentLevel - 1);
this.onchange();
break;
}
aevent.Stop();
},
AddSection: function(prev_row){
var next_row = prev_row.nextSibling;
this.touchIndentFactor();
var binop = this.getBinop(); var section = this.getSection();
this.appendRow(binop, prev_row);
this.appendRow(section, binop);
var indentLevel = this.getIndentLevel(prev_row);
this.setIndentLevel(binop, indentLevel);
this.setIndentLevel(section, indentLevel);
this.refreshTabOrder();
this.onchange();
},
RemoveSection: function(section){
if (!section) return;
var prev_binop = section.previousSibling;
var next_binop = section.nextSibling;
if (!prev_binop && !next_binop) return;
var prev_section = prev_binop ? prev_binop.previousSibling : null;
var next_section = next_binop ? next_binop.nextSibling : null;
Element.remove(section);
Element.remove(prev_binop ? prev_binop : next_binop);
if (prev_section) this.refreshIndentLevel(prev_section);
if (next_section) this.refreshIndentLevel(next_section);
var rows = Element.childElements(this.element);
if (rows.length == 1) this.setButtonsVisibility(rows[0]);
this.onchange();
},
isShadowControl: function(jscontrol){ return Element.descendantOf(jscontrol.ID(), this.shadow); },
onControlChange: function(aevent){
var emitter = aevent.Emitter();
if (!this.isChildControl(emitter) || this.isShadowControl(emitter)) return;
var data = aevent.Data() || {};
if (typeof data["args"] == "undefined") data["args"] = {};
var row = this.getRow(emitter.ID());
if (typeof data["args"]["rownum"] == "undefined") data["args"]["rownum"] = row.num;
if (typeof data["args"]["Receiver"] == "undefined") data["args"]["Receiver"] = this.ID();
aevent.Stop();
var shadow_jscontrol = $(this.ID() + "." + this.getLocalID(emitter)).JSControl;
this.getChildControls(this.shadow, false).each(function(jscontrol){
if (jscontrol == shadow_jscontrol) return;
var source_element = $(jscontrol.ID() + "-" + row.num);
if (!source_element || !source_element.JSControl) return;
jscontrol.SetValue(source_element.JSControl.Value());
new AEvent("WM_INIT", {}, jscontrol);
}, this);
shadow_jscontrol.SetValue(emitter.Value());
new AEvent("CHANGE", data, shadow_jscontrol);
this.initialized = true;
this.onchange();
},
onControlInit: function(aevent){
var emitter = aevent.Emitter();
if (!this.isChildControl(emitter) || this.isShadowControl(emitter)) return;
if(this.initialized) new AEvent("CHANGE", aevent.Data(), emitter);
aevent.Stop();
},
SetTabOrder: function(nTabBase){
this.nTabBase = nTabBase;
this.refreshTabOrder();
return this.nTabBase + 512;
},
refreshTabOrder: function(){
if (typeof(this.nTabBase) == "undefined") return;
var nTabBase = this.nTabBase;
Element.childElements(this.element).each(function(block){
this.getChildControls(block, true).each(function(jscontrol){
if (jscontrol.SetTabOrder) nTabBase = jscontrol.SetTabOrder(nTabBase);
}, this);
}, this);
},
getValue: function(block){
var struct = {"indent": this.getIndentLevel(block)};
if (block.attrs_) struct["__attributes__"] = block.attrs_;
this.getChildControls(block).each(function(jscontrol){
struct[this.getLocalID(jscontrol)] = jscontrol.Value() }, this);
return struct;
},
Value: function(){ return Element.childElements(this.element).collect(this.getValue, this); },
getRowByNum: function(rownum){
for (var child = this.element.firstChild; child; child = child.nextSibling){
if (child.nodeType != Node.ELEMENT_NODE) continue;
if (child.num == rownum) return child;
}
return null;
},
callback: function(aevent){
var data = aevent.Data();
var args = URLRestoreVS(data["arguments"]);
if (!args || args["Receiver"] != this.ID() || typeof args["rownum"] == "undefined") return;
var row = this.getRowByNum(args["rownum"]);
if (!row) return;
var child_eles = AXML.SelectNodes(data["xml"], "/ai:wnd/ai:ele[@id='" + this.element.getAttribute("localid") + "']/ai:ele", AINS);
var controls = {};
this.getChildControls(row, false).each(function(jscontrol){
var localid = $(jscontrol.ID()).getAttribute("localid");
var dashindex = localid.lastIndexOf("-");
if (dashindex > -1) localid = localid.substr(0, dashindex);
controls[localid] = jscontrol;
});
$A(child_eles).each(function(ele){
var jscontrol = controls[ele.getAttribute("id")];
if (jscontrol){
this.awindow.SetAttributes(jscontrol.ID(), ele);
var localid = this.getLocalID(jscontrol);
if (typeof row.attrs_ === "undefined") row.attrs_ = {};
if (!(localid in row.attrs_)) row.attrs_[localid] = {};
$A(ele.attributes).each(function(attr){
if (["value", "id", "htmlid", "localid", "class", "type", "handle"].indexOf(attr.name) === -1)
row.attrs_[localid][attr.name] = attr.value;
}, this);
}
}, this);
},
clear: function(){
if (typeof this.init_timer_ !== "undefined"){
window.clearTimeout(this.init_timer_);
delete this.init_timer_;
}
Element.clear(this.element);
},
SetValue: function(val){
if (this.initialized && !this.isDisabled()) return;
this.clear();
$A(val).each(function(struct, iii){
var row = this[iii % 2 === 0 ? "getSection" : "getBinop"](struct["__attributes__"]);
this.appendRow(row, null, struct["__attributes__"]);
this.setIndentLevel(row, struct["indent"]);
this.getChildControls(row, false).each(function(jscontrol){
var localid = this.getLocalID(jscontrol);
if (localid in struct) jscontrol.SetValue(struct[localid]);
}, this);
}, this);
this.refreshTabOrder();
new AEvent("WM_INIT", {}, this);
this.initialized = true;
},
isDisabled: function(){ return typeof this.visibility != "undefined" && this.visibility != "yes" },
SetAttribute: function($super, nam, val){
switch (nam){
case "visibility":
if (!["yes", "ro", "vo", "link", "no"].include(val)) break;
if (typeof this.visibility == "undefined") this.visibility = "yes";
if (this.visibility == val) break;
this.visibility = val;
var disabled = this.isDisabled();
Element.childElements(this.element).each(function(row){
if (typeof row.num == "undefined") return;
this.getChildControls(row, true).each(function(jscontrol){
if (nam == "visibility" && this.isButton(jscontrol))
Element.setStyle(jscontrol.ID(), {"display": disabled ? "none" : ""});
else if (typeof jscontrol.SetAttribute == "function") jscontrol.SetAttribute(nam, val);
}, this);
this.getChildDescrs().each(function(struct){ struct[nam] = val; });
this.setIndentLevel(row, this.getIndentLevel(row));
}, this);
Element[disabled ? "addClassName" : "removeClassName"](this.element, "Disabled");
break;
default: $super(nam, val);
}
},
restore: function(str){
str = String(str);
if (str.startsWith("Value:")) return URLRestore(str);
else return URLRestoreVS(str);
},
onrewind: function(aevent){
var localid = Element.readAttribute(this.element, "localid");
if (!aevent || !Object.isFunction(aevent.Data) || aevent.Data()["id"] != localid) return;
var params = this.restore(aevent.Data()["data"] || "");
if (!Object.isArray(params)) params = [params];
params.each(function(struct){
var id = struct["id"]; if (!id) return;
var descr = this.children_by_id_[id]; if (!descr) return;
for (var key in struct)
if (key != "id") descr[key] = struct[key];
}, this);
this.clear();
this.resetShadow();
this.appendRow(this.getSection());
this.refreshTabOrder();
this.initialized = false;
},
setAttrs: function(jscontrol, extra_attrs){
if (!jscontrol) return;
if (typeof extra_attrs !== "object") extra_attrs = null;
var attrs = this.children_by_id_[this.getLocalID(jscontrol)];
if (!attrs && !extra_attrs) return;
else if (!attrs) attrs = extra_attrs;
else if (extra_attrs) attrs = Object.extend(Object.clone(attrs), extra_attrs);
for (var nam in attrs){
if (["id", "localid", "class", "type"].include(nam)) continue;
if (nam == "value" && jscontrol.SetValue) jscontrol.SetValue(attrs[nam]);
else if (jscontrol.SetAttribute) jscontrol.SetAttribute(nam, attrs[nam]);
}
},
resetShadow: function(){
if (!this.shadow) return;
var descr = $A(this.children_original_).collect(function(struct){
var res = {};
for (var key in struct) if ("type" !== key) res[key] = struct[key];
res["class"] = "SimpleValue";
return res;
});
var children_html = this.getHTML(descr);
this.shadow.innerHTML = children_html.stripScripts();
try{ children_html.evalScripts(); }catch(err){ this.process_error(err); }
this.getChildControls(this.shadow, true).each(this.setAttrs, this);
}
});
Query.indentFactor = 20;
Query.bracketWidth = 10;
Query.NBSP = "\u00A0";