d29a6ef2418c919855c1a1809e05a933f22e198e
[Packages/TYPO3.CMS.git] / typo3 / js / clickmenu.js
1 /**
2 * Javascript functions regarding the clickmenu
3 * relies on the javascript library "prototype"
4 *
5 * (c) 2007 Benjamin Mack <www.xnos.org>
6 * All rights reserved
7 *
8 * This script is part of TYPO3 by
9 * Kasper Skaarhoj <kasperYYYYY@typo3.com>
10 *
11 * Released under GNU/GPL (see license file in tslib/)
12 *
13 * This script is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * This copyright notice MUST APPEAR in all copies of this script
18 */
19
20
21 /**
22 * extends the window object to get cross-browser window dimensions
23 *
24 * @return an object with a width and height property
25 */
26 window.getDimensions = function() {
27 var w = window.innerWidth
28 || document.documentElement.clientWidth
29 || document.body.clientWidth
30 || 0;
31 var h = window.innerHeight
32 || document.documentElement.clientHeight
33 || document.body.clientHeight
34 || 0;
35 return { width: w, height: h };
36 }
37
38
39 /**
40 * extends prototype's Position object
41 *
42 * @return an object with a top and a left position property
43 */
44 Position.getScrollOffset = function() {
45 this.prepare();
46 return { top: this.deltaY, left: this.deltaX };
47 }
48
49 /**
50 * new clickmenu code to make an AJAX call and render the
51 * AJAX result in a layer next to the mouse cursor
52 */
53 var Clickmenu = {
54 clickURL: 'alt_clickmenu.php', // URL to the clickmenu.php file, see template.php
55 ajax: true, // template.php -> isCMLayers check
56 mousePos: { X: null, Y: null },
57
58
59 /**
60 * main function, called from most clickmenu links
61 * @param table table from where info should be fetched
62 * @param uid the UID of the item
63 * @param listFr list Frame?
64 * @param enDisItems Items to disable / enable
65 * @param backPath TYPO3 backPath
66 * @param addParams additional params
67 * @return nothing
68 */
69 show: function(table, uid, listFr, enDisItems, backPath, addParams) {
70 var params = 'table=' + encodeURIComponent(table)
71 + '&uid=' + uid
72 + '&listFr=' + listFr
73 + '&enDisItems=' + enDisItems
74 + '&backPath=' + backPath
75 + '&addParams=' + addParams;
76 this.callURL(params);
77 },
78
79
80 /**
81 * switch function that either makes an AJAX call
82 * or loads the request in the top frame
83 *
84 * @param params parameters added to the URL
85 * @return nothing
86 */
87 callURL: function(params) {
88 if (this.ajax && Ajax.getTransport()) { // run with AJAX
89 params += '&ajax=1';
90 new Ajax.Request(this.clickURL, {
91 method: 'get',
92 parameters: params,
93 onComplete: function(xhr) {
94 var response = xhr.responseXML;
95 if (!response.getElementsByTagName('data')[0]) return;
96 var menu = response.getElementsByTagName('data')[0].getElementsByTagName('clickmenu')[0];
97 var data = menu.getElementsByTagName('htmltable')[0].firstChild.data;
98 var level = menu.getElementsByTagName('cmlevel')[0].firstChild.data;
99 this.populateData(data, level);
100 }.bind(this)
101 });
102 } else { // fallback with no AJAX, no isCMLayers
103 top.loadTopMenu(this.clickURL + '?' + params);
104 }
105 },
106
107
108 /**
109 * fills the clickmenu with content and displays it correctly
110 * depending on the mouse position
111 * @param data the data that will be put in the menu
112 * @param level the depth of the clickmenu
113 */
114 populateData: function(data, level) {
115 if (!$('contentMenu0')) this.addClickmenuItem();
116 level = parseInt(level) || 0;
117 var obj = $('contentMenu' + level);
118
119 if (obj && (level == 0 || Element.visible('contentMenu' + (level-1)))) {
120 obj.innerHTML = data;
121 var x = this.mousePos.X;
122 var y = this.mousePos.Y;
123 var dimsWindow = window.getDimensions();
124 dimsWindow.width = dimsWindow.width-20; // saving margin for scrollbars
125
126 var dims = Element.getDimensions(obj); // dimensions for the clickmenu
127 var offset = Position.getScrollOffset();
128 var relative = { X: this.mousePos.X - offset.left, Y: this.mousePos.Y - offset.top };
129
130 // adjusting the Y position of the layer to fit it into the window frame
131 // if there is enough space above then put it upwards,
132 // otherwise adjust it to the bottom of the window
133 if (dimsWindow.height - dims.height < relative.Y) {
134 if (relative.Y > dims.height) {
135 y -= (dims.height - 10);
136 } else {
137 y += (dimsWindow.height - dims.height - relative.Y);
138 }
139 }
140 // adjusting the X position like Y above
141 if (dimsWindow.width - dims.width < relative.X) {
142 if (relative.X > dims.width) {
143 x -= (dims.width - 10);
144 } else {
145 x += (dimsWindow.width - dims.width - relative.X);
146 }
147 }
148
149 obj.style.left = x + 'px';
150 obj.style.top = y + 'px';
151 Element.show(obj);
152 }
153 if (/MSIE5/.test(navigator.userAgent)) {
154 this._toggleSelectorBoxes('hidden');
155 }
156 },
157
158 /**
159 * event handler function that saves the actual position of the mouse
160 * in the Clickmenu object
161 * @param event the event object
162 */
163 calcMousePosEvent: function(event) {
164 if (!event) {
165 event = window.event;
166 }
167 this.mousePos.X = Event.pointerX(event);
168 this.mousePos.Y = Event.pointerY(event);
169 this.mouseOutFromMenu('contentMenu0');
170 this.mouseOutFromMenu('contentMenu1');
171 },
172
173
174 /**
175 * hides a visible menu if the mouse has moved outside
176 * of the object
177 * @param obj the object to hide
178 * @result nothing
179 */
180 mouseOutFromMenu: function(obj) {
181 obj = $(obj);
182 if (obj && Element.visible(obj) && !Position.within(obj, this.mousePos.X, this.mousePos.Y)) {
183 this.hide(obj);
184 if (/MSIE5/.test(navigator.userAgent) && obj.id == 'contentMenu0') {
185 this._toggleSelectorBoxes('visible');
186 }
187 }
188 },
189
190 /**
191 * hides a clickmenu
192 *
193 * @param obj the clickmenu object to hide
194 * @result nothing
195 */
196 hide: function(obj) {
197 Element.hide(obj);
198 },
199
200 /**
201 * hides all clickmenus
202 */
203 hideAll: function() {
204 this.hide('contentMenu0');
205 this.hide('contentMenu1');
206 },
207
208
209 /**
210 * hides / displays all selector boxes in a page, fixes an IE 5 selector problem
211 * originally by Michiel van Leening
212 *
213 * @param action hide (= "hidden") or show (= "visible")
214 * @result nothing
215 */
216 _toggleSelectorBoxes: function(action) {
217 for (i = 0; i < document.forms.length; i++) {
218 for (j = 0; j < document.forms[i].elements.length; j++) {
219 if (document.forms[i].elements[j].type == 'select-one') {
220 document.forms[i].elements[j].style.visibility = action;
221 }
222 }
223 }
224 },
225
226
227 /**
228 * manipulates the DOM to add the divs needed for clickmenu at the bottom of the <body>-tag
229 *
230 * @return nothing
231 */
232 addClickmenuItem: function() {
233 var code = '<div id="contentMenu0" style="display: block;"></div><div id="contentMenu1" style="display: block;"></div>';
234 new Insertion.Bottom(document.getElementsByTagName('body')[0], code);
235 }
236 }
237
238 // register mouse movement inside the document
239 Event.observe(document, 'mousemove', Clickmenu.calcMousePosEvent.bindAsEventListener(Clickmenu), true);
240
241
242 // deprecated functions since 4.2, here for compatibility, remove in 4.4
243 function showClickmenu(table, uid, listFr, enDisItems, backPath, addParams) {
244 Clickmenu.show(table, uid, listFr, enDisItems, backPath, addParams);
245 }
246
247 function showClickmenu_raw(url) {
248 var parts = url.split('?');
249 if (parts.length == 2) {
250 Clickmenu.clickURL = parts[0];
251 Clickmenu.callURL(parts[1]);
252 } else {
253 Clickmenu.callURL(url);
254 }
255 }
256 function showClickmenu_noajax(url) {
257 Clickmenu.ajax = false; showClickmenu_raw(url);
258 }
259 function setLayerObj(tableData, cmLevel) {
260 Clickmenu.populateData(tableData, cmLevel);
261 }
262 function hideEmpty() {
263 Clickmenu.hideAll();
264 return false;
265 }
266 function hideSpecific(level) {
267 if (level == 0 || level == 1) {
268 Clickmenu.hide('contentMenu'+level);
269 }
270 }
271 function showHideSelectorBoxes(action) {
272 toggleSelectorBoxes(action);
273 }