PageSourceSearch

https://villatavernasf.com/CHO/UserControls/Scripts/ps!input.js?639257960254284842

js villatavernasf.com collected 2026-09-29 03:46:53 UTC 104,068 bytes, 2,693 lines download raw bytes

1//-----------------------------------------------------------------------------\dlo/
2// ps!Ext.UI.Input Control v2.0
3// Jonas Software  2013, by Dmitry Lopyrev
4//-----------------------------------------------------------------------------
5//  
6//-----------------------------------------------------------------------------
7// Note: Requires Prototype JS library (v.1.7.1 - modified) and Utility.js  
8//-----------------------------------------------------------------------------
9
10//Note: all methods can be overriden by derived class
11//Changes:
12/*
13    April 1, 2015
14        - CMS-9149 : Client side modification: added support of new option "selectall" (as a text to show as  a label to chekbox) to check/uncheck all items for control Type="Tree" and <cho:Option Text="checkbox" Value="true"/>" 
15        - added call to "onBeforeChanged"  to Selector control to do custom validation or custom business logic on before value is stored into input field
16
17
18*/
19
20
21//Simple Data validation. Verifies if given data is matched following conditions
22Utility.UI.Validation = {
23    IsEmail: function (value) {
24        return /^(([\w.-]+@[\w.-]+\.[a-zA-Z]{2,6})[;,]?\s?)+$/gi.test(value);
25        //return /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/gi.test(value);
26    },
27    IsNumber: function (value) {
28        return /^(\*?-?[\d]*(\.?[\d]+)?\*?;?)+$/gi.test(value);
29    },
30    IsDate: function (value) {
31        return !isNaN(new Date(value));
32    },
33    IsTime: function (value) {
34        return /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ ?[AaPp][Mm]*))$|^(0?\d|[1]\d|2[0-3])(:[0-5]\d){0,2}$/.test(value);
35    },
36    IsBoolean: function (value) {
37        return /^0|1|true|false$/gi.test(value);
38    },
39};
40
41Utility.UI.Bit = Class.create({
42    initialize: function (host, options) {
43        if (!$p(host))
44            return undefined;
45        Object.extend(this, options || {});
46        this.host = host.addClassName('bit');
47        if (this.x) {
48            this.host.data = this.host.getActions({ camelize: true });
49            this.host.insert(this.host.x = new Element('span', { className: 'x' }));
50            this.$click = this.host.x.on('click', function (e) {
51                e.stop();
52                this.host.remove();
53                this.Parent && this.Parent.fire(':delete', this.host.getActions({ camelize: true }));
54            }.bind(this));
55            this.host.remove = this.host.remove.wrap(function (f) { f(); this.$click && this.$click.stop(); }.bind(this));
56        }
57        return this;
58    }
59});
60
61//Base input class
62Utility.UI.Base = Class.create(Utility.Base, {
63    defaults: function () {
64        return this.options = this.host.getActions({ camelize: true, cast: true });
65    },
66    initialize: function ($super) {
67        //Initialize a new instance and create base structure
68        //host - main input field: (<input ....>)
69        if (!$super.apply(this, $A(arguments).slice(1)))
70            return false;
71        //set refernce to current instance
72        this.host.$class = this;
73
74        //Find field containr
75        this.FieldContainer = this.host.up('[data-role^="field"]');
76        //Find a contaner
77        this.InputContainer = this.host.up('[data-role="holder"]');
78        //Find field Caption
79        this.FieldCaption = this.FieldContainer.down('[data-role="caption"]');
80
81        this.FieldContainer.getActions({ cast: true }, this.options || this);
82        this.Name = this.host.readAttribute("name").replace(/!.+$/i, "");
83
84        //Overrides/Wraps important methods of host to do customization
85        this.host.setValue = this.host.setValue.wrap(function (proceed, value, simulate) {
86            var old = this.host.value;
87            if (simulate) {
88                var disabled = this.Is('disabled');
89                if (disabled)
90                    this.host.disabled = false;
91                //call original 
92                proceed(value);
93                if (disabled)
94                    this.host.disabled = true;
95            } else
96                //call original 
97                proceed(value);
98            this.onSetValue(value, old != value, simulate);
99        }.bind(this));
100        this.host.getValue = this.host.getValue.wrap(function (f, opt) { return opt ? this.getValue(opt) : f(); }.bind(this));
101        this.host.activate = this.Activate.bind(this);
102        this.host.deactivate = this.Deactivate.bind(this);
103        this.host.enable = this.enable.bind(this);
104        this.host.disable = this.disable.bind(this);
105        this.host.show = this.show.bind(this);
106        this.host.hide = this.hide.bind(this);
107        this.host.Run = this.run.bind(this);
108        this.host.isvalid = function () { return !this.Is('invalid'); }.bind(this);
109        this.host.simulate = this.host.simulate.wrap(function(proceed, name, memo) {
110            if (memo) {
111                var disabled = this.Is('disabled');
112                if (disabled)
113                    this.host.disabled = false;
114                proceed(name, memo);
115                if (disabled)
116                    this.host.disabled = true;
117            } else
118                proceed(name);
119
120        }.bind(this));
121
122        this.on('focus', function (e) { this.Activate(e); }.bind(this));
123        this.on('blur', function (e) { this.Deactivate(e); }.bind(this));
124
125        return this;
126    },
127    onSetValue: function (value, changed, simulate) {
128        //validate 
129        this.Validate(value);
130        //simulates the event to call custom handler
131        if (Object.isUndefined(simulate) ? changed : Boolean(simulate))
132            this.host.simulate('change');
133    },
134    setValue: function (value, opt) {
135        //Setting value
136        this.host.setValue(value, opt);
137    },
138    getValue: function () {
139        //Getting value
140        return this.host.getValue();
141    },
142    getText: function (text) {
143        var value = this.host.velue;
144        return value;
145    },
146    enable: function () {
147        //Customize enable functionality. removes fake "cover" element
148        this.RemoveCss('disabled');
149        this.host.disabled = false;
150        return this;
151    },
152    disable: function () {
153        //Customize enable functionality: 
154        //NOTE this is not actual disable. Instead, an new element is treated as "cover" to be placed after current field container and disables all user interaction 
155        this.AddCss('disabled');
156        this.host.disabled = true;
157        return this;
158    },
159    show: function() {
160        this.FieldContainer.show();
161    },
162    hide: function() {
163        this.FieldContainer.hide();
164    },
165    Activate: function (e) {
166        //Field activation. Do not activate if specific css classes already set
167        if (this.Is('disabled'))
168            return this;
169        this.RemoveCss('invalid').AddCss('active');
170        return this;
171    },
172    Deactivate: function (e) {
173        //Field deactivation. A validation is required here
174        //        this.stop('blur');
175        this.RemoveCss('active');
176        this.Validate(this.host.value);
177
178        if (this.IsChanged()) {
179            this.oldValue = this.getValue();
180        }
181
182        return this;
183    },
184    IsChanged: function () {
185        //Verifies if field value has changed ()
186        //To be used in derived class
187        return this.oldValue != this.getValue();
188    },
189    Validate: function (value) {
190        //Validation. Call custom validation logic from derived class
191        this.RemoveCss('invalid');
192        var result = Object.isFunction(this.onValidate) ? this.onValidate(value) : true;
193        !result && this.AddCss('invalid');
194        return result;
195    },
196    Create: Prototype.emptyFunction,
197    AddCss: function (attr) {
198        //Helper. appends Css class name
199        if (attr && Object.isString(attr))
200            this.FieldContainer.addClassName(attr);
201        return this;
202    },
203    RemoveCss: function (attr) {
204        //Helper. removes Css class name
205        this.FieldContainer.removeClassName(attr);
206        return this;
207    },
208    Is: function (attr) {
209        //Helper. checks if given attribute is set (class or specific value)
210        if (attr == 'visible')
211            return this.FieldContainer.visible();
212        return this.FieldContainer.hasClassName(attr);
213    },
214    Submit: function () {
215        if (!Object.isFunction(self.__doPostBack) || !this.Name)
216            return;
217        self.__doPostBack(this.Name, '');
218    }
219});
220
221
222Utility.UI.Input = Class.create(Utility.UI.Base, {
223    defaults: function () {
224        return this.options = this.host.getActions({ camelize: true, cast: true });
225    },
226    initialize: function ($super) {
227        //Initialize a new instance and create base structure
228        //host - main input field: (<input ....>)
229        try {
230            if (!$super.apply(this, $A(arguments).slice(1)))
231                return false;
232
233            this.host.writeAttribute('autocomplete', 'off');
234
235            if (this.ishidden = !this.FieldContainer.visible())
236                this.FieldContainer.setStyle('visibility:hidden;display:inline-block');
237
238            //calculate
239            this.InputContainer.dimensions = {
240                width: this.InputContainer.measure('border-box-width') || (this.InputContainer.getStyle('width') || '').toNumber(),
241                height: this.InputContainer.measure('border-box-height') || (this.InputContainer.getStyle('height') || '').toNumber(),
242            };
243            this.InputContainer.setStyle({ position: 'relative' });
244
245            this.ishidden && this.FieldContainer.setStyle('visibility:inherit;display:none;');
246
247            
248            this.host.insert({ before: this.Activator = new Element('span', {'data-activator': '' }).setStyle('width:100%; height:100%; min-height:#{height};'.interpolate(this.InputContainer.dimensions)) });
249
250            this.Activator.$stopclick = this.Activator.on('click', function(e) {e.stop();}).stop();
251            this.Activator.on('dblclick', function (e) {
252                e.stop();
253            }).stop();
254            this.on("::deactivate", Event.on(document, 'mousedown', function (e) {
255                var el = Event.element(e);
256                if (el !== this.InputContainer && !el.descendantOf(this.InputContainer)) { // && el !== this.host
257                    this.Deactivate();
258                }
259            }.bindAsEventListener(this)));
260
261
262        } catch (ex) {
263            $alert(ex.message, 'UI::Input Field');
264        }
265        return this;
266    },
267    Focus: function (e) {
268        this.host.activate();
269    },
270    onSetValue: function (value, changed, simulate) {
271        //validate 
272        this.Validate(value);
273        //simulates the event to call custom handler
274        if (Object.isUndefined(simulate) ? changed : Boolean(simulate))
275            this.host.simulate('change');
276        this.UpdateActivator();
277    },
278    getText: function (text) {
279        var value = this.host.velue;
280        return value;
281    },
282    Create: function () {
283        //Actual instance creator. To be called by derived class during initialization
284        //Adds base event handlers  and options verifiers
285        this.FieldContainer.on('selectstart', function () { return false; });
286        this.on("toggle", this.InputContainer.on('click', this.Activate.bind(this)));
287        this.on('keydown', this.KeyDown.bindAsEventListener(this));
288        this.options.length && this.host.writeAttribute('maxlength', this.options.length);
289        if (this.host.disabled = this.host.readAttribute('disabled')) {
290            this.host.disable();
291        }
292
293        this.setValue(this.oldValue = this.getValue());
294
295        return this;
296    },
297    onEnable: function () {
298        this.host.setStyle('visibility:inherit');
299        this.UpdateActivator();
300    },
301    onDisable: function () {
302        this.host.setStyle('visibility:hidden');
303        this.UpdateActivator();
304    },
305    enable: function ($super) {
306        //Customize enable functionality. removes fake "cover" element
307        $super();
308        this.Activator.$stopclick.stop();
309        this.onEnable($A(arguments).slice(1));
310        return this;
311    },
312    disable: function ($super) {
313        //Customize enable functionality: 
314        //NOTE this is not actual disable. Instead, an new element is treated as "cover" to be placed after current field container and disables all user interaction 
315        $super();
316        this.Deactivate();
317        this.Activator.$stopclick.start();
318        this.onDisable.apply(this,$A(arguments).slice(1));
319        return this;
320    },
321    onActivate: function () {
322        this.UpdateActivator(true);
323    },
324    onDeactivate: function () {
325        this.UpdateActivator(false);
326    },
327    Activate: function ($super,e) {
328        $super();
329        this.oldValue = this.getValue();
330        this.onActivate();
331        this.host.focus();
332        return this;
333    },
334    Deactivate: function ($super,e) {
335        $super();
336        this.Validate(this.host.value);
337        this.onDeactivate();
338
339        if (this.IsChanged()) {
340            this.oldValue = this.getValue();
341        }
342        
343        return this;
344    },
345    UpdateActivator: Prototype.emptyFunction,
346    KeyDown: function (e) {
347        if (e.keyCode == Event.KEY_RETURN || e.keyCode == Event.KEY_TAB) {
348            e.stop();
349            this.options.autopostback ? this.Submit() : this.Leave(e);
350        }
351    },
352    Leave: function (e) {
353        this.Deactivate(e);
354        if (self.form && Object.isFunction(self.form.TabsHandler)) {
355            e.stop();
356            self.form.TabsHandler(this.host);
357            return;
358        }
359
360        if (!Object.isArray(self.$$inputs))
361            self.$$inputs = $$('input[tabindex]').collect(function(it) {
362                return it.tabIndex.toNumber() > 0 ? $p(it).identify() : null;
363            }).filter(function(it) { return it; });
364
365        if (!self.$$inputs.length)
366            return;
367        var idx = (e && e.shift) ? Math.max(self.$$inputs.indexOf(this.host.identify()) - 1, 0) : Math.min(self.$$inputs.indexOf(this.host.identify()) + 1, self.$$inputs.length - 1);
368        $p(self.$$inputs[idx]).activate();
369
370    }
371});
372
373Utility.UI.LabelField = Class.create(Utility.UI.Input, {
374    initialize: function ($super, host, options) {
375        try {
376            if (!$super.apply(this, $A(arguments).slice(1)))
377                return false;
378            this.Create();
379        } catch (ex) {
380            $alert(ex.message, 'UI :: Label Field');
381        }
382        return this;
383    },
384    onActivate : function($super) {
385        $super();
386        !this.Is('disabled') && this.host.fire(":activate");
387    },
388    UpdateActivator: function () {
389        this.Activator.update(this.getValue());
390    },
391});
392
393Utility.UI.TextField = Class.create(Utility.UI.Input, {
394    initialize: function ($super, host, options) {
395        try {
396            if (!$super.apply(this, $A(arguments).slice(1)))
397                return false;
398            this.Create();
399            !this.Is('disabled') && this.host.setStyle('visibility:inherit');
400            this.Deactivate();
401        } catch (ex) {
402            $alert(ex.message, 'UI :: Text Field');
403        }
404        return this;
405    },
406    onValidate: function (value) {
407        if (!value)
408            return true;
409        switch (String(this.options.validate).toLowerCase()) {
410            case "email":
411                return Utility.UI.Validation.IsEmail(value);
412            case "number":
413                return Utility.UI.Validation.IsNumber(value);
414            case "boolean":
415                return Utility.UI.Validation.IsNumber(value);
416        }
417        return true;
418    },
419    UpdateActivator: function (isactive) {
420        var text = this.host.getValue();
421
422        text = this.htmlEncode(text);
423
424        if (this.Is('disabled')) {
425            this.Activator.update('<span  class="bit">' + text + '</span>').setStyle('visibility:inherit');
426            return;
427        }
428        if (isactive) {
429            this.host.setStyle('visibility:inherit');
430            this.Activator.hide();
431            this.host.focus();
432        } else {
433            this.host.setStyle('visibility:hidden');
434            this.Activator.update('<span class="bit #{css}">#{text}</span>'.interpolate({
435                text: text || this.options.prompt || '',
436                css : !text ? 'placeholder' : ''
437            })).show();
438        }
439    },
440    htmlEncode: function (str) {
441        if (typeof str !== "string") return str;
442        return str
443            .replace(/&/g, "&amp;")
444            .replace(/</g, "&lt;")
445            .replace(/>/g, "&gt;")
446            .replace(/"/g, "&quot;")
447            .replace(/'/g, "&#39;");
448    }
449
450});
451
452Utility.UI.NumberField = Class.create(Utility.UI.Input, {
453    defaults: function ($super) {
454        return this.options = Object.extend($super(), {
455            type: 'number',
456            format: 'N',
457            min: 0,
458            delta: 1,
459            defvalue: 0,
460            allowedit:true
461        });
462    },
463    initialize: function ($super, host, options) {
464        if (!$super.apply(this, $A(arguments).slice(1)))
465            return false;
466        this.Activator.writeAttribute('data-activator', 'spinner');
467        //Assign custom event handlers
468        this.Create();
469        this.Deactivate();
470        return this;
471    },
472    Create: function ($super) {
473        this.on('mousewheel', this.WheelScroll.bindAsEventListener(this));
474        this.on('click', this.Activator.on('click', this.MouseDown.bind(this)));
475
476        this.min = this.SetLimit(this.options.min);
477        this.max = this.SetLimit(this.options.max);
478
479        $super();
480        return this;
481    },
482    getValue: function($super) {
483        var v = $super();
484        if (v === '' && this.min)
485            v=String(this.min.value);
486        return v.toNumber();
487    },
488    setValue: function (value, delta, opt) {
489
490        value = String(value);
491        if (this.min && (value === '' || value == this.min.value || value.toLowerCase() == this.min.text.toLowerCase()))
492            value = this.min.value;
493        else if (this.max && (value == this.max.value || value.toLowerCase() == this.max.text.toLowerCase()))
494            value = this.max.value;
495        else 
496            value = value.toNumber(this.min ? this.min.value : 0);
497
498        //value is a number, In case Delta is number inrease value by delta (might be negative)
499        if (Object.isNumber(delta)) {
500            value += delta;
501        }
502
503        this.min != null && (value = Math.max(value, this.min.value));
504        this.max != null && (value = Math.min(value, this.max.value));
505
506        this.host.setValue(value.toString());
507    },
508    onSetValue: function ($super,value, changed, simulate) {
509        $super(value, changed, simulate);
510        this.UpdateActivator();
511    },
512    onEnable: function ($super) {
513        $H(this.events).each(function (it) {
514            it.value.start();
515        });
516        this.UpdateActivator(false);
517    },
518    onDisable: function ($super) {
519        this.UpdateActivator(false);
520        $H(this.events).each(function (it) {
521            it.value.stop();
522        });
523    },
524    onActivate: function ($super) {
525        $super();
526
527        if (this.options.allowedit) {
528            this.host.value = this.formatValue(this.getValue());
529            this.Activator[this.Is('active') ? "hide" : "show"]();
530            this.host.setStyle("visibility:inherit" );
531            this.host.select();
532        }
533
534    },
535    onDeactivate: function ($super) {
536        this.host.setStyle("visibility:hidden");
537        $super();
538    },
539    UpdateActivator: function (state) {
540        var text = this.formatValue(this.host.getValue());
541        if (this.Is('disabled')) {
542            this.Activator.update('<span  class="bit">' + text + '</span>');
543            return;
544        }
545        if (this.Is('active')) {
546            this.host.value = text;
547            this.Activator.hide();
548            this.host.focus();
549
550        } else {
551            this.Activator.update('<span class="bit #{css}">#{text}</span><span class="up"></span><span class="down"></span>'.interpolate({
552                text: text || this.options.prompt || '',
553                css : !text ? 'placeholder' : ''
554            })).show();
555        }
556    },
557    SetLimit: function (v) {
558        v = String(v);
559        if (/^-?\d+(\:.*)?/.test(v))
560            return {
561                value: (v.indexOf(':')>=0 ? v.split(':')[0] : v).toNumber(),
562                text: v.indexOf(':')>=0 ? v.split(':')[1] : v.toNumber().toString(this.options.format)
563            }
564        return null;
565    },
566    KeyDown: function ($super, e) {
567        var key = e.keyCode;
568        switch (key) {
569            case Event.KEY_UP:
570                this.setValue(this.getValue(), this.options.delta);
571                this.host.select();
572                e.stop();
573                break;
574            case Event.KEY_DOWN:
575                this.setValue(this.getValue(), this.options.delta * -1);
576                this.host.select();
577                e.stop();
578                break;
579            default:
580                $super(e);
581                break;
582        }
583    },
584    MouseDown: function (e) {
585        if (e.element().hasClassName('up')) {
586            this.setValue(this.getValue(), this.options.delta);
587            e.stop();
588        }
589        else if (e.element().hasClassName('down')) {
590            this.setValue(this.getValue(), this.options.delta * -1);
591            e.stop();
592        }
593    },
594    WheelScroll: function (e) {
595        if (e.wheelDelta > 0)
596            this.setValue(this.getValue(), this.options.delta);
597        else if (e.wheelDelta < 0)
598            this.setValue(this.getValue(), this.options.delta * -1);
599        e.stop();
600    },
601    Validate: function(value) {
602        if (this.min && (value == this.min.value || value.toLowerCase() == this.min.text.toLowerCase()))
603            value = this.min.value;
604        else if (this.max && (value == this.max.value || value.toLowerCase() == this.max.text.toLowerCase()))
605            value = this.max.value;
606        else {
607            value = value.toNumber(this.min ? this.min.value : 0);
608            this.min != null && (value = Math.max(value, this.min.value));
609            this.max != null && (value = Math.min(value, this.max.value));
610        }
611
612        this.host.value = value;
613    },
614    formatValue: function (value, b) {
615        if (this.min && (value == this.min.value || String(value).toLowerCase() == this.min.text.toLowerCase()))
616            value = this.min.text;
617        else if (this.max && (value == this.max.value || String(value).toLowerCase() == this.max.text.toLowerCase()))
618            value = this.max.text;
619        else if (this.options.format)
620            value = value.toNumber(this.min ? this.min.value : 0).toString(this.options.format);
621        return value;
622    }
623});
624
625Utility.UI.Check = Class.create(Utility.UI.Base, {
626    initialize: function ($super, host, options) {
627        if (!$super.apply(this, $A(arguments).slice(1)))
628            return false;
629        this.host.insert({ after: this.Activator = new Element('label', { 'for': this.host.id }) });
630        this.setValue(this.oldValue = this.getValue());
631
632        //IE 5-8 fires the event when the checkbox or radio is blurred, and not when it is activated.
633        //See http://www.quirksmode.org/dom/events/change.html
634        if (/MSIE\s([\d.]+)/.test(navigator.userAgent) && new Number(RegExp.$1) <= 8)
635            this.host.on('click', function () { this.simulate.bind(this).defer('change'); });
636
637        this.Activator.$stopclick = this.Activator.on('click', function (e) {e.stop();}).stop();
638        if (this.FieldCaption) {
639            this.FieldCaption.writeAttribute('for', this.host.id);
640            this.FieldCaption.$stopclick = this.FieldCaption.on('click', function (e) { e.stop(); }).stop();
641        }
642
643        if (this.host.disabled = this.host.readAttribute('disabled')) 
644            this.host.disable();
645        if (this.options.autopostback) {
646            this.on("change", function() { this.Submit(); }.bind(this));
647        }
648        
649        return this;
650    },
651    getValue: function (opt) {
652        return opt ? { Value: this.host.checked, Text: this.host.getValue() } : this.host.checked;
653    },
654    enable: function ($super) {
655        //Customize enable functionality. removes fake "cover" element
656        $super();
657        
658        this.Activator.$stopclick.stop();
659        this.FieldCaption && this.FieldCaption.$stopclick.stop();
660        return this;
661    },
662    disable: function ($super) {
663        //Customize enable functionality: 
664        $super();
665        this.Deactivate();
666        this.Activator.$stopclick.start();
667        this.FieldCaption && this.FieldCaption.$stopclick.start();
668        return this;
669    },
670
671});
672
673Utility.UI.SelectorInternal = Class.create(Utility.UI.Input, {
674    defaults: function ($super, o) {
675        return this.options = Object.extend($super(o), {
676            layout: 'popup',
677            allowedit: false,
678            allowremove: true,
679            //            height: 200,
680        });
681    },
682    initialize: function ($super, host, options) {
683        try {
684            if (!$super.apply(this, $A(arguments).slice(1)))
685                return false;
686            this.Activator.writeAttribute('data-activator', 'arrow');
687            //Add new Web Request object
688            this.WebRequest = new Utility.WebMethodRequest(this);
689            this.Create();
690            return this;
691        } catch (ex) {
692            $alert(ex.message, 'UI::Field Selector');
693        }
694    },
695    onSetValue: function (value, changed, simulate) {
696        //        $super(value, changed, simulate);
697        this.Validate(value);
698        //simulates the event to call custom handler
699        this.Selector && this.Selector.setValue(value);
700        this.UpdateActivator();
701        if (Object.isUndefined(simulate) ? changed : Boolean(simulate))
702            this.host.simulate('change');
703
704    },
705    getValue: function (opt) {
706        var v = this.Selector ? this.Selector.getValue() : { Value: this.host.getValue(), Text: this.host.getValue() };
707        v = opt ? v : (Object.isArray(v) ? v.pluck('Value').join(',') : v.Value);
708        return v;
709    },
710    addValue: function (value, opt) {
711        var o = this.getValue();
712        var a = o.split(',');
713        if (a.include(value))
714            return;
715        a.push(value);
716        value = a.compact().toString();
717        o != value && this.setValue(value, opt);
718    },
719    removeValue: function (value, opt) {
720        var o = this.getValue().toString();
721        value = (o.split(",")).without(value).toString();
722        o != value && this.setValue(value, opt);
723    },
724    getText: function (text) {
725        return this.Selector ? this.Selector.getText(text, this.Is('disabled')) : '';
726    },
727    Create: function () {
728        this.FieldContainer.on('selectstart', function () { return false; });
729        this.on("toggle", this.InputContainer.on('click', this.Activate.bind(this)));
730        this.on('keydown', this.KeyDown.bindAsEventListener(this));
731
732        this.off('blur');
733
734        this.Container = this.InputContainer.down('[data-role^="selector"]');
735        if (!this.Container)
736            throw new Error("Invalid layout");
737
738        //Move selector container to field fontainer
739        this.InputContainer.insert(this.Container);
740
741        this.host.on(':delete', function (e) { this.Delete(e.memo); }.bind(this));
742        this.Container.on('click', function (e) { e.stop(); });
743        
744        this.Container.layout = this.Container.getLayout().toObject();
745
746
747        if (this.options.layout != 'inline') {
748            // adding selector activator to container
749            this.Container.setStyle('position:absolute').hide();
750            // modify activator
751            this.Activator.setStyle({ 'backgroundColor': this.InputContainer.getStyle('background-color') });
752        } else {
753            this.InputContainer.addClassName('inline');
754            this.Activator.hide();
755            
756        }
757        
758        this.oldValue = this.getValue();
759        this.onCreate();
760        this.setValue(this.oldValue);
761        this.Deactivate();
762
763        if (this.options.initload)
764            this.Load(this.options.data);
765
766        if (this.options.layout == 'inline') {
767            this.UpdatePosition(true);
768            this.Show();
769        }
770        if (this.host.disabled = this.host.readAttribute('disabled')) {
771            this.host.disable();
772        }
773
774
775        return this;
776    },
777    onCreate: Prototype.emptyFunction,
778    onRequest: Prototype.emptyFunction,
779    onSelect: function (data, done) {
780        if (this.Is('disabled')) {
781            this.setValue(this.oldValue, false);
782            return false;
783        }
784
785        ///April 1, 2015:
786        //Call custom function to do custom validation and update value before value is stored to and input field
787        if (done && Object.isFunction(this.onBeforeChanged)) {
788            //update data only ir result is returned!
789            var ret = this.onBeforeChanged(data);
790            data = Object.isUndefined(ret) ? data : ret;
791        }
792
793
794        var v = '';
795        if (Object.isArray(data)) {
796            v = data.pluck('Value').join(',');
797        } else if ('Value' in data) {
798            v = data.Value;
799        }
800        this.host.setValue(v, true);
801        
802        if (done) {
803//            this.Deactivate();
804            this.options.autopostback ? this.Submit() : this.Leave();
805        } else {
806            this.UpdateActivator(Object.get(data, 'Text', ''));
807        }
808
809    },  
810    onEnable: function ($super) {
811//        this.host.setStyle('visibility:hidden');
812        //Loads data and update selector
813        this.run("Selector.enable", $A(arguments).slice(1));
814
815    },
816    onDisable: function ($super) {
817        this.run("Selector.disable", $A(arguments).slice(1));
818    },
819    onActivate: function ($super) { $super(); this.Show(); },
820    onDeactivate: function ($super) { $super(); this.Hide(); },
821    Show: function (e) {
822        this.Container.setStyle("visibility:hidden").show();
823        this.UpdatePosition();
824
825        //Loads data and update selector
826        this.run("Selector.onShow", this.Container.layout);
827
828        //Check if a popup container is out of viewport area, Thus change its location to "ON TOP" of input field
829        if (this.options.layout != 'inline' && (this.Container.viewportOffset().top + this.Container.getHeight()) > $Screen.viewport.height) {
830            this.Container.setStyle({ top: (this.Container.getHeight() * -1) + 'px' }).addClassName('top');
831        }
832
833        this.Container.setStyle("visibility:inherit");
834//        this.run("onShow");
835        return this;
836    },
837    Hide: function (e) {
838        if (this.Container && this.options.layout != 'inline') {
839            this.Container.removeClassName('top').setStyle("top:-1000px").hide();
840        }
841        this.run("Selector.onHide");
842        this.run("onHide");
843        return this;
844    },
845    Delete: function (it) {
846        this.removeValue(it.Value);
847        this.Deactivate();        
848    },
849    Load: function (data, prms) {
850        try {
851            if (Object.isUndefined(data) || data == null) {
852                this.status = 'requesting';
853                if (this.options.webmethod) {
854                    this.Selector && this.Selector.Load('<div style="margin-top:10px;margin-left:10px;">Loading...</div>');
855                    this.WebRequest.Update(this.options.webmethod, Object.extend({ callback: this.Load.bind(this) }, prms || {}));
856                } else {
857                    delete this.status;
858                }
859                return;
860            }
861            this.Selector && this.Selector.Load(data);
862            prms && this.setValue(prms.toString());
863        } catch (ex) {
864            $alert(ex.message, 'Update Selector error.');
865        }
866    },
867    UpdatePosition: function (force) {
868        var layout = this.InputContainer.getLayout().toObject();
869        
870        var stylestring;
871        if (this.options.layout == 'inline'){
872            stylestring = "top:0px;left:0;width:100%;height:100%;";
873        } else {
874            stylestring = "top:#{top}px;width:#{width}px;height:#{height}px;left:-#{border-left}px;";
875            layout.top = layout['padding-box-height'];// + layout['border-top'];
876            layout.width = this.options.width || (layout['border-box-width'] - (this.Container.layout['border-box-width'] - this.Container.layout['width']));
877            layout.height = this.options.height || (layout['border-box-height']-(this.Container.layout['border-box-height'] - this.Container.layout['height']));
878        } 
879
880        this.Container.layout = layout;
881        this.Container.setStyle(stylestring.interpolate(layout));
882    },
883    KeyDown: function (e) {
884        if (!this.options.allowedit) {
885            e.stop();
886            return;
887        }
888
889        //Handle Key Press event
890        switch (e.keyCode) {
891            case Event.KEY_ESC:
892            case Event.KEY_TAB:
893//                
894                this.Leave(e);
895                break;
896            case Event.KEY_RETURN:
897                this.Deactivate(e);
898                this.Leave(e);
899                break;
900        }
901    },
902    UpdateActivator: function (isactive) {
903        if (!this.Selector)
904            return;
905        if (this.options.layout == 'inline') {
906            this.Activator.setStyle('visibility:visible').update('');
907        } else {
908
909            var text = this.getText(this.options.activator);
910            if (isactive && this.options.allowedit) {
911                this.host.setStyle('visibility:inherit;width:100%;');
912                this.Activator.hide();
913                this.host.focus();
914            } else {
915                this.host.setStyle('visibility:hidden;width:0px;');
916                this.Activator.updat
916e((text || '<span class="bit #{css}">#{text}</span>').interpolate({
917                        text: this.options.prompt || '',
918                        css: !text ? 'placeholder' : ''
919                    })).show();
920            }
921        }
922        if (this.options.allowremove && this.getValue())
923            this.Activator.childElements().each(function (it) {
924                new Utility.UI.Bit(it, { Parent: this, x: !this.Is('disabled') });
925            }, this);
926    }
927});
928
929Utility.UI.AutoComplete = Class.create(Utility.UI.SelectorInternal, {
930    defaults: function ($super) {
931        return this.options = Object.extend($super(), {
932            data: [],
933            delay: .5,
934            limit: 0,
935            visibleitems: 7,
936            ActiveIndex: -1,
937            allowedit: true,
938            height: 200
939        });
940    },
941    Change: Prototype.emptyFunction,
942    onCreate: function ($super) {
943
944        //Disable a progress message for web requests
945        this.progressMessage = undefined;
946        if (!(this.host.textfield = this.host.next('input[data-text]')))
947            this.host.insert({
948                after: this.host.textfield = new Element('input', { type: 'text', tabindex: -1, autocomplete: 'off' })
949                    .update(this.options.textvalue || '')
950            });
951        this.host.writeAttribute('data-text', this.host.textfield.getValue());
952        this.host.textfield.identify();
953        this.host.textfield.setStyle('position:absolute;left:0;width:99%; width:#{0}px;'.interpolate([this.host.getWidth() - 4]));
954        this.host.textfield.writeAttribute('autocomplete', 'off');
955        this.off('blur');
956        //Keyboard events
957        this.host.textfield.on('keyup', this.KeyUp.bindAsEventListener(this));
958        this.host.textfield.on(window.opera ? 'keypress' : 'keydown', this.KeyDown.bindAsEventListener(this));
959
960        if (!Utility.UI.ListSelector)
961            return;
962
963        this.Selector = new Utility.UI.ListSelector(this.Container, this.options, {
964            Parent: this,
965            onSelect: this.onSelect.bind(this)
966        });
967        this.oldValue = this.getValue();
968
969    },
970    onHide: function () {
971        this.run('Selector.Load', '');
972    },
973    onActivate: function () {
974        //Text box activation. Handle a case of hiding a prompt message
975        this.host.textfield.setStyle('visibility:inherit');
976        this.host.textfield.data = this.getValue();
977        this.UpdateActivator(true);
978        this.DoAction(this.host.textfield.getValue().length > this.options.limit);
979    },
980    onDeactivate: function ($super) {
981        //Text box activation. Handle a case of hiding a prompt message
982        $super();
983        this.host.textfield && this.host.textfield.setStyle('visibility:hidden');
984    },
985    onSetValue: function (value, changed, simulate) {
986        //simulates the event to call custom handler
987        if (Object.isUndefined(simulate) ? changed : Boolean(simulate))
988            this.host.simulate('change');
989    },
990    onSelect: function (data, done) {
991        if (done) {
992            delete this.host.textfield.data;
993            this.setValue(data);
994            this.Deactivate();
995            this.options.autopostback ? this.Submit() : this.Leave();
996        } else {
997            this.host.textfield.data = data;
998            this.host.textfield.setValue(Object.get(data, 'Text', ''));
999            this.host.textfield.select();
1000        }
1001    },
1002    getValue: function ($super) {
1003        var data = {
1004            Value: this.host.getValue()
1005        };
1006        if (this.Selector)
1007            data.Text = this.host.readAttribute('data-text');
1008        return data;
1009    },
1010    updateValue: function (value, text) {
1011        this.host.writeAttribute('data-text', text);
1012        this.host.setValue(value);
1013    },
1014    setValue: function (data) {
1015        this.updateValue(Object.get(data, 'Value', ''), Object.get(data, 'Text', ''));
1016        this.host.textfield.setValue(Object.get(data, 'Text', ''));
1017        this.Validate(data || {});
1018        this.UpdateActivator();
1019    },
1020    IsChanged: function () {
1021        var v = this.getValue();
1022        return this.oldValue && (this.oldValue.Text != v.Text || this.oldValue.Value != v.Value);
1023    },
1024    DoAction: function () {
1025        if (!this.options.webmethod)
1026            return;
1027        if (this.host.textfield.value.length >= Math.max(this.options.limit, 0)) {
1028            this.onActionInterval && clearInterval(this.onActionInterval);
1029            //Stops any other request
1030            this.WebRequest.Stop();
1031            // see this.onRequest(this); to modify parameters
1032            this.WebRequest.Update(this.options.webmethod, Object.extend({ callback: 'Complete', filter: this.host.textfield.getValue() }, this.parameters || {}));
1033        }
1034    },
1035    Delete: function () {
1036        this.onSelect(null, true);
1037    },
1038    Complete: function () {
1039        //Override. Checks and updates popup container. If there is no items to select close popup with delay
1040        if (this.Selector.Load($A(arguments), this.host.textfield.value))
1041            this.Show();
1042        else
1043            this.Hide();
1044    },
1045    KeyUp: function (e) {
1046        //Handle KeyUp event 
1047        var clear = false;
1048        switch (e.keyCode) {
1049            case Event.KEY_UP:
1050            case Event.KEY_DOWN:
1051                !this.Container.visible() && this.DoAction();
1052                return;
1053            case Event.KEY_ESC:
1054            case Event.KEY_TAB:
1055            case Event.KEY_RETURN:
1056                return;
1057            case Event.KEY_DELETE:
1058            case Event.KEY_BACKSPACE:
1059                clear = true;
1060                break;
1061            default:
1062                clear = e.char;
1063
1064        }
1065        if (clear) {
1066            delete this.host.textfield.data;
1067            this.updateValue('', '');
1068        }
1069        //delay is broken. set it to 1 second as user type. it's causing too many ajax requests killing server and db
1070        this.delay = 1;
1071
1072        if (Object.isNumber(this.delay) && this.delay) {
1073            this.onActionInterval = this.DoAction.bind(this).delay(this.delay); 
1074        } else {
1075            this.DoAction();
1076        }
1077
1078    },
1079    KeyDown: function (e) {
1080        //Handle Key Press event (IE specific) 
1081        // return will exit the function
1082        // and event will not fire
1083        switch (e.keyCode) {
1084            case Event.KEY_ESC:
1085                this.onSelect(this.oldValue, true);
1086                break;
1087
1088            case Event.KEY_TAB:
1089            case Event.KEY_RETURN:
1090                Event.stop(e);
1091                this.onSelect(this.host.textfield.data, true);
1092                break;
1093
1094            case Event.KEY_UP:
1095                Event.stop(e);
1096                this.run('Selector.Up');
1097                break;
1098            case Event.KEY_DOWN:
1099                Event.stop(e);
1100                this.run('Selector.Down');
1101                break;
1102            default:
1103                break;
1104
1105        }
1106    },
1107    UpdateActivator: function (state) {
1108        var data = this.getValue();
1109        if (this.Is('disabled')) {
1110            this.Activator.update('<span class="#{css}">#{text}</span>'.interpolate({
1111                text: data.Text,
1112                css: (data.Value ? 'bit ' : '')
1113            }));
1114            return;
1115        }
1116        if (state) {
1117            this.Activator.setStyle('visibility:hidden');
1118            this.host.textfield.select();
1119        } else {
1120            this.Activator.setStyle('visibility:inherit');
1121            this.Activator.update('<span class="#{css}">#{text}</span>'.interpolate({
1122                text: data.Text || this.options.prompt || '',
1123                css: !data.Text ? 'placeholder' : (data.Value ? 'bit ':'')
1124            }));
1125        }
1126        if (this.options.allowremove && data.Value && data.Text)
1127            new Utility.UI.Bit(this.Activator.down(), { Parent: this, x: !this.Is('disabled') });
1128    }
1129});
1130
1131Utility.UI.ListField = Class.create(Utility.UI.SelectorInternal, {
1132    defaults: function ($super) {
1133        return this.options = Object.extend($super(), {
1134            type: 'list',
1135            height: 250,
1136            allowremove: false
1137        });
1138    },
1139    onCreate: function ($super) {
1140        if (!Utility.UI.ListSelector)
1141            return;
1142        //        this.host.addClassName('hidden');
1143        this.Selector = new Utility.UI.ListSelector(this.Container, this.options, {
1144            Parent: this,
1145            defaultValue: arguments[1],
1146            onSelect: this.onSelect.bind(this)
1147        });
1148    }
1149});
1150
1151Utility.UI.TreeField = Class.create(Utility.UI.SelectorInternal, {
1152    defaults: function ($super) {
1153        return this.options = Object.extend($super(), {
1154            type: 'selector',
1155            allowremove: false
1156        });
1157    },
1158    enable: function ($super) {
1159        //Customize enable functionality. removes fake "cover" element
1160        if (arguments.length == 1)
1161            $super();
1162        else {
1163            this.onEnable($A(arguments).slice(1));            
1164        }
1165        return this;
1166    },
1167    disable: function ($super) {
1168        if (arguments.length == 1)
1169            $super.apply(this, this.Selector.getValues());
1170        else {
1171            this.onDisable($A(arguments).slice(1));
1172        }
1173        return this;
1174    },
1175    onSelect: function ($super,data, done) {
1176        $super(data, done);
1177        if (this.Is('disabled'))
1178            return;
1179        if (!done) 
1180            this.UpdatePosition(this.options.layout != 'inline');
1181    },
1182
1183    onCreate: function (e) {
1184        this.options.active = [];
1185        if (!Utility.UI.TreeSelector)
1186            return;
1187        this.Selector = new Utility.UI.TreeSelector(this.Container, this.options, {
1188            Parent: this,
1189            onSelect: this.onSelect.bind(this)
1190        });
1191    },
1192    IsChanged: function () {
1193        return this.oldValue != this.getValue();
1194    }
1195});
1196
1197Utility.UI.DateField = Class.create(Utility.UI.SelectorInternal, {
1198    //options:
1199    //stick
1200    defaults: function ($super) {
1201        return this.options = Object.extend($super(), {
1202            type: 'date',
1203            allowedit: false,
1204            allowremove: false,
1205            height: 220,
1206            width: 220
1207        });
1208    },
1209    onCreate: function (value) {
1210        if (!Utility.UI.DatePicker)
1211            return;
1212        this.Selector = new Utility.UI.DatePicker(this.Container, this.options, {
1213            Parent: this,
1214            selected: this.getValue(),
1215            onSelect: this.onSelect.bind(this)
1216        });
1217        if (this.options.allowedit)
1218            //Restore event handlers
1219            this.start('focus', 'toggle');
1220
1221    },
1222    onValidate: function (data) {
1223        if (!data)
1224            return true;
1225        return !isNaN(new Date(data));
1226    }
1227});
1228
1229Utility.UI.TimeField = Class.create(Utility.UI.SelectorInternal, {
1230    defaults: function ($super) {
1231        return this.options = Object.extend($super(), {
1232            type: 'time',
1233            allowedit: false,
1234            allowremove: false,
1235            height: 250,
1236            width: 250
1237        });
1238    },
1239    onCreate: function (value) {
1240        if (!Utility.UI.TimePicker)
1241            return;
1242        this.Selector = new Utility.UI.TimePicker(this.Container, this.options, {
1243            Parent: this,
1244            selected: this.getValue(),
1245            onSelect: this.onSelect.bind(this)
1246        });
1247        if (this.options.allowedit)
1248            //Restore event handlers
1249            this.start('focus', 'toggle');
1250
1251    },
1252    onValidate: function (data) {
1253        if (!data)
1254            return true;
1255        var date = new Date();
1256        // autocomplete entered  value for different cases
1257        if (/^\d{1,2}$/.test(data))
1258            date = date.add('h', data).add('min', '0');
1259        else if (/^\d{3,4}$/.test(data)) {
1260            var a = (data.substring(0, data.length - 2) + ':' + data.substring(data.length - 2)).split(':');
1261            date = date.add('h', a[0]).add('min', a[1]);
1262        } else if (/^\d{1,2}:\d{0,2}$/.test(data)) {
1263            var a = data.split(':');
1264            date = date.add('h', a[0]).add('min', a[1]);
1265        } else if (/^(0?[1-9]|1[012])(\ ?[AaPp][Mm]*)$/.test(data)) {
1266            var a = data.toNumber() + (/p/.test(data) ? 12 : 0);
1267            date = date.add('h', a.toString()).add('min', '0');
1268        } else if (/^(0?[1-9]|1[012])(:[0-5]\d){0,2}(\ ?[AaPp][Mm]*)$/.test(data)) {
1269            date = date.setTime((data + (/[Mm]$/.test(data) ? '' : 'M')).toUpperCase());
1270        } else if (/^(0?\d|[1]\d|2[0-3])(:[0-5]\d){0,2}$/.test(data))
1271            date = date.setTime(data);
1272        else
1273            return false;
1274        if (this.Selector)
1275            this.host.value = date = date.toString(this.Selector.options.format);
1276        return isNaN(date);
1277    },
1278    onActivate: function ($super) {
1279        $super();
1280        if (this.options.allowedit) {
1281            this.host.setStyle('visibility:inherit');
1282            this.Activator.setStyle('visibility:hidden');
1283            this.host.select();
1284        }
1285        
1286    },
1287    onDeactivate: function ($super) {
1288        $super();
1289        if (this.options.allowedit) {
1290            this.host.setStyle('visibility:hidden');
1291            this.Activator.setStyle('visibility:inherit');
1292            this.onSetValue(this.host.value, true);
1293        }
1294    }
1295});
1296
1297
1298Utility.UI.ColorField = Class.create(Utility.UI.SelectorInternal, {
1299    defaults: function ($super) {
1300        return this.options = Object.extend($super(), {
1301            width: 250,
1302            height: 250
1303            /*
1304                        tilewidth: 20,
1305                        tileheight: 20,
1306            */
1307        });
1308    },
1309    onCreate: function (e) {
1310        this.options.allowremove = false; //!IMPORTANT
1311        if (!Utility.UI.ColorPicker)
1312            return;
1313        
1314        this.Selector = new Utility.UI.ColorPicker(this.Container, this.options, {
1315            Parent: this,
1316            onSelect: this.onSelect.bind(this)
1317        });
1318        this.host.simulate('change');
1319    }
1320});
1321
1322/*Second version of inline edit.
1323NOTE::(Aug 29, 2013, (DL)) the old version used by PlayerSelector and will be updated to new verson after Events 2.0 release
1324*/
1325Utility.UI.TextEdit = Class.create(Utility.Base, {
1326    initialize: function ($super) {
1327        if (!$super.apply(this, $A(arguments).slice(1)))
1328            return false;
1329        this.host.setStyle('visibility:hidden');
1330        this.container = this.host.insert(this.Layout()).down('[data-role="textedit"]');
1331        if (this.Input = this.container.down('input')) {
1332            if (this.SaveButton = this.container.down('[data-action="save"]')) {
1333                this.SaveButton[this.options.save ? 'show' : 'hide']().on('click', this.Close.bind(this));
1334            }
1335            if (this.CancelButton = this.container.down('[data-action="cancel"'))
1336                this.CancelButton.on('click', this.Cancel.bind(this));
1337            this.on(window.opera ? 'keypress' : 'keydown', this.keyDown.bindAsEventListener(this));
1338            this.on(document.on("mousedown", this.Exit.bindAsEventListener(this)));
1339            this.container.clonePosition(this.host);
1340            this.Input.activate();
1341        }
1342        return true;
1343    },
1344    Layout: function () {
1345        return ('<div data-role="textedit" style="position:absolute;visibility:visible;">' +
1346			        '<input type="text" value="#{value}" maxlength="#{options.length}" style="width:100%;height:100%;"/>' +
1347    			    '<span style="position:absolute; right:0px; top:0px;"><span data-role="button" data-action="save" class="icon save"></span><span data-role="button" data-action="cancel" class="icon cancel"></span></span>' +
1348		        '</div>').interpolate(this);
1349    },
1350    //Handle Key Press event (IE specific) 
1351    keyDown: function (e) {
1352        // return will exit the function
1353        // and event will not fire
1354        switch (e.keyCode) {
1355            case Event.KEY_ESC:
1356                this.Cancel();
1357                break;
1358            case Event.KEY_TAB:
1359            case Event.KEY_RETURN:
1360                this.Save();
1361                return;
1362            default:
1363                return;
1364        }
1365        e.stop();
1366    },
1367    Save: function () { this.Close('save'); },
1368    Cancel: function () { this.Close('cancel'); },
1369    Exit: function (e) {
1370        var el = e.element();
1371        if (el !== this.container && !el.descendantOf(this.container) && el !== this.host) { this.Save(); }
1372    },
1373    onClose: function (data) { this.Parent.fire('edit:end', data); },
1374    Close: function (state) {
1375        var data = { state: state || '', value: this.Input.getValue() };
1376        this.off();
1377        this.container.remove();
1378        this.host.setStyle('visibility:inherit');
1379        this.onClose(data);
1380    }
1381});
1382
1383
1384Utility.UI.Collapsable = Class.create({
1385    initialize: function (host) {
1386        this.host = $p(host);
1387        if (this.host && this.host.childElements().length > 1) {
1388            this.data = this.host.getActions();
1389
1390            this.anchor = this.host.down();
1391            this.state = this.anchor.siblings().first().visible();
1392            this.anchor.text = this.anchor.getInnerText();
1393            this.anchor.alttext = this.data.alttext || this.anchor.getInnerText();
1394
1395
1396            this.host.toggle = this.host.toggle.wrap(function (proceed, state) {
1397                if (Object.isUndefined(state))
1398                    proceed();
1399                else {
1400                    this.host.removeClassName('collapsed').addClassName(Boolean(state) ? 'collapsed' : '');
1401                    this.anchor.update(Boolean(state) ? this.anchor.alttext : this.anchor.text);
1402                    this.anchor.siblings().invoke(Boolean(state) ? 'show' : 'hide');
1403                }
1404            }.bind(this));
1405            this.host.toggle(Boolean(this.state));
1406            this.anchor.on('click', function (e) {
1407                e.stop();
1408                this.host.toggle(this.state = !this.state);
1409            }.bind(this));
1410        }
1411        return this;
1412
1413    }
1414});
1415
1416
1417Utility.UI.ColorPicker = Class.create(Utility.Base, {
1418    initialize: function ($super, host, options) {
1419
1420        if (!$super.apply(this, $A(arguments).slice(1)))
1421            return false;
1422        this.host.insert(this.Colours = new Element('div', { 'data-role': 'colorpicker' }));
1423        //        this.Colours.on('mouseover', this.Select.bindAsEventListener(this));
1424        this.Colours.on('click', this.Select.bindAsEventListener(this, true));
1425        return this;
1426    },
1427    Cell: function (r, g, b) {
1428        var css = { width: this.options.tilewidth + 'px', height: this.options.tileheight + 'px' };
1429        css.backgroundColor = (r && g && b) ? "#" + r + g + b : (r && r[0] == "#" ? r : '');
1430        var c = new Element('div').setStyle(css).writeAttribute("data-color", css.backgroundColor);
1431        return c;
1432    },
1433    Create: function (data) {
1434        data = data || { schema: 'standard' };
1435        this.Colours.update();
1436
1437        if (Object.isArray(data.colors) && String(data.schema).include('custom')) {
1438            data.colors.push('');
1439            data.colors = data.colors.uniq();
1440            data.colors.each(function (it) {
1441                this.Colours.insert(this.Cell(it).setStyle(String(data.style)));
1442            }, this);
1443            this.Colours.insert(new Element('div', { className: 'clear' }));
1444        }
1445        if (String(data.schema).include('standard')) {
1446            var h = ["00", "00", "11", "22", "33", "44", "55", "66", "77", "88", "99", "AA", "BB", "CC", "DD", "EE", "FF", ""],
1447                d = ["00", "33", "66", "99", "CC", "FF"], r, g, b;
1448            for (r = 0; r < 18; r++) {
1449                this.Colours.insert(this.Cell(h[r], h[r], h[r]));
1450            }
1451            this.Colours.insert(new Element('div', { className: 'clear' }));
1452
1453
1454            for (b = 0; b < 6; b++) {
1455                for (r = 0; r < 3; r++)
1456                    for (g = 0; g < 6; g++)
1457                        this.Colours.insert(this.Cell(d[r], d[g], d[b]));
1458                this.Colours.insert(new Element('div', { className: 'clear' }));
1459            }
1460            this.Colours.insert(new Element('div', { className: 'clear' }));
1461
1462            for (b = 0; b < 6; b++) {
1463                for (r = 3; r < 6; r++)
1464                    for (g = 0; g < 6; g++)
1465                        this.Colours.insert(this.Cell(d[r], d[g], d[b]));
1466                this.Colours.insert(new Element('div', { className: 'clear' }));
1467            }
1468        }
1469    },
1470    Load: function (data, opt) {
1471        this.data = data;
1472        this.Parent.setValue(Object.get(data, 'select', ''));
1473    },
1474    Select: function (e, done) {
1475        this.selectedColor = e.element().readAttribute('data-color');
1476        this.onSelect(this.getValue(), done);
1477    },
1478    onSelect: Prototype.emptyFunction,
1479    onShow: function (dim) {
1480        //!!make container bigger!!!! to adjust by inner dimension after creation
1481        this.Parent.Container.setStyle('height: 1000px;width: 1000px');
1482        this.Create(this.data);
1483        this.Parent.Container.setStyle({
1484            height: this.Colours.measure('margin-box-height') + 'px',
1485            width: this.Colours.measure('margin-box-width') + 'px'
1486        });
1487    },
1488    onHide: function () {
1489        this.Colours.update('');
1490    },
1491    setValue: function (value) {
1492        this.selectedColor = value;
1493    },
1494    getValue: function (def) {
1495        return { Value: this.selectedColor || '', Text: this.selectedColor || '' };
1496    },
1497    getText: function (msg) {
1498        var v = this.getValue();
1499        v.Contrast = v.Value ? Utility.RGB.toContrast(v.Value) : "#000";
1500        v.msg = msg || v.Value;
1501        return '<span class="bit" style="" data-value="#{Value}"><span style="background-color:
1501#{Value};color:#{Contrast};">#{msg}</span></span>'.interpolate(v);
1502    },
1503});
1504
1505
1506//-----------------------------------------------------------------------------\dlo/
1507// CHO.Input.Tree Control v1.0
1508// Jonas Software © 2013, by Dmitry Lopyrev
1509//-----------------------------------------------------------------------------
1510// Shows UL structure as TreeView controld width node selection
1511//-----------------------------------------------------------------------------
1512// Note: Requires Prototype JS library (v.1.7.1 - modified) and Utility.js  
1513//-----------------------------------------------------------------------------
1514
1515
1516
1517Utility.UI.TreeSelector = Class.create(Utility.Base, {
1518    defaults: function () {
1519        this.options = Object.extend({
1520            horizontal: false,
1521            lines: false,
1522            collapsed: true,
1523            checkbox: '',
1524            bittemplate: '<span class="bit" style="#{style}" data-value="#{Value}" data-text="#{Text}">#{Text}</span>',
1525            multiple: false,
1526            text: '',
1527            selectall:'', //Text to use 'Select All' functionali
1528        }, this.host.getActions({ camelize: true, cast: true }));
1529    },
1530    onSelect: Prototype.emptyFunction,
1531    initialize: function ($super, host, options) {
1532        try {
1533
1534            if (!$super.apply(this, $A(arguments).slice(1)))
1535                return false;
1536
1537            if (Object.isBoolean(this.options.checkbox))
1538                this.options.checkbox = this.options.checkbox === true ? 'check' : 'radio';
1539            if (this.options.checkbox === 'radio')
1540                this.options.multiple = false;
1541            else if (this.options.checkbox === 'check')
1542                this.options.multiple = true;
1543
1544//            this.host.addClassName('ps-tree');
1545            this.options.horizontal && this.host.addClassName('horizontal');
1546
1547            if (!this.NameContainer)
1548                this.host.insert(this.NameContainer = new Element('ul'));
1549
1550            this.Load();
1551
1552            this.Parent && this.setValue(this.Parent.host.getValue());
1553
1554            return this;
1555
1556        } catch (er) {
1557            $alert(er.message, 'Tree Picker error');
1558        }
1559        return this;
1560    },
1561    getValues: function () {
1562        var data = this.Children.invoke("collectNodes", true).flatten().pluck('data').pluck('Value');
1563        return data;
1564    },
1565
1566    getValue: function () {
1567        var data = this.Children.invoke("collectNodes", true).flatten();
1568        data = data.filter(function (it) {
1569//            return !it.Children && it.data.Checked == 2;
1570            return it.data.Checked;
1571        });
1572        return data.pluck('data');
1573    },
1574    setValue: function (values, state) {
1575        if (!Object.isArray(values)) {
1576            values = values ? String(values).split(',') : [];
1577        }
1578        (this.Children || []).invoke("setValue", values, state);
1579        
1580        this.Refresh(values);
1581    },
1582    formatBits: function (data, separator) {
1583
1584        var text = data.collect(function (it) {
1585            return this.options.bittemplate.interpolate(it).trim();
1586        }, this);
1587        return text.join(this.options.allowremove ? '' : (separator || '')).toString();
1588    },
1589    getText: function (text, disabled) {
1590        var data = this.Children.invoke("collectNodes", true).flatten().filter(function (it) { return !it.Children; }).pluck('data');
1591        var selected = data.filter(function (it) { return it.Checked == 2; });
1592
1593        if (Object.isString(text))
1594            if (text.startsWith('|')) {
1595                text = (text + '||').split('|');
1596                var counter = 'none';
1597                if (data.length > 0 && data.length == selected.length)
1598                    return text[3] || 'All';
1599                else if (selected.length) {
1600                    var parts = /^(\d+:)?(.+)/.exec(text[2]);
1601                    parts[1] = Object.isUndefined(parts[1]) ? '0' : parts[1];
1602                    if (selected.length > parts[1].toNumber()) {
1603                        return this.formatBits(selected.slice(0, parts[1].toNumber()), ',') + parts[2];
1604                    }
1605                    return this.formatBits(selected, ', ');
1606                }
1607                return text[1] || this.options.propmpt || '';
1608            } else
1609                return text;
1610
1611        return this.formatBits(selected, disabled ? ',' : '');
1612    },
1613    updateValue: function (state) {
1614        var selected = this.getValue(true);
1615        if (!Object.isUndefined(state))
1616            this.onSelect(selected, this.options.autopostback || !state);
1617    },
1618
1619    disable: function (values) {
1620        if (values) {
1621            values = Object.isArray(values) ? values : String(values).split(',');
1622            this.Children.invoke("collectNodes", true).flatten().filter(function(it) {
1623                return values.include(it.data.Value);
1624            }).invoke('disable');
1625        } else {
1626            (this.Children || []).invoke("disable");
1627        }
1628    },
1629    enable: function(values) {
1630        if (values) {
1631            values = Object.isArray(values) ? values : String(values).split(',');
1632            this.Children.invoke("collectNodes", true).flatten().filter(function(it) {
1633                return values.include(it.data.Value);
1634            }).invoke('enable');
1635        } else {
1636            (this.Children || []).invoke("enable");
1637        }
1638    },
1639    Load: function (html) {
1640        try {
1641            //accepts only a text (html)
1642            if (Object.isString(html)) {
1643                (this.Children || []).invoke('dispose');
1644                delete this.Children;
1645                this.NameContainer.remove();
1646                this.host.update(html);
1647            }
1648            if (!(this.NameContainer = this.host.down('ul')))
1649                this.host.insert(this.NameContainer = new Element('ul'));
1650
1651           !this.Children && (this.Children = this.NameContainer.childElements().inject([], function (o, it) {
1652               if (it.tagName == 'LI') {
1653                   var a = new Utility.UI.TreeSelector.Node(it, { options: this.options, Tree: this });
1654                   a.GUID = new Date();
1655                   o.push(a);
1656                }
1657                return o;
1658            }, this) || []);
1659            this.data = this.Children.invoke("collectNodes", true).flatten().filter(function (it) { return !it.Children; }).pluck('data');
1660
1661            // April 1, 2015
1662            // Add "Select all" chekbox if needed
1663            if (this.options.multiple && this.options.selectall) {
1664
1665                this.NameContainer.insert({ before: '<div class="item all"><span class="xti check"></span><a href="javascript:void(0);" unselectable="on">#{selectall}</a></div>'.interpolate(this.options) });
1666                //find an element 
1667                if (this.ALL = this.host.down('.item.all')) {
1668                    // WEB-426: add support for disabled items
1669                    this.ALL.MaxItems = this.data.filter(function (it) { return !it.Disabled || it.Checked; });
1670                    this.ALL.MinItems = this.data.filter(function (it) { return it.Disabled && it.Checked; });
1671                    var maxItemsValue = this.ALL.MaxItems.pluck('Value').join(',');
1672                    var minItemsValue = this.ALL.MinItems.pluck('Value').join(',');
1673                    //assign onclick event
1674                    this.ALL.on('click', function() {
1675                        //get current state state
1676                        var checked = this.ALL.hasClassName('partial|checked');                        
1677                        //toggle state
1678                        this.setValue(checked ? minItemsValue : maxItemsValue);
1679                        this.updateValue(true);
1680                    }.bind(this));
1681                }
1682            }
1683
1684        } catch (ex) {
1685            $alert(ex.message, 'Tree Selector load error.');
1686        }
1687
1688    },
1689    Refresh: function (selected) {
1690        //April 1, 2015
1691        //refreshes state of "Check All" checkbox if exists (unchecke, checked, partially checked)
1692        if (this.ALL) {
1693            this.ALL.removeClassName('checked|partial');
1694            if (Object.isArray(selected) && selected.length) {
1695                // WEB-426: set state according to number of selected items
1696                if (selected.length == this.ALL.MaxItems.length)
1697                    this.ALL.addClassName('checked');
1698                else if (selected.length != this.ALL.MinItems.length)
1699                    this.ALL.addClassName('partial');
1700            }
1701        }
1702    },   
1703});
1704Utility.UI.TreeSelector.Node = Class.create(Utility.Base, {
1705    initialize: function ($super) {
1706
1707        if (!$super.apply(this, $A(arguments).slice(1)))
1708            return false;
1709
1710        this.Text = this.host.down('a'); //first child
1711        this.data = this.host.getActions({ camelize: true, cast: true }, { Text: this.Text.getInnerText() });
1712        //if data contains "Indpendent" - the item can be check/unckeck without changing its parent
1713        if ('Independent' in this.data) {
1714            this.Independent = this.data.Independent;
1715            delete this.data.Independent;
1716        }
1717        
1718        if ('Color' in this.data) {
1719            this.data.style = "background-color:#{0}; color:#{1};".interpolate([this.data.Color, Utility.RGB.toContrast(this.data.Color)]);
1720        }
1721
1722        //Validate and convert data
1723        this.data.Checked = /true/i.test(String(this.data.Checked)) ? 2 : 0;
1724
1725        if (this.Children = this.collectChildren(this.host.down('ul'))) {
1726            if (!this.options.multiple)
1727                this.data.group = true;
1728        }
1729        this.NameContainer = this.buildContainer(this.host.down(), !this.options.multiple && this.Children ? null : this.options.checkbox, this.data.Disabled);
1730
1731        //hide item if 'hidden' state is set
1732        this.host.toggle(!Boolean(this.data.Hidden));
1733
1734        this.on(this.NameContainer.on('click', this.mouseAction.bind(this)));
1735        this.NameContainer.on('dblclick', function(e) { e.stop(); });
1736
1737
1738        return this;
1739    },
1740    dispose: function () {
1741        this.off();
1742        (this.Children || []).invoke('dispose');
1743    },
1744    collectChildren: function (container) {
1745        // Collects all children (<LI> element) and create Node instances and Trees
1746        if ((container = $p(container), !container || container.tagName != 'UL'))
1747            return null;
1748
1749        this.GroupContainer = container;
1750
1751        var collection = container.childElements().inject([], function (o, it) {
1752            if (it.tagName == 'LI') {
1753                o.push(new Utility.UI.TreeSelector.Node(it, { Parent: this, options: this.options, Tree: this.Tree }));
1754            }
1755            return o;
1756        }, this);
1757
1758        return collection.length ? collection : undefined;
1759    },
1760    buildContainer: function (it, check, disabled) {
1761        //Create container and all connectors
1762        it.writeAttribute("unselectable", "on");
1763        this.Container = new Element('span', { className: 'item ' + (disabled ? 'disabled' : '') });
1764        check && this.Container.insert({ top: this.Checkbox = new Element('span', { className: 'xti ' + check }) });
1765        var node = this;
1766        //NOTE:: create image connectors
1767        do {
1768            var siblings = node.host.up().childElements() || [];
1769            var hasChildren = node.host.down('ul');
1770            var cls = "X";
1771            var isLast = siblings.indexOf(node.host) == siblings.length - 1;
1772            if (this.options.lines) {
1773                if (node.host === this.host)
1774                    cls = (isLast ? "L" : "T") + (hasChildren ? "-group" : "");
1775                else
1776                    cls = isLast ? "B" : "I";
1777            }
1778
1779            var img = new Element('span', { className: 'xti ' + cls });
1780            this.Container.insert({ top: img });
1781            if (/-group/i.test(cls)) {
1782                this.Connector = img;
1783                this.host.addClassName(this.data.collapsed || this.options.collapsed ? "collapsed" : "");
1784            }
1785            node = node.Parent;
1786        } while (node)
1787
1788        it.wrap(this.Container);
1789        if (this.data.style) {
1790            it.setStyle(this.data.style);
1791        }
1792
1793        return this.Container;
1794    },
1795    collectNodes: function (opt) { //true
1796        // Recursively collects all children. 
1797        // Parameters: (optional): opt : "false" - olny children; "true" - children and their parents  
1798        // Returns flat array
1799        var result = [];
1800        if (opt || !this.Children)
1801            result = [this].concat(result);
1802        if (this.Children)
1803            result = result.concat(this.Children.invoke("collectNodes", opt).flatten());
1804        return result;
1805    },
1806    getState: function () {
1807        var states = this.collectNodes().collect(function (it) { return it.data.Checked; });
1808        var sum = states.inject(0, function (o, it) { return (o = o + it, o); });
1809        var state = (sum > 0 && sum < states.length * 2) ? 1 : (sum == 0) ? 0 : 2;
1810        if (this.Independent) {
1811            return  state || this.data.Checked;
1812        }
1813        return state;
1814    },
1815    getValues: function (opt) {
1816        return this.collectNodes().collect(function (it) {
1817            return opt ? (it.data.Checked ? it.data.Value : null) : it.data.Value;
1818        });
1819    },
1820    getValue: function (opt) {
1821        // Gets a list of selected nodes
1822        // Parameters: (optional): opt : "false" - olny checked; "true" - checked and partially checked
1823        // Returns flat array
1824        return this.collectNodes(opt).collect(function (it) {
1825            return it.data.Checked ? it.data : null;
1826        });
1827    },
1828    setParentValue : function() {
1829        
1830    },
1831    setValue: function (values, state, flag) {
1832        //Select nodes by its values
1833        //values = Object.isArray(values) ? values : (values || '').split(',');
1834        //no state passed in, set Checked if value exists in value list
1835        if (Object.isUndefined(state))
1836            this.data.Checked = values.include(this.data.Value) ? 2 : 0;
1837        else if (values)
1838            values.include(this.data.Value) && (this.data.Checked = state ? 2 : 0);
1839
1840        if (!flag && this.Children)
1841            if (Object.isUndefined(state))
1842                this.Children.invoke('setValue', values, state);
1843            else //if (!this.Independent)
1844                this.Children.invoke('setValue', this.getValues(), this.data.Checked);
1845
1846        //Modify "Checked" state to full(2) or partial(1)
1847        if (this.Children)
1848            this.data.Checked = this.getState();
1849
1850        //Update Parent state only (passing flag=true)
1851        if (this.Parent)
1852            this.Parent.setValue("", this.data.Checked, true);
1853
1854        this.update(this.data);
1855    },
1856    Is: function (attr) {
1857        //Helper. checks if given attribute is set (class or specific value)
1858        return this.Container.hasClassName(attr);
1859    },
1860    disable: function() {
1861        this.Container.addClassName('disabled');
1862        (this.Children ||[]).invoke('disable');
1863    },
1864    enable: function () {
1865        this.Container.removeClassName('disabled');
1866        (this.Children || []).invoke('enable');
1867    },
1868    update: function (data) {
1869        this.data = Object.extend(data || {});
1870        this.Text.update(data.Text);
1871        this.NameContainer.removeClassName('checked').removeClassName('partial');
1872        this.data.Checked && this.NameContainer.addClassName('checked');
1873        this.data.Checked == 1 && this.NameContainer.addClassName('partial');
1874    },
1875    mouseAction: function (e) {
1876        //Click handler for connector. Detects action based on active element 
1877        e.stop();
1878        var el = e.element();
1879        if (el && e.type == 'dblclick')
1880            el = this.Connector;
1881        if (this.Connector && el === this.Connector) {
1882            this.host.toggleClassName('collapsed');
1883        } else if (el && (el === this.Text || el === this.Checkbox)) {
1884            if (!this.Is('disabled')) {
1885                if (!this.options.multiple) {
1886                    if (this.Children) {
1887                        this.toggleGroup(e);
1888                        return;
1889                    }
1890                    this.Tree.setValue();
1891                }
1892                this.setValue(this.data.Value.toString(), this.data.Checked == 2 ? 0 : 2);              
1893                this.Tree.updateValue(e.CtrlKey || this.options.multiple);                
1894            }
1895        }
1896    },
1897});
1898
1899
1900Utility.UI.ListSelector = Class.create(Utility.Base, {
1901    defaults: function () {
1902        this.options = Object.extend({
1903            Delimiter: ',',
1904            maxitems: 5,
1905            itemheight: 20,
1906            itemproperties: 'Value,Text'
1907        }, this.host.getActions({ camelize: true, cast: true }));
1908    },
1909    initialize: function ($super, host, options) {
1910        try {
1911            if (!$super.apply(this, $A(arguments).slice(1)))
1912                return false;
1913            if (!(this.Container = this.host.down('ul')))
1914                this.host.insert(this.Container = new Element('ul'));
1915            this.Collect(this.defaultValue);
1916
1917
1918            return this;
1919
1920        } catch (er) {
1921            $alert(er.message);
1922        }
1923        return this;
1924    },
1925    onSelect: Prototype.emptyFunction,
1926    getValue: function () {
1927        return this.ActiveItem ? this.ActiveItem.data : { Value: '', Text: '' };
1928    },
1929    setValue: function (value) {
1930        this.ActivateItem(this.Items.find(function (it) {
1931            return it.data.Value == value;
1932        }));
1933    },
1934    getText: function (text) {
1935        var v = this.getValue();
1936        v.text = text || v.Text;
1937        return '<span class="bit" data-value="#{Value}" data-text="#{Text}">#{text}</span>'.interpolate(v);
1938    },
1939    onShow: function (dim) {
1940        if (!this.Items.length)
1941            return;
1942        dim = this.Items.inject(dim, function (o, it,idx) {
1943            o.width = Math.max(it.getWidth(), o.width);
1944            o.height = Math.min((it.getHeight() * Math.min(this.Items.length, this.options.maxitems)), o.height);
1945            return o;
1946        }, this);
1947        this.Parent.Container.setStyle({
1948            height: dim.height + 'px',
1949            width: (dim.width) + 'px'
1950        });
1951    },
1952    CreateItem: function (item, highlight, keys) {
1953        //check keys: Array[2] - 0- value, 1-text
1954        var v = keys[0], t = keys[1];
1955        item.DisplayName = highlight ? item[keys[1]].replace(new RegExp(highlight, 'gi'), function ($1) { return '<span class="highlight">' + $1 + '</span>'; }) : item[keys[1]];
1956        item[t] = escape(item[t]); // escape 'text' properties        
1957        return ('<li data-index="#{index}" data-' + v + '="#{' + v + '}"data-' + t + '="#{' + t + '}"><a>#{DisplayName}<a></li>').interpolate(item);
1958    },
1959    Collect: function (def) {
1960        this.DeactivateItem();
1961        delete this.Items;
1962        this.itemWidth = this.Container.getWidth();
1963        this.itemHeight = this.Container.getHeight() / this.options.itemheight;
1964        this.Items = this.Container.select('li').collect(function (item, index) {
1965            item.data = item.getActions({ cast: true, camelize: true });
1966            item.data.Text = item.getInnerText();
1967            item.empty() && item.update("&nbsp;");
1968            item.index = index;
1969            item.on("mousedown", this.Select.bind(this, item, true));
1970            this.itemWidth = Math.max(item.getWidth(), this.itemWidth);
1971            this.itemHeight = Math.max(item.getHeight(), this.itemHeight);
1972            return item;
1973        }, this);
1974        if (def = this.Items.detect(function (it) { return it.data.Value == def; }))
1975            this.ActivateItem(def);
1976
1977    },
1978    Load: function (data, value) {
1979
1980        if (Object.isArray(data)) {
1981            this.Container.update('');
1982            //transform and add options to container 
1983            data.each(function (it) {
1984                //call transformation function with two parameters: current item data and text box value 
1985                this.Container.insert(this.CreateItem.call(this.Container, it, value, String(this.options.itemproperties).split(',')));
1986            }, this);
1987        } else if (Object.isString(data)) {
1988            this.Container.update(data);
1989        }
1990        this.Collect();
1991        return this.Items.length > 0;
1992    },
1993    Select: function (it, done) {
1994        this.ActivateItem(it);
1995        this.onSelect(this.getValue(), true);
1996        //done && this.run('Parent.Deactivate');
1997    },
1998    DeactivateItem: function () {
1999        Object.isArray(this.Items) && this.Items.invoke('removeClassName', "selected");
2000        delete this.ActiveItem;
2001    },
2002    ActivateItem: function (it) {
2003        this.DeactivateItem();
2004        it && (this.ActiveItem = it.addClassName('selected'));
2005        return this;
2006    },
2007    Up: function (e) {
2008        if (this.Items && this.Items.length) {
2009            var index = this.Items.length - 1;
2010            if (this.ActiveItem)
2011                index = this.ActiveItem.index == 0 ? this.ActiveItem.index : this.ActiveItem.index - 1;
2012            this.ActivateItem(this.Items[index]);
2013            this.onSelect(this.getValue());
2014            this.Scroll();
2015        }
2016    },
2017    Down: function (e) {
2018        if (this.Items && this.Items.length) {
2019            var index = 0;
2020            if (this.ActiveItem)
2021                index = this.ActiveItem.index == this.Items.length - 1 ? this.ActiveItem.index : this.ActiveItem.index + 1;
2022            this.ActivateItem(this.Items[index]);
2023            this.onSelect(this.getValue());
2024            this.Scroll();
2025        }
2026    },
2027    Scroll: function (i) {
2028        var offsetTop = this.ActiveItem.offsetTop;
2029        var upperBound = this.host.scrollTop;
2030        var lowerBound = upperBound + (this.host.measure('border-box-height') - this.ActiveItem.measure('border-box-height'));
2031        if (offsetTop < upperBound) {
2032            this.host.scrollTop = offsetTop;
2033        } else if (offsetTop > lowerBound) {
2034            this.host.scrollTop = offsetTop - (this.host.measure('border-box-height') - this.ActiveItem.measure('border-box-height'));
2035        }
2036    },
2037
2038});
2039
2040
2041
2042//-----------------------------------------------------------------------------\dlo/
2043// CHO.Input Control v1.0
2044// Jonas Software © 2013, by Dmitry Lopyrev
2045//-----------------------------------------------------------------------------
2046// 
2047//-----------------------------------------------------------------------------
2048// Note: Requires Prototype JS library (v.1.7.1 - modified) and Utility.js  
2049//-----------------------------------------------------------------------------
2050
2051Utility.UI.DateTime = Class.create(Utility.Base, {
2052    defaults: function () {
2053        return this.options = this.host.getActions({ camelize: true, cast: true }, {
2054            views: 'days,months'
2055        });
2056
2057    },
2058    initialize: function ($super, host, options) {
2059
2060        if (!$super.apply(this, $A(arguments).slice(1)))
2061            return false;
2062
2063        this.GlobalContainer = this.host;
2064        this.current = new Date();
2065        this.options.views = this.options.views.split(',').invoke('capitalize').inject({}, function (o, it) {
2066            o[it] = true;
2067            return o;
2068        }, this);
2069
2070        /*
2071                //Assign custom event handlers
2072                this.on('on:show', this.onShow.bindAsEventListener(this));
2073                this.on('on:hide', this.onHide.bindAsEventListener(this));
2074                this.on('on:load', this.onLoad.bindAsEventListener(this));
2075        */
2076        return this;
2077
2078    },
2079    getValue: function () {
2080        return {
2081            Value: this.selected ? this.selected.CustomFormat(this._format) : '',
2082            Text: this.selected ? this.selected.CustomFormat(this.options.format) : ''
2083        };
2084    },
2085    getText: function (text) {
2086        var v = this.getValue();
2087        v.text = Object.isString(text) ? text : v.Text;
2088        return '<span class="bit" data-value="#{Value}" data-text="#{Text}">#{text}</span>'.interpolate(v);
2089    },
2090    setOptions: function (opt) {
2091        Object.extend(this.options, opt || {});
2092        this.Create();
2093    },
2094    onSelect: Prototype.emptyFunction,
2095    Create: function () {
2096        this.GlobalContainer.writeAttribute("data-type", "datetime");
2097    },
2098    onShow: function (e) {
2099        this.UpdateLayout();
2100    },
2101    onLoad: function (e) {
2102        this.options.data = e.memo;
2103        this.status = 'ready';
2104    },
2105    ValidateRange: function (dt) {
2106        return true;
2107    }
2108});
2109
2110
2111Utility.UI.DatePicker = Class.create(Utility.UI.DateTime, {
2112    defaults: function ($super) {
2113        this._format = 'yyyy/MM/dd';
2114
2115        this.WeekDays = [], this.Days = [], this.Months = [], this.Years = [];
2116
2117        return this.options = Object.extend($super(), {
2118            format: 'MM/dd/yyyy',
2119            full: 'w, MMMM d, yyyy',
2120            today: "Today: ",
2121            firstday: 0,
2122            delta: 6,
2123            min: true
2124        });
2125    },
2126    initialize: function ($super, host, options) {
2127
2128        if (!$super.apply(this, $A(arguments).slice(1)))
2129            return false;
2130        this.selected = Date.parse(this.selected) ? new Date(this.selected) : null;
2131        this.picked = new Date(this.selected || this.current);
2132
2133        if (this.options.min)
2134            this.options.min = Date.parse(this.options.min) ? new Date(this.options.min) : this.current.setTime();
2135        if (this.options.max)
2136            this.options.max = Date.parse(this.options.max) ? new Date(this.options.max) : null;
2137
2138        this.Create();
2139        return this;
2140
2141    },
2142    Layout: function ($super, id, data) {
2143        switch (id) {
2144            case 'days':
2145                return ('<table style="width: 100%; height: 100%;" data-view="days"><tbody>' +
2146						'<tr class="navi">' +
2147							'<td><div title="Previous" class="icon prev"></div></td>' +
2148							'<td colspan="5" style="white-space: nowrap;"><span class="title" title="Click to select month and year"></span><br/><span class="subtitle" title="Today. Click to select" ></span></td>' +
2149							'<td><div title="Next" class="icon next"></div></td>' +
2150						'</tr>' +
2151		   			   '</tbody></table>').interpolate(data);
2152            case 'months':
2153                return ('<table style="width: 100%; height: 100%;" data-view="months"><tbody>' +
2154						'<tr class="header">' +
2155							'<th colspan="2" style="width:50%">Months</th>' +
2156							'<th rowspan="7"></td>' +
2157							'<th colspan="2" style="width:50%">' +
2158                    '<span data-year-nav="prev"></span>Years<span data-year-nav="next"></span></th>' +
2159						'</tr>' +
2160		   			   '</tbody></table>').interpolate(data);
2161
2162            case 'dayofweek':
2163                return '<td width="14.28%" title="#{title}" class="#{class}">#{1}</td>'.interpolate(data);
2164            case 'day':
2165                return '<td class="day disabled"></td>'.interpolate(data);
2166            default:
2167                return $super(id, data);
2168        }
2169    },
2170    CreateCell: function (host, type, value, tag) {
2171        var cell = new Element(tag || "td");
2172        switch (type) {
2173            case 'weekday':
2174                cell.addClassName(value.weekend() ? 'weekend' : 'weekday').update(value.CustomFormat("w").substr(0, 2)).setStyle("width:14.28%");
2175                break;
2176            case 'month':
2177                cell.addClassName("month").update(value.CustomFormat("MMM"))._value = value.getMonth();
2178                break;
2179            case 'year':
2180                cell.addClassName("year")._value = 0;
2181                break;
2182            case 'day':
2183                cell.addClassName("day");
2184                break;
2185        }
2186        cell.on('click', this.Pick.bindAsEventListener(this));
2187        return host.appendChild(cell);
2188    },
2189    Create: function ($super) {
2190
2191        $super();
2192        var d = this.current.toObject();
2193        this.GlobalContainer.update('');
2194
2195        if (this.options.views.Days) {
2196            this.GlobalContainer.insert(this.Layout('days'));
2197
2198            this.GlobalContainer.down('.subtitle').update(this.current.CustomFormat('w, MMM d, yyyy')).on('click', this.Pick.bindAsEventListener(this, this.current));
2199            this.options.views.Days = this.GlobalContainer.down('[data-view="days"]');
2200            this.Prev = this.GlobalContainer.down('.prev');
2201            this.Prev.on('click', this.Navigate.bindAsEventListener(this));
2202
2203            this.Header = this.GlobalContainer.down('.title');
2204
2205            this.Next = this.GlobalContainer.down('.next');
2206            this.Next.on('click', this.Navigate.bindAsEventListener(this));
2207
2208            var row = $p(this.options.views.Days.insertRow(-1)).addClassName('header');
2209            var start = new Date(d.year, d.month, 1).getDay() - this.options.firstday;
2210            if (start < 0) start += 7;
2211            for (var i = 0; i < 7; i++) {
2212                this.WeekDays.push(this.CreateCell(row, 'weekday', new Date(d.year, d.month, (i - start + 1)),'th'));
2213            }
2214            for (var i = 0; i < 42; i++) {
2215                (i % 7 == 0) && (row = $p(this.options.views.Days.insertRow(-1)));
2216                this.Days.push(this.CreateCell(row, 'day'));
2217            }
2218            this.options.views.Days.hide();
2219        }
2220        if (this.options.views.Months) {
2221            this.GlobalContainer.insert(this.Layout('months'));
2222            this.options.views.Months = this.GlobalContainer.down('[data-view="months"]');
2223            for (var i = 0; i < 6; i++) {
2224                row = this.options.views.Months.insertRow(-1);
2225                this.Months.push(this.CreateCell(row, 'month', new Date(d.year, i * 2, 1)));
2226                this.Months.push(this.CreateCell(row, 'month', new Date(d.year, i * 2 + 1, 1)));
2227                this.Years.push(this.CreateCell(row, 'year', d.year));
2228                this.Years.push(this.CreateCell(row, 'year', d.year));
2229            }
2230            if (this.options.views.Days) {
2231                this.Header.on('click', function (e) { e.stop(); this.Toggle('Months'); }.bind(this));
2232            }
2233            this.options.views.Months.hide();
2234
2235        }
2236        this.Toggle();
2237
2238    },
2239    setValue: function ($super, value) {
2240        if (Utility.UI.Validation.IsDate(value))
2241            this.selected = new Date(value);
2242        else
2243            this.selected = null;
2244        this.picked = new Date(this.selected || this.current);
2245        this.UpdateLayout();
2246
2247    },
2248    getValue: function ($super) {
2249        var v = $super();
2250        v.Value && (v.Date = this.selected);
2251        return v;
2252    },
2253    Toggle: function (view) {
2254        for (var it in this.options.views) {
2255            !view && (view = it);
2256            this.options.views[it][it == view ? 'show' : 'hide']();
2257        }
2258        return this;
2259    },
2260    UpdateDays: function () {
2261        if (!this.options.views.Days)
2262            return;
2263        var o = this.picked.toObject('YM');
2264        this.Header.update(this.picked.CustomFormat('MMMM, yyyy'));
2265        this.Prev.setStyle('visibility:#{0}'.interpolate([this.ValidateMin(new Date(o.year, o.month, 0)) ? 'visible' : 'hidden']));
2266        //        this.Next.setStyle('visibility:#{0}'.interpolate([this.ValidateRange(new Date(o.year, o.month + 1, 0)) ? 'visible' : 'hidden']));
2267        this.Next.setStyle('visibility:#{0}'.interpolate([this.ValidateMax(new Date(o.year, o.month, 0)) ? 'visible' : 'hidden']));
2268
2269        var start = new Date(o.year, o.month, 1).getDay() - this.options.firstday;
2270        if (start < 0) start += 7;
2271        for (var i = 0, cell; cell = this.Days[i]; i++) {
2272
2273            var cellValue = (cell._value = new Date(o.year, o.month, (i - start + 1))).CustomFormat(this._format);
2274
2275            cell.update(cell._value.getDate());
2276            cell.className = 'day';
2277
2278            cell.title = cell._value.CustomFormat(this.options.full);
2279            cell.addClassName(cell._value.getMonth() == o.month ? '' : 'out');
2280
2281            if (cellValue == this.current.CustomFormat(this._format)) {
2282                cell.addClassName('today');
2283                cell.title = this.options.today + cell.title;
2284            }
2285
2286
2287            if (Object.isArray(this.options.data) && this.options.data.include(cellValue) && cell._value >= curentDateOnly) {
2288                cell.addClassName('special');
2289                cell.title += ". Special date";
2290            }
2291
2292            if (this.selected && cellValue == this.selected.CustomFormat(this._format))
2293                cell.addClassName('selected');
2294
2295            if (!this.ValidateRange(cell._value))
2296                cell.addClassName('disabled');
2297
2298        }
2299
2300    },
2301    UpdateMonths: function (dim) {
2302        if (!this.options.views.Months)
2303            return;
2304
2305        var d = this.picked.toObject();
2306
2307        this.Months.invoke('removeClassName', 'selected|selected-over|disabled');
2308
2309        this.Months[this.picked.getMonth()].addClassName('selected');
2310        for (var i = 0, cell; cell = this.Months[i++];) {
2311            cell._value == d.month && cell.addClassName('selected');
2312            if (!this.ValidateRange(new Date(d.year, cell._value + 1, 0)))
2313                cell.addClassName('disabled');
2314        }
2315
2316        this.Years.invoke('removeClassName', 'selected|selected-over|disabled');
2317        var delta = this.options.delta;
2318        var b = (this.Years[0]._value == 0 || this.Years[0]._value == d.year || this.Years[this.Years.length - 1]._value == d.year)
2319        for (var i = 0, cell; cell = this.Years[i++];) {
2320            b && (cell.update(cell._value = d.year - delta + i));
2321            if (b && i == 1) cell.update("« " + cell.innerHTML);
2322            if (b && i == this.Years.length) cell.update(cell.innerHTML + " »");
2323            (cell._value == d.year) && (cell.addClassName("selected"));
2324            if (!this.ValidateRange(new Date(cell._value + 1, 0, 0)))
2325                cell.addClassName('disabled');
2326
2327        }
2328    },
2329    UpdateLayout: function (dim) {
2330
2331        var curentDateOnly = new Date(this.current.CustomFormat(this._format));
2332        this.UpdateDays();
2333        this.UpdateMonths();
2334
2335        return this;
2336    },
2337    Navigate: function (e) {
2338        Event.stop(e);
2339        var delta = 1, id;
2340        switch (Event.element(e)) {
2341            case this.Prev: delta *= -1; id = e.ctrlKey ? "y" : "m"; break;
2342            case this.TPrev: delta *= -1; id = e.ctrlKey ? "h" : "min"; break;
2343            case this.Next: id = e.ctrlKey ? "y" : "m"; break;
2344            case this.TNext: id = e.ctrlKey ? "h" : "min"; break;
2345            default:
2346                if (this.startPos > 0 && e.type == 'touchend') {
2347                    delta *= (e.changedTouches[0].pageX - this.startPos) > 0 ? -1 : 1;
2348                    id = 'm';
2349                }
2350                break;
2351        }
2352        this.picked = this.picked.add(id, delta);
2353        this.UpdateLayout();
2354    },
2355    GetDateValue: function (o) {
2356        var dt = new Date((this.picked || this.current)).toObject();
2357
2358        if (/^(day|out)/i.test(o.className) && o._value instanceof Date) {
2359            dt = new Date(o._value).toObject();
2360        }
2361        else if (/month/i.test(o.className) && typeof (o._value) == 'number')
2362            dt.month = o._value;
2363        else if (/year/i.test(o.className) && typeof (o._value) == 'number')
2364            dt.year = o._value;
2365
2366        return new Date(dt.year, dt.month, dt.day);
2367    },
2368    Pick: function (e, dt) {
2369
2370        var element = Event.element(e), done = true;
2371        dt = dt ? dt : this.GetDateValue(element);
2372
2373        if (element.hasClassName('disabled')) {
2374            e.stop();
2375            return;
2376        }
2377        if (!e.ctrlKey) {
2378            if (/(month|year)/i.test(element.className)) {
2379                if (this.options.views.Days) {
2380                    (this.Toggle('Days'));
2381                    done = false;
2382                }
2383            }
2384        } else {
2385            done = false;
2386        }
2387
2388        if (!this.ValidateRange(dt))
2389            return false;
2390
2391        this.selected = dt;
2392        this.picked = this.selected.clone();
2393        this.UpdateLayout();
2394        e.stop();
2395        this.onSelect(this.getValue(), Object.isBoolean(this.options.stick) ? !this.options.stick : done);//this.Refresh(true);
2396
2397    },
2398    ValidateRange: function (dt) {
2399        var d = dt.clone().setTime();
2400        if (this.options.min && dt < this.options.min)
2401            return false;
2402        if (this.options.max && dt > this.options.max)
2403            return false;
2404        return true;
2405    },
2406    ValidateMin: function (dt) {
2407        if (this.options.min && dt < this.options.min)
2408            return false;
2409        
2410        return true;
2411    },
2412    ValidateMax: function (dt) {
2413        if (this.options.max && dt > this.options.max)
2414            return false;
2415
2416        return true;
2417    },
2418});
2419
2420
2421Utility.UI.TimePicker = Class.create(Utility.UI.DateTime, {
2422    defaults: function ($super) {
2423        this._format = 'hh:mm';
2424        return this.options = Object.extend($super(), {
2425            format: 'h:mm tt',
2426            group: 'p',
2427            delta: 15
2428        });
2429    },
2430    initialize: function ($super, host, options) {
2431
2432        if (!$super.apply(this, $A(arguments).slice(1)))
2433            return false;
2434        this.selected = this.current.setTime(this.selected || '') || null;
2435        this.picked = new Date(this.selected || this.current);
2436
2437        if (this.options.min)
2438            this.options.min = this.current.setTime(this.options.min);
2439        if (this.options.max)
2440            this.options.max = this.current.setTime(this.options.max);
2441
2442
2443        this.Times = [];
2444        this.Create();
2445        return this;
2446
2447    },
2448    setValue: function ($super, value) {
2449        if (Utility.UI.Validation.IsTime(value))
2450            this.selected = new Date(this.current.setTime(value));
2451        else
2452            this.selected = null;
2453        this.picked = new Date(this.selected || this.current).round(this.options.delta);
2454        this.UpdateLayout();
2455    },
2456    getValue: function ($super) {
2457        var v = $super();
2458        v.Value && (v.Time = this.selected);
2459        return v;
2460    },
2461    Layout: function ($super, id, data) {
2462        switch (id) {
2463            case 'main':
2464                return ('<table style="width: 100%; height: 100%;"></table>').interpolate(data);
2465            case 'timecell':
2466                return '<td class="time">#{0}</td>'.interpolate(data);
2467            case 'group':
2468                return '<th class="header" colspan="#{0}">#{1}</th>'.interpolate(data);
2469            default:
2470                return $super(id, data);
2471        }
2472    },
2473    CreateCell: function (host, type, value) {
2474        var cell;
2475        switch (type) {
2476            case 'group':
2477                cell = this.Layout(type, [4, value.toString(String(this.options.group).strip())]);
2478                break;
2479            case 'timecell':
2480                cell = this.Layout(type, [value.toString('h:mmtt')]);
2481                break;
2482        }
2483        cell = host.insert(cell).childElements().last();
2484        cell.on('click', this.Pick.bindAsEventListener(this, cell._value = value));
2485        return cell;
2486    },
2487    Create: function ($super) {
2488
2489        $super();
2490
2491        var tbody, row;
2492        var total = 1440 / this.options.delta;
2493        var ind = 4;
2494
2495
2496        this.GlobalContainer.insert(this.Layout('main')).addClassName("f10"); //, { height: this.options.height }
2497
2498        this.TimeContainer = this.GlobalContainer.down('table');
2499        var p, dt = this.picked.setTime();
2500
2501        for (var i = 0; i < total; i++) {
2502            var value = dt.add('min', i * this.options.delta);
2503            if (i % ind == 0) {
2504
2505                if (this.options.group && p != value.CustomFormat('p')) {
2506                    //tbody = $p(this.TimeContainer.createTBody());
2507                    this.TimeContainer.insert(tbody = new Element('tbody'));
2508
2509                    row = tbody.insertRow(-1).addClassName('header');
2510                    this.CreateCell(row, 'group', value);
2511                    p = value.CustomFormat('p');
2512                }
2513                row = tbody.insertRow(-1);
2514            }
2515            this.Times.push(this.CreateCell(row, 'timecell', value));
2516        }
2517
2518    },
2519    UpdateLayout: function () {
2520        this.picked = this.picked.setTime();
2521        delete this.selectedTime;
2522        this.Times.each(function (it, index) {
2523            var cellValue = it._value.toString(this._format);
2524            it.className = 'time';
2525            if (this.selected && cellValue == this.selected.CustomFormat(this._format)) {
2526                it.addClassName('selected');
2527                this.selectedTime = it;
2528            }
2529
2530            if (!this.ValidateRange(it._value))
2531                it.addClassName('disabled');
2532
2533        }.bind(this));
2534        if (!this.options.inactive)
2535            this.TimeContainer.select('tbody').each(function (tb) {
2536                var v = tb.select('tr').inject(0, function (result, row) {
2537                    if (row.select('td.disabled').length != 4)
2538                        return result + 1;
2539                    row.hide();
2540                    return result;
2541                });
2542                v <= (this.options.group ? 1 : 0) && tb.hide();
2543            }, this);
2544
2545    },
2546    GetDateValue: function (o) {
2547        var dt = new Date((this.picked || this.current)).toObject();
2548
2549        if (/^(day|out)/i.test(o.className) && o._value instanceof Date) {
2550            dt = new Date(o._value).toObject();
2551        }
2552        else if (/month/i.test(o.className) && typeof (o._value) == 'number')
2553            dt.month = o._value;
2554        else if (/year/i.test(o.className) && typeof (o._value) == 'number')
2555            dt.year = o._value;
2556
2557        return new Date(dt.year, dt.month, dt.day);
2558    },
2559    Pick: function (e, dt) {
2560        var element = Event.element(e), done = true;
2561
2562        if (e.ctrlKey) {
2563            done = false;
2564        }
2565
2566        dt = dt ? dt : this.GetDateValue(element);
2567
2568        if (!this.ValidateRange(dt))
2569            return false;
2570
2571        this.selected = dt;
2572        this.picked = this.selected.clone();
2573        e.stop();
2574        this.onSelect(this.getValue(), Object.isBoolean(this.options.stick) ? !this.options.stick : done);//this.Refresh(true);
2575    },
2576    ValidateRange: function (dt) {
2577
2578        if (this.options.min && dt < dt.setTime(this.options.min))
2579            return false;
2580        if (this.options.max && dt > dt.setTime(this.options.max))
2581            return false;
2582        return true;
2583    },
2584    onShow: function ($super) {
2585        $super();
2586        this.selectedTime && (this.GlobalContainer.scrollTop = this.selectedTime.offsetTop);
2587    },
2588
2589});
2590
2591
2592
2593Utility.UI.OptionList = Class.create(Utility.Base, {
2594    initialize: function ($super) {
2595        try {
2596            if (!$super.apply(this, $A(arguments).slice(1)))
2597                return false;
2598            this.host.$class = this;
2599            this.options = this.host.select('input[type][data-field-option="#{field}"]'.interpolate(this));
2600            this.host.getValue = this.getValue.bind(this);
2601            this.host.setValue = this.setValue.bind(this);
2602            this.host.disable = this.disable.bind(this);
2603            this.host.enable = this.enable.bind(this);
2604            this.host.on = this.on.bind(this);
2605            this.host.Run = this.run.bind(this);
2606            this.host.simulate = this.simulate.bind(this);
2607            if (this.host.disabled = this.host.readAttribute('disabled')) {
2608                this.host.disabled = false;
2609                this.host.disable();
2610            }
2611        } catch (ex) {
2612            $alert(ex.message, 'UI::Option List');
2613        }
2614        return this;
2615    },
2616    getValue: function () {
2617        if (!this.options.length)
2618            return '';
2619        return this.options.inject([], function (list, it) {
2620            it.checked && list.push(it.value);
2621            return list;
2622        }).toString();
2623    },
2624    setValue: function (value) {
2625        if (!this.options.length)
2626            return;
2627        var i = 0;
2628        value = String(value).split(',');
2629        this.options.each(function (it) {
2630            var disabled = it.disabled;
2631            if (disabled)
2632                it.enable();
2633            if (it.checked = value.indexOf(it.value) != -1) {
2634                it.simulate('change'), i++;
2635            }
2636            if (disabled)
2637                it.disable();
2638        });
2639        if (i == 0) {
2640            this.simulate('change');
2641        }
2642    },
2643    on: function () {
2644        if (!this.options.length)
2645            this.host.on.apply(this.host, $A(arguments));
2646        else {
2647            var args = $A(arguments);
2648            this.options.each(function (it) {
2649                it.on.apply(it, args);
2650            });
2651        }
2652    },
2653    simulate: function () {
2654        if (!this.options.length)
2655            this.host.simulate.apply(this.host, $A(arguments));
2656        else {
2657            var args = $A(arguments);
2658            this.options.each(function (it) {
2659                var disabled = it.disabled;
2660                if (disabled)
2661                    it.enable();
2662                it.simulate.apply(it, args);
2663                if (disabled)
2664                    it.disable();
2665            });
2666        }
2667    },
2668    disable: function () {
2669        if (!this.overlay) {
2670            this.host.setStyle('position:relative;display:inline-block;');
2671            (this.host.insert(this.overlay = new Element('div', { className: 'overlay' })));
2672            this.overlay.$click = this.overlay.on('click', function (e) { e.stop(); });
2673
2674        }
2675        this.options.invoke('disable');
2676        this.overlay.setStyle('visibility:inherit').clonePosition(this.host);
2677        this.host.addClassName('disabled');
2678        this.overlay.$click.start();
2679        return this;
2680    },
2681    enable: function () {
2682        if (this.overlay) {
2683            this.overlay.$click.stop();
2684            this.overlay.setStyle('visibility:hidden');
2685        }
2686        this.options.invoke('enable');
2687        this.host.removeClassName('disabled');
2688        return this;
2689    }
2690});
2691
2692
2693

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.