Import src directory from OpenRico 2.1
[misc/kostenrechnung] / lib / rico / ricoMenu.js
1 /*
2  *  (c) 2005-2009 Matt Brown (http://dowdybrown.com)
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  *
7  *         http://www.apache.org/licenses/LICENSE-2.0
8  *
9  *  Unless required by applicable law or agreed to in writing, software distributed under the
10  *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11  *  either express or implied. See the License for the specific language governing permissions
12  *  and limitations under the License.
13  */
14
15 Rico.Menu = Class.create(
16 /** @lends Rico.Menu# */
17 {
18 /**
19  * @class Implements popup menus and submenus
20  * @extends Rico.Popup
21  * @constructs
22  */
23   initialize: function(options) {
24     Object.extend(this, new Rico.Popup());
25     Object.extend(this.options, {
26       width        : "15em"
27     });
28     if (typeof options=='string')
29       this.options.width=options;
30     else
31       Object.extend(this.options, options || {});
32     this.hideFunc=null;
33     this.highlightElem=null;
34     new Image().src = Rico.imgDir+'left.gif';
35     new Image().src = Rico.imgDir+'right.gif';
36   },
37   
38   createDiv: function(parentNode) {
39     if (this.div) return;
40     this.div = document.createElement('div');
41     this.div.className = Prototype.Browser.WebKit ? 'ricoMenuSafari' : 'ricoMenu';
42     this.div.style.position="absolute";
43     this.div.style.top='0px';
44     this.div.style.left='0px';
45     this.div.style.width=this.options.width;
46     if (!parentNode) parentNode = document.getElementsByTagName("body")[0];
47     parentNode.appendChild(this.div);
48     this.width=this.div.offsetWidth;
49     this.setDiv(this.div,this.cancelmenu.bindAsEventListener(this));
50     this.direction=Element.getStyle(this.div,'direction') || 'ltr';
51     this.direction=this.direction.toLowerCase();  // ltr or rtl
52     this.hidemenu();
53     this.itemCount=0;
54   },
55   
56   showmenu: function(e,hideFunc){
57     Event.stop(e);
58     this.hideFunc=hideFunc;
59     if (this.div.childNodes.length==0) {
60       this.cancelmenu();
61       return false;
62     }
63     this.openmenu(e.clientX,e.clientY,0,0);
64   },
65   
66   openmenu: function(x,y,clickItemWi,clickItemHt) {
67     var newLeft=RicoUtil.docScrollLeft()+x;
68     //window.status='openmenu: newLeft='+newLeft+' width='+this.width+' windowWi='+RicoUtil.windowWidth();
69     if (this.direction == 'rtl') {
70       if (newLeft > this.width+clickItemWi) newLeft-=this.width+clickItemWi;
71     } else {
72       if (x+this.width+this.options.margin > RicoUtil.windowWidth()) newLeft-=this.width+clickItemWi;
73     }
74     var newTop=RicoUtil.docScrollTop()+y;
75     this.div.style.visibility="hidden";
76     this.div.style.display="block";
77     var contentHt=this.div.offsetHeight;
78     if (y+contentHt+this.options.margin > RicoUtil.windowHeight())
79       newTop=Math.max(newTop-contentHt+clickItemHt,0);
80     this.openPopup(newLeft,newTop);
81     this.div.style.visibility ="visible";
82     return false;
83   },
84
85   clearMenu: function() {
86     this.div.innerHTML="";
87     this.defaultAction=null;
88     this.itemCount=0;
89   },
90
91   addMenuHeading: function(hdg) {
92     var el=document.createElement('div');
93     el.innerHTML=hdg;
94     el.className='ricoMenuHeading';
95     this.div.appendChild(el);
96   },
97
98   addMenuBreak: function() {
99     var brk=document.createElement('div');
100     brk.className="ricoMenuBreak";
101     this.div.appendChild(brk);
102   },
103
104   addSubMenuItem: function(menutext, submenu, translate) {
105     var dir=this.direction=='rtl' ? 'left' : 'right';
106     var a=this.addMenuItem(menutext,null,true,null,translate);
107     a.className='ricoSubMenu';
108     a.style.backgroundImage='url('+Rico.imgDir+dir+'.gif)';
109     a.style.backgroundRepeat='no-repeat';
110     a.style.backgroundPosition=dir;
111     a.onmouseover=this.showSubMenu.bind(this,a,submenu);
112     a.onmouseout=this.subMenuOut.bindAsEventListener(this);
113   },
114   
115   showSubMenu: function(a,submenu) {
116     if (this.openSubMenu) this.hideSubMenu();
117     this.openSubMenu=submenu;
118     this.openMenuAnchor=a;
119     var pos=Position.page(a);
120     if (a.className=='ricoSubMenu') a.className='ricoSubMenuOpen';
121     submenu.openmenu(pos[0]+a.offsetWidth, pos[1], a.offsetWidth-2, a.offsetHeight+2);
122   },
123   
124   subMenuOut: function(e) {
125     if (!this.openSubMenu) return;
126     Event.stop(e);
127     var elem=Event.element(e);
128     var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
129     try {
130       while (reltg != null && reltg != this.openSubMenu.div)
131         reltg=reltg.parentNode;
132     } catch(err) {}
133     if (reltg == this.openSubMenu.div) return;
134     this.hideSubMenu();
135   },
136   
137   hideSubMenu: function() {
138     if (this.openMenuAnchor) {
139       this.openMenuAnchor.className='ricoSubMenu';
140       this.openMenuAnchor=null;
141     }
142     if (this.openSubMenu) {
143       this.openSubMenu.hidemenu();
144       this.openSubMenu=null;
145     }
146   },
147
148   addMenuItemId: function(phraseId,action,enabled,title,target) {
149     if ( arguments.length < 3 ) enabled=true;
150     this.addMenuItem(RicoTranslate.getPhraseById(phraseId),action,enabled,title,false,target);
151   },
152
153   addMenuItem: function(menutext,action,enabled,title,translate,target) {
154     this.itemCount++;
155     if (translate==null) translate=true;
156     var a = document.createElement(typeof action=='string' ? 'a' : 'div');
157     if ( arguments.length < 3 || enabled ) {
158       switch (typeof action) {
159         case 'function': 
160           a.onclick = action; 
161           break;
162         case 'string'  : 
163           a.href = action; 
164           if (target) a.target = target; 
165           break;
166       }
167       a.className = 'enabled';
168       if (this.defaultAction==null) this.defaultAction=action;
169     } else {
170       a.disabled = true;
171       a.className = 'disabled';
172     }
173     a.innerHTML = translate ? RicoTranslate.getPhrase(menutext) : menutext;
174     if (typeof title=='string')
175       a.title = translate ? RicoTranslate.getPhrase(title) : title;
176     a=this.div.appendChild(a);
177     Event.observe(a,"mouseover", this.mouseOver.bindAsEventListener(this));
178     Event.observe(a,"mouseout", this.mouseOut.bindAsEventListener(this));
179     return a;
180   },
181   
182   mouseOver: function(e) {
183     if (this.highlightElem && this.highlightElem.className=='enabled-hover') {
184       // required for Safari
185       this.highlightElem.className='enabled';
186       this.highlightElem=null;
187     }
188     var elem=Event.element(e);
189     if (this.openMenuAnchor && this.openMenuAnchor!=elem)
190       this.hideSubMenu();
191     if (elem.className=='enabled') {
192       elem.className='enabled-hover';
193       this.highlightElem=elem;
194     }
195   },
196
197   mouseOut: function(e) {
198     var elem=Event.element(e);
199     if (elem.className=='enabled-hover') elem.className='enabled';
200     if (this.highlightElem==elem) this.highlightElem=null;
201   },
202
203   isVisible: function() {
204     return this.div && Element.visible(this.div);
205   },
206   
207   cancelmenu: function() {
208     if (!this.isVisible()) return;
209     if (this.hideFunc) this.hideFunc();
210     this.hideFunc=null;
211     this.hidemenu();
212   },
213
214   hidemenu: function() {
215     if (!this.div) return;
216     if (this.openSubMenu) this.openSubMenu.hidemenu();
217     this.closePopup();
218   }
219
220 });
221
222 Rico.includeLoaded('ricoMenu.js');