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";