228e55b6cd48ccc2bc7b0900d07d5ead1644610c
[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, but align it to the left side of the viewport if it does not fit completely
141 if (dimsWindow.width - dims.width < relative.X) {
142 if (relative.X > dims.width) {
143 x -= (dims.width - 10);
144 } else if ((dimsWindow.width - dims.width - relative.X) < offset.left) {
145 x = offset.left;
146 }
147 else {
148 x += (dimsWindow.width - dims.width - relative.X);
149 }
150 }
151
152 obj.style.left = x + 'px';
153 obj.style.top = y + 'px';
154 Element.show(obj);
155 }
156 if (/MSIE5/.test(navigator.userAgent)) {
157 this._toggleSelectorBoxes('hidden');
158 }
159 },
160
161 /**
162 * event handler function that saves the actual position of the mouse
163 * in the Clickmenu object
164 * @param event the event object
165 */
166 calcMousePosEvent: function(event) {
167 if (!event) {
168 event = window.event;
169 }
170 this.mousePos.X = Event.pointerX(event);
171 this.mousePos.Y = Event.pointerY(event);
172 this.mouseOutFromMenu('contentMenu0');
173 this.mouseOutFromMenu('contentMenu1');
174 },
175
176
177 /**
178 * hides a visible menu if the mouse has moved outside
179 * of the object
180 * @param obj the object to hide
181 * @result nothing
182 */
183 mouseOutFromMenu: function(obj) {
184 obj = $(obj);
185 if (obj && Element.visible(obj) && !Position.within(obj, this.mousePos.X, this.mousePos.Y)) {
186 this.hide(obj);
187 if (/MSIE5/.test(navigator.userAgent) && obj.id == 'contentMenu0') {
188 this._toggleSelectorBoxes('visible');
189 }
190 }
191 },
192
193 /**
194 * hides a clickmenu
195 *
196 * @param obj the clickmenu object to hide
197 * @result nothing
198 */
199 hide: function(obj) {
200 Element.hide(obj);
201 },
202
203 /**
204 * hides all clickmenus
205 */
206 hideAll: function() {
207 this.hide('contentMenu0');
208 this.hide('contentMenu1');
209 },
210
211
212 /**
213 * hides / displays all selector boxes in a page, fixes an IE 5 selector problem
214 * originally by Michiel van Leening
215 *
216 * @param action hide (= "hidden") or show (= "visible")
217 * @result nothing
218 */
219 _toggleSelectorBoxes: function(action) {
220 for (i = 0; i < document.forms.length; i++) {
221 for (j = 0; j < document.forms[i].elements.length; j++) {
222 if (document.forms[i].elements[j].type == 'select-one') {
223 document.forms[i].elements[j].style.visibility = action;
224 }
225 }
226 }
227 },
228
229
230 /**
231 * manipulates the DOM to add the divs needed for clickmenu at the bottom of the <body>-tag
232 *
233 * @return nothing
234 */
235 addClickmenuItem: function() {
236 var code = '<div id="contentMenu0" style="display: block;"></div><div id="contentMenu1" style="display: block;"></div>';
237 new Insertion.Bottom(document.getElementsByTagName('body')[0], code);
238 }
239 }
240
241 // register mouse movement inside the document
242 Event.observe(document, 'mousemove', Clickmenu.calcMousePosEvent.bindAsEventListener(Clickmenu), true);
243
244
245 // deprecated functions since 4.2, here for compatibility, remove in 4.4
246 function showClickmenu(table, uid, listFr, enDisItems, backPath, addParams) {
247 Clickmenu.show(table, uid, listFr, enDisItems, backPath, addParams);
248 }
249
250 function showClickmenu_raw(url) {
251 var parts = url.split('?');
252 if (parts.length == 2) {
253 Clickmenu.clickURL = parts[0];
254 Clickmenu.callURL(parts[1]);
255 } else {
256 Clickmenu.callURL(url);
257 }
258 }
259 function showClickmenu_noajax(url) {
260 Clickmenu.ajax = false; showClickmenu_raw(url);
261 }
262 function setLayerObj(tableData, cmLevel) {
263 Clickmenu.populateData(tableData, cmLevel);
264 }
265 function hideEmpty() {
266 Clickmenu.hideAll();
267 return false;
268 }
269 function hideSpecific(level) {
270 if (level == 0 || level == 1) {
271 Clickmenu.hide('contentMenu'+level);
272 }
273 }
274 function showHideSelectorBoxes(action) {
275 toggleSelectorBoxes(action);
276 }