var ControlArray = Class.create(JSControl, { initialize: function($super, element, children){ $super(element); this.container = Element.down(this.element, "tbody"); this.children = children; $A(this.children).each(function(descr){ if ("acceptor" in descr){ var acceptor = String(descr["acceptor"]); if (!acceptor.startsWith(this.LocalID() + ".")) descr["acceptor"] = this.LocalID() + "." + acceptor; } var localid = descr["id"]; if (!localid) return; localid = localid.substr(localid.indexOf(".") + 1); this.children[localid] = descr; }, this); this.buttons = [// {"class": "AButton", "label": "+", "id": "AddRow", "css-class": "AddRowButton"}, // {"class": "AButton", "label": "-", "id": "RemoveRow", "css-class": "RemoveRowButton"}]; this.rownum = 0; this.value_callback = []; this.addShadow(); this.addRow(); var wnd = AControl.GetParentWindow(this.element); if (wnd){ // wnd.Subscribe("CHANGE", this.onControlChange, this); // wnd.Subscribe("WM_INIT", this.onControlInit, this); // wnd.Subscribe("CLICK", this.onControlClick, this); wnd.Subscribe("CALLBACK", this.callback, this); wnd.Subscribe("CA:REWIND", this.onrewind, this); wnd.SubscribeToAllEvents(this.processAEVENT, this); this.awnd_ = wnd; } }, LocalID: function(){ return this.element.getAttribute("localid"); }, modifyAttrs: function(attrs, num){ if (typeof num !== "undefined"){ var suff = "-" + num; ["id", "htmlid", "acceptor"].each(function(nam){ if (nam in attrs) attrs[nam] += suff; }); if ("rets" in attrs) attrs["rets"] = attrs["rets"].split(" ").collect(function(expr){ if (expr.length === 0 || !expr.startsWith(this.LocalID())) return ""; var ind = expr.indexOf("="); if (ind === -1) return expr + suff + "=" + expr; else return expr.substr(0, ind) + suff + "=" + expr.substr(ind + 1); }, this).join(" "); } return attrs; }, getHTML: function(attrs, num){ if (!("htmlid" in attrs)) attrs["htmlid"] = this.ID() + "." + attrs["id"]; var html = JSControl.TransformElementAndUnwrap(this.modifyAttrs(Object.clone(attrs), num), this.getTypeset()); return {"scripts": html.extractScripts(), "html": html.stripScripts()}; }, setAttrs: function(jscontrol){ if (!jscontrol) return; var attrs = this.children[this.getLocalID(jscontrol)]; if (!attrs) return; attrs = this.modifyAttrs(Object.clone(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]); } }, process_error: function(err){ alert(["ControlArray [id=\"" + this.element.getAttribute("localid") + "\"] ERROR", // "Error name: " + err.name, // "Error message: " + err.message].join("\n")); }, eval_scripts: function(arr){ for (var iii = 0; iii < arr.length; ++iii) try{ eval(arr[iii]); }catch(err){ this.process_error(err); } }, addShadow: function(){ if (!this.shadow) this.shadow = Element.down(this.element, "tfoot"); var row = this.shadow.insertRow(0); var scripts = []; this.children.each(function(attrs){ var cell = row.insertCell(-1); var properties = Object.clone(attrs); properties["class"] = "SimpleValue"; var content = this.getHTML(properties); cell.innerHTML = content["html"]; scripts = scripts.concat(content["scripts"]); }, this); row.insertCell(-1); this.eval_scripts(scripts); this.getChildControls(row).each(this.setAttrs, this); }, addRow: function(ref){ var row = this.container.insertRow(ref ? (ref.sectionRowIndex + 1) : this.container.rows.length); row.num = this.rownum++; var scripts = []; this.children.each(function(attrs){ var cell = row.insertCell(-1); var content = this.getHTML(attrs, row.num); cell.innerHTML = content["html"]; scripts = scripts.concat(content["scripts"]); ["align", "valign"].each(function(nam){ if (typeof attrs[nam] !== "undefined") cell[nam] = attrs[nam]; }); }, this); var cell = row.insertCell(-1); this.buttons.each(function(attrs){ var content = this.getHTML(attrs, row.num); cell.innerHTML += content["html"]; scripts = scripts.concat(content["scripts"]); }, this); this.eval_scripts(scripts); this.getChildControls(row).each(this.setAttrs, this); this.applyVisibility([row.previousSibling, row]); this.refreshTabOrder(); return row; }, removeRow: function(row){ // if (!row || !row.previousSibling && !row.nextSibling) return; if (!row) return; if( !row.previousSibling && !row.nextSibling ) { this.getChildControls( row ).each(function( jscontrol ){ jscontrol.SetValue(); }, this); return; } var parentNode = row.parentNode; if (!parentNode) return; parentNode.deleteRow(row.sectionRowIndex); // if (parentNode.rows.length == 1) this.applyVisibility(parentNode.rows[0]); }, getLocalID: function(jscontrol){ var localid = jscontrol.ID().substr(this.ID().length + 1); var dashindex = localid.lastIndexOf("-"); return dashindex == -1 ? localid : localid.substr(0, dashindex); }, getChildControls: function(row, include_buttons){ if (!row) return []; if (include_buttons) return JSControl.GetChildControls(row); else{ var result = []; for (var iii = 0; iii < row.cells.length - 1; ++iii) result.push.apply(result, JSControl.GetChildControls(row.cells[iii])); return result; } }, getButtons: function(row){ if (!row) return []; return JSControl.GetChildControls(row.cells[row.cells.length - 1]); }, getRow: function(ele){ for (ele = $(ele); ele && Element.descendantOf(ele, this.container); ele = ele.parentNode) if (Node.localName(ele).toLowerCase() == "tr") return ele; return null; }, onControlClick: function(aevent){ var emitter = aevent.Emitter(); if (!this.isChildControl(emitter)) return; var row = this.getRow(emitter.ID()); switch (this.getLocalID(emitter)){ case "AddRow": this.addRow(row); this.onchange(); break; case "RemoveRow": this.removeRow(row); this.onchange(); break; } aevent.Stop(); }, isShadowControl: function(jscontrol){ return Element.descendantOf(jscontrol.ID(), this.shadow); }, processCHANGE: function(aevent){ this.reroute_aevent(aevent); this.initialized = true; this.onchange(); }, onControlChange: function(aevent){ var emitter = aevent.Emitter(); if (!this.isChildControl(emitter) || this.isShadowControl(emitter)) return; if (typeof emitter.SubscribeOnValue == "function"){ this.inc_waited(); emitter.SubscribeOnValue(function(){ this.processCHANGE(aevent); this.dec_waited(); }.bind(this)); }else this.processCHANGE(aevent); aevent.Stop(); }, copyValues: function(rownum){ this.getChildControls(this.shadow.rows[0], false).each(function(jscontrol){ if (!jscontrol.ID || !jscontrol.SetValue) return; var source_element = $(jscontrol.ID() + "-" + rownum); if (!source_element || !source_element.JSControl || !source_element.JSControl.Value) return; jscontrol.SetValue(source_element.JSControl.Value()); new AEvent("WM_INIT", {}, jscontrol); }, this); }, processAEVENT: function(aevent){ var emitter = aevent.Emitter(); if (emitter === this.awnd_){// IN var edata = aevent.Data(); if (edata && "id" in edata && "xml" in edata){ var id = edata.id; var prefix = this.LocalID() + "."; if (id.startsWith(prefix)){ id = id.substr(prefix.length); if (id in this.children){ var desc = AXML.SelectNodes(edata.xml, "/ai:wnd/ai:e/ai:evt[@type='CALLBACK']", AINS); for (var iii = 0; iii < desc.length; ++iii){ var args = URLRestoreVS(desc[iii].getAttribute("arguments")); if (args && args["Receiver"] === this.ID() && "rownum" in args){ aevent.Stop(); edata.id += "-" + args.rownum; new AEvent(aevent.Name(), edata, emitter); break; } } } } } }else if (this.isChildControl(emitter) && !this.isShadowControl(emitter)){// OUT switch (aevent.Name()){ case "WM_INIT": return this.onControlInit(aevent); case "CHANGE": return this.onControlChange(aevent); case "CLICK": if (["AddRow", "RemoveRow"].indexOf(this.getLocalID(emitter)) !== -1) return this.onControlClick(aevent); //fall-through default: aevent.Stop(); this.reroute_aevent(aevent); break; } } }, reroute_aevent: function(aevent){ var emitter = aevent.Emitter(); if (!this.isChildControl(emitter) || this.isShadowControl(emitter)) return; var data = aevent.Data() || {}; if (!("args" in data)) data["args"] = {}; var row = this.getRow(emitter.ID()); if (!row) return; if (!("rownum" in data["args"])) data["args"]["rownum"] = row.num; if (!("Receiver" in data["args"])) data["args"]["Receiver"] = this.ID(); this.copyValues(row.num); var shadow_id = this.ID() + "." + this.getLocalID(emitter); var shadow_element = $(shadow_id); if (!shadow_element) return; if (shadow_element.JSControl){ if (this.awnd_.IsDefaultHandler(aevent.Name(), emitter.ID()) && // !this.awnd_.IsDefaultHandler(aevent.Name(), shadow_id)) this.awnd_.AddDefaultHandler(aevent.Name(), shadow_id); new AEvent(aevent.Name(), data, shadow_element.JSControl); } }, 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 = $A(this.container.rows).find(function(row){ return row.num == 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){ controls[this.getLocalID(jscontrol)] = jscontrol; }, this); var main_localid = this.element.getAttribute("localid"); $A(child_eles).each(function(ele){ var id = ele.getAttribute("id"); if (!id.startsWith(main_localid)) return; var jscontrol = controls[id.substr(main_localid.length + 1)]; if (jscontrol && jscontrol.ID) this.awnd_.SetAttributes(jscontrol.ID(), ele); }, this); this.onchange(); }, Value: function(){ return $A(this.container.rows).collect(function(row){ var result = {}; this.getChildControls(row, false).each(function(jscontrol){ result[this.getLocalID(jscontrol)] = jscontrol.Value(); }, this); return result; }, this); }, SubscribeOnValue: function(func){ if (typeof this.wait_for_ == "undefined" || this.wait_for_ <= 0) return func(); else this.value_callback.push(func); }, inc_waited: function(){ if (typeof this.wait_for_ == "undefined" || this.wait_for_ < 0) this.wait_for_ = 0; ++this.wait_for_; }, dec_waited: function(){ if (typeof this.wait_for_ == "undefined") this.wait_for_ = 0; else --this.wait_for_; if (this.wait_for_ <= 0) { var c = this.value_callback; this.value_callback = []; for (var i = 0; i < c.length; ++i) { c[i](); } } }, SetTabOrder: function(nTabBase){ this.nTabBase = nTabBase; this.refreshTabOrder(); return this.nTabBase + 512; }, refreshTabOrder: function(){ if (typeof(this.nTabBase) == "undefined") return; var nTabBase = this.nTabBase; $A(this.container.rows).each(function(row){ this.getChildControls(row, true).each(function(jscontrol){ if (jscontrol.SetTabOrder) nTabBase = jscontrol.SetTabOrder(nTabBase); }, this); }, this); }, 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; Element.setStyle(this.element, {"display": val == "no" ? "none" : ""}); this.visibility = val; var disabled = this.isDisabled(); $A(this.container.rows).each(function(row){ if (typeof row.num == "undefined") return; this.getChildControls(row, false).each(function(jscontrol){ if (typeof jscontrol.SetAttribute == "function") jscontrol.SetAttribute(nam, val); }, this); }, this); this.children.each(function(struct){ struct[nam] = val; }); this.applyVisibility($A(this.container.rows)); Element[disabled ? "addClassName" : "removeClassName"](this.element, "Disabled"); Element[val == "vo" || val == "link" ? "addClassName" : "removeClassName"](this.element, "VO"); Element[val == "link" ? "addClassName" : "removeClassName"](this.element, "Link"); var wrapper = Element.up(this.element, ".Wrapper"); if (wrapper && wrapper.resizer__ && wrapper.resizer__.SetAttribute) wrapper.resizer__.SetAttribute(nam, val); if (val == "link"){ if (!this.link_click_handler_) this.link_click_handler_ = function(event){ new AEvent("CLICK", {}, this); }.bind(this); Event.observe(this.element, "click", this.link_click_handler_); }else if(this.link_click_handler_) Event.stopObserving(this.element, "click", this.link_click_handler_); break; case "hide-buttons": if (!["yes", "no"].include(val)) break; var hide = val == "yes"; if ((this.hide_buttons_ || false) == hide) break; this.hide_buttons_ = hide; this.applyVisibility($A(this.container.rows)); break; default: $super(nam, val); } }, applyVisibility: function(rows){ if (!rows) return; if (!Object.isArray(rows)) rows = [rows]; var disabled = this.isDisabled(); $A(rows).each(function(row){ this.getButtons(row).each(function(jscontrol){ if( !row.previousSibling && disabled == false ) return; // 1-ю строку пропускаем полностью, если visibility аналогичен "yes" Element.setStyle(jscontrol.ID(), {"display": disabled || this.hide_buttons_ ||// !row.previousSibling && !row.nextSibling && this.getLocalID(jscontrol) == "RemoveRow" ? "none" : ""}); }, this); }, this); }, SetValue: function(val){ if (this.initialized && !this.isDisabled()) return; this.initializing_ = true; while (this.container.rows.length < val.length) this.addRow(); while (this.container.rows.length > val.length) this.removeRow(this.container.rows[this.container.rows.length - 1]); $A(val).each(function(struct, iii){ if (!struct) return; var row = this.container.rows[iii]; this.getChildControls(row, false).each(function(jscontrol){ var control_value = struct[this.getLocalID(jscontrol)]; if (typeof control_value != "undefined" && jscontrol.SetValue) jscontrol.SetValue(control_value); }, this); }, this); this.refreshTabOrder(); delete this.initializing_; this.initialized = true; }, 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[id]; if (!descr) return; for (var key in struct) if (key != "id") descr[key] = struct[key]; }, this); Element.clear(this.container); Element.clear(this.shadow); this.addShadow(); this.addRow(); this.initialized = false; }, onControlInit: function(aevent){ var emitter = aevent.Emitter(); if (!this.isChildControl(emitter) || this.isShadowControl(emitter)) return; if (this.initializing_) new AEvent("WM_INIT", {}, this); else new AEvent("CHANGE", aevent.Data(), emitter); aevent.Stop(); } });