3b662246300aeea9cb221f6fe1a2ee152b69a062
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / layout / js / typo3pageModule.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2010 Steffen Gebert <steffen@steffen-gebert.de>
5 * All rights reserved
6 *
7 * This script is part of the TYPO3 project. The TYPO3 project is
8 * free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The GNU General Public License can be found at
14 * http://www.gnu.org/copyleft/gpl.html.
15 * A copy is found in the textfile GPL.txt and important notices to the license
16 * from the author is found in LICENSE.txt distributed with these scripts.
17 *
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 Ext.ns('TYPO3', 'TYPO3.Components');
28
29 TYPO3.Components.PageModule = {
30 /**
31 * Initialization
32 */
33 init: function() {
34 this.enableHighlighting();
35 this.enableDragDrop();
36 },
37
38 /**
39 * This method is used to bind the higlighting function "setElementActive"
40 * to the mouseover event and the "setElementInactive" to the mouseout event.
41 */
42 enableHighlighting: function() {
43 Ext.select('div.t3-page-ce')
44 .on('mouseover',this.setElementActive, this)
45 .on('mouseout',this.setElementInactive, this);
46 Ext.select('td.t3-page-column')
47 .on('mouseover',this.setColumnActive, this)
48 .on('mouseout',this.setColumnInactive, this);
49 },
50
51 /**
52 * This method is used to unbind the higlighting function "setElementActive"
53 * from the mouseover event and the "setElementInactive" from the mouseout event.
54 */
55 disableHighlighting: function() {
56 Ext.select('div.t3-page-ce')
57 .un('mouseover', this.setElementActive, this)
58 .un('mouseout', this.setElementInactive, this);
59 Ext.select('td.t3-page-column')
60 .un('mouseover',this.setColumnActive, this)
61 .un('mouseout',this.setColumnInactive, this);
62 },
63
64 /**
65 * This method is used as an event handler when the
66 * user hovers the a content element.
67 */
68 setElementActive: function(event, target) {
69 Ext.get(target).findParent('div.t3-page-ce', null, true).addClass('active');
70 },
71
72 /**
73 * This method is used as event handler to unset active state of
74 * a content element when the mouse of the user leaves the
75 * content element.
76 */
77 setElementInactive: function(event, target) {
78 Ext.get(target).findParent('div.t3-page-ce', null, true).removeClass('active');
79
80 },
81
82 /**
83 * This method is used as an event handler when the
84 * user hovers the a content element.
85 */
86 setColumnActive: function(event, target) {
87 Ext.get(target).findParent('td.t3-page-column', null, true).addClass('active');
88 },
89
90 /**
91 * This method is used as event handler to unset active state of
92 * a content element when the mouse of the user leaves the
93 * content element.
94 */
95 setColumnInactive: function(event, target) {
96 Ext.get(target).findParent('td.t3-page-column', null, true).removeClass('active');
97 },
98
99 /**
100 * This method configures the drag'n'drop behavior in the page module
101 */
102 enableDragDrop: function() {
103 var overrides = {
104 // Called the instance the element is dragged.
105 b4StartDrag: function () {
106 // Cache the drag element
107 if (!this.el) {
108 this.el = Ext.get(this.getEl());
109 }
110
111 // Add css class for the drag shadow
112 this.el.child('.t3-page-ce-dragitem').addClass('dragitem-shadow');
113 // Hide create new element button
114 this.el.child('.t3-icon-document-new').addClass('drag-start');
115
116 // Cache the original XY Coordinates of the element, we'll use this later.
117 this.originalXY = this.el.getXY();
118
119 // Hide create new element button
120 this.el.findParent('td.t3-page-column', null, true).removeClass('active');
121 TYPO3.Components.PageModule.disableHighlighting();
122
123 var dropZones = Ext.select('.t3-page-ce-dropzone');
124 var self = this;
125 Ext.each(dropZones.elements, function(el) {
126 var dropZoneElement = Ext.get(el);
127 // Only highlight valid drop targets
128 if (dropZoneElement.id != self.el.prev().child('.t3-page-ce-dropzone').id &&
129 dropZoneElement.id != self.el.child('.t3-page-ce-dropzone').id) {
130 dropZoneElement.addClass('t3-page-ce-dropzone-available');
131 }
132 });
133 },
134 // Called when element is dropped not anything other than a dropzone with the same ddgroup
135 onInvalidDrop: function () {
136 // Set a flag to invoke the animated repair
137 this.invalidDrop = true;
138 },
139 // Called when the drag operation completes
140 endDrag: function () {
141 // Invoke the animation if the invalidDrop flag is set to true
142 if (this.invalidDrop === true) {
143 // Remove the drop invitation
144 this.el.removeClass('dropOK');
145
146 // Create the animation configuration object
147 var animCfgObj = {
148 easing:'easeOut',
149 duration:0.3,
150 scope:this,
151 callback: function () {
152 // Remove the position attribute
153 this.el.dom.style.position = '';
154 }
155 };
156
157 // Apply the repair animation
158 this.el.moveTo(this.originalXY[0], this.originalXY[1], animCfgObj);
159 delete this.invalidDrop;
160 }
161
162 var dropZones = Ext.select('.t3-page-ce-dropzone');
163 Ext.each(dropZones.elements, function(el) {
164 Ext.get(el).removeClass('t3-page-ce-dropzone-available');
165 });
166
167 // Remove dragitem-shadow after dragging
168 this.el.child('.t3-page-ce-dragitem').removeClass('dragitem-shadow');
169 // Show create new element button again
170 this.el.child('.t3-icon-document-new').removeClass('drag-start');
171 TYPO3.Components.PageModule.enableHighlighting();
172
173 // Remove dragitem-shadow after dragging
174 this.el.child('.t3-page-ce-dragitem').removeClass('dragitem-shadow');
175 },
176
177 // Called upon successful drop of an element on a DDTarget with the same
178 onDragDrop: function (evtObj, targetElId) {
179 // Wrap the drop target element with Ext.Element
180 var dropEl = Ext.get(targetElId);
181
182 // Perform the node move only if not dropped on the dropzone directly above
183 // this element
184 if (this.el.prev().child('.t3-page-ce-dropzone').id != targetElId &&
185 targetElId != this.el.child('.t3-page-ce-dropzone').id) {
186
187 // Remove the drag invitation
188 this.onDragOut(evtObj, targetElId);
189
190 // Add height to drop zone
191 var oldHeight = dropEl.getHeight();
192 var elementNewY = dropEl.getY() + dropEl.getHeight();
193 dropEl.setHeight(dropEl.getHeight() + this.el.getHeight(), true);
194
195 // Create the animation configuration object
196 var animCfgObj = {
197 easing: 'easeOut',
198 duration: 0.3,
199 scope: this,
200 callback: function () {
201
202 // restore dropzone height
203 // animation is necessary to let it work.
204 dropEl.setHeight(oldHeight, {duration: 0.1});
205
206 // Move the element
207 dropEl.parent().insertSibling(this.el, 'after');
208
209 // Clear the styles
210 this.el.dom.style.position = '';
211 this.el.dom.style.top = '';
212 this.el.dom.style.left = '';
213 }
214 };
215
216 // Animate to new position
217 this.el.moveTo(dropEl.getX(), elementNewY, animCfgObj);
218
219 // Show create new element button again
220 dropEl.findParent('td.t3-page-column', null, true).addClass('active');
221
222 // Try to save changes to the backend
223 // There is no feedback from the server side functions, just hope for the best
224 TYPO3.Components.DragAndDrop.CommandController.moveContentElement(
225 this.el.id,
226 targetElId,
227 dropEl.parent().id,
228 this
229 );
230
231 } else {
232 // This was an invalid drop, initiate a repair
233 this.onInvalidDrop();
234 }
235 },
236 // Only called when the drag element is dragged over the a drop target with the same ddgroup
237 onDragEnter: function (evtObj, targetElId) {
238 // Perform the node move only if not dropped on the dropzone directly above
239 // this element
240 if (targetElId != this.el.prev().child('.t3-page-ce-dropzone').id &&
241 targetElId != this.el.child('.t3-page-ce-dropzone').id) {
242 this.el.addClass('dropOK');
243 Ext.get(targetElId).addClass('dropReceiveOK');
244 } else {
245 // Remove the invitation
246 this.onDragOut();
247 }
248 },
249 // Only called when element is dragged out of a dropzone with the same ddgroup
250 onDragOut: function (evtObj, targetElId) {
251 this.el.removeClass('dropOK');
252 if (targetElId) {
253 Ext.get(targetElId).removeClass('dropReceiveOK');
254 }
255 },
256
257 /**
258 * Evaluates a response from an ext direct call and shows a flash message
259 * if it was an exceptional result
260 *
261 * @param {Object} response
262 * @return {Boolean}
263 */
264 evaluateResponse: function (response) {
265 if (response.success === false) {
266 TYPO3.Flashmessage.display(4, 'Exception', response.message);
267 return false;
268 }
269
270 return true;
271 }
272 };
273
274 var contentElements = Ext.select('.t3-page-ce');
275 Ext.each(contentElements.elements, function (el) {
276 if (Ext.DomQuery.is(el, 'div:has(.t3-page-ce-dragitem)')) {
277 var dd = new Ext.dd.DD(el, 'ceDDgroup', {
278 isTarget : false
279 });
280 // Apply overrides to newly created instance
281 Ext.apply(dd, overrides);
282 }
283 });
284
285 // Find dropzones and add them to the group
286 var dropZones = Ext.select('.t3-page-ce-dropzone');
287 Ext.each(dropZones.elements, function(el) {
288 var dropTarget = new Ext.dd.DDTarget(el, 'ceDDgroup');
289 });
290 }
291 }
292
293 Ext.onReady(function() {
294 TYPO3.Components.PageModule.init();
295 });