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