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