Commit b185823cc64cf068ca684591a59cee41f65bc534
1 parent
9cd58692
Exists in
master
and in
111 other branches
Use IntervalUI module, code refactoring, add comments on .js files.
Showing
5 changed files
with
986 additions
and
691 deletions
Show diff stats
js/app/AmdaApp.js
1 | -/** | |
1 | +/** | |
2 | 2 | * Project : AMDA-NG4 |
3 | 3 | * Name : AmdaApp.js |
4 | - * @class amdaApp.AmdaApp | |
4 | + * @class amdaApp.AmdaApp | |
5 | 5 | * @extends Ext.ux.desktop.App |
6 | 6 | * @brief Main class defining Amda Desktop and its Modules |
7 | 7 | * @author Ext JS Library 4.0 Copyright(c) 2006-2011 Sencha Inc. licensing@sencha.com |
8 | 8 | */ |
9 | 9 | |
10 | - | |
10 | + | |
11 | 11 | Ext.define('amdaApp.AmdaApp', { |
12 | 12 | extend: 'Ext.ux.desktop.App', |
13 | 13 | |
14 | - requires: [ | |
14 | + requires: [ | |
15 | 15 | 'Ext.window.MessageBox', |
16 | 16 | 'Ext.ux.desktop.ShortcutModel', |
17 | 17 | 'amdaUI.SampToolBarUI', |
18 | 18 | 'amdaDesktop.DynamicModule', |
19 | 19 | 'MyDesktop.Settings' |
20 | 20 | ], |
21 | - | |
21 | + | |
22 | 22 | dynamicModules: { |
23 | 23 | visu : { |
24 | 24 | id : 'visu-win', |
... | ... | @@ -26,7 +26,7 @@ Ext.define('amdaApp.AmdaApp', { |
26 | 26 | title : 'Visualization', |
27 | 27 | source : 'amdaDesktop.VisuModule', |
28 | 28 | useLauncher : true |
29 | - }, | |
29 | + }, | |
30 | 30 | statistics : { |
31 | 31 | id : 'statistics-win', |
32 | 32 | icon : 'icon-statistics', |
... | ... | @@ -97,22 +97,22 @@ Ext.define('amdaApp.AmdaApp', { |
97 | 97 | source : 'amdaDesktop.InteropModule', |
98 | 98 | useLauncher : true |
99 | 99 | }, |
100 | - epntap : { | |
101 | - id : 'epntap-win', | |
102 | - icon : 'icon-epntap', | |
103 | - title : 'EPN-TAP data', | |
104 | - source : 'amdaDesktop.EpnTapModule', | |
105 | - useLauncher : true | |
106 | - }, | |
100 | + epntap : { | |
101 | + id : 'epntap-win', | |
102 | + icon : 'icon-epntap', | |
103 | + title : 'EPN-TAP data', | |
104 | + source : 'amdaDesktop.EpnTapModule', | |
105 | + useLauncher : true | |
106 | + }, | |
107 | 107 | info : { |
108 | 108 | id : 'info-win', |
109 | 109 | icon : 'icon-information', |
110 | 110 | title : 'About AMDA', |
111 | 111 | source : 'amdaDesktop.AboutModule', |
112 | 112 | useLauncher : false |
113 | - }, | |
113 | + }, | |
114 | 114 | explorer : { |
115 | - id : 'explorer-win', | |
115 | + id : 'explorer-win', | |
116 | 116 | icon : 'icon-elements', |
117 | 117 | title : 'Workspace Explorer', |
118 | 118 | source : 'amdaDesktop.ExplorerModule', |
... | ... | @@ -162,13 +162,13 @@ Ext.define('amdaApp.AmdaApp', { |
162 | 162 | useLauncher : false |
163 | 163 | } |
164 | 164 | }, |
165 | - | |
166 | -// IDs of Modules working with parameters; used in Alias Node | |
165 | + | |
166 | +// IDs of Modules working with parameters; used in Alias Node | |
167 | 167 | paramModulesID : ['plot-win', 'param-win', 'search-win', 'down-win'], |
168 | - | |
168 | + | |
169 | 169 | // Important system constants |
170 | 170 | MAX_UPLOADED_FILE_SIZE : 30000000, // 30MB |
171 | - | |
171 | + | |
172 | 172 | listeners : { |
173 | 173 | scope : this, |
174 | 174 | beforeunload : function () |
... | ... | @@ -179,19 +179,19 @@ Ext.define('amdaApp.AmdaApp', { |
179 | 179 | interopModule.forceSampDisconnect(); |
180 | 180 | return true; |
181 | 181 | }, |
182 | - ready : function () | |
182 | + ready : function () | |
183 | 183 | { |
184 | 184 | //AKKA - Clean user WS |
185 | 185 | AmdaAction.cleanUserWS(function(res,e){},this); |
186 | 186 | } |
187 | 187 | }, |
188 | - | |
188 | + | |
189 | 189 | init: function() { |
190 | 190 | // custom logic before getXYZ methods get called... |
191 | 191 | |
192 | 192 | this.callParent(); |
193 | 193 | |
194 | - // now ready... | |
194 | + // now ready... | |
195 | 195 | //override createWindow method of desktop |
196 | 196 | Ext.override(Ext.ux.desktop.Desktop, { |
197 | 197 | createWindow: function (config, cls) { |
... | ... | @@ -206,16 +206,16 @@ Ext.define('amdaApp.AmdaApp', { |
206 | 206 | w.resizer.widthIncrement = me.xTickSize; |
207 | 207 | w.resizer.heightIncrement = me.yTickSize; |
208 | 208 | } |
209 | - | |
209 | + | |
210 | 210 | if (w.y < 0) |
211 | 211 | w.el.setY(0); |
212 | - | |
212 | + | |
213 | 213 | if (w.x + w.width > me.el.getWidth()) |
214 | 214 | w.el.setX(me.el.getWidth()-w.width); |
215 | - | |
215 | + | |
216 | 216 | if (w.y + w.height > me.el.getHeight()) |
217 | 217 | w.el.setY((me.el.getHeight()-w.height > 0) ? me.el.getHeight()-w.height : 0); |
218 | - | |
218 | + | |
219 | 219 | }, |
220 | 220 | single: true |
221 | 221 | }); |
... | ... | @@ -224,12 +224,12 @@ Ext.define('amdaApp.AmdaApp', { |
224 | 224 | }); |
225 | 225 | |
226 | 226 | }, |
227 | -//create InfoBox | |
227 | +//create InfoBox | |
228 | 228 | infoMsg : function(msg) { |
229 | 229 | Ext.Msg.show({ |
230 | 230 | title: 'AMDA Info', |
231 | 231 | cls: 'infoMsg', |
232 | - msg: msg, | |
232 | + msg: msg, | |
233 | 233 | modal: false, |
234 | 234 | autoScroll: true, |
235 | 235 | resizable: true, |
... | ... | @@ -237,35 +237,35 @@ Ext.define('amdaApp.AmdaApp', { |
237 | 237 | buttons: Ext.Msg.OK |
238 | 238 | }); |
239 | 239 | }, |
240 | - | |
241 | -//create WarningBox | |
240 | + | |
241 | +//create WarningBox | |
242 | 242 | warningMsg : function(msg) { |
243 | 243 | Ext.Msg.show({ |
244 | 244 | title: 'Attention', |
245 | - msg: msg, | |
245 | + msg: msg, | |
246 | 246 | icon: Ext.Msg.WARNING, |
247 | 247 | buttons: Ext.Msg.OK |
248 | 248 | }); |
249 | 249 | }, |
250 | - | |
251 | -//create ErrorBox | |
250 | + | |
251 | +//create ErrorBox | |
252 | 252 | errorMsg : function(msg) { |
253 | 253 | Ext.Msg.show({ |
254 | 254 | title: 'Failure', |
255 | - msg: msg, | |
255 | + msg: msg, | |
256 | 256 | icon: Ext.Msg.ERROR, |
257 | 257 | buttons: Ext.Msg.OK |
258 | 258 | }); |
259 | - }, | |
260 | - | |
259 | + }, | |
260 | + | |
261 | 261 | getModules : function(){ |
262 | 262 | var allModules = []; |
263 | - | |
263 | + | |
264 | 264 | //Add dynamic modules |
265 | 265 | Ext.Object.each(this.dynamicModules, function(key, def) { |
266 | 266 | allModules.push(new amdaDesktop.DynamicModule(def.id, def.icon, def.title, def.source, def.useLauncher)); |
267 | 267 | }); |
268 | - | |
268 | + | |
269 | 269 | return allModules; |
270 | 270 | }, |
271 | 271 | |
... | ... | @@ -284,9 +284,9 @@ Ext.define('amdaApp.AmdaApp', { |
284 | 284 | |
285 | 285 | shortcuts: Ext.create('Ext.data.Store', { |
286 | 286 | model: 'Ext.ux.desktop.ShortcutModel', |
287 | - data: [ | |
288 | - { name: 'Help', iconCls: 'help', module: 'help-win' }, | |
289 | - { name: 'Create/Modify parameter', iconCls: 'edit', module: 'param-win' }, | |
287 | + data: [ | |
288 | + { name: 'Help', iconCls: 'help', module: 'help-win' }, | |
289 | + { name: 'Create/Modify parameter', iconCls: 'edit', module: 'param-win' }, | |
290 | 290 | { name: 'Plot data', iconCls: 'plot', module: 'plot-win'}, |
291 | 291 | { name: 'Data mining', iconCls: 'search', module: 'search-win'}, |
292 | 292 | { name: 'Statistics', iconCls: 'statistics', module: 'statistics-win'}, |
... | ... | @@ -296,8 +296,8 @@ Ext.define('amdaApp.AmdaApp', { |
296 | 296 | { name: 'TimeTables operations', iconCls: 'operations', module: 'ttsOpe-win' }, |
297 | 297 | { name: 'Manage catalogs', iconCls: 'catalog', module: 'catalog-win'}, |
298 | 298 | { name: 'Visualize catalogs', iconCls: 'visu_catalog', module: 'visu-win'}, |
299 | - { name: 'EPN-TAP', iconCls: 'epntap', module: 'epntap-win' }, | |
300 | - { name: 'Interoperability', iconCls: 'interop', module: 'interop-win' } | |
299 | + { name: 'Interoperability', iconCls: 'interop', module: 'interop-win' }, | |
300 | + { name: 'EPN-TAP', iconCls: 'epntap', module: 'epntap-win' } | |
301 | 301 | ] |
302 | 302 | }), |
303 | 303 | |
... | ... | @@ -310,7 +310,7 @@ Ext.define('amdaApp.AmdaApp', { |
310 | 310 | getStartConfig : function() { |
311 | 311 | var me = this, ret = me.callParent(); |
312 | 312 | return Ext.apply(ret, { |
313 | - title: sessionID, | |
313 | + title: sessionID, | |
314 | 314 | iconCls: 'icon-user', |
315 | 315 | height: 270, |
316 | 316 | toolConfig: { |
... | ... | @@ -322,7 +322,7 @@ Ext.define('amdaApp.AmdaApp', { |
322 | 322 | handler: me.onSettings, |
323 | 323 | scope: me |
324 | 324 | }, |
325 | - '-', | |
325 | + '-', | |
326 | 326 | /* { |
327 | 327 | text : 'Manage Workspaces', |
328 | 328 | iconCls : 'icon-manage-ws', |
... | ... | @@ -372,9 +372,9 @@ Ext.define('amdaApp.AmdaApp', { |
372 | 372 | this.getLoadedModule(moduleId.replace('-tool', ''), true, function(module) { |
373 | 373 | module.createWindow(); |
374 | 374 | }); |
375 | - | |
375 | + | |
376 | 376 | }, |
377 | - scope : this | |
377 | + scope : this | |
378 | 378 | }, { |
379 | 379 | text : 'Help', |
380 | 380 | iconCls : 'icon-help', |
... | ... | @@ -407,24 +407,24 @@ Ext.define('amdaApp.AmdaApp', { |
407 | 407 | }, '-', { |
408 | 408 | text : 'Logout', |
409 | 409 | iconCls : 'logout', |
410 | - scope : this, | |
410 | + scope : this, | |
411 | 411 | handler : me.onLogout |
412 | 412 | } |
413 | 413 | ] |
414 | 414 | } |
415 | 415 | }); |
416 | 416 | }, |
417 | - | |
417 | + | |
418 | 418 | getModuleDefinition: function(id) { |
419 | 419 | return this.getModule(id); |
420 | 420 | }, |
421 | - | |
421 | + | |
422 | 422 | getLoadedModule: function(id, forceLoad, onReady) { |
423 | 423 | var moduleDef = this.getModuleDefinition(id); |
424 | 424 | if (!moduleDef) |
425 | 425 | return null; |
426 | 426 | if (!moduleDef.isReady()) |
427 | - { | |
427 | + { | |
428 | 428 | if (forceLoad) |
429 | 429 | { |
430 | 430 | //loadMask.show(); |
... | ... | @@ -440,14 +440,14 @@ Ext.define('amdaApp.AmdaApp', { |
440 | 440 | onReady(moduleDef.get()); |
441 | 441 | return moduleDef.get(); |
442 | 442 | }, |
443 | - | |
443 | + | |
444 | 444 | getTaskbarConfig: function () { |
445 | 445 | var ret = this.callParent(); |
446 | 446 | return Ext.apply(ret, { |
447 | 447 | quickStart: [], |
448 | 448 | trayItems: [ |
449 | 449 | { |
450 | - name: this.dynamicModules.feedback.title, iconCls: 'icon-feedback', | |
450 | + name: this.dynamicModules.feedback.title, iconCls: 'icon-feedback', | |
451 | 451 | tooltip: { text: this.dynamicModules.feedback.title, align: 'bl-tl' }, |
452 | 452 | overflowText: this.dynamicModules.feedback.title, |
453 | 453 | iconCls: this.dynamicModules.feedback.icon, |
... | ... | @@ -460,7 +460,7 @@ Ext.define('amdaApp.AmdaApp', { |
460 | 460 | } |
461 | 461 | }, |
462 | 462 | { |
463 | - name: this.dynamicModules.info.title, iconCls: 'icon-information', | |
463 | + name: this.dynamicModules.info.title, iconCls: 'icon-information', | |
464 | 464 | tooltip: { text: this.dynamicModules.info.title, align: 'bl-tl' }, |
465 | 465 | overflowText: this.dynamicModules.info.title, |
466 | 466 | iconCls: this.dynamicModules.info.icon, |
... | ... | @@ -476,7 +476,7 @@ Ext.define('amdaApp.AmdaApp', { |
476 | 476 | name: 'Logout', iconCls : 'logout', |
477 | 477 | tooltip: { text: 'Logout', align: 'bl-tl' }, |
478 | 478 | overflowText: 'Logout', |
479 | - scope : this, | |
479 | + scope : this, | |
480 | 480 | handler : this.onLogout |
481 | 481 | }, |
482 | 482 | '-', |
... | ... | @@ -486,23 +486,23 @@ Ext.define('amdaApp.AmdaApp', { |
486 | 486 | }, |
487 | 487 | |
488 | 488 | onLogout: function (obj,e) { |
489 | - e.stopEvent(); | |
490 | - // var interopModule = this.getModule(amdaDesktop.InteropModule.id); | |
491 | - if (isGuest) { | |
492 | - this.guestLogout(); | |
489 | + e.stopEvent(); | |
490 | + // var interopModule = this.getModule(amdaDesktop.InteropModule.id); | |
491 | + if (isGuest) { | |
492 | + this.guestLogout(); | |
493 | 493 | } |
494 | 494 | else { |
495 | 495 | this.saveSessionState(); |
496 | - } | |
496 | + } | |
497 | 497 | }, |
498 | - | |
498 | + | |
499 | 499 | onGetUserInfo : function (result, e){ |
500 | 500 | var t = e.getTransaction(); |
501 | - if (e.status) | |
502 | - { | |
501 | + if (e.status) | |
502 | + { | |
503 | 503 | if (result && result.success) |
504 | 504 | { |
505 | - // SUCCESS | |
505 | + // SUCCESS | |
506 | 506 | var msg = '<b>Login :</b> '+result['login']+'<br/>'; |
507 | 507 | msg += ('<b>Last Name :</b> '+result['name']+'<br/>'); |
508 | 508 | msg += ('<b>First Name :</b> '+result['first_name']+'<br/>'); |
... | ... | @@ -510,7 +510,7 @@ Ext.define('amdaApp.AmdaApp', { |
510 | 510 | msg += ('<b>Email :</b> '+result['email']+'<br/>'); |
511 | 511 | msg += ('<b>Registration date :</b> '+result['date']+'<br/>'); |
512 | 512 | msg += ('<b>Receive Newsletter :</b> '+(result['news'] == "1"?"true":"false")+'<br/>'); |
513 | - | |
513 | + | |
514 | 514 | this.infoMsg(msg); |
515 | 515 | } |
516 | 516 | else |
... | ... | @@ -523,46 +523,46 @@ Ext.define('amdaApp.AmdaApp', { |
523 | 523 | { |
524 | 524 | // FAILURE |
525 | 525 | this.errorMsg('Cannot get user info : '+e.message); |
526 | - } | |
526 | + } | |
527 | 527 | }, |
528 | - | |
529 | - | |
528 | + | |
529 | + | |
530 | 530 | guestLogout: function() |
531 | 531 | { |
532 | 532 | Ext.Msg.show({ |
533 | - title : 'Logout', | |
533 | + title : 'Logout', | |
534 | 534 | msg :'Your guest workspace is to be deleted. Continue logout ?', |
535 | 535 | buttons : Ext.Msg.YESNO, |
536 | - iconCls : 'logout', | |
536 | + iconCls : 'logout', | |
537 | 537 | fn : function(btn) { |
538 | 538 | if (btn == 'yes') |
539 | 539 | { |
540 | 540 | AmdaAction.logout(true, function(){ |
541 | 541 | sessionID = ''; |
542 | - window.location.href ='index.html'; | |
543 | - }); | |
544 | - } | |
542 | + window.location.href ='index.html'; | |
543 | + }); | |
544 | + } | |
545 | 545 | } |
546 | - }); | |
546 | + }); | |
547 | 547 | }, |
548 | - | |
548 | + | |
549 | 549 | forceLogout: function() |
550 | 550 | { |
551 | 551 | // myDesktopApp.warningMsg('Your guest session is finished'); |
552 | 552 | AmdaAction.logout(true, function(){ |
553 | 553 | sessionID = ''; |
554 | - window.location.href ='index.html'; | |
555 | - }); | |
554 | + window.location.href ='index.html'; | |
555 | + }); | |
556 | 556 | }, |
557 | - | |
557 | + | |
558 | 558 | saveSessionState : function() |
559 | 559 | { |
560 | 560 | var me = this; |
561 | 561 | Ext.Msg.show({ |
562 | - title : 'Logout', | |
562 | + title : 'Logout', | |
563 | 563 | msg :'Do you want to keep current windows sizes and locations<br/> for the next sessions?', |
564 | 564 | buttons : Ext.Msg.YESNOCANCEL, |
565 | - iconCls : 'logout', | |
565 | + iconCls : 'logout', | |
566 | 566 | fn : function(btn) { |
567 | 567 | if (btn == 'yes') |
568 | 568 | { |
... | ... | @@ -577,8 +577,8 @@ Ext.define('amdaApp.AmdaApp', { |
577 | 577 | window.location.href ='index.html'; |
578 | 578 | } |
579 | 579 | }); |
580 | - Ext.state.Manager.getProvider().saveState(); | |
581 | - AmdaAction.logout(); | |
580 | + Ext.state.Manager.getProvider().saveState(); | |
581 | + AmdaAction.logout(); | |
582 | 582 | } |
583 | 583 | else if (btn == 'no') |
584 | 584 | { |
... | ... | @@ -590,9 +590,9 @@ Ext.define('amdaApp.AmdaApp', { |
590 | 590 | window.location.href ='index.html'; |
591 | 591 | } |
592 | 592 | }); |
593 | - Ext.state.Manager.getProvider().set(me.desktop.id+'_wallpaper',me.desktop.getWallpaper()); | |
594 | - Ext.state.Manager.getProvider().saveLastTime(); | |
595 | - AmdaAction.logout(); | |
593 | + Ext.state.Manager.getProvider().set(me.desktop.id+'_wallpaper',me.desktop.getWallpaper()); | |
594 | + Ext.state.Manager.getProvider().saveLastTime(); | |
595 | + AmdaAction.logout(); | |
596 | 596 | } |
597 | 597 | } |
598 | 598 | }); |
... | ... | @@ -604,7 +604,7 @@ Ext.define('amdaApp.AmdaApp', { |
604 | 604 | }); |
605 | 605 | dlg.show(); |
606 | 606 | }, |
607 | - | |
607 | + | |
608 | 608 | /** |
609 | 609 | * initialization at the start of AMDA-NG webApplication |
610 | 610 | */ |
... | ... | @@ -612,64 +612,63 @@ Ext.define('amdaApp.AmdaApp', { |
612 | 612 | moduleIds = new Ext.util.MixedCollection(); |
613 | 613 | // Adding Workspace Explorer Id |
614 | 614 | moduleIds.add(this.dynamicModules.explorer.id); |
615 | - | |
615 | + | |
616 | 616 | moduleIds.each(function(item) { |
617 | 617 | this.getLoadedModule(item, true, function (module) { |
618 | 618 | module.createWindow(); |
619 | 619 | }); |
620 | 620 | }, this); |
621 | - | |
621 | + | |
622 | 622 | if (freeSpace < diskQuota / 20) { |
623 | - myDesktopApp.warningMsg('Think of cleaning up your work space.<br/>Only ' + | |
623 | + myDesktopApp.warningMsg('Think of cleaning up your work space.<br/>Only ' + | |
624 | 624 | Math.round(freeSpace/1024/1024)+ 'MB of '+Math.round(diskQuota/1024/1024) + |
625 | 625 | 'MB rests'); |
626 | 626 | } |
627 | - | |
627 | + | |
628 | 628 | if (isFirstVisit && !isGuest) { |
629 | - if (isSpecialInfo) { | |
629 | + if (isSpecialInfo) { | |
630 | 630 | myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.info.id, true, function(module) { |
631 | 631 | module.createWindow(isSpecialInfo, 'Welcome to AMDA', true); |
632 | 632 | }); |
633 | 633 | } else { |
634 | - | |
634 | + | |
635 | 635 | myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.help.id, true, function(module) { |
636 | 636 | module.createWindow(); |
637 | 637 | }); |
638 | 638 | } |
639 | - } | |
639 | + } | |
640 | 640 | else { |
641 | 641 | if (isSpecialInfo && !isNewInfo) { |
642 | - myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.info.id, true, function(module) { | |
642 | + myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.info.id, true, function(module) { | |
643 | 643 | module.createWindow(isSpecialInfo, 'Welcome to AMDA', true); |
644 | 644 | }); |
645 | 645 | } |
646 | 646 | } |
647 | - | |
647 | + | |
648 | 648 | if (isNewInfo) { |
649 | 649 | myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.info.id, true, function(module) { |
650 | - // module.createWindow('releaseNotes.' + AMDAVERSION, 'New Release V'+ AMDAVERSION); | |
650 | + // module.createWindow('releaseNotes.' + AMDAVERSION, 'New Release V'+ AMDAVERSION); | |
651 | 651 | module.createWindow(news, 'Amda Latest News'); |
652 | 652 | }); |
653 | 653 | } |
654 | - | |
654 | + | |
655 | 655 | if (isGuest) { |
656 | 656 | myDesktopApp.warningMsg("Welcome to Guest Session<br/>Guest session lasts for "+ |
657 | 657 | guestSessionDuration/3600+" h maximum<br/>"+ |
658 | 658 | "For extended use time and functionalities (saved sessions)<br/> please register at amda@irap.omp.eu"); |
659 | 659 | Ext.Function.defer(myDesktopApp.warningMsg,(guestSessionDuration-300)*1000, this, ["Your session will be closed in 5 min!"]); |
660 | - Ext.Function.defer(myDesktopApp.forceLogout, guestSessionDuration*1000); | |
660 | + Ext.Function.defer(myDesktopApp.forceLogout, guestSessionDuration*1000); | |
661 | 661 | } |
662 | 662 | |
663 | - | |
664 | - | |
663 | + | |
664 | + | |
665 | 665 | this.desktop.taskbar.tray.width = 130; |
666 | 666 | this.desktop.taskbar.insert(4,new amdaUI.SampToolBarUI({id : 'samptb', onSwitchConnect : function () |
667 | 667 | { |
668 | 668 | myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.interop.id, true, function(module) { |
669 | 669 | module.switchSampConnect(); |
670 | 670 | }); |
671 | - | |
671 | + | |
672 | 672 | }})); |
673 | 673 | } |
674 | 674 | }); |
675 | - | |
... | ... |
js/app/controllers/EpnTapModule.js
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | * @author Nathanael Jourdane |
8 | 8 | */ |
9 | 9 | |
10 | -// Load text with Ajax synchronously: takes path to file and optional MIME type | |
10 | +// Load text with Ajax synchronously: takes path to file and optional MIME type. | |
11 | 11 | function loadTextFileAjaxSync(filePath, mimeType) { |
12 | 12 | var xmlhttp=new XMLHttpRequest(); |
13 | 13 | xmlhttp.open("GET", filePath, false); |
... | ... | @@ -24,47 +24,9 @@ function loadTextFileAjaxSync(filePath, mimeType) { |
24 | 24 | } |
25 | 25 | } |
26 | 26 | |
27 | -function prettify(name) { | |
28 | - return name.charAt(0).toUpperCase() + name.replace(/_/g, ' ').substr(1).toLowerCase(); | |
29 | -} | |
30 | - | |
31 | -function allPrettify(name) { | |
32 | - return 'All ' + (name[name.length-1] == 's' ? name : name + 's').replace(/_/g, ' ').toLowerCase(); | |
33 | -} | |
34 | - | |
35 | -function isLatest(newStrDate, oldStrDate) { | |
36 | - if (newStrDate === null) { | |
37 | - return false; | |
38 | - } | |
39 | - if (oldStrDate === null) { | |
40 | - return true; | |
41 | - } | |
42 | - | |
43 | - var newDate = newStrDate.split('/'); | |
44 | - var oldDate = oldStrDate.split('/'); | |
45 | - | |
46 | - if(newDate[2]>oldDate[2]) { | |
47 | - return true; | |
48 | - } else if(newDate[2]<oldDate[2]) { | |
49 | - return false; | |
50 | - } | |
51 | - if(newDate[1]>oldDate[1]) { | |
52 | - return true; | |
53 | - } else if(newDate[1]<oldDate[1]) { | |
54 | - return false; | |
55 | - } | |
56 | - if(newDate[0]>oldDate[0]) { | |
57 | - return true; | |
58 | - } else { | |
59 | - return false; | |
60 | - } | |
61 | -} | |
62 | - | |
63 | 27 | Ext.define('amdaDesktop.EpnTapModule', { |
64 | 28 | |
65 | 29 | extend: 'amdaDesktop.AmdaModule', |
66 | - | |
67 | - // requires: ['amdaUI.EpnTapUI', 'amdaReader.EpnTapReader'], | |
68 | 30 | requires: ['amdaUI.EpnTapUI'], |
69 | 31 | contentId : 'EpnTapUI', |
70 | 32 | |
... | ... | @@ -81,8 +43,13 @@ Ext.define('amdaDesktop.EpnTapModule', { |
81 | 43 | width : 1000, |
82 | 44 | height: 550, |
83 | 45 | |
84 | - /** @class Module initialisation. */ | |
46 | + /** | |
47 | + Module initialisation. | |
48 | + */ | |
85 | 49 | init: function() { |
50 | + | |
51 | + // TODO: Utiliser des stores pour accรฉder aux fichiers JS !! | |
52 | + | |
86 | 53 | this.metadata = JSON.parse(loadTextFileAjaxSync('../../generic_data/EpnTapData/metadata.json', 'application/json')); |
87 | 54 | this.services = JSON.parse(loadTextFileAjaxSync('../../generic_data/EpnTapData/services.json', 'application/json')); |
88 | 55 | this.productTypeDict = JSON.parse(loadTextFileAjaxSync('../../generic_data/EpnTapData/dataproduct_types.json', 'application/json')); |
... | ... | @@ -101,36 +68,93 @@ Ext.define('amdaDesktop.EpnTapModule', { |
101 | 68 | }; |
102 | 69 | }, |
103 | 70 | |
71 | + /** | |
72 | + Capitalize a name and replace underscores with spaces. | |
73 | + - `name`: The string to make pretty. | |
74 | + */ | |
75 | + prettify: function(name) { | |
76 | + return name.charAt(0).toUpperCase() + name.replace(/_/g, ' ').substr(1).toLowerCase(); | |
77 | + }, | |
78 | + | |
79 | + /** | |
80 | + Capitalize a name, replace underscores with spaces, and write it in a plurial form. | |
81 | + - `name`: The string to make pretty. | |
82 | + */ | |
83 | + allPrettify: function(name) { | |
84 | + return 'All ' + (name[name.length-1] == 's' ? name : name + 's').replace(/_/g, ' ').toLowerCase(); | |
85 | + }, | |
86 | + | |
87 | + /** | |
88 | + Compare two dates formated as dd/mm/yyyy and return: | |
89 | + - `true` if `newStrDate` is more recent than `oldStrDate`, or if `oldStrDate` is null; | |
90 | + - `false` if `oldStrDate` is more recent than `newStrDate`, or if `newStrDate` is null; | |
91 | + - `null` if a date is not well formed. | |
92 | + */ | |
93 | + isLatest: function(newStrDate, oldStrDate) { | |
94 | + if (newStrDate === null) { | |
95 | + return false; | |
96 | + } | |
97 | + if (oldStrDate === null) { | |
98 | + return true; | |
99 | + } | |
100 | + | |
101 | + var newDate = newStrDate.split('/'); | |
102 | + var oldDate = oldStrDate.split('/'); | |
103 | + | |
104 | + if(newDate[2]>oldDate[2]) { | |
105 | + return true; | |
106 | + } else if(newDate[2]<oldDate[2]) { | |
107 | + return false; | |
108 | + } | |
109 | + if(newDate[1]>oldDate[1]) { | |
110 | + return true; | |
111 | + } else if(newDate[1]<oldDate[1]) { | |
112 | + return false; | |
113 | + } | |
114 | + if(newDate[0]>oldDate[0]) { | |
115 | + return true; | |
116 | + } else { | |
117 | + return false; | |
118 | + } | |
119 | + return null; | |
120 | + }, | |
121 | + | |
122 | + /**************************** | |
123 | + *** Service filter events *** | |
124 | + ****************************/ | |
125 | + | |
126 | + /** | |
127 | + Trigerred after the render of `gridsPanel` (containing `servicesGrid` and `granulesGrid`). Among other things, | |
128 | + initializes the `productType` combobox and the `servicesGrid` table. | |
129 | + */ | |
104 | 130 | onWindowLoaded: function() { |
105 | - // UI elements | |
106 | - this.dataProdutTypeCB = Ext.getCmp('productTypeCB'); | |
107 | - this.targetClassCB = Ext.getCmp('targetClassCB'); | |
108 | - this.targetNameCB = Ext.getCmp('targetNameCB'); | |
109 | - this.startTimeDF = Ext.getCmp('startTimeDF'); | |
110 | - this.stopTimeDF = Ext.getCmp('stopTimeDF'); | |
111 | - | |
112 | - this.servicesGrid = Ext.getCmp('servicesGrid'); | |
113 | - this.granulesGrid = Ext.getCmp('granulesGrid'); | |
114 | - | |
115 | - this.rowsPerPageNf = Ext.getCmp('rowsPerPageNf'); | |
116 | - this.currentPageLb = Ext.getCmp('currentPageLb'); | |
117 | - this.totalPagesLb = Ext.getCmp('totalPagesLb'); | |
118 | - | |
119 | - this.previousBtn = Ext.getCmp('previousPageBtn'); | |
120 | - this.nextBtn = Ext.getCmp('nextPageBtn'); | |
121 | - this.firstBtn = Ext.getCmp('firstPageBtn'); | |
122 | - this.lastBtn = Ext.getCmp('lastPageBtn'); | |
123 | - | |
124 | - this.dataProdutTypeCB.getStore().removeAll(); | |
125 | - this.dataProdutTypeCB.getStore().add({'id': 'all', 'name': 'All data product types'}); | |
131 | + | |
132 | + this.productTypeCB = Ext.getCmp('epnTapProductTypeCB'); | |
133 | + this.targetClassCB = Ext.getCmp('epnTapTargetClassCB'); | |
134 | + this.targetNameCB = Ext.getCmp('epnTapTargetNameCB'); | |
135 | + this.timeSelector = Ext.getCmp('epnTapTimeSelector'); | |
136 | + this.rowsPerPageNf = Ext.getCmp('epnTapRowsPerPageNf'); | |
137 | + this.servicesGrid = Ext.getCmp('epnTapServicesGrid'); | |
138 | + this.granulesGrid = Ext.getCmp('epnTapGranulesGrid'); | |
139 | + this.currentPageLb = Ext.getCmp('epnTapCurrentPageLb'); | |
140 | + this.totalPagesLb = Ext.getCmp('epnTapTotalPagesLb'); | |
141 | + this.firstPageBtn = Ext.getCmp('epnTapFirstPageBtn'); | |
142 | + this.previousPageBtn = Ext.getCmp('epnTapPreviousPageBtn'); | |
143 | + this.nextPageBtn = Ext.getCmp('epnTapNextPageBtn'); | |
144 | + this.lastPageBtn = Ext.getCmp('epnTapLastPageBtn'); | |
145 | + | |
146 | + this.timeSelector.setInterval(new Date(), new Date()); // TODO: use min/max dates | |
147 | + | |
148 | + this.productTypeCB.getStore().removeAll(); | |
149 | + this.productTypeCB.getStore().add({'id': 'all', 'name': 'All data product types'}); | |
126 | 150 | for (var productTypeId in this.metadata) { |
127 | 151 | if (productTypeId in this.productTypeDict) { |
128 | - this.dataProdutTypeCB.getStore().add({'id': productTypeId, 'name': prettify(this.productTypeDict[productTypeId])}); | |
152 | + this.productTypeCB.getStore().add({'id': productTypeId, 'name': this.prettify(this.productTypeDict[productTypeId])}); | |
129 | 153 | } else { |
130 | 154 | console.log('Unknown data product type "' + productTypeId + '"'); |
131 | 155 | } |
132 | 156 | } |
133 | - this.dataProdutTypeCB.select('all'); | |
157 | + this.productTypeCB.select('all'); | |
134 | 158 | |
135 | 159 | this.targetClassCB.getStore().removeAll(); |
136 | 160 | this.targetClassCB.getStore().add({'id': 'all', 'name': 'All target names'}); |
... | ... | @@ -145,26 +169,28 @@ Ext.define('amdaDesktop.EpnTapModule', { |
145 | 169 | this.updateServices(); |
146 | 170 | }, |
147 | 171 | |
148 | - // *** form events *** | |
149 | - | |
172 | + /** | |
173 | + Trigerred when a new item is selected in `productTypeCB` (see `EpnTapUI.createProductTypeCB()`). Among other things, | |
174 | + updates the `targetClassCB` combobox and the `servicesGrid` table. | |
175 | + */ | |
150 | 176 | onProductTypeCBChanged: function() { |
151 | 177 | this.targetClassCB.getStore().removeAll(); |
152 | 178 | this.targetNameCB.getStore().removeAll(); |
153 | 179 | this.targetNameCB.disable(); |
154 | 180 | |
155 | - if (this.dataProdutTypeCB.value == 'all') { | |
181 | + if (this.productTypeCB.value == 'all') { | |
156 | 182 | this.targetClassCB.disable(); |
157 | 183 | } else { |
158 | - var targetClasses = this.metadata[this.dataProdutTypeCB.value]; | |
184 | + var targetClasses = this.metadata[this.productTypeCB.value]; | |
159 | 185 | |
160 | 186 | if (Object.keys(targetClasses).length == 1) { |
161 | - this.targetClassCB.getStore().add({'id': Object.keys(targetClasses)[0], 'name': prettify(Object.keys(targetClasses)[0])}); | |
187 | + this.targetClassCB.getStore().add({'id': Object.keys(targetClasses)[0], 'name': this.prettify(Object.keys(targetClasses)[0])}); | |
162 | 188 | this.targetClassCB.disable(); |
163 | 189 | this.targetClassCB.select(this.targetClassCB.getStore().getAt(0)['internalId']); |
164 | 190 | } else { |
165 | - this.targetClassCB.getStore().add({'id': 'all', 'name': allPrettify(this.productTypeDict[this.dataProdutTypeCB.value])}); | |
191 | + this.targetClassCB.getStore().add({'id': 'all', 'name': this.allPrettify(this.productTypeDict[this.productTypeCB.value])}); | |
166 | 192 | for (var targetClassId in targetClasses) { |
167 | - this.targetClassCB.getStore().add({'id': targetClassId, 'name': prettify(targetClassId)}); | |
193 | + this.targetClassCB.getStore().add({'id': targetClassId, 'name': this.prettify(targetClassId)}); | |
168 | 194 | } |
169 | 195 | this.targetClassCB.select('all'); |
170 | 196 | this.targetClassCB.enable(); |
... | ... | @@ -175,6 +201,10 @@ Ext.define('amdaDesktop.EpnTapModule', { |
175 | 201 | this.updateServices(); |
176 | 202 | }, |
177 | 203 | |
204 | + /** | |
205 | + Trigerred when a new item is selected in `targetClassCB` (see `EpnTapUI.createTargetClassCB()`). Among other things, | |
206 | + updates the `targetNameCB` combobox and the `servicesGrid` table. | |
207 | + */ | |
178 | 208 | onTargetClassCBChanged: function() { |
179 | 209 | this.targetNameCB.getStore().removeAll(); |
180 | 210 | |
... | ... | @@ -183,16 +213,16 @@ Ext.define('amdaDesktop.EpnTapModule', { |
183 | 213 | this.targetNameCB.select('all'); |
184 | 214 | this.targetNameCB.disable(); |
185 | 215 | } else { |
186 | - var targetNames = this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value]; | |
216 | + var targetNames = this.metadata[this.productTypeCB.value][this.targetClassCB.value]; | |
187 | 217 | |
188 | 218 | if (Object.keys(targetNames).length == 1) { |
189 | - this.targetNameCB.getStore().add({'id': Object.keys(targetNames)[0], 'name': prettify(Object.keys(targetNames)[0])}); | |
219 | + this.targetNameCB.getStore().add({'id': Object.keys(targetNames)[0], 'name': this.prettify(Object.keys(targetNames)[0])}); | |
190 | 220 | this.targetNameCB.select(this.targetNameCB.getStore().getAt(0)['internalId']); |
191 | 221 | this.targetNameCB.disable(); |
192 | 222 | } else { |
193 | - this.targetNameCB.getStore().add({'id': 'all', 'name': allPrettify(this.targetClassCB.value)}); | |
223 | + this.targetNameCB.getStore().add({'id': 'all', 'name': this.allPrettify(this.targetClassCB.value)}); | |
194 | 224 | for (var targetNameId in targetNames) { |
195 | - this.targetNameCB.getStore().add({'id': targetNameId, 'name': prettify(targetNameId)}); | |
225 | + this.targetNameCB.getStore().add({'id': targetNameId, 'name': this.prettify(targetNameId)}); | |
196 | 226 | } |
197 | 227 | this.targetNameCB.select('all'); |
198 | 228 | this.targetNameCB.enable(); |
... | ... | @@ -201,89 +231,112 @@ Ext.define('amdaDesktop.EpnTapModule', { |
201 | 231 | this.updateServices(); |
202 | 232 | }, |
203 | 233 | |
234 | + /** | |
235 | + Trigerred when a new item is selected in `targetNameCB` (see `EpnTapUI.createTargetNameCB()`). Updates the | |
236 | + `servicesGrid` table. | |
237 | + */ | |
204 | 238 | onTargetNameCBChanged: function() { |
205 | 239 | this.updateServices(); |
206 | 240 | }, |
207 | 241 | |
242 | + /** | |
243 | + Trigerred when the value of `rowsPerPageNf` is updated (see `EpnTapUI.createRowsPerPageNf()`). Do nothing yet, used | |
244 | + for debug purposes only. | |
245 | + */ | |
208 | 246 | onRowsPerPageChanged: function() { |
209 | - console.log("rows per page: " + this.rowsPerPageNf.value); | |
247 | + console.log("rows per page: " + this.productTypeCB); | |
210 | 248 | }, |
211 | 249 | |
212 | - // *** Buttons events *** | |
250 | + /********************* | |
251 | + *** Buttons events *** | |
252 | + *********************/ | |
253 | + | |
254 | + /** | |
255 | + Disable or enable the navigation buttons (see `EpnTapUI.createNavigationPanel()`). | |
256 | + */ | |
257 | + disableNavBtns: function(firt, previous, next, last) { | |
258 | + Ext.getCmp('epnTapFirstPageBtn').setDisabled(firt); | |
259 | + Ext.getCmp('epnTapPreviousPageBtn').setDisabled(previous); | |
260 | + Ext.getCmp('epnTapNextPageBtn').setDisabled(next); | |
261 | + Ext.getCmp('epnTapLastPageBtn').setDisabled(last); | |
262 | + }, | |
213 | 263 | |
264 | + /** | |
265 | + Trigerred when the `firstPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things, | |
266 | + send a new query and fill `granulesGrid`. | |
267 | + */ | |
214 | 268 | onFirstPageBtnClicked: function() { |
215 | - this.wait(); | |
216 | - this.currentPageLb.setText('1'); | |
217 | - | |
218 | - this.nextBtn.setDisabled(false); | |
219 | - this.lastBtn.setDisabled(false); | |
220 | - this.firstBtn.setDisabled(true); | |
221 | - this.previousBtn.setDisabled(true); | |
222 | - | |
269 | + var newPageNumber = 1; | |
270 | + var limit = Number(this.rowsPerPageNf.value); | |
271 | + var offset = 0; | |
223 | 272 | var selectedServiceURL = this.services[this.selectedServiceId]['accessurl']; |
224 | - var limit = this.rowsPerPageNf.value; | |
225 | - var offset = '0'; | |
226 | 273 | |
274 | + this.wait(); | |
275 | + this.disableNavBtns(true, true, false, false); | |
276 | + this.currentPageLb.setText('' + newPageNumber); | |
227 | 277 | AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules); |
228 | 278 | }, |
229 | 279 | |
280 | + /** | |
281 | + Trigerred when the `previousPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things, | |
282 | + send a new query and fill `granulesGrid`. | |
283 | + */ | |
230 | 284 | onPreviousPageBtnClicked: function() { |
231 | - this.wait(); | |
232 | 285 | var newPageNumber = Number(this.currentPageLb.text) - 1; |
233 | - this.currentPageLb.setText('' + newPageNumber); | |
234 | - | |
235 | - this.nextBtn.setDisabled(false); | |
236 | - this.lastBtn.setDisabled(false); | |
237 | - if (this.currentPageLb.text === '1') { | |
238 | - this.previousBtn.setDisabled(true); | |
239 | - this.firstBtn.setDisabled(true); | |
240 | - } | |
241 | - | |
286 | + var limit = Number(this.rowsPerPageNf.value); | |
287 | + var offset = (newPageNumber-1) * limit; | |
242 | 288 | var selectedServiceURL = this.services[this.selectedServiceId]['accessurl']; |
243 | - var limit = this.rowsPerPageNf.value; | |
244 | - var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value); | |
245 | 289 | |
290 | + this.wait(); | |
291 | + this.currentPageLb.setText('' + newPageNumber); | |
292 | + var isFirstPage = this.currentPageLb.text === '1'; | |
293 | + this.disableNavBtns(isFirstPage, isFirstPage, false, false); | |
246 | 294 | AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules); |
247 | 295 | }, |
248 | 296 | |
297 | + /** | |
298 | + Trigerred when the `nextPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things, | |
299 | + send a new query and fill `granulesGrid`. | |
300 | + */ | |
249 | 301 | onNextPageBtnClicked: function() { |
250 | - this.wait(); | |
251 | 302 | var newPageNumber = Number(this.currentPageLb.text) + 1; |
252 | - this.currentPageLb.setText('' + newPageNumber); | |
253 | - | |
254 | - this.previousBtn.setDisabled(false); | |
255 | - this.firstBtn.setDisabled(false); | |
256 | - if (this.currentPageLb.text === this.totalPagesLb.text) { | |
257 | - this.nextBtn.setDisabled(true); | |
258 | - this.lastBtn.setDisabled(true); | |
259 | - } | |
260 | - | |
303 | + var limit = Number(this.rowsPerPageNf.value); | |
304 | + var offset = (newPageNumber-1) * limit; | |
261 | 305 | var selectedServiceURL = this.services[this.selectedServiceId]['accessurl']; |
262 | - var limit = this.rowsPerPageNf.value; | |
263 | - var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value); | |
264 | 306 | |
307 | + this.wait(); | |
308 | + this.currentPageLb.setText('' + newPageNumber); | |
309 | + var isLastPage = this.currentPageLb.text == this.totalPagesLb.text; | |
310 | + this.disableNavBtns(false, false, isLastPage, isLastPage); | |
265 | 311 | AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules); |
266 | 312 | }, |
267 | 313 | |
314 | + /** | |
315 | + Trigerred when the `lastPageBtn` button is clicked (see `EpnTapUI.createNavigationPanel()`). Among other things, | |
316 | + send a new query and fill `granulesGrid`. | |
317 | + */ | |
268 | 318 | onLastPageBtnClicked: function() { |
269 | - this.wait(); | |
270 | - var newPageNumber = this.totalPagesLb.text; | |
271 | - this.currentPageLb.setText('' + newPageNumber); | |
272 | - | |
273 | - this.previousBtn.setDisabled(false); | |
274 | - this.firstBtn.setDisabled(false); | |
275 | - this.nextBtn.setDisabled(true); | |
276 | - this.lastBtn.setDisabled(true); | |
277 | - | |
319 | + var newPageNumber = Number(this.totalPagesLb.text); | |
320 | + var limit = Number(this.rowsPerPageNf.value); | |
321 | + var offset = (newPageNumber-1) * limit; | |
278 | 322 | var selectedServiceURL = this.services[this.selectedServiceId]['accessurl']; |
279 | - var limit = this.rowsPerPageNf.value; | |
280 | - var offset = '' + (newPageNumber-1) * Number(this.rowsPerPageNf.value); | |
281 | 323 | |
324 | + console.log(newPageNumber, limit, offset, selectedServiceURL); | |
325 | + | |
326 | + this.wait(); | |
327 | + this.currentPageLb.setText('' + newPageNumber); | |
328 | + this.disableNavBtns(false, false, true, true); | |
282 | 329 | AmdaAction.epnTapGetGranules(this.selectedServiceId, selectedServiceURL, this.filter, this.select, limit, offset, this.fillGranules); |
283 | 330 | }, |
284 | 331 | |
285 | - // *** Grid click events *** | |
332 | + /******************* | |
333 | + *** Grids events *** | |
334 | + *******************/ | |
286 | 335 | |
336 | + /** | |
337 | + Trigerred when a row is clicked in `servicesGrid` table (see `EpnTapUI.createServicesGrid()`). Among other things, | |
338 | + send a new query and fill `granulesGrid`. | |
339 | + */ | |
287 | 340 | onServiceSelected: function(selectedServiceId) { |
288 | 341 | this.wait(); |
289 | 342 | this.selectedServiceId = selectedServiceId; |
... | ... | @@ -302,64 +355,32 @@ Ext.define('amdaDesktop.EpnTapModule', { |
302 | 355 | } |
303 | 356 | } |
304 | 357 | this.filter = Array( |
305 | - this.dataProdutTypeCB.value !== 'all' ? this.dataProdutTypeCB.value : null, // product type | |
358 | + this.productTypeCB.value !== 'all' ? this.productTypeCB.value : null, // product type | |
306 | 359 | this.targetNameCB.value !== 'all' ? this.targetNameCB.value : null, // target name |
307 | - Ext.getCmp('startTimeDF').getRawValue() !== '' ? Ext.getCmp('startTimeDF').getRawValue() : null, // start time | |
308 | - Ext.getCmp('stopTimeDF').getRawValue() !== '' ? Ext.getCmp('stopTimeDF').getRawValue() : null // stop time | |
360 | + this.timeSelector.getStartTime() !== '' ? this.timeSelector.getStartTime() : null, // start time | |
361 | + this.timeSelector.getStopTime() !== '' ? this.timeSelector.getStopTime() : null // stop time | |
309 | 362 | ); |
310 | 363 | |
311 | - var limit = this.rowsPerPageNf.value; | |
312 | 364 | AmdaAction.epnTapGetNbRows(selectedServiceId, selectedServiceURL, this.filter, this.updateNbRows); |
313 | - AmdaAction.epnTapGetGranules(selectedServiceId, selectedServiceURL, this.filter, this.select, limit, 0, this.fillGranules); | |
365 | + AmdaAction.epnTapGetGranules(selectedServiceId, selectedServiceURL, this.filter, this.select, this.rowsPerPageNf.value, 0, this.fillGranules); | |
314 | 366 | }, |
315 | 367 | |
316 | - onGranuleSelected: function() { | |
317 | - // console.log('selected granule: ' + granule.targetName); | |
368 | + /** | |
369 | + Trigerred when a row is clicked in `granulesGrid` table (see `EpnTapUI.createGranulesGrid()`). Do nothing yet, used | |
370 | + for debug purposes only. | |
371 | + */ | |
372 | + onGranuleSelected: function(ui) { | |
373 | + console.log('selected granule: ' + granule.targetName); | |
318 | 374 | }, |
319 | 375 | |
320 | - // *** Other functions *** | |
321 | - | |
322 | - updateNbRows: function(nb_results) { | |
323 | - /* /!\ Can not get `this`. */ | |
324 | - var totalPages = '' + Math.ceil(Number(nb_results) / Ext.getCmp('rowsPerPageNf').value); | |
325 | - | |
326 | - Ext.getCmp('currentPageLb').setText('1'); | |
327 | - Ext.getCmp('totalPagesLb').setText(totalPages); | |
328 | - Ext.getCmp('previousPageBtn').setDisabled(true); | |
329 | - Ext.getCmp('firstPageBtn').setDisabled(true); | |
330 | - if (totalPages === '1') { | |
331 | - Ext.getCmp('nextPageBtn').setDisabled(true); | |
332 | - Ext.getCmp('lastPageBtn').setDisabled(true); | |
333 | - } else { | |
334 | - Ext.getCmp('nextPageBtn').setDisabled(false); | |
335 | - Ext.getCmp('lastPageBtn').setDisabled(false); | |
336 | - } | |
337 | - }, | |
338 | - | |
339 | - fillGranules: function(granules) { | |
340 | - /* /!\ Can not get `this`. */ | |
341 | - | |
342 | - if (granules == null) { | |
343 | - console.log("There is no granules to add."); | |
344 | - } else { | |
345 | - try { | |
346 | - console.log('Added granules:', granules); | |
347 | - Ext.getCmp('granulesGrid').getStore().removeAll(); | |
348 | - Ext.getCmp('granulesGrid').getStore().add(granules); | |
349 | - } catch( e ) { | |
350 | - console.log('Can not add granules: ' + e); | |
351 | - } | |
352 | - } | |
353 | - Ext.getCmp('servicesGrid').setDisabled(false); | |
354 | - Ext.getCmp('servicesGrid').getEl().setStyle('cursor', 'default'); // CSS is correctly changed but without visible result. | |
355 | - }, | |
356 | - | |
357 | - wait: function() { | |
358 | - this.servicesGrid.getEl().setStyle('cursor', 'wait'); | |
359 | - this.servicesGrid.setDisabled(true); // CSS is correctly changed but without visible result. | |
360 | - }, | |
376 | + /********************** | |
377 | + *** Other functions *** | |
378 | + **********************/ | |
361 | 379 | |
362 | - updateServices: function() { | |
380 | + /** | |
381 | + Update the services store (see `EpnTapUI.servicesStore`), according to the field values in `serviceFilterPanel`. | |
382 | + */ | |
383 | + updateServices: function(ui) { | |
363 | 384 | this.servicesGrid.getStore().removeAll(); |
364 | 385 | this.granulesGrid.getStore().removeAll(); |
365 | 386 | |
... | ... | @@ -368,9 +389,12 @@ Ext.define('amdaDesktop.EpnTapModule', { |
368 | 389 | var timeMaxArr = null; |
369 | 390 | var timeMin = null; |
370 | 391 | var timeMax = null; |
392 | + var productType = this.productTypeCB.value; | |
393 | + var targetClass = this.targetClassCB.value; | |
394 | + var targetName = this.targetNameCB.value; | |
371 | 395 | |
372 | 396 | var filterDict = new Array(); |
373 | - if(this.dataProdutTypeCB.value === 'all') { | |
397 | + if(productType === 'all') { | |
374 | 398 | for (var dpt in this.metadata) { |
375 | 399 | for (var tc in this.metadata[dpt]) { |
376 | 400 | for (tn in this.metadata[dpt][tc]) { |
... | ... | @@ -378,10 +402,10 @@ Ext.define('amdaDesktop.EpnTapModule', { |
378 | 402 | service = this.metadata[dpt][tc][tn][serv]; |
379 | 403 | timeMinArr = service[1].split('/'); |
380 | 404 | filterDict[serv] = service[0] + (serv in filterDict ? filterDict[serv] : 0); |
381 | - if (isLatest(service[1], timeMin)) { | |
405 | + if (this.isLatest(service[1], timeMin)) { | |
382 | 406 | timeMin = service[1]; |
383 | 407 | } |
384 | - if (isLatest(service[2], timeMax)) { | |
408 | + if (this.isLatest(service[2], timeMax)) { | |
385 | 409 | timeMax = service[2]; |
386 | 410 | } |
387 | 411 | } |
... | ... | @@ -389,41 +413,41 @@ Ext.define('amdaDesktop.EpnTapModule', { |
389 | 413 | } |
390 | 414 | } |
391 | 415 | } else if (this.targetClassCB.value === 'all') { |
392 | - for (var tc in this.metadata[this.dataProdutTypeCB.value]) { | |
393 | - for (tn in this.metadata[this.dataProdutTypeCB.value][tc]) { | |
394 | - for (serv in this.metadata[this.dataProdutTypeCB.value][tc][tn]) { | |
395 | - service = this.metadata[this.dataProdutTypeCB.value][tc][tn][serv]; | |
416 | + for (var tc in this.metadata[productType]) { | |
417 | + for (tn in this.metadata[productType][tc]) { | |
418 | + for (serv in this.metadata[productType][tc][tn]) { | |
419 | + service = this.metadata[productType][tc][tn][serv]; | |
396 | 420 | filterDict[serv] = service[0] + (serv in filterDict ? filterDict[serv] : 0); |
397 | - if (isLatest(service[1], timeMin)) { | |
421 | + if (this.isLatest(service[1], timeMin)) { | |
398 | 422 | timeMin = service[1]; |
399 | 423 | } |
400 | - if (isLatest(service[2], timeMax)) { | |
424 | + if (this.isLatest(service[2], timeMax)) { | |
401 | 425 | timeMax = service[2]; |
402 | 426 | } |
403 | 427 | } |
404 | 428 | } |
405 | 429 | } |
406 | 430 | } else if (this.targetNameCB.value === 'all') { |
407 | - for (tn in this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value]) { | |
408 | - for (serv in this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value][tn]) { | |
409 | - service = this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value][tn][serv]; | |
431 | + for (tn in this.metadata[productType][targetClass]) { | |
432 | + for (serv in this.metadata[productType][targetClass][tn]) { | |
433 | + service = this.metadata[productType][targetClass][tn][serv]; | |
410 | 434 | filterDict[serv] = service[0] + (serv in filterDict ? filterDict[serv] : 0); |
411 | - if (isLatest(service[1], timeMin)) { | |
435 | + if (this.isLatest(service[1], timeMin)) { | |
412 | 436 | timeMin = service[1]; |
413 | 437 | } |
414 | - if (isLatest(service[2], timeMax)) { | |
438 | + if (this.isLatest(service[2], timeMax)) { | |
415 | 439 | timeMax = service[2]; |
416 | 440 | } |
417 | 441 | } |
418 | 442 | } |
419 | 443 | } else { |
420 | - for (serv in this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value][this.targetNameCB.value]) { | |
421 | - service = this.metadata[this.dataProdutTypeCB.value][this.targetClassCB.value][this.targetNameCB.value][serv]; | |
444 | + for (serv in this.metadata[productType][targetClass][targetName]) { | |
445 | + service = this.metadata[productType][targetClass][targetName][serv]; | |
422 | 446 | filterDict[serv] = service[0] + (serv in filterDict ? filterDict[serv] : 0); |
423 | - if (isLatest(service[1], timeMin)) { | |
447 | + if (this.isLatest(service[1], timeMin)) { | |
424 | 448 | timeMin = service[1]; |
425 | 449 | } |
426 | - if (isLatest(service[2], timeMax)) { | |
450 | + if (this.isLatest(service[2], timeMax)) { | |
427 | 451 | timeMax = service[2]; |
428 | 452 | } |
429 | 453 | } |
... | ... | @@ -443,6 +467,54 @@ Ext.define('amdaDesktop.EpnTapModule', { |
443 | 467 | var service = this.services[filter[s][0]]; |
444 | 468 | this.servicesGrid.getStore().add({'id': filter[s][0], 'nbResults': filter[s][1], 'shortName': service['shortname'], 'title': service['title'], 'accessURL': service['accessurl']}); |
445 | 469 | } |
470 | + }, | |
471 | + | |
472 | + /** | |
473 | + Callback function, called from the PHP script when the query result is received, when a service is selected. | |
474 | + | |
475 | + Among other things, update the `epnTapCurrentPageLb` label (see `EpnTapUI.createNavigationPanel()`). | |
476 | + */ | |
477 | + updateNbRows: function(nb_results) { | |
478 | + var totalPages = '' + Math.ceil(Number(nb_results) / Ext.getCmp('epnTapRowsPerPageNf').value); | |
479 | + | |
480 | + Ext.getCmp('epnTapCurrentPageLb').setText('1'); | |
481 | + Ext.getCmp('epnTapTotalPagesLb').setText(totalPages); | |
482 | + | |
483 | + Ext.getCmp('epnTapPreviousPageBtn').setDisabled(true); | |
484 | + Ext.getCmp('epnTapFirstPageBtn').setDisabled(true); | |
485 | + Ext.getCmp('epnTapNextPageBtn').setDisabled(totalPages === '1'); | |
486 | + Ext.getCmp('epnTapLastPageBtn').setDisabled(totalPages === '1'); | |
487 | + }, | |
488 | + | |
489 | + /** | |
490 | + Callback function, called from the PHP script when the query result is received, when a service is selected or a | |
491 | + navigation button is clicked. | |
492 | + | |
493 | + Among other things, fill the `epnTapGranulesGrid` table (see `EpnTapUI.granulesStore`). | |
494 | + */ | |
495 | + fillGranules: function(granules) { | |
496 | + if (granules == null) { | |
497 | + console.log("There is no granules to add."); | |
498 | + } else { | |
499 | + try { | |
500 | + console.log('Added granules:', granules); | |
501 | + Ext.getCmp('epnTapGranulesGrid').getStore().removeAll(); | |
502 | + Ext.getCmp('epnTapGranulesGrid').getStore().add(granules); | |
503 | + } catch( e ) { | |
504 | + console.log('Can not add granules: ' + e); | |
505 | + } | |
506 | + } | |
507 | + Ext.getCmp('epnTapServicesGrid').setDisabled(false); | |
508 | + Ext.getCmp('epnTapServicesGrid').getEl().setStyle('cursor', 'default'); // CSS is correctly changed but without visible result. | |
509 | + }, | |
510 | + | |
511 | + /** | |
512 | + Called before to send a query. Set the EpnTap panel in "waiting mode", informing to the user that a request is | |
513 | + processing. The altered elements are resetted in `fillGranules()`. | |
514 | + */ | |
515 | + wait: function() { | |
516 | + this.servicesGrid.getEl().setStyle('cursor', 'wait'); | |
517 | + this.servicesGrid.setDisabled(true); // CSS is correctly changed but without visible result. | |
446 | 518 | } |
447 | 519 | |
448 | 520 | }); |
... | ... |
js/app/views/EpnTapUI.js
... | ... | @@ -3,379 +3,590 @@ |
3 | 3 | * Name: EpnTapUI.js |
4 | 4 | * @class amdaUI.EpnTapUI |
5 | 5 | * @extends Ext.tab.Panel |
6 | - * @brief client for EPN-TAP services (View) | |
7 | 6 | * @author Nathanael JOURDANE |
8 | 7 | * 24/10/2016: file creation |
9 | 8 | */ |
10 | 9 | |
11 | - Ext.create('Ext.data.Store', { | |
10 | +// TODO: Dรฉplacer les stores dans un fichier sรฉparรฉ dans js.stores ! | |
11 | + | |
12 | +/** | |
13 | +`productTypesStore`: An ExtJS Store containing the list of the different data product types defined on all granules, on | |
14 | +all available EPN-TAP services (defined in `generic_data/EpnTapData/metadata.json`, updated periodically with a cron | |
15 | +script). | |
16 | + | |
17 | +This list is used to fill the `productTypeCB` combo box, which is initilized in `EpnTapModule` at the panel creation. | |
18 | + | |
19 | +- `id`: the data product type IDs, according to the EPN-TAP specification (see | |
20 | + https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=1148225); | |
21 | +- `name`: the data product name, according to the EPN-TAP specification (ibid). | |
22 | + | |
23 | +These IDs and names are hard-defined in the JSon file `generic_data/EpnTapData/dataproduct_types.json`. | |
24 | + | |
25 | +Notes: | |
26 | +- if a granule contains a data product type which is not conform to the EPN-TAP definition (ibid), it is not displayed | |
27 | +in this store and an information message is displayed on the JavaScript console during the panel creation. | |
28 | +- if a data product type is not present in any of the granules from the EPN-TAP services, it is not present in this | |
29 | +store. | |
30 | +*/ | |
31 | +Ext.create('Ext.data.Store', { | |
12 | 32 | storeId:'productTypesStore', |
13 | 33 | fields: ['id', 'name'] |
14 | 34 | }); |
15 | 35 | |
36 | +/** | |
37 | +`targetClassesStore`: An ExtJS Store containing the list of the different target classes defined on all granules, on | |
38 | +all available EPN-TAP services (defined in `generic_data/EpnTapData/metadata.json`, updated periodically with a cron | |
39 | +script), which match with the selected data product type. | |
40 | + | |
41 | +This list is used to fill the `targetClassCB` combo box, which is updated by `EpnTapModule` each time a new product type | |
42 | +is selected. | |
43 | + | |
44 | +- `id`: the target class in lowercase, with the underscore between each word; | |
45 | +- `name`: the target class, capitalized with spaces between each word (done `EpnTapModule.prettify()`). | |
46 | +*/ | |
16 | 47 | Ext.create('Ext.data.Store', { |
17 | 48 | storeId:'targetClassesStore', |
18 | 49 | fields: ['id', 'name'] |
19 | 50 | }); |
20 | 51 | |
52 | +/** | |
53 | +`targetNamesStore`: An ExtJS Store containing the list of the different target names defined on all granules, on | |
54 | +all available EPN-TAP services (defined in `generic_data/EpnTapData/metadata.json`, updated periodically with a cron | |
55 | +script), which match with the selected data product and target class. | |
56 | + | |
57 | +This list is used to fill the `targetNameCB` combo box, which is updated by `EpnTapModule` each time a new target class | |
58 | +(or, by transitivity, product type) is selected. | |
59 | + | |
60 | +- `id`: the target name in lowercase, with the underscore between each word; | |
61 | +- `name`: the target name, capitalized with spaces between each word (done `EpnTapModule.prettify()`). | |
62 | +*/ | |
21 | 63 | Ext.create('Ext.data.Store', { |
22 | 64 | storeId: 'targetNamesStore', |
23 | 65 | fields: ['id', 'name'] |
24 | 66 | }); |
25 | 67 | |
68 | +/** | |
69 | +`servicesStore`: An ExtJS Store containing the list of the EPN-TAP services (defined in | |
70 | +`generic_data/EpnTapData/metadata.json`, updated periodically with a cron script), which contains at least one granule | |
71 | +matching with the granules filter (the selected data product type, target class and target name). | |
72 | + | |
73 | +This list is used to fill the `servicesGrid` table, which is updated by `EpnTapModule` each time a new target name | |
74 | +(or, by transitivity, target class or product type) is selected. | |
75 | + | |
76 | +- `id`: the database name of the service, according to the `table_name` column from the `rr.res_table` in the | |
77 | + registry database; | |
78 | +- `nbResults`: the number of granules matching with the granules filter for this service; | |
79 | +- `shortName`: the service short name, according to the `short_name` column from the `rr.resource` table in the registry | |
80 | + database; | |
81 | +- `title`: the service title, according to the `res_title` column from the `rr.resource` table in the registry database; | |
82 | +- `accessURL`: the service access URL, according to the `access_url` column from the `rr.interface` table in the | |
83 | + registry database. | |
84 | +*/ | |
26 | 85 | Ext.create('Ext.data.Store', { |
27 | 86 | storeId: 'servicesStore', |
28 | 87 | fields: ['id', 'nbResults', 'shortName', 'title', 'accessURL'] |
29 | 88 | }); |
30 | 89 | |
90 | +/** | |
91 | +`granulesStore`: An ExtJS Store containing the list of granules of the selected service (on `servicesGrid`), which match | |
92 | +with tge granules filter (the selected data product type, target class and target name). | |
93 | + | |
94 | +This list is used to fill the `granulesGrid` table, which is updated by `EpnTapModule` each time a new service is | |
95 | +selected. | |
96 | + | |
97 | +- `num`: the line number, according to the order of the query response and the current page (see `currentPageLb`); | |
98 | +- `dataproduct_type`: the dataproduct_type EPN-TAP parameter, as defined in | |
99 | + https://voparis-confluence.obspm.fr/display/VES/EPN-TAP+V2.0+parameters. | |
100 | +- `target_name`: the target_name EPN-TAP parameter (ibid); | |
101 | +- `time_min`: the time_min EPN-TAP parameter (ibid); | |
102 | +- `time_max`: the time_max EPN-TAP parameter (ibid); | |
103 | +- `access_format`: the access_format EPN-TAP parameter (ibid); | |
104 | +- `granule_uid`: the granule_uid EPN-TAP parameter (ibid); | |
105 | +- `access_estsize`: the access_estsize EPN-TAP parameter (ibid); | |
106 | +- `access_url`: the access_url EPN-TAP parameter (ibid); | |
107 | +- `thumbnail_url`: the thumbnail_url EPN-TAP parameter (ibid). | |
108 | +*/ | |
31 | 109 | Ext.create('Ext.data.Store', { |
32 | 110 | storeId:'granulesStore', |
33 | 111 | fields:['num', 'dataproduct_type', 'target_name', 'time_min', 'time_max', 'access_format', 'granule_uid', 'access_estsize', 'access_url', 'thumbnail_url'] |
34 | 112 | }); |
35 | 113 | |
114 | +/** | |
115 | +`EpnTapUI`: The view of the AMDA EPN-TAP module, allowing the user to query and display granules information from | |
116 | +EPN-TAP services. | |
117 | + | |
118 | +Note: The controller part of this module is defined in `js/app/controller/EpnTapModule`. | |
119 | +*/ | |
36 | 120 | Ext.define('amdaUI.EpnTapUI', { |
37 | - extend: 'Ext.container.Container', | |
121 | + extend: 'Ext.panel.Panel', | |
38 | 122 | alias: 'widget.panelEpnTap', |
123 | + requires: ['amdaUI.IntervalUI'], | |
39 | 124 | |
40 | - txtRender: function(val) { | |
41 | - return '<p style="white-space: normal;">' + val + '</p>'; | |
42 | - }, | |
43 | - linkRender: function(val) { | |
44 | - return '<a href="' + val + '">data</a>'; | |
45 | - }, | |
46 | - imgRender: function(val) { | |
47 | - return '<img width="40px height="40px" src="' + val + '">'; | |
48 | - }, | |
49 | - dptRender: function(val) { | |
50 | - var productTypeDict = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).productTypeDict; | |
51 | - return (val in productTypeDict) ? '<p style="white-space: normal;">' + productTypeDict[val] + '</p>' : '<em>' + val + '</em>'; | |
52 | - }, | |
53 | - formatRender: function(val) { | |
54 | - var mimetypeDict = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id).mimetypeDict; | |
55 | - return (val in mimetypeDict) ? mimetypeDict[val] : '<em style="white-space: normal;">' + val + '</em>'; | |
56 | - }, | |
57 | - sizeRender: function(val) { | |
58 | - var size = parseInt(val); | |
59 | - if (isNaN(size)) { | |
60 | - return ''; | |
61 | - } else if (size >= 1024*1024) { | |
62 | - return (size/(1024*1024)).toPrecision(3) + 'Go'; | |
63 | - } else if (size >= 1024) { | |
64 | - return (size/1024).toPrecision(3) + 'Mo'; | |
65 | - } else { | |
66 | - return size + 'Ko'; | |
67 | - } | |
68 | - }, | |
69 | - | |
125 | + /** | |
126 | + Method constructor, which basically call the `init()` method to create the EpnTap panel. | |
127 | + */ | |
70 | 128 | constructor: function(config) { |
71 | 129 | this.init(config); |
72 | 130 | this.callParent(arguments); |
73 | 131 | }, |
74 | 132 | |
133 | + /** | |
134 | + Create all the EpnTapPanel UI elements, and apply the AMDA module `config` (which includes the created items). | |
135 | + | |
136 | + When the panel is correctly rendered, the panel triggers `EpnTapModule.onWindowLoaded()`. | |
137 | + | |
138 | + Note: All the UI elements creation are defined as functions in this init method and not as methods in order to make | |
139 | + them private (ie. to avoid `EpnTapUI.createServicesGrid();`, which doesn't make sense). | |
140 | + */ | |
75 | 141 | init: function(config) { |
142 | + var mod = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id); | |
143 | + | |
144 | + /************ | |
145 | + *** Grids *** | |
146 | + ************/ | |
147 | + | |
148 | + /** | |
149 | + Create `epnTapServicesGrid`, an ExtJS grid containing the EPN-TAP services matching with the filter form | |
150 | + (`serviceFilterPanel`). | |
151 | + | |
152 | + For each service, this grid displays: | |
153 | + - the service name; | |
154 | + - the number of granules matching with the filter. | |
155 | + | |
156 | + Other informations are available through the tooltip `serviceTooltip`. | |
157 | + | |
158 | + A click on a service triggers `EpnTapModule.onServiceSelected()`, which basically fills `GranulesGrid` by the | |
159 | + service granules. | |
160 | + */ | |
161 | + var createServicesGrid = function() { | |
162 | + return new Ext.grid.Panel({ | |
163 | + id: 'epnTapServicesGrid', | |
164 | + title: 'Services', | |
165 | + store: Ext.data.StoreManager.lookup('servicesStore'), | |
166 | + flex: 1, | |
167 | + columns: [ | |
168 | + {text: 'Name', dataIndex: 'id', flex: 3}, | |
169 | + {text: 'Results', dataIndex: 'nbResults', flex: 2} | |
170 | + ], | |
171 | + renderer: function(value, metadata,record) { | |
172 | + return getExpandableImage(value, metadata,record); | |
173 | + }, | |
174 | + listeners: { | |
175 | + 'cellclick': function(grid, td, cellIndex, record) { mod.onServiceSelected(record.data['id']); } | |
176 | + }, | |
177 | + renderTo: Ext.getBody() | |
178 | + }); | |
179 | + }; | |
76 | 180 | |
77 | - var epnTapModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.epntap.id); | |
78 | - | |
79 | - // *** Grids *** | |
80 | - | |
81 | - this.servicesGrid = new Ext.grid.Panel({ | |
82 | - id: 'servicesGrid', | |
83 | - title: 'Services', | |
84 | - store: Ext.data.StoreManager.lookup('servicesStore'), | |
85 | - flex: 1, | |
86 | - columns: [ | |
87 | - {text: 'Name', dataIndex: 'id', flex: 3}, | |
88 | - {text: 'Results', dataIndex: 'nbResults', flex: 2} | |
89 | - ], | |
90 | - renderer: function(value, metadata,record) { | |
91 | - return getExpandableImage(value, metadata,record); | |
92 | - }, | |
93 | - listeners: { | |
94 | - 'cellclick': function(grid, td, cellIndex, record) { | |
95 | - epnTapModule.onServiceSelected(record.data['id']); | |
96 | - } | |
97 | - }, | |
98 | - renderTo: Ext.getBody() | |
99 | - }); | |
100 | - | |
101 | - this.serviceTooltip = new Ext.tip.ToolTip({ | |
102 | - id: 'serviceTooltip', | |
103 | - target: Ext.getCmp('servicesGrid').getView().el, | |
104 | - delegate: Ext.getCmp('servicesGrid').getView().itemSelector, | |
105 | - trackMouse: true, | |
106 | - listeners: { | |
107 | - beforeshow: function updateTipBody(tooltip) { | |
108 | - var service = Ext.getCmp('servicesGrid').getView().getRecord(tooltip.triggerElement); | |
109 | - var ttContent = '<h3>' + service.get('shortName') + '</h3>'; | |
110 | - ttContent += '<p>' + service.get('title') + '</p>'; | |
111 | - ttContent += '<p>' + service.get('accessURL') + '</p>'; | |
112 | - tooltip.update(ttContent); | |
113 | - } | |
114 | - }, | |
115 | - renderTo: Ext.getBody() | |
116 | - }); | |
117 | - | |
118 | - this.granulesGrid = new Ext.grid.Panel({ | |
119 | - id: 'granulesGrid', | |
120 | - title: 'Granules', | |
121 | - store: Ext.data.StoreManager.lookup('granulesStore'), | |
122 | - flex: 5, | |
123 | - columns: [ | |
124 | - { text: 'Num', dataIndex: 'num', flex: 1, renderer: this.txtRender }, | |
125 | - { text: 'Type', dataIndex: 'dataproduct_type', flex: 2, renderer: this.dptRender }, | |
126 | - { text: 'Target', dataIndex: 'target_name', flex: 2, renderer: this.txtRender }, | |
127 | - { text: 'Time min', dataIndex: 'time_min', flex: 2, renderer: this.txtRender }, | |
128 | - { text: 'Time max', dataIndex: 'time_max', flex: 2, renderer: this.txtRender }, | |
129 | - { text: 'Format', dataIndex: 'access_format', flex: 2, renderer: this.formatRender }, | |
130 | - { text: 'uid', dataIndex: 'granule_uid', flex: 2, renderer: this.txtRender }, | |
131 | - { text: 'Size', dataIndex: 'access_estsize', flex: 1, renderer: this.sizeRender }, | |
132 | - { text: 'URL', dataIndex: 'access_url', flex: 1, renderer: this.linkRender }, | |
133 | - { text: 'Thumb.', dataIndex: 'thumbnail_url', flex: 1, renderer: this.imgRender} | |
134 | - ], | |
135 | - listeners: { | |
136 | - 'cellclick': function(grid, td, cellIndex, record) { | |
137 | - epnTapModule.onGranuleSelected(record.data['id']); | |
138 | - } | |
139 | - }, | |
140 | - renderTo: Ext.getBody() | |
141 | - }); | |
142 | - | |
143 | - this.granuleTooltip = new Ext.tip.ToolTip({ | |
144 | - id: 'granuleTooltip', | |
145 | - target: Ext.getCmp('granulesGrid').getView().el, | |
146 | - delegate: Ext.getCmp('granulesGrid').getView().itemSelector, | |
147 | - trackMouse: true, | |
148 | - listeners: { | |
149 | - beforeshow: function updateTipBody(tooltip) { | |
150 | - var thumb = Ext.getCmp('granulesGrid').getView().getRecord(tooltip.triggerElement).get('thumbnail_url'); | |
151 | - tooltip.update('<img src="' + thumb + '">'); | |
152 | - } | |
153 | - }, | |
154 | - renderTo: Ext.getBody() | |
155 | - }); | |
156 | - | |
157 | - // *** Service filter elements, left part *** | |
158 | - | |
159 | - this.productTypeCB = new Ext.form.field.ComboBox({ | |
160 | - id: 'productTypeCB', | |
161 | - fieldLabel: 'Product type', | |
162 | - store: Ext.data.StoreManager.lookup('productTypesStore'), | |
163 | - queryMode: 'local', | |
164 | - displayField: 'name', | |
165 | - valueField: 'id', | |
166 | - name: 'productType', | |
167 | - editable: false, | |
168 | - listeners: { | |
169 | - 'select': function(combo) { | |
170 | - epnTapModule.onProductTypeCBChanged(combo.value); | |
181 | + /** | |
182 | + Create `epnTapServiceTooltip`, an ExtJS tooltip for the `servicesGrid` rows, in order to display additional | |
183 | + information for each service, such as: | |
184 | + - short name; | |
185 | + - title; | |
186 | + - access URL. | |
187 | + */ | |
188 | + var createServiceTooltip = function() { | |
189 | + return new Ext.tip.ToolTip({ | |
190 | + id: 'epnTapServiceTooltip', | |
191 | + target: Ext.getCmp('epnTapServicesGrid').getView().el, | |
192 | + delegate: Ext.getCmp('epnTapServicesGrid').getView().itemSelector, | |
193 | + trackMouse: true, | |
194 | + listeners: { | |
195 | + beforeshow: function updateTipBody(tooltip) { | |
196 | + var service = Ext.getCmp('servicesGrid').getView().getRecord(tooltip.triggerElement); | |
197 | + var ttContent = '<h3>' + service.get('shortName') + '</h3>'; | |
198 | + ttContent += '<p>' + service.get('title') + '</p>'; | |
199 | + ttContent += '<p>' + service.get('accessURL') + '</p>'; | |
200 | + tooltip.update(ttContent); | |
201 | + } | |
202 | + }, | |
203 | + renderTo: Ext.getBody() | |
204 | + }); | |
205 | + }; | |
206 | + | |
207 | + /** | |
208 | + Create `epnTapGranulesGrid`, an ExtJS grid containing the granules of the selected service in | |
209 | + `epnTapServiceGrid`. | |
210 | + | |
211 | + For each granule, this grid displays: | |
212 | + - the row number; | |
213 | + - the dataproduct type; | |
214 | + - the target name; | |
215 | + - the min and max times; | |
216 | + - the format; | |
217 | + - the UID (granule identifier); | |
218 | + - the estimated size; | |
219 | + - the URL; | |
220 | + - the thumbnail. | |
221 | + | |
222 | + For more information about these parameters, see https://voparis-confluence.obspm.fr/display/VES/EPN-TAP+V2.0+parameters. | |
223 | + Each of these information are displayed in a specific rendering to improve user experience. | |
224 | + Other informations are available through the tooltip `granuleTooltip`. | |
225 | + | |
226 | + A click on a granule triggers `EpnTapModule.onGranuleSelected()`. | |
227 | + */ | |
228 | + var createGranulesGrid = function() { | |
229 | + var txtRender = function(val) { | |
230 | + return '<p style="white-space: normal;">' + val + '</p>'; | |
231 | + }; | |
232 | + var linkRender = function(val) { | |
233 | + return '<a href="' + val + '">data</a>'; | |
234 | + }; | |
235 | + var imgRender = function(val) { | |
236 | + return '<img width="40px height="40px" src="' + val + '">'; | |
237 | + }; | |
238 | + var dptRender = function(val) { | |
239 | + return (val in mod.productTypeDict) ? '<p style="white-space: normal;">' + mod.productTypeDict[val] + '</p>' : '<em>' + val + '</em>'; | |
240 | + }; | |
241 | + var formatRender = function(val) { | |
242 | + return (val in mod.mimetypeDict) ? mod.mimetypeDict[val] : '<em style="white-space: normal;">' + val + '</em>'; | |
243 | + }; | |
244 | + var sizeRender = function(val) { | |
245 | + var size = parseInt(val); | |
246 | + if (isNaN(size)) { | |
247 | + return ''; | |
248 | + } else if (size >= 1024*1024) { | |
249 | + return (size/(1024*1024)).toPrecision(3) + 'Go'; | |
250 | + } else if (size >= 1024) { | |
251 | + return (size/1024).toPrecision(3) + 'Mo'; | |
252 | + } else { | |
253 | + return size + 'Ko'; | |
171 | 254 | } |
172 | - } | |
173 | - }); | |
174 | - | |
175 | - this.targetClassCB = new Ext.form.field.ComboBox({ | |
176 | - id: 'targetClassCB', | |
177 | - fieldLabel: 'Target class', | |
178 | - store: Ext.data.StoreManager.lookup('targetClassesStore'), | |
179 | - queryMode: 'local', | |
180 | - displayField: 'name', | |
181 | - valueField: 'id', | |
182 | - name: 'targetClass', | |
183 | - editable: false, | |
184 | - listeners: { | |
185 | - 'select': function(combo) { | |
186 | - epnTapModule.onTargetClassCBChanged(combo.value); | |
255 | + }; | |
256 | + | |
257 | + return new Ext.grid.Panel({ | |
258 | + id: 'epnTapGranulesGrid', | |
259 | + title: 'Granules', | |
260 | + store: Ext.data.StoreManager.lookup('granulesStore'), | |
261 | + flex: 5, | |
262 | + columns: [ | |
263 | + { text: 'Num', dataIndex: 'num', flex: 1, renderer: txtRender }, | |
264 | + { text: 'Type', dataIndex: 'dataproduct_type', flex: 2, renderer: dptRender }, | |
265 | + { text: 'Target', dataIndex: 'target_name', flex: 2, renderer: txtRender }, | |
266 | + { text: 'Time min', dataIndex: 'time_min', flex: 2, renderer: txtRender }, | |
267 | + { text: 'Time max', dataIndex: 'time_max', flex: 2, renderer: txtRender }, | |
268 | + { text: 'Format', dataIndex: 'access_format', flex: 2, renderer: formatRender }, | |
269 | + { text: 'uid', dataIndex: 'granule_uid', flex: 2, renderer: txtRender }, | |
270 | + { text: 'Size', dataIndex: 'access_estsize', flex: 1, renderer: sizeRender }, | |
271 | + { text: 'URL', dataIndex: 'access_url', flex: 1, renderer: linkRender }, | |
272 | + { text: 'Thumb.', dataIndex: 'thumbnail_url', flex: 1, renderer: imgRender} | |
273 | + ], | |
274 | + listeners: { | |
275 | + 'cellclick': function(grid, td, cellIndex, record) { mod.onGranuleSelected(record.data['id']); } | |
276 | + }, | |
277 | + renderTo: Ext.getBody() | |
278 | + }); | |
279 | + }; | |
280 | + | |
281 | + /** | |
282 | + Create `epnTapGranuleTooltip`, an ExtJS tooltip for the `granulesGrid` rows, in order to display additional | |
283 | + information for each granule which is currently only the granule thumbnail, in full size. | |
284 | + */ | |
285 | + var createGranuleTooltip = function() { | |
286 | + return new Ext.tip.ToolTip({ | |
287 | + id: 'epnTapGranuleTooltip', | |
288 | + target: Ext.getCmp('granulesGrid').getView().el, | |
289 | + delegate: Ext.getCmp('granulesGrid').getView().itemSelector, | |
290 | + trackMouse: true, | |
291 | + listeners: { | |
292 | + beforeshow: function updateTipBody(tooltip) { | |
293 | + var thumb = Ext.getCmp('granulesGrid').getView().getRecord(tooltip.triggerElement).get('thumbnail_url'); | |
294 | + tooltip.update('<img src="' + thumb + '">'); | |
295 | + } | |
296 | + }, | |
297 | + renderTo: Ext.getBody() | |
298 | + }); | |
299 | + }; | |
300 | + | |
301 | + /** | |
302 | + Create `epnTapGridsPanel`, an ExtJS Panel, containing `epnTapServicesGrid` and `epnTapGranulesGrid`. | |
303 | + | |
304 | + After the rendering of the grids, it triggers `epnTapModule.onWindowLoaded()`, which basically fill | |
305 | + `epnTapServicesGrid` for the first time. | |
306 | + */ | |
307 | + var createGridsPanel = function() { | |
308 | + var self = this; | |
309 | + return new Ext.panel.Panel({ | |
310 | + id: 'epnTapGridsPanel', | |
311 | + region: 'center', | |
312 | + height: 350, | |
313 | + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
314 | + items: [ | |
315 | + createServicesGrid(), | |
316 | + createGranulesGrid() | |
317 | + ], | |
318 | + listeners: { | |
319 | + afterrender: function() { mod.onWindowLoaded(self); } | |
187 | 320 | } |
188 | - } | |
189 | - }); | |
190 | - | |
191 | - this.targetNameCB = new Ext.form.field.ComboBox({ | |
192 | - id: 'targetNameCB', | |
193 | - fieldLabel: 'Target name', | |
194 | - store: Ext.data.StoreManager.lookup('targetNamesStore'), | |
195 | - queryMode: 'local', | |
196 | - displayField: 'name', | |
197 | - valueField: 'id', | |
198 | - name: 'targetName', | |
199 | - triggerAction: 'all', | |
200 | - typeAhead: true, | |
201 | - mode: 'remote', | |
202 | - minChars: 2, | |
203 | - forceSelection: true, | |
204 | - listeners: { | |
205 | - 'select': function(combo) { | |
206 | - epnTapModule.onTargetNameCBChanged(combo.value); | |
321 | + }); | |
322 | + }; | |
323 | + | |
324 | + /*************************** | |
325 | + *** Service filter panel *** | |
326 | + ***************************/ | |
327 | + | |
328 | + /** | |
329 | + Create `epnTapProductTypeCB`, an ExtJS ComboBox, containing a list of product types as defined in | |
330 | + `epnTapProductTypesStore`, which is initilized by `EpnTapModule`. | |
331 | + | |
332 | + The selection of a produt type triggers `EpnTapModule.onProductTypeCBChanged()`, which basically update | |
333 | + `epnTapTargetClassCB` and `epnTapGranulesGrid`. | |
334 | + */ | |
335 | + var createProductTypeCB = function() { | |
336 | + return new Ext.form.field.ComboBox({ | |
337 | + id: 'epnTapProductTypeCB', | |
338 | + fieldLabel: 'Product type', | |
339 | + store: Ext.data.StoreManager.lookup('productTypesStore'), | |
340 | + queryMode: 'local', | |
341 | + displayField: 'name', | |
342 | + valueField: 'id', | |
343 | + name: 'productType', | |
344 | + editable: false, | |
345 | + listeners: { | |
346 | + 'select': function(combo) { mod.onProductTypeCBChanged(combo.value); } | |
207 | 347 | } |
208 | - } | |
209 | - }); | |
210 | - | |
211 | - // *** Service filter elements, right part *** | |
212 | - | |
213 | - this.startTimeDF = new Ext.form.field.Date({ | |
214 | - id: 'startTimeDF', | |
215 | - fieldLabel: 'Start time', | |
216 | - format: 'Y/m/d H:i:s', | |
217 | - width: 100, | |
218 | - listeners: { | |
219 | - 'select': function(dateField, value) { | |
220 | - epnTapModule.onTargetNameCBChanged(value); | |
348 | + }); | |
349 | + }; | |
350 | + | |
351 | + /** | |
352 | + Create `epnTapTargetClassCB`, an ExtJS ComboBox, containing a list of target classes corresponding to the | |
353 | + selected product type, as defined in `targetClassesStore`, which is initilized by `EpnTapModule`. | |
354 | + | |
355 | + The selection of a target class triggers the `EpnTapModule.onTargetClassCBChanged()`, which basically updates | |
356 | + `targetNameCB` and `granulesGrid`. | |
357 | + */ | |
358 | + var createTargetClassCB = function() { | |
359 | + return new Ext.form.field.ComboBox({ | |
360 | + id: 'epnTapTargetClassCB', | |
361 | + fieldLabel: 'Target class', | |
362 | + store: Ext.data.StoreManager.lookup('targetClassesStore'), | |
363 | + queryMode: 'local', | |
364 | + displayField: 'name', | |
365 | + valueField: 'id', | |
366 | + name: 'targetClass', | |
367 | + editable: false, | |
368 | + listeners: { | |
369 | + 'select': function(combo) { mod.onTargetClassCBChanged(combo.value); } | |
221 | 370 | } |
222 | - } | |
223 | - }); | |
224 | - | |
225 | - this.stopTimeDF = new Ext.form.field.Date({ | |
226 | - id: 'stopTimeDF', | |
227 | - fieldLabel: 'Stop time', | |
228 | - format: 'Y/m/d H:i:s', | |
229 | - width: 100, | |
230 | - listeners: { | |
231 | - 'select': function(dateField, value) { | |
232 | - epnTapModule.onTargetNameCBChanged(value); | |
371 | + }); | |
372 | + }; | |
373 | + | |
374 | + /** | |
375 | + Create `epnTapTargetNameCB`, an ExtJS ComboBox, containing a list of target names corresponding to the selected | |
376 | + target class, as defined in `targetNamesStore`, which is initilized by `EpnTapModule`. | |
377 | + | |
378 | + The selection of a target name triggers `EpnTapModule.onTargetNameCBChanged()`, which basically updates | |
379 | + `granulesGrid`. | |
380 | + */ | |
381 | + var createTargetNameCB = function() { | |
382 | + return new Ext.form.field.ComboBox({ | |
383 | + id: 'epnTapTargetNameCB', | |
384 | + fieldLabel: 'Target name', | |
385 | + store: Ext.data.StoreManager.lookup('targetNamesStore'), | |
386 | + queryMode: 'local', | |
387 | + displayField: 'name', | |
388 | + valueField: 'id', | |
389 | + name: 'targetName', | |
390 | + triggerAction: 'all', | |
391 | + typeAhead: true, | |
392 | + mode: 'remote', | |
393 | + minChars: 2, | |
394 | + forceSelection: true, | |
395 | + listeners: { | |
396 | + 'select': function(combo) { mod.onTargetNameCBChanged(combo.value); } | |
233 | 397 | } |
234 | - } | |
235 | - }); | |
236 | - | |
237 | - this.durationPanel = new Ext.panel.Panel({ | |
238 | - id: 'duration', | |
239 | - layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
240 | - border: false, | |
241 | - defaults: { width: 60, margin: '0, 5, 0, 5', xtype: 'numberfield', listeners: { 'select': function(elmt) { epnTapModule.onDurationChanged(elmt); } } }, | |
242 | - items: [{ | |
243 | - id: 'days', | |
244 | - margin: '0, 5, 0, 0', | |
245 | - fieldLabel: 'Duration', | |
246 | - emptyText: 'Days', | |
247 | - width: 170 | |
248 | - }, { | |
249 | - id: 'hours', | |
250 | - emptyText: 'Hours' | |
251 | - }, { | |
252 | - id: 'minutes', | |
253 | - emptyText: 'Min.' | |
254 | - }, { | |
255 | - id: 'seconds', | |
256 | - emptyText: 'Sec.' | |
257 | - }] | |
258 | - }); | |
259 | - | |
260 | - this.rowPerPageNf = new Ext.form.field.Number({ | |
261 | - id: 'rowsPerPageNf', | |
262 | - fieldLabel: 'Rows per page', | |
263 | - margin: '4 0 4 0', | |
264 | - width: 160, | |
265 | - height: 20, | |
266 | - value: 20, | |
267 | - minValue: 1, | |
268 | - maxValue: 2000, | |
269 | - listeners: { | |
270 | - 'change': function(rowPerPageNf, newValue) { | |
271 | - epnTapModule.onRowsPerPageChanged(newValue); | |
398 | + }); | |
399 | + }; | |
400 | + | |
401 | + /** | |
402 | + Create `epnTapServiceFilterPanel`, an ExtJS Panel containing two containers: | |
403 | + - the left container, containing the combo boxes (for product type, target class and target name) | |
404 | + and the navigation panel; | |
405 | + - the right container, containing the time selector. | |
406 | + */ | |
407 | + var createServiceFilterPanel = function() { | |
408 | + return new Ext.panel.Panel({ | |
409 | + id: 'epnTapServiceFilterPanel', | |
410 | + region : 'north', | |
411 | + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
412 | + defaults: { margin: 5 }, | |
413 | + items: [{ // Left part | |
414 | + xtype : 'container', | |
415 | + layout: 'form', | |
416 | + flex: 2, | |
417 | + items: [ | |
418 | + createProductTypeCB(), | |
419 | + createTargetClassCB(), | |
420 | + createTargetNameCB(), | |
421 | + { | |
422 | + xtype: 'panel', | |
423 | + layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
424 | + border: false, | |
425 | + items: [ | |
426 | + createRowPerPageNf(), | |
427 | + createNavigationPanel() | |
428 | + ] | |
429 | + } | |
430 | + ] | |
431 | + }, { // Right part | |
432 | + xtype : 'form', | |
433 | + id: 'epnTapIntervalSelector', | |
434 | + layout: 'form', | |
435 | + border: 'false', | |
436 | + flex: 2, | |
437 | + items: [ | |
438 | + createTimeSelector() | |
439 | + ] | |
440 | + }] | |
441 | + }); | |
442 | + }; | |
443 | + | |
444 | + /** | |
445 | + Create `epnTapTimeSelector`, an IntervalUI object, allowing the user to select a time interval (by filling two | |
446 | + dates and/or a duration). | |
447 | + | |
448 | + See `js/app/views/IntervalUI.js` for more information about this component. | |
449 | + */ | |
450 | + var createTimeSelector = function() { | |
451 | + return Ext.create('amdaUI.IntervalUI', { | |
452 | + id: 'epnTapTimeSelector' | |
453 | + }); | |
454 | + }; | |
455 | + | |
456 | + /*********************** | |
457 | + *** Navigation panel *** | |
458 | + ***********************/ | |
459 | + | |
460 | + /** | |
461 | + Create `epnTapRowsPerPageNf`, a ExtJS Number field, allowing the user to select the number of rows to display in | |
462 | + `epnTapGranulesGrid`. | |
463 | + | |
464 | + When a new number is entered, it triggers `EpnTapModule.onRowsPerPageChanged()`. | |
465 | + */ | |
466 | + var createRowPerPageNf = function() { | |
467 | + return new Ext.form.field.Number({ | |
468 | + id: 'epnTapRowsPerPageNf', | |
469 | + fieldLabel: 'Rows per page', | |
470 | + margin: '4 0 4 0', | |
471 | + width: 160, | |
472 | + height: 20, | |
473 | + value: 20, | |
474 | + minValue: 1, | |
475 | + maxValue: 2000, | |
476 | + listeners: { | |
477 | + 'change': function(rowPerPageNf, newValue) { mod.onRowsPerPageChanged(newValue); } | |
272 | 478 | } |
273 | - } | |
274 | - }); | |
275 | - | |
276 | - // *** Panels *** | |
277 | - | |
278 | - this.pageSelectPanel = new Ext.panel.Panel({ | |
279 | - id: 'pageSelect', | |
280 | - border: false, | |
281 | - margin: '2 0 2 50', | |
282 | - defaults: { margin: '0 5 0 5', width: 20, xtype: 'button', disabled: true}, | |
283 | - items: [{ | |
284 | - xtype: 'label', | |
285 | - text: 'Page:' | |
286 | - }, { | |
287 | - id: 'firstPageBtn', | |
288 | - text: '|<', | |
289 | - tooltip: 'First page', | |
290 | - handler: function() { epnTapModule.onFirstPageBtnClicked(); } | |
291 | - }, { | |
292 | - id: 'previousPageBtn', | |
293 | - text: '<', | |
294 | - tooltip: 'Previous page', | |
295 | - handler: function() { epnTapModule.onPreviousPageBtnClicked(); } | |
296 | - }, { | |
297 | - xtype: 'label', | |
298 | - id: 'currentPageLb', | |
299 | - tooltip: 'Current page', | |
300 | - text: '-' | |
301 | - }, { | |
302 | - xtype: 'label', | |
303 | - text: '/' | |
304 | - }, { | |
305 | - xtype: 'label', | |
306 | - id: 'totalPagesLb', | |
307 | - tooltip: 'Total pages', | |
308 | - text: '-' | |
309 | - }, { | |
310 | - id: 'nextPageBtn', | |
311 | - text: '>', | |
312 | - tooltip: 'Next page', | |
313 | - handler: function() { epnTapModule.onNextPageBtnClicked(); } | |
314 | - }, { | |
315 | - id: 'lastPageBtn', | |
316 | - text: '>|', | |
317 | - tooltip: 'Last page', | |
318 | - handler: function() { epnTapModule.onLastPageBtnClicked(); } | |
319 | - }] | |
320 | - }); | |
321 | - | |
322 | - this.granulePagePanel = new Ext.panel.Panel({ | |
323 | - id: 'granulePagePanel', | |
324 | - layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
325 | - border: false, | |
326 | - items: [this.rowPerPageNf, this.pageSelectPanel] | |
327 | - }); | |
328 | - | |
329 | - this.serviceFilterPanel = new Ext.panel.Panel({ | |
330 | - id: 'serviceFilterPanel', | |
331 | - region : 'north', | |
332 | - layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
333 | - defaults: { margin: 5 }, | |
334 | - items: [{ // Left part | |
335 | - xtype : 'container', | |
336 | - layout: 'form', | |
337 | - flex: 2, | |
338 | - items: [ this.productTypeCB, this.targetClassCB, this.targetNameCB ] | |
339 | - }, { // Right part | |
340 | - xtype : 'container', | |
341 | - layout: 'form', | |
342 | - flex: 2, | |
343 | - items: [ this.startTimeDF, this.stopTimeDF, this.durationPanel, this.granulePagePanel ] | |
344 | - }] | |
345 | - }); | |
346 | - | |
347 | - this.gridsPanel = new Ext.panel.Panel({ | |
348 | - id: 'gridsPanel', | |
349 | - region: 'center', | |
350 | - height: 350, | |
351 | - layout: { type: 'hbox', pack: 'start', align: 'stretch' }, | |
352 | - items: [ this.servicesGrid, this.granulesGrid ], | |
353 | - listeners: { | |
354 | - afterrender: function() { epnTapModule.onWindowLoaded(); } | |
355 | - } | |
356 | - }); | |
357 | - | |
358 | - this.infoPanel = new Ext.panel.Panel({ | |
359 | - id: 'infoPanel', | |
360 | - region: 'south', | |
361 | - title: 'Information', | |
362 | - collapsible: true, | |
363 | - flex: 0, | |
364 | - height: 100, | |
365 | - autoHide: false, | |
366 | - bodyStyle: 'padding: 5px', | |
367 | - iconCls: 'icon-information', | |
368 | - loader: { autoLoad: true, url: helpDir + 'epnTapHOWTO' } | |
369 | - }); | |
479 | + }); | |
480 | + }; | |
481 | + | |
482 | + /** | |
483 | + Create `epnTapNavigationPanel`, an ExtJSPanel containing several elements in order to navigate through the | |
484 | + different pages of the query result. If the number of results is highter than the `epnTapRowsPerPageNf` field | |
485 | + value, the result appears to be displayed in different pages. This panel is used to select and display the page | |
486 | + number, mainly with these following elements: | |
487 | + - `epnTapFirstPageBtn`: an ExtJS Button, used to come back to the first page of result, | |
488 | + handling `EpnTapModule.onFirstPageBtnClicked()`; | |
489 | + - `epnTapPreviousPageBtn`: an ExtJS Button, used to come back to the previous page of result, | |
490 | + handling `EpnTapModule.onPreviousPageBtnClicked()`; | |
491 | + - `epnTapCurrentPageLb`: an ExtJS Label, displaying the actual current page; TODO: use a Number field instead! | |
492 | + - `epnTapTotalPagesLb`: an ExtJS Label, displaying the total page number of results (according to the | |
493 | + `epnTapRowsPerPageNf` field value); | |
494 | + - `epnTapNextPageBtn`: an ExtJS Button, used to go to the next page of result, | |
495 | + handling `EpnTapModule.onNextPageBtnClicked()`; | |
496 | + - `epnTapLastPageBtn`: an ExtJS Button, used to come back to the last page of result, | |
497 | + handling `EpnTapModule.onLastPageBtnClicked()`. | |
498 | + | |
499 | + Note: Pages are not actually a "graphical filter": when the user navigate through the pages, a new query is send | |
500 | + to the server with the corresponding range, which improves the response time on large requests. | |
501 | + */ | |
502 | + var createNavigationPanel = function() { | |
503 | + return new Ext.panel.Panel({ | |
504 | + name: 'epnTapNavigationPanel', | |
505 | + border: false, | |
506 | + margin: '2 0 2 50', | |
507 | + defaults: { margin: '0 5 0 5', width: 20, xtype: 'button', disabled: true}, | |
508 | + items: [{ | |
509 | + xtype: 'label', | |
510 | + text: 'Page:' | |
511 | + }, { | |
512 | + id: 'epnTapFirstPageBtn', | |
513 | + text: '|<', | |
514 | + tooltip: 'First page', | |
515 | + handler: function() { mod.onFirstPageBtnClicked(); } | |
516 | + }, { | |
517 | + id: 'epnTapPreviousPageBtn', | |
518 | + text: '<', | |
519 | + tooltip: 'Previous page', | |
520 | + handler: function() { mod.onPreviousPageBtnClicked(); } | |
521 | + }, { | |
522 | + xtype: 'label', | |
523 | + id: 'epnTapCurrentPageLb', | |
524 | + tooltip: 'Current page', | |
525 | + text: '-' | |
526 | + }, { | |
527 | + xtype: 'label', | |
528 | + text: '/' | |
529 | + }, { | |
530 | + xtype: 'label', | |
531 | + id: 'epnTapTotalPagesLb', | |
532 | + tooltip: 'Total pages', | |
533 | + text: '-' | |
534 | + }, { | |
535 | + id: 'epnTapNextPageBtn', | |
536 | + text: '>', | |
537 | + tooltip: 'Next page', | |
538 | + handler: function() { mod.onNextPageBtnClicked(); } | |
539 | + }, { | |
540 | + id: 'epnTapLastPageBtn', | |
541 | + text: '>|', | |
542 | + tooltip: 'Last page', | |
543 | + handler: function() { mod.onLastPageBtnClicked(); } | |
544 | + }] | |
545 | + }); | |
546 | + }; | |
547 | + | |
548 | + /******************* | |
549 | + *** Other panels *** | |
550 | + *******************/ | |
551 | + | |
552 | + /** | |
553 | + Create `epnTapInfoPanel`, an ExtJS Panel used to display a brief user guide about how to use this module. | |
554 | + */ | |
555 | + var createInfoPanel = function() { | |
556 | + return new Ext.panel.Panel({ | |
557 | + id: 'epnTapInfoPanel', | |
558 | + region: 'south', | |
559 | + title: 'Information', | |
560 | + collapsible: true, | |
561 | + flex: 0, | |
562 | + height: 100, | |
563 | + autoHide: false, | |
564 | + bodyStyle: 'padding: 5px', | |
565 | + iconCls: 'icon-information', | |
566 | + loader: { autoLoad: true, url: helpDir + 'epnTapHOWTO' } | |
567 | + }); | |
568 | + }; | |
569 | + | |
570 | + // TODO tester ceci: | |
571 | + // config.title = 'EPN-TAP'; | |
572 | + // config.layout = 'border'; | |
573 | + // config.items = [ | |
574 | + // createServiceFilterPanel(config.targetName), | |
575 | + // createGridsPanel(), | |
576 | + // createInfoPanel() | |
577 | + // ]; | |
578 | + // Ext.apply(this, Ext.apply(arguments, config)); | |
370 | 579 | |
371 | 580 | var myConf = { |
372 | 581 | width: 1000, |
373 | 582 | height: 550, |
374 | 583 | layout: 'border', |
375 | - items: [ this.serviceFilterPanel, this.gridsPanel, this.infoPanel ] | |
584 | + items: [ | |
585 | + createServiceFilterPanel(), | |
586 | + createGridsPanel(), | |
587 | + createInfoPanel() | |
588 | + ] | |
376 | 589 | }; |
377 | - | |
378 | 590 | Ext.apply(this, Ext.apply(arguments, myConf)); |
379 | - | |
380 | 591 | } |
381 | 592 | }); |
... | ... |
js/app/views/IntervalUI.js
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | * @brief common component to select interval |
7 | 7 | * @author Benjamin |
8 | 8 | * @version $Id: IntervalUI.js 2077 2014-02-11 11:33:36Z elena $ |
9 | - * @todo Validations | |
9 | + * @todo Validations | |
10 | 10 | ***************************************************************************** |
11 | 11 | * FT Id : Date : Name - Description |
12 | 12 | ****************************************************************************** |
... | ... | @@ -15,17 +15,21 @@ |
15 | 15 | |
16 | 16 | Ext.define('amdaUI.IntervalUI', { |
17 | 17 | extend: 'Ext.container.Container', |
18 | - | |
19 | 18 | alias: 'widget.intervalSelector', |
20 | - | |
21 | 19 | activeField : null, |
22 | - | |
20 | + | |
23 | 21 | constructor: function(config) { |
24 | 22 | this.init(config); |
25 | 23 | this.callParent(arguments); |
26 | 24 | }, |
27 | - | |
28 | - setInterval : function(startDate,stopDate) | |
25 | + | |
26 | + /** | |
27 | + Set the start and stop date, and update the duration field. | |
28 | + - startDate: A Extjs Date object representing the new start time. | |
29 | + - stopDate: A Extjs Date object representing the new stop time. | |
30 | + - return: None. | |
31 | + */ | |
32 | + setInterval : function(startDate, stopDate) | |
29 | 33 | { |
30 | 34 | // get the search form |
31 | 35 | var form = this.findParentByType('form').getForm(); |
... | ... | @@ -33,44 +37,55 @@ Ext.define('amdaUI.IntervalUI', { |
33 | 37 | var startField = form.findField('startDate'); |
34 | 38 | // get stop field |
35 | 39 | var stopField = form.findField('stopDate'); |
36 | - | |
40 | + | |
37 | 41 | if (startField != null) |
38 | 42 | startField.setValue(startDate); |
39 | - | |
43 | + | |
40 | 44 | if (stopField != null) |
41 | 45 | stopField.setValue(stopDate); |
42 | - | |
46 | + | |
43 | 47 | this.updateDuration(); |
44 | 48 | }, |
45 | - | |
49 | + | |
50 | + /** | |
51 | + Get the start time field value. | |
52 | + - return: A Extjs Date object representing the start time. | |
53 | + */ | |
46 | 54 | getStartTime : function() |
47 | 55 | { |
48 | 56 | // get the search form |
49 | 57 | var form = this.findParentByType('form').getForm(); |
50 | 58 | // get start field |
51 | 59 | var startField = form.findField('startDate'); |
52 | - | |
60 | + | |
53 | 61 | return startField.getValue(); |
54 | 62 | }, |
55 | - | |
63 | + | |
64 | + /** | |
65 | + Get the stop time field value. | |
66 | + - return: A Extjs Date object representing the stop time. | |
67 | + */ | |
56 | 68 | getStopTime : function() |
57 | 69 | { |
58 | 70 | // get the search form |
59 | 71 | var form = this.findParentByType('form').getForm(); |
60 | 72 | // get stop field |
61 | 73 | var stopField = form.findField('stopDate'); |
62 | - | |
63 | - return stopField.getValue(); | |
74 | + | |
75 | + return stopField.getValue(); | |
64 | 76 | }, |
65 | - | |
66 | - updateDuration: function() { | |
67 | 77 | |
78 | + /* | |
79 | + #### Private methods from here #### | |
80 | + */ | |
81 | + | |
82 | + updateDuration: function() { | |
68 | 83 | // get the search form |
69 | 84 | var form = this.findParentByType('form').getForm(); |
70 | 85 | // get start value |
71 | - var start = form.findField('startDate').getValue(); | |
86 | + var start = this.getStartTime(); | |
72 | 87 | // get stop value |
73 | - var stop = form.findField('stopDate').getValue(); | |
88 | + var stop = this.getStopTime(); | |
74 | 89 | // if duration computable |
75 | 90 | if (stop != null && start != null) { |
76 | 91 | |
... | ... | @@ -78,18 +93,17 @@ Ext.define('amdaUI.IntervalUI', { |
78 | 93 | var zoneOffset = stop.getTimezoneOffset() - start.getTimezoneOffset(); |
79 | 94 | // compute duration |
80 | 95 | var diff = stop - start - zoneOffset*60000; |
81 | - | |
96 | + | |
82 | 97 | var durationDays = Math.floor(diff/86400000); |
83 | 98 | // set all duration values |
84 | - form.findField('durationDay').setValue(Ext.String.leftPad(durationDays,4,'0')); | |
99 | + form.findField('durationDay').setValue(Ext.String.leftPad(durationDays,4,'0')); | |
85 | 100 | form.findField('durationHour').setValue(Ext.String.leftPad(Math.floor(diff/3600000 % 24),2,'0')); |
86 | 101 | form.findField('durationMin').setValue(Ext.String.leftPad(Math.floor(diff/60000 % 60),2,'0')); |
87 | 102 | form.findField('durationSec').setValue(Ext.String.leftPad(Math.floor(diff/1000 % 60),2,'0')); |
88 | - | |
89 | - if (durationDays > 9999) { | |
103 | + | |
104 | + if (durationDays > 9999) { | |
90 | 105 | form.findField('durationDay').markInvalid('Maximum interval is 9999 days!'); |
91 | 106 | } |
92 | - | |
93 | 107 | } |
94 | 108 | |
95 | 109 | }, |
... | ... | @@ -99,13 +113,12 @@ Ext.define('amdaUI.IntervalUI', { |
99 | 113 | var form = this.findParentByType('form').getForm(); |
100 | 114 | // get global validation status for duration fields |
101 | 115 | return ( |
102 | - form.findField('durationDay').isValid() && form.findField('durationHour').isValid() | |
116 | + form.findField('durationDay').isValid() && form.findField('durationHour').isValid() | |
103 | 117 | && form.findField('durationMin').isValid() && form.findField('durationSec').isValid() |
104 | 118 | );// return true if all duration fields are Valid false otherwise |
105 | 119 | }, |
106 | 120 | |
107 | 121 | updateStop: function() { |
108 | - | |
109 | 122 | // get the time form |
110 | 123 | var form = this.findParentByType('form').getForm(); |
111 | 124 | // get duration value |
... | ... | @@ -121,68 +134,72 @@ Ext.define('amdaUI.IntervalUI', { |
121 | 134 | form.findField('stopDate').setValue(stop); |
122 | 135 | |
123 | 136 | }, |
124 | - | |
125 | - onChangeStartField : function(field, newValue, oldValue) | |
126 | - { | |
127 | - if (field.isValid()) { | |
128 | - // get the search form | |
129 | - var form = this.findParentByType('form').getForm(); | |
130 | - // set to the stop datefield the newValue as minValue | |
131 | - form.findField('stopDate').setMinValue(newValue); | |
132 | - // if it's a user modification | |
133 | - if (oldValue != null && this.activeField == 'start') { | |
134 | - // launch the update of duration fields | |
135 | - this.updateDuration(); | |
136 | - } | |
137 | - } | |
137 | + | |
138 | + onChangeStartField : function(field, newValue, oldValue) | |
139 | + { | |
140 | + if (field.isValid()) { | |
141 | + // get the search form | |
142 | + var form = this.findParentByType('form').getForm(); | |
143 | + // set to the stop datefield the newValue as minValue | |
144 | + form.findField('stopDate').setMinValue(newValue); | |
145 | + // if it's a user modification | |
146 | + if (oldValue != null && this.activeField == 'start') { | |
147 | + // launch the update of duration fields | |
148 | + this.updateDuration(); | |
149 | + } | |
150 | + } | |
138 | 151 | }, |
139 | - | |
140 | - onChangeStopField: function(field, newValue, oldValue){ | |
141 | - if (field.isValid() && oldValue != null && this.activeField == 'stop') { | |
142 | - // launch the update of duration fields | |
143 | - this.updateDuration(); | |
144 | - } | |
152 | + | |
153 | + onChangeStopField: function(field, newValue, oldValue) { | |
154 | + if (field.isValid() && oldValue != null && this.activeField == 'stop') { | |
155 | + // launch the update of duration fields | |
156 | + this.updateDuration(); | |
157 | + } | |
145 | 158 | }, |
146 | - | |
159 | + | |
147 | 160 | getDateField : function(fieldName,fieldText,fieldId,onChangeField) |
148 | 161 | { |
149 | 162 | return { |
150 | 163 | layout: {type: 'hbox', align: 'middle'}, |
151 | 164 | items: [ |
152 | - { | |
153 | - xtype: 'datefield', name: fieldName, format: 'Y/m/d H:i:s', | |
154 | - enforceMaxLength : true, | |
155 | - maxLength: 19, | |
156 | - fieldLabel: fieldText, labelAlign: 'right', labelWidth: 60, | |
165 | + { | |
166 | + xtype: 'datefield', | |
167 | + name: fieldName, | |
168 | + format: 'Y/m/d H:i:s', | |
169 | + enforceMaxLength: true, | |
170 | + maxLength: 19, | |
171 | + fieldLabel: fieldText, | |
172 | + labelAlign: 'right', | |
173 | + labelWidth: 60, | |
157 | 174 | listeners: { |
158 | 175 | change: onChangeField, |
159 | 176 | focus: function(field) { |
160 | 177 | this.activeField = fieldId; |
161 | 178 | }, |
162 | 179 | scope : this |
163 | - } | |
164 | - } | |
165 | - ] | |
180 | + } | |
181 | + } | |
182 | + ] | |
166 | 183 | }; |
167 | 184 | }, |
168 | - | |
185 | + | |
169 | 186 | getStartField : function() |
170 | 187 | { |
171 | - return this.getDateField('startDate','Start Time','start',this.onChangeStartField); | |
188 | + return this.getDateField('startDate','Start Time','start', this.onChangeStartField); | |
172 | 189 | }, |
173 | - | |
190 | + | |
174 | 191 | getStopField : function() |
175 | 192 | { |
176 | 193 | return this.getDateField('stopDate','Stop Time','stop',this.onChangeStopField); |
177 | 194 | }, |
178 | - | |
195 | + | |
179 | 196 | getDurationField : function() |
180 | 197 | { |
181 | 198 | return { |
182 | 199 | layout: {type: 'hbox', align: 'middle'}, |
183 | 200 | height: 45, |
184 | - defaults: { | |
185 | - xtype: 'textfield', labelAlign: 'top', width: 30, | |
201 | + defaults: { | |
202 | + xtype: 'textfield', labelAlign: 'top', width: 30, | |
186 | 203 | allowBlank: false, maxLength:2, enforceMaxLength : true, |
187 | 204 | hideTrigger: true, |
188 | 205 | regex: /^[0-9]([0-9])*$/i, |
... | ... | @@ -190,15 +207,15 @@ Ext.define('amdaUI.IntervalUI', { |
190 | 207 | change: function(field, newValue, oldValue){ |
191 | 208 | if (this.isValidDuration() && oldValue != null && this.activeField == 'duration') { |
192 | 209 | // launch the update of stop datefield |
193 | - this.updateStop(); | |
194 | - } | |
210 | + this.updateStop(); | |
211 | + } | |
195 | 212 | }, |
196 | 213 | focus: function(field) { |
197 | - this.activeField = 'duration'; | |
198 | - }, | |
214 | + this.activeField = 'duration'; | |
215 | + }, | |
199 | 216 | scope : this |
200 | - } | |
201 | - }, | |
217 | + } | |
218 | + }, | |
202 | 219 | items:[ |
203 | 220 | { xtype: 'displayfield', labelWidth: 60, labelAlign: 'right', width: 60, fieldLabel: '<br>Duration'}, |
204 | 221 | { xtype: 'component', width: 5}, |
... | ... | @@ -206,20 +223,19 @@ Ext.define('amdaUI.IntervalUI', { |
206 | 223 | { xtype: 'component', width: 5}, |
207 | 224 | { name: 'durationHour', fieldLabel: 'Hrs'}, |
208 | 225 | { xtype: 'component', width: 5}, |
209 | - { name: 'durationMin', fieldLabel: 'Mins'}, | |
226 | + { name: 'durationMin', fieldLabel: 'Mins'}, | |
210 | 227 | { xtype: 'component', width: 5}, |
211 | 228 | { name: 'durationSec', fieldLabel: 'Secs'} |
212 | 229 | ] |
213 | 230 | }; |
214 | 231 | }, |
215 | - | |
232 | + | |
216 | 233 | init : function(config) { |
217 | - | |
218 | 234 | var me = this; |
219 | - | |
235 | + | |
220 | 236 | var myConf = { |
221 | 237 | border: false, |
222 | - plain: true, | |
238 | + plain: true, | |
223 | 239 | flex: 1, |
224 | 240 | layout: 'anchor', |
225 | 241 | defaults: { height : 30, xtype : 'container'}, |
... | ... | @@ -230,9 +246,6 @@ Ext.define('amdaUI.IntervalUI', { |
230 | 246 | me.getDurationField() |
231 | 247 | ] |
232 | 248 | }; |
233 | - | |
234 | - Ext.apply (this , Ext.apply (arguments, myConf)); | |
249 | + Ext.apply (this , Ext.apply (arguments, myConf)); | |
235 | 250 | } |
236 | 251 | }); |
237 | - | |
238 | - | |
239 | 252 | \ No newline at end of file |
... | ... |
php/classes/EpnTapMgr.php
... | ... | @@ -54,7 +54,7 @@ class EpnTapMgr { |
54 | 54 | |
55 | 55 | /* filter order: product type, target name, time min, time max */ |
56 | 56 | public function getGranules($table_name, $access_url, $filter, $select, $limit, $offset) { |
57 | - $query = "SELECT TOP $limit " . join(', ', $select) . " FROM $table_name.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]) . " OFFSET $offset"; | |
57 | + $query = "SELECT TOP {$limit} " . join(', ', $select) . " FROM {$table_name}.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]) . " OFFSET {$offset}"; | |
58 | 58 | // return $query; |
59 | 59 | $result = $this->request($access_url, $query); |
60 | 60 | for ($i = 0 ; $i < sizeof($result) ; $i++) { |
... | ... | @@ -67,7 +67,7 @@ class EpnTapMgr { |
67 | 67 | |
68 | 68 | /* filter order: product type, target name, time min, time max */ |
69 | 69 | public function getNbRows($table_name, $access_url, $filter) { |
70 | - $query = "SELECT COUNT(*) AS nb_rows FROM $table_name.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]); | |
70 | + $query = "SELECT COUNT(*) AS nb_rows FROM {$table_name}.epn_core " . $this->createFilter($filter[0], $filter[1], $filter[2], $filter[3]); | |
71 | 71 | // return $query; |
72 | 72 | return $this->request($access_url, $query)[0]['nb_rows']; |
73 | 73 | } |
... | ... |