1 // Copyright (c) 2005 spinelz.org (http://script.spinelz.org/)
3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 var MenuBar = Class.create();
26 menuBody: 'menubar_menuBody',
27 menuBodyHover: 'menubar_menuBodyHover',
28 subMenu: 'menubar_subMenu',
29 subMenuBody: 'menubar_subMenuBody',
30 subMenuBodyHover: 'menubar_subMenuBodyHover',
31 subMenuContainer: 'menubar_menuContainer',
32 dirMark: 'menubar_dirMark'
41 initialize: function(element) {
42 this.options = Object.extend({
43 hideOnClickSubmenu: true
46 this.element = $(element);
47 Element.setStyle(this.element, {visibility: 'hidden'});
48 Element.hide(this.element);
50 var options = Object.extend({
52 }, arguments[1] || {});
54 var customCss = CssUtil.appendPrefix(options.cssPrefix, MenuBar.cssNames);
55 this.classNames = new CssUtil([MenuBar.cssNames, customCss]);
59 var nodes = this.element.childNodes;
61 for (var i = 0; i < nodes.length; i++) {
62 if (nodes[i].nodeType == 1) {
63 this.build(nodes[i], 'menu');
64 topMenus.push(nodes[i]);
68 this.menubar = Builder.node('DIV', topMenus)
69 this.classNames.addClassNames(this.menubar, 'container');
70 this.element.appendChild(this.menubar);
72 Event.observe(document, "click", this.hideAllTrigger(this.menubar).bindAsEventListener(this));
73 Element.setStyle(this.element, {visibility: 'visible'});
74 Element.show(this.element);
77 build: function(element, className) {
78 this.classNames.addClassNames(element, className);
80 var bodyContents = new Array();
81 var subMenus = new Array();
82 var nodes = element.childNodes;
84 for (var i = 0; i < nodes.length; i++) {
85 if (nodes[i].nodeType == 1 && nodes[i].tagName == 'DIV') {
86 this.build(nodes[i], 'subMenu');
87 subMenus.push(nodes[i]);
89 bodyContents.push(nodes[i]);
93 var bodyClass= className + 'Body';
94 var body = Builder.node('DIV', bodyContents);
95 this.classNames.addClassNames(body, bodyClass);
97 element.appendChild(body);
99 if (subMenus.length > 0) {
100 if (className == 'subMenu') {
101 var subMenu = Builder.node('DIV', [MenuBar.mark.dir]);
102 this.classNames.addClassNames(subMenu, 'dirMark');
103 body.appendChild(subMenu);
106 var container = Builder.node('DIV', subMenus);
107 this.classNames.addClassNames(container, 'subMenuContainer');
108 element.appendChild(container);
110 this.hide(container);
112 Event.observe(element, "click", this.onClick.bindAsEventListener(this, body));
115 onClick: function(event, menuBody) {
116 var menu = menuBody.parentNode;
117 var parentContainer = this.getParentContainer(menu);
119 var container = this.getContainer(menu);
120 var className = MenuBar.cssNames.menu;
121 if (Element.hasClassName(menu, className)) {
122 if (this.clicked.length > 0) {
123 this.hideAll(this.menubar);
126 if (container) this.showAtBottom(container, menuBody);
130 var lastMenuBody = this.clicked.pop();
131 var lastMenu = lastMenuBody.parentNode;
132 var lastContainer = this.getContainer(lastMenu);
133 var lastParentContainer = this.getParentContainer(lastMenu);
135 if (lastMenu == menu) {
136 this.hide(container);
138 } else if (Element.hasClassName(lastContainer, MenuBar.cssNames.container)) {
139 this.clicked.push(last);
141 } else if (lastParentContainer == parentContainer) {
142 this.hide(lastContainer);
145 this.clicked.push(lastMenuBody);
147 this.showAtLeft(container, menu);
148 } else if (this.options.hideOnClickSubmenu) {
149 this.hideAll(this.menubar);
153 if (container) this.clicked.push(menuBody);
157 showAtBottom: function(contents, menuBody) {
158 var offset = Position.positionedOffset(menuBody);
161 if (menuBody.style.height) height = Element.getHeight(menuBody);
162 else height = menuBody.clientHeight;
164 height += (document.all) ? 4 : 3;
166 contents.style.top = height + 'px';
167 contents.style.left = offset[0] + 'px';
172 showAtLeft: function(contents, menuBody) {
173 var offset = Position.positionedOffset(menuBody);
175 contents.style.top = (offset[1] - 1) + 'px';
176 contents.style.left = (offset[0] + menuBody.offsetWidth + 2) + 'px';
181 hideAllTrigger: function(element) {
182 return function(event) {
183 if (!this.isMenuElement(Event.element(event))) this.hideAll(element);
187 hideAll: function(element) {
188 var nodes = element.childNodes;
189 for (var i = 0; i < nodes.length; i++) {
190 if (nodes[i].nodeType == 1) {
191 if (Element.hasClassName(nodes[i], MenuBar.cssNames.subMenuContainer)) {
195 this.hideAll(nodes[i]);
200 show: function(element) {
201 element.style.visibility = 'visible';
204 hide: function(element) {
205 element.style.visibility = 'hidden';
208 getContainer: function(element) {
210 if (!element) return;
211 return document.getElementsByClassName(MenuBar.cssNames.subMenuContainer, element)[0];
214 getParentContainer: function(element) {
215 var container = Element.getParentByClassName(MenuBar.cssNames.subMenuContainer, element);
217 container = Element.getParentByClassName(MenuBar.cssNames.container, element);
223 isMenuElement: function(element) {
224 return Element.hasClassName(element, MenuBar.cssNames.menuBodyHover)
225 || Element.hasClassName(element, MenuBar.cssNames.subMenuBodyHover)
226 || Element.hasClassName(element, MenuBar.cssNames.dirMark);