Support filling of form for editing data
[misc/kostenrechnung] / lib / rico / ricoBehaviors.js
1 /**
2   *  (c) 2005-2007 Richard Cowin (http://openrico.org)
3   *
4   *  Rico is licensed under the Apache License, Version 2.0 (the "License"); you may not use this
5   *  file except in compliance with the License. You may obtain a copy of the License at
6   *   http://www.apache.org/licenses/LICENSE-2.0
7   **/
8
9 /** @ignore */
10 Rico.selectionSet = function(set, options){
11   new Rico.SelectionSet(set, options);
12 };
13
14 Rico.SelectionSet = Class.create(
15 /** @lends Rico.SelectionSet# */
16 {
17 /**
18  * @class
19  * @constructs
20  * @param selectionSet collection of DOM elements (or a CSS selection string)
21  * @param options object may contain any of the following:<dl>
22  *   <dt>selectedClass</dt><dd>class name to add when element is selected, default is "selected"</dd>
23  *   <dt>selectNode   </dt><dd>optional function that returns the element to be selected</dd>
24  *   <dt>onSelect     </dt><dd>optional function that gets called when element is selected</dd>
25  *   <dt>onFirstSelect</dt><dd>optional function that gets called the first time element is selected</dd>
26  *   <dt>noDefault    </dt><dd>when true, no element in the set is initially selected, default is false</dd>
27  *   <dt>selectedIndex</dt><dd>index of the element that should be initially selected, default is 0</dd>
28  *   <dt>cookieName   </dt><dd>optional name of cookie to use to remember selected element. If specified, and the cookie exists, then the cookie value overrides selectedIndex.</dd>
29  *   <dt>cookieDays   </dt><dd>specifies how long cookie should persist (in days). If unspecified, then the cookie persists for the current session.</dd>
30  *   <dt>cookiePath   </dt><dd>optional cookie path</dd>
31  *   <dt>cookieDomain </dt><dd>optional cookie domain</dd>
32  *</dl>
33  */
34         initialize: function(selectionSet, options){
35                 this.options = options || {};
36     if (typeof selectionSet == 'string')
37       selectionSet = $$(selectionSet);
38           this.previouslySelected = [];
39                 this.selectionSet = selectionSet;
40                 this.selectedClassName = this.options.selectedClass || "selected";
41                 this.selectNode = this.options.selectNode || function(e){return e;};
42                 this.onSelect = this.options.onSelect;
43     this.onFirstSelect = this.options.onFirstSelect;
44                 this.clickHandler = this.click.bind(this);
45                 selectionSet.each(function(e) {Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,e).wrapper);}.bind(this));
46     if (!this.options.noDefault) {
47                   var cookieIndex=this.options.cookieName ? this.getCookie() : 0;
48       this.selectIndex(cookieIndex || this.options.selectedIndex || 0);
49     }
50         },
51   getCookie: function() {
52     var cookie = RicoUtil.getCookie(this.options.cookieName);
53     if (!cookie) return 0;
54     var index = parseInt(cookie);
55     return index < this.selectionSet.length ? index : 0;
56         },
57         reset: function(){
58           this.previouslySelected = [];
59           this.notifySelected(this.selected);
60         },
61         select: function(element){
62                 if (this.selected == element)
63                         return;
64
65                 if (this.selected)
66                   Element.removeClassName(this.selectNode(this.selected), this.selectedClassName);
67
68     this.notifySelected(element);
69
70                 this.selected = element;
71     Element.addClassName(this.selectNode(this.selected), this.selectedClassName);
72         },
73         notifySelected: function(element){
74     var index = this.selectionSet.indexOf(element);
75                 if (this.options.cookieName)
76       RicoUtil.setCookie(this.options.cookieName, index, this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
77     if (this.onFirstSelect && !this.previouslySelected[index]){
78       this.onFirstSelect(element, index);
79       this.previouslySelected[index] = true;
80     }
81         if (this.onSelect)
82       try{
83             this.onSelect(element, index);
84       } catch (e) {};
85         },
86         selectIndex: function(index){
87                 this.select(this.selectionSet[index]);
88         },
89         nextSelectItem: function(){
90     var index = this.selectionSet.indexOf(this.selected);
91     if (index + 1 >= this.selectionSet.length)
92       return this.selectionSet[index - 1];
93     else
94       return this.selectionSet[index + 1];
95         },
96         selectNext: function(){
97     var index = this.selectionSet.indexOf(this.selected);
98     if (index >= this.selectionSet.length)
99       this.selectIndex(index - 1);
100     else
101       this.selectIndex(index + 1);
102         },
103         click: function(event,target) {
104                 this.select(target);
105         },
106         add: function(item){
107         //      this.selectionSet.push(item)
108           if (item.constructur == Array) {
109             item.each(function(e){
110                 Event.observe(e, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
111             }.bind(this));
112           } else {
113                   Event.observe(item, "click", new Rico.EventWrapper(this.clickHandler,item).wrapper);
114     }
115         },
116         remove: function(item){
117           this.selectionSet = this.selectionSet.without(item);
118                         //Todo: need to cleanup all events on item - need to keep track of eventwrappers
119         },
120         removeAll: function(){
121         }
122  });
123
124 Rico.HoverSet = Class.create(
125 /** @lends Rico.HoverSet# */
126 {
127 /**
128  * @class
129  * @constructs
130  * @param hoverSet collection of DOM elements
131  * @param options object may contain any of the following:<dl>
132  *   <dt>hoverClass</dt><dd> class name to add when mouse is over element, default is "hover"</dd>
133  *   <dt>hoverNodes</dt><dd> optional function to select/filter which nodes are in the set</dd>
134  *</dl>
135  */
136   initialize: function(hoverSet, options){
137     options = options || [];
138     this.hoverSet = hoverSet;
139     this.hoverClassName = options.hoverClass || "hover";
140     this.hoverNodes = options.hoverNodes || function(e){return [e];};
141     this.listenerHover    = this._onHover.bind(this);
142     this.listenerEndHover = this._onUnHover.bind(this);
143     for (var i=0; i<this.hoverSet.length; i++) this.add(this.hoverSet[i]);
144   },
145   _onHover: function(event,target) {
146     this.hover(target);
147   },
148   _onUnHover: function(event,target) {
149     this.unHover(target);
150   },
151   hover: function(target) {
152     this.hoverNodes(target).each((function(t){Element.addClassName(t,this.hoverClassName);}).bind(this));
153   },
154   unHover: function(target) {
155     this.hoverNodes(target).each((function(t){Element.removeClassName(t,this.hoverClassName);}).bind(this));
156   },
157   add: function(item){
158     Event.observe(item, "mousemove", new Rico.EventWrapper(this.listenerHover,item).wrapper);
159     Event.observe(item, "mouseout", new Rico.EventWrapper(this.listenerEndHover,item).wrapper);
160   }
161 });
162
163
164 /**
165  * @namespace
166  */
167 Rico.Hover = {
168   groups: {},
169   clearCurrent: function(group) {
170     var last_hover = Rico.Hover.groups[group];
171     if(!last_hover) return;
172     clearTimeout(last_hover[0]);
173     last_hover[1].end();
174     Rico.Hover.groups[group] = null;
175   },
176   end: function(group) {
177         Rico.Hover.groups[group][1].end();
178   },
179   endWith: function(hover, group) {
180         var timer = setTimeout('Rico.Hover.end("'+ group + '")', hover.exitDelay);
181     Rico.Hover.groups[group] = [timer, hover];
182   }
183 };
184
185 Rico.HoverDisplay = Class.create(
186 /** @lends Rico.HoverDisplay# */
187 {
188 /**
189  * @class
190  * @constructs
191  * @param element
192  * @param options object may contain any of the following:<dl>
193  *   <dt>group</dt><dd> </dd>
194  *   <dt>delay</dt><dd> </dd>
195  *</dl>
196  */
197   initialize: function(element, options) {
198         this.element = element;
199         this.options = options || {};
200         this.group = this.options.group;
201         this.exitDelay = this.options.delay || 1000;
202   },
203   begin: function() {
204     Rico.Hover.clearCurrent(this.group);
205                 Element.show(this.element);
206   },
207   end: function(delay) {
208     if(delay)
209       Rico.Hover.endWith(this, this.group);
210     else
211                   Element.hide(this.element);
212   }
213 });
214
215
216 Rico.EventWrapper = Class.create(
217 /** @lends Rico.EventWrapper# */
218 {
219 /**
220  * @class
221  * @constructs
222  * @param handler
223  * @param target
224  */
225   initialize: function(handler, target){
226     this.handler = handler;
227     this.target = target;
228     this.wrapper = this.wrapperCall.bindAsEventListener(this);
229   },
230   wrapperCall: function(event){
231     this.handler(event, this.target);
232   }
233 });
234
235 Rico.includeLoaded('ricoBehaviors.js');