ce02b248642825b695aa790c85126e33b8322f09
[Packages/TYPO3.CMS.git] / typo3 / js / modulemenu.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2010-2011 Steffen Kamper <steffen@typo3.org>
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
28 /**
29 * Class to render the module menu and handle the BE navigation
30 *
31 * @author Steffen Kamper
32 */
33
34
35 Ext.ns('TYPO3', 'ModuleMenu');
36
37 TYPO3.ModuleMenu = {};
38
39 TYPO3.ModuleMenu.Store = new Ext.data.JsonStore({
40 storeId: 'ModuleMenuStore',
41 root: 'root',
42 fields: [
43 {name: 'index', type: 'int', mapping: 'sub.index'},
44 {name: 'key', type: 'string'},
45 {name: 'label', type: 'string'},
46 {name: 'menuState', type: 'int'},
47 {name: 'subitems', type: 'int'},
48 'sub'
49 ],
50 url: 'ajax.php?ajaxID=ModuleMenu::getData',
51 baseParams: {
52 'action': 'getModules'
53 }
54
55 });
56
57 TYPO3.ModuleMenu.Template = new Ext.XTemplate(
58 '<div id="typo3-docheader">',
59 ' <div id="typo3-docheader-row1">',
60 ' <div class="buttonsleft"></div>',
61 ' <div class="buttonsright"></div>',
62 ' </div>',
63 '</div>',
64 '<ul id="typo3-menu">',
65 '<tpl for=".">',
66 ' <li class="menuSection" id="{key}">',
67 ' <div class="modgroup {[this.getStateClass(values)]}">{label}</div>',
68 ' <ul {[this.getStateStyle(values)]}>',
69 ' <tpl for="sub">',
70 ' <li id="{name}" class="submodule mod-{name}">',
71 ' <a title="{description}" href="#" class="modlink">',
72 ' <span class="submodule-icon">',
73 ' <img width="16" height="16" alt="{label}" title="{label}" src="{icon}" />',
74 ' </span>',
75 ' <span>{label}</span>',
76 ' </a>',
77 ' </li>',
78 ' </tpl>',
79 ' </ul>',
80 ' </li>',
81 '</tpl>',
82 '</ul>',
83 {
84 getStateClass: function(value) {
85 return value.menuState ? 'collapsed' : 'expanded';
86 },
87 getStateStyle: function(value) {
88 return value.menuState ? 'style="display:none"' : '';
89 }
90 }
91 );
92
93 TYPO3.ModuleMenu.App = {
94 loadedModule: null,
95 loadedNavigationComponentId: '',
96 availableNavigationComponents: {},
97
98 init: function() {
99 TYPO3.ModuleMenu.Store.load({
100 scope: this,
101 callback: function(records, options) {
102 this.renderMenu(records);
103 if (top.startInModule) {
104 this.showModule(top.startInModule[0], top.startInModule[1]);
105 } else {
106 this.loadFirstAvailableModule();
107 }
108 }
109 });
110 },
111
112 renderMenu: function(records) {
113 TYPO3.Backend.ModuleMenuContainer.removeAll();
114 TYPO3.Backend.ModuleMenuContainer.add({
115 xtype: 'dataview',
116 animCollapse: true,
117 store: TYPO3.ModuleMenu.Store,
118 tpl: TYPO3.ModuleMenu.Template,
119 singleSelect: true,
120 itemSelector: 'li.submodule',
121 overClass: 'x-view-over',
122 selectedClass: 'highlighted',
123 autoHeight: true,
124 itemId: 'modDataView',
125 tbar: [{text: 'test'}],
126 listeners: {
127 click: function(view, index, node, event) {
128 var el = Ext.fly(node);
129 if (el.hasClass('submodule')) {
130 TYPO3.ModuleMenu.App.showModule(el.getAttribute('id'));
131 }
132 },
133 containerclick: function(view, event) {
134 var item = event.getTarget('li.menuSection', view.getEl());
135 if (item) {
136 var el = Ext.fly(item);
137 var id = el.getAttribute('id');
138 var section = el.first('div'), state;
139 if (section.hasClass('expanded')) {
140 state = true;
141 section.removeClass('expanded').addClass('collapsed');
142 el.first('ul').slideOut('t', {
143 easing: 'easeOut',
144 duration: .2,
145 remove: false,
146 useDisplay: true
147 });
148
149 } else {
150 state = false;
151 section.removeClass('collapsed').addClass('expanded');
152 el.first('ul').slideIn('t', {
153 easing: 'easeIn',
154 duration: .2,
155 remove: false,
156 useDisplay: true
157 });
158 }
159 // save menu state
160 Ext.Ajax.request({
161 url: 'ajax.php?ajaxID=ModuleMenu::saveMenuState',
162 params: {
163 'menuid': 'modmenu_' + id,
164 'state': state
165 }
166 });
167 }
168 return false;
169 },
170 scope: this
171 }
172 });
173 TYPO3.Backend.ModuleMenuContainer.doLayout();
174 },
175
176 getRecordFromIndex: function(index) {
177 var i, record;
178 for (i = 0; i < TYPO3.ModuleMenu.Store.getCount(); i++) {
179 record = TYPO3.ModuleMenu.Store.getAt(i);
180 if (index < record.data.subitems) {
181 return record.data.sub[index];
182 }
183 index -= record.data.subitems;
184 }
185 },
186
187 getRecordFromName: function(name) {
188 var i, j, record;
189 for (i = 0; i < TYPO3.ModuleMenu.Store.getCount(); i++) {
190 record = TYPO3.ModuleMenu.Store.getAt(i);
191 for (j = 0; j < record.data.subitems; j++) {
192 if (record.data.sub[j].name === name) {
193 return record.data.sub[j];
194 }
195 }
196 }
197 },
198
199 showModule: function(mod, params) {
200 params = params || '';
201 this.selectedModule = mod;
202
203 params = this.includeId(mod, params);
204 var record = this.getRecordFromName(mod);
205
206 if (record) {
207 this.loadModuleComponents(record, params);
208 } else {
209 //defined startup module is not present, use the first available instead
210 this.loadFirstAvailableModule(params);
211 }
212 },
213
214 loadFirstAvailableModule: function(params) {
215 params = params || '';
216 if (TYPO3.ModuleMenu.Store.getCount() === 0) {
217 // Store is empty, something went wrong
218 TYPO3.Flashmessage.display(TYPO3.Severity.error, 'Module loader', 'No module found. If this is a temporary error, please reload the Backend!', 50000);
219 } else {
220 mod = TYPO3.ModuleMenu.Store.getAt(0).data.sub[0];
221 this.loadModuleComponents(mod, params);
222 }
223 },
224
225 loadModuleComponents: function(record, params) {
226 var mod = record.name;
227 if (record.navigationComponentId) {
228 this.loadNavigationComponent(record.navigationComponentId);
229 TYPO3.Backend.NavigationDummy.hide();
230 TYPO3.Backend.NavigationIframe.getEl().parent().setStyle('overflow', 'auto');
231 } else if (record.navframe || record.navigationFrameScript) {
232 TYPO3.Backend.NavigationDummy.hide();
233 TYPO3.Backend.NavigationContainer.show();
234 this.loadNavigationComponent('typo3-navigationIframe');
235 this.openInNavFrame(record.navigationFrameScript || record.navframe, record.navigationFrameScriptParam);
236 TYPO3.Backend.NavigationIframe.getEl().parent().setStyle('overflow', 'hidden');
237 } else {
238 TYPO3.Backend.NavigationContainer.hide();
239 TYPO3.Backend.NavigationDummy.show();
240 }
241 if (Ext.getCmp('typo3-card-' + record.name)) {
242 // Check wether the panel is an iframe or not - if it is try to set the uri
243 if (Ext.getCmp('typo3-card-' + record.name).getXType() == 'iframePanel') {
244 // Handle click on already opened module and evt. force reload
245 if (Ext.getCmp('typo3-contentContainerWrapper').layout.activeItem.id == 'typo3-card-' + record.name) {
246 Ext.getCmp('typo3-card-'+record.name).setUrl(url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : ''));
247 } else {
248 url = record.originalLink;
249 Ext.getCmp('typo3-card-'+record.name).setUrlIfChanged(url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : ''));
250 }
251 }
252 // Independed of the xtype activate the module
253 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem('typo3-card-' + record.name);
254 } else {
255 this.openInContentFrame(record.originalLink, params);
256 }
257 this.loadedModule = mod;
258 this.highlightModuleMenuItem(mod);
259
260 // compatibility
261 top.currentSubScript = record.originalLink;
262 top.currentModuleLoaded = mod;
263
264 TYPO3.Backend.doLayout();
265 },
266
267 includeId: function(mod, params) {
268 //get id
269 var section = mod.split('_')[0];
270 if (top.fsMod.recentIds[section]) {
271 params = 'id=' + top.fsMod.recentIds[section] + '&' + params;
272 }
273
274 return params;
275 },
276
277 loadNavigationComponent: function(navigationComponentId) {
278 if (navigationComponentId === this.loadedNavigationComponentId) {
279 if (TYPO3.Backend.NavigationContainer.hidden) {
280 TYPO3.Backend.NavigationContainer.show();
281 }
282
283 return;
284 }
285
286 if (this.loadedNavigationComponentId !== '') {
287 Ext.getCmp(this.loadedNavigationComponentId).hide();
288 }
289
290 var component = Ext.getCmp(navigationComponentId);
291 if (typeof component !== 'object') {
292 if (typeof this.availableNavigationComponents[navigationComponentId] !== 'function') {
293 throw 'The navigation component "' + navigationComponentId + '" is not available ' +
294 'or has no valid callback function';
295 }
296
297 component = this.availableNavigationComponents[navigationComponentId]();
298 TYPO3.Backend.NavigationContainer.add(component);
299 }
300
301 component.show()
302
303 // backwards compatibility
304 top.nav = component;
305
306 TYPO3.Backend.NavigationContainer.show();
307 this.loadedNavigationComponentId = navigationComponentId;
308 },
309
310 registerNavigationComponent: function(componentId, initCallback) {
311 this.availableNavigationComponents[componentId] = initCallback;
312 },
313
314 openInNavFrame: function(url, params) {
315 var navUrl = url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : '');
316 var currentUrl = this.relativeUrl(TYPO3.Backend.NavigationIframe.getUrl());
317 if (currentUrl !== navUrl) {
318 TYPO3.Backend.NavigationIframe.setUrl(navUrl);
319 }
320 },
321
322 openInContentFrame: function(url, params) {
323 if (top.nextLoadModuleUrl) {
324 urlToLoad = top.nextLoadModuleUrl;
325 top.nextLoadModuleUrl = '';
326 } else {
327 urlToLoad = url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : '');
328 }
329 // Make shourtcut to card
330 relatedCard = Ext.getCmp('typo3-contentContainerWrapper').get('typo3-card-' + this.loadedModule);
331 // Decide where to load module, either in card or compatibility card
332 if (relatedCard) {
333 if (relatedCard.getXType() == 'iframePanel') {
334 relatedCard.setUrlIfChanged(urlToLoad);
335 }
336 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem('typo3-card-' + this.loadedModule);
337 } else {
338 TYPO3.Backend.ContentContainer.setUrl(urlToLoad);
339 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem(0);
340 }
341 },
342
343 highlightModuleMenuItem: function(module, mainModule) {
344 TYPO3.Backend.ModuleMenuContainer.getComponent('modDataView').select(module, false, false);
345 },
346
347 relativeUrl: function(url) {
348 return url.replace(TYPO3.configuration.siteUrl + 'typo3/', '');
349 },
350
351 refreshMenu: function() {
352 TYPO3.ModuleMenu.Store.load({
353 scope: this,
354 callback: function(records, options) {
355 this.renderMenu(records);
356 if (this.loadedModule) {
357 this.highlightModuleMenuItem(this.loadedModule);
358 }
359 }
360 });
361 },
362
363 reloadFrames: function() {
364 TYPO3.Backend.NavigationIframe.refresh();
365 TYPO3.Backend.ContentContainer.refresh();
366 }
367
368 };
369
370
371
372 Ext.onReady(function() {
373 TYPO3.ModuleMenu.App.init();
374
375 // keep backward compatibility
376 top.list = TYPO3.Backend.ContentContainer;
377 top.list_frame = top.list.getIframe();
378 top.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
379
380 top.TYPO3ModuleMenu = TYPO3.ModuleMenu.App;
381 top.content = {
382 nav_frame: TYPO3.Backend.NavigationContainer.PageTree,
383 list_frame: TYPO3.Backend.ContentContainer.getIframe(),
384 location: TYPO3.Backend.ContentContainer.getIframe().location,
385 document: TYPO3.Backend.ContentContainer.getIframe()
386 }
387 });
388
389
390 /*******************************************************************************
391 *
392 * Backwards compatability handling down here
393 *
394 ******************************************************************************/
395
396 /**
397 * Highlight module:
398 */
399 var currentlyHighLightedId = '';
400 var currentlyHighLighted_restoreValue = '';
401 var currentlyHighLightedMain = '';
402 function highlightModuleMenuItem(trId, mainModule) {
403 TYPO3.ModuleMenu.App.highlightModule(trId, mainModule);
404 }