6d7d84514bc446539f643edd6715a01a1ee6f284
[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 url;
227 var mod = record.name;
228 var relatedCard;
229 if (record.navigationComponentId) {
230 this.loadNavigationComponent(record.navigationComponentId);
231 TYPO3.Backend.NavigationDummy.hide();
232 TYPO3.Backend.NavigationIframe.getEl().parent().setStyle('overflow', 'auto');
233 } else if (record.navframe || record.navigationFrameScript) {
234 TYPO3.Backend.NavigationDummy.hide();
235 TYPO3.Backend.NavigationContainer.show();
236 this.loadNavigationComponent('typo3-navigationIframe');
237 this.openInNavFrame(record.navigationFrameScript || record.navframe, record.navigationFrameScriptParam);
238 TYPO3.Backend.NavigationIframe.getEl().parent().setStyle('overflow', 'hidden');
239 } else {
240 TYPO3.Backend.NavigationContainer.hide();
241 TYPO3.Backend.NavigationDummy.show();
242 }
243 relatedCard = Ext.getCmp('typo3-card-' + record.name);
244 if (relatedCard) {
245 // Check wether the panel is an iframe or not - if it is try to set the uri
246 if (relatedCard.getXType() == 'iframePanel') {
247 // Handle click on already opened module and evt. force reload
248 if ((Ext.getCmp('typo3-contentContainerWrapper').layout.activeItem.id == 'typo3-card-' + record.name)
249 || (relatedCard.getUrl() == 'about:blank')) {
250 url = record.originalLink;
251 Ext.getCmp('typo3-card-'+record.name).setUrl(url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : ''));
252 }
253 }
254 // Independed of the xtype activate the module
255 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem('typo3-card-' + record.name);
256 } else {
257 this.openInContentFrame(record.originalLink, params);
258 }
259 this.loadedModule = mod;
260 this.highlightModuleMenuItem(mod);
261
262 // compatibility
263 top.currentSubScript = record.originalLink;
264 top.currentModuleLoaded = mod;
265
266 TYPO3.Backend.doLayout();
267 },
268
269 includeId: function(mod, params) {
270 //get id
271 var section = mod.split('_')[0];
272 if (top.fsMod.recentIds[section]) {
273 params = 'id=' + top.fsMod.recentIds[section] + '&' + params;
274 }
275
276 return params;
277 },
278
279 loadNavigationComponent: function(navigationComponentId) {
280 if (navigationComponentId === this.loadedNavigationComponentId) {
281 if (TYPO3.Backend.NavigationContainer.hidden) {
282 TYPO3.Backend.NavigationContainer.show();
283 }
284
285 return;
286 }
287
288 if (this.loadedNavigationComponentId !== '') {
289 Ext.getCmp(this.loadedNavigationComponentId).hide();
290 }
291
292 var component = Ext.getCmp(navigationComponentId);
293 if (typeof component !== 'object') {
294 if (typeof this.availableNavigationComponents[navigationComponentId] !== 'function') {
295 throw 'The navigation component "' + navigationComponentId + '" is not available ' +
296 'or has no valid callback function';
297 }
298
299 component = this.availableNavigationComponents[navigationComponentId]();
300 TYPO3.Backend.NavigationContainer.add(component);
301 }
302
303 component.show()
304
305 // backwards compatibility
306 top.nav = component;
307
308 TYPO3.Backend.NavigationContainer.show();
309 this.loadedNavigationComponentId = navigationComponentId;
310 },
311
312 registerNavigationComponent: function(componentId, initCallback) {
313 this.availableNavigationComponents[componentId] = initCallback;
314 },
315
316 openInNavFrame: function(url, params) {
317 var navUrl = url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : '');
318 var currentUrl = this.relativeUrl(TYPO3.Backend.NavigationIframe.getUrl());
319 if (currentUrl !== navUrl) {
320 TYPO3.Backend.NavigationIframe.setUrl(navUrl);
321 }
322 },
323
324 openInContentFrame: function(url, params) {
325 var urlToLoad, relatedCard;
326
327 if (top.nextLoadModuleUrl) {
328 urlToLoad = top.nextLoadModuleUrl;
329 top.nextLoadModuleUrl = '';
330 } else {
331 urlToLoad = url + (params ? (url.indexOf('?') !== -1 ? '&' : '?') + params : '');
332 }
333 // Make shourtcut to card
334 relatedCard = Ext.getCmp('typo3-contentContainerWrapper').get('typo3-card-' + this.loadedModule);
335 // Decide where to load module, either in card or compatibility card
336 if (relatedCard) {
337 if (relatedCard.getXType() == 'iframePanel') {
338 relatedCard.setUrlIfChanged(urlToLoad);
339 }
340 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem('typo3-card-' + this.loadedModule);
341 } else {
342 TYPO3.Backend.ContentContainer.setUrl(urlToLoad);
343 Ext.getCmp('typo3-contentContainerWrapper').layout.setActiveItem(0);
344 }
345 },
346
347 highlightModuleMenuItem: function(module, mainModule) {
348 TYPO3.Backend.ModuleMenuContainer.getComponent('modDataView').select(module, false, false);
349 },
350
351 relativeUrl: function(url) {
352 return url.replace(TYPO3.configuration.siteUrl + 'typo3/', '');
353 },
354
355 refreshMenu: function() {
356 TYPO3.ModuleMenu.Store.load({
357 scope: this,
358 callback: function(records, options) {
359 this.renderMenu(records);
360 if (this.loadedModule) {
361 this.highlightModuleMenuItem(this.loadedModule);
362 }
363 }
364 });
365 },
366
367 reloadFrames: function() {
368 TYPO3.Backend.NavigationIframe.refresh();
369 TYPO3.Backend.ContentContainer.refresh();
370 }
371
372 };
373
374
375
376 Ext.onReady(function() {
377 TYPO3.ModuleMenu.App.init();
378
379 // keep backward compatibility
380 top.list = TYPO3.Backend.ContentContainer;
381 top.list_frame = top.list.getIframe();
382 top.nav_frame = TYPO3.Backend.NavigationContainer.PageTree;
383
384 top.TYPO3ModuleMenu = TYPO3.ModuleMenu.App;
385 top.content = {
386 nav_frame: TYPO3.Backend.NavigationContainer.PageTree,
387 list_frame: TYPO3.Backend.ContentContainer.getIframe(),
388 location: TYPO3.Backend.ContentContainer.getIframe().location,
389 document: TYPO3.Backend.ContentContainer.getIframe()
390 }
391 });
392
393
394 /*******************************************************************************
395 *
396 * Backwards compatability handling down here
397 *
398 ******************************************************************************/
399
400 /**
401 * Highlight module:
402 */
403 var currentlyHighLightedId = '';
404 var currentlyHighLighted_restoreValue = '';
405 var currentlyHighLightedMain = '';
406 function highlightModuleMenuItem(trId, mainModule) {
407 TYPO3.ModuleMenu.App.highlightModule(trId, mainModule);
408 }