WebIf - Movies: Move location selection to the right of the content header to avoid...
[enigma2-plugins.git] / webinterface / src / web-data / handler.js
1 var AbstractContentHandler = Class.create({
2         initialize: function(tpl, target, onFinished){
3                 this.tpl = tpl;
4                 this.target = target;
5                 this.onFinished = onFinished;
6                 if(this.onFinished === undefined || this.onFinished == null){
7                         this.onFinished = [];
8                 }
9                 this.eventsRegistered = false;
10                 this.provider = null;
11                 this.ajaxload = false;
12                 this.data = {};
13         },
14
15         load: function(parms, fnc){
16                 this.requestStarted();
17                 this.parms = parms;
18                 this.provider.load(parms, fnc);
19         },
20
21         reload: function(){
22                 this.requestStarted();
23                 this.provider.reload();
24         },
25
26         /**
27          * requestStarted
28          * if this.ajaxload is true setAjaxLoad(this.target) will be called
29          **/
30         requestStarted: function(){
31                 if(this.ajaxload){
32                         core.setAjaxLoad(this.target);
33                 }
34         },
35
36         /**
37          *requestFinished
38          * What to do when a request has finished. Does nothing in the Abstract class definition
39          **/
40         requestFinished: function(){
41 //              TODO requestFinished actions
42         },
43
44         /**
45          * show
46          * Show the data that has been fetched by a request (and prepared by renderXML)
47          * in this.target.
48          * Afterwards call this.finished()
49          */
50         show: function(data){
51                 this.data = data;
52                 templateEngine.process(this.tpl, data, this.target, this.finished.bind(this));
53         },
54
55         /**
56          * notify
57          * fade in to show text in the $('notification') area and fade out afterwards
58          * Parameters:
59          * @text - the text of the notification
60          * @state - false == error (bgcolor red), true == success (bgcolor green)
61          */
62         notify: function(text, state){
63                 core.notify(text, state);
64         },
65
66         /**
67          * simpleResultCallback
68          * Callback for @ onSuccess of this.simpleResultQuery()
69          * Parameters:
70          * @transport - the xmlhttp transport object
71          */
72         simpleResultCallback: function(transport){
73                 this.provider.simpleResultCallback(transport, this.showSimpleResult.bind(this));
74         },
75
76         showSimpleResult: function(result){
77                 this.notify(result.getStateText(), result.getState());
78         },
79
80         registerEvents : function(){},
81
82         /**
83          * finished
84          * Calls all functions this.onFinished contains this.registerEvents
85          * Is usually called after this.show() has finished
86          */
87         finished : function(){
88                 if(!this.eventsRegistered){
89                         try{
90                                 this.registerEvents();
91                         } catch (e){
92                                 debug(e);
93                         }
94                         this.eventsRegistered = true;
95                 }
96
97                 if(this.onFinished !== undefined){
98                         for(var i = 0; i < this.onFinished.length; i++){
99                                 var fnc = this.onFinished[i];
100                                 if(typeof(fnc) === 'function'){
101                                         fnc();
102                                 }
103                         }
104                 }
105         }
106 });
107
108 var DeviceInfoHandler = Class.create(AbstractContentHandler,{
109         initialize: function($super, target, cached){
110                 $super('tplDeviceInfo', target);
111                 this.provider = new DeviceInfoProvider(this.show.bind(this));
112                 this.isCached = true;
113                 if(cached === false)
114                         this.isCached = false;
115                 this.data = null;
116         },
117
118         load: function($super, parms, callback){
119                 if(this.data == null)
120                         $super(parms, callback);
121                 else
122                         this.show(this.data);
123         },
124
125         get: function(parms, callback){
126                 this.requestStarted();
127                 if(this.data == null){
128                         this.provider.load(parms,
129                                         function(transport){
130                                                 var data = this.provider.renderXML(this.provider.getXML(transport));
131                                                 this.data = data;
132                                                 callback(data);
133                                         }.bind(this));
134                 } else {
135                         callback(this.data);
136                 }
137         }
138 });
139
140 var ExternalsHandler = Class.create(AbstractContentHandler, {
141         initialize: function($super, target){
142                 $super('tplNavExtrasExternals', target);
143                 this.provider = new ExternalsProvider(this.show.bind(this));
144                 this.ajaxload = false;
145         }
146 });
147
148 var SimplePageHandler = Class.create(AbstractContentHandler,{
149         initialize: function($super, target){
150                 $super(null, target);
151         },
152
153         show: function(tpl, data){
154                 templateEngine.process(tpl, data, this.target, this.finished.bind(this));
155         }
156 });
157
158 var BouquetListHandler = Class.create(AbstractContentHandler, {
159         initialize: function($super, target, targetMain){
160                 $super('tplBouquetList', target);
161                 this.provider = new SimpleServiceListProvider(this.show.bind(this));
162                 this.ajaxload = false;
163                 this.targetMain = targetMain;
164         },
165
166         show : function(data){
167                 this.data = data;
168                 if($(this.target)){
169                         templateEngine.process(this.tpl, data, this.target, this.finished.bind(this));
170                 } else {
171                         templateEngine.process(
172                                         'tplBouquetsAndServices',
173                                         null,
174                                         this.targetMain,
175                                         function(){
176                                                 this.show(data);
177                                         }.bind(this)
178                         );
179                 }
180         }
181 });
182
183 var CurrentHandler  = Class.create(AbstractContentHandler, {
184         initialize: function($super, curTarget, volTarget){
185                 $super('tplCurrent', curTarget);
186                 this.provider = new CurrentProvider(this.show.bind(this));
187                 this.volTpl = 'tplVolume';
188                 this.volTarget = volTarget;
189         },
190
191         show : function(data){
192                 this.data = data;
193                 templateEngine.process(this.volTpl, data, this.volTarget);
194                 templateEngine.process(this.tpl, data, this.target, this.finished.bind(this));
195         }
196 });
197
198 var ServiceListHandler = Class.create(AbstractContentHandler, {
199         initialize: function($super, target){
200                 $super('tplServiceList', target, [this.getSubservices.bind(this)]);
201
202                 this.provider = new ServiceListProvider(this.show.bind(this));
203                 this.epgHandler = new ServiceListEpgHandler();
204                 this.subServiceHandler = new ServiceListSubserviceHandler();
205
206                 this.ajaxload = true;
207         },
208
209         /**
210          * getNowNext
211          * calls this.epgHandler.getNowNext to show Now/Next epg information
212          * using this.parms.sRef as the servicereference of the bouquet
213          */
214         getNowNext: function(){
215                 this.epgHandler.load({bRef : this.provider.parms.bRef});
216         },
217
218         /**
219          * getSubservices
220          * calls this.subServiceHandler.load() to show Now/Next epg information
221          */
222         getSubservices: function(){
223                 this.subServiceHandler.load({});
224         },
225
226         /**
227          * call this to switch to a service
228          * Parameters:
229          * @servicereference - the (unescaped) reference to the service that should be shown
230          */
231         zap: function(parms, callback){
232                 this.provider.simpleResultQuery(
233                                 URL.zap,
234                                 parms,
235                                 function(transport){
236                                         this.simpleResultCallback.bind(this);
237                                         if(callback)
238                                                 callback();
239                                 }.bind(this));
240         },
241
242         showSimpleResult: function($super, result){
243                 if(result.getState()){
244                         core.updateItemsLazy();
245                 }
246                 $super(result);
247         }
248 });
249
250 var EpgListHandler = Class.create(AbstractContentHandler,{
251         initialize: function($super, showEpgFnc){
252                 $super('tplEpgList');
253                 this.provider = new ServiceEpgListProvider(this.show.bind(this));
254                 this.showEpg = showEpgFnc;
255                 this.data = '';
256         },
257
258         search : function(parms, fnc){
259                 this.requestStarted();
260                 this.provider.search(parms, fnc);
261         },
262
263         show : function(data){
264                 this.data = data;
265                 templateEngine.fetch(
266                                 this.tpl,
267                                 function(){
268                                         var html = templateEngine.templates[this.tpl].process(this.data);
269                                         this.showEpg(html);
270                                 }.bind(this)
271                         );
272         }
273 });
274
275 var ServiceListEpgHandler  = Class.create(AbstractContentHandler, {
276         EPG_NOW : 'NOW',
277         EPG_NEXT : 'NEXT',
278         PROGRESS : 'PROGRESS',
279
280         initialize: function($super){
281                 $super('tplServiceListEPGItem');
282                 this.provider = new ServiceListProvider(this.show.bind(this));
283         },
284
285         /**
286          * show
287          * calls this.showItem for each item of @list
288          * @list - An array of EPGEvents
289          */
290         show: function(list){
291                 var len = list.items.length;
292                 for(var i = 0; i < len; i++){
293                         this.updateEpg(list.items[i]);
294                 }
295                 this.finished();
296         },
297
298         /**
299          * Shows an EPGEvent item in the DOM
300          * templates.tplServiceListEPGItem needs to be present!
301          * Parameters:
302          * @item - The EPGEvent object
303          */
304         //TODO: move showItem outta here
305         updateEpg: function(item){
306                 if(item.now.eventid != ''){
307                         var progress = $(this.PROGRESS + item.now.servicereference);
308                         if(progress){
309                                 progress.down('.sListSProgress').title = item.now.progress + "%";
310                                 progress.down('.sListSProgressBar').style.width = item.now.progress + "%";
311                         }
312                 }
313                 this.showItem(this.EPG_NOW, item.now,'.sListEPGNow');
314                 this.showItem(this.EPG_NEXT, item.next,'.sListEPGNext');
315         },
316
317         showItem: function(type, epgItem, parent){
318                 var id = type + epgItem.servicereference;
319                 var epgElement = $(id);
320                 if(epgElement){ //Markers don't have any EPG
321                         var isVisible = false;
322                         var target = epgElement.down('.sListExtEpgLong');
323                         if(target){
324                                 isVisible = target.visible();
325                         }
326
327                         templateEngine.process('tplServiceListEPGItem', {'item' : epgItem, 'isVisible' : isVisible}, id, true);
328                         var element = $(id).up(parent);
329                         if(element){
330                                 element.show();
331                         }
332                 }
333         }
334 });
335
336 var ServiceListSubserviceHandler  = Class.create(AbstractContentHandler, {
337         //constants
338         PREFIX : 'SUB',
339
340         initialize: function($super){
341                 $super('tplSubServices');
342                 this.provider = new ServiceListSubserviceProvider(this.show.bind(this));
343         },
344
345         /**
346          * show
347          * Show all subervices of a service (if there are any)
348          * Overrides default show
349          */
350         show: function(list){
351                 var id = this.PREFIX + list[0].servicereference;
352                 var parent = $('tr' + id);
353
354                 if(parent !== null && list.length > 1){
355                         list.shift();
356
357                         var data = { subservices : list };
358                         templateEngine.process(this.tpl, data, id);
359                         parent.show();
360                 }
361         }
362 });
363
364 var SignalHandler = Class.create(AbstractContentHandler,{
365         initialize: function($super, showSignalFnc){
366                 $super('tplSignalPanel');
367                 this.provider = new SignalProvider(this.show.bind(this));
368                 this.showSignal = showSignalFnc;
369         },
370
371         show : function(data){
372                 this.data = data;
373                 templateEngine.fetch(
374                                 this.tpl,
375                                 function(){
376                                         var html = templateEngine.templates[this.tpl].process(this.data);
377                                         this.showSignal(html);
378                                 }.bind(this)
379                         );
380         }
381 });
382
383 var MediaPlayerHandler = Class.create(AbstractContentHandler, {
384         initialize: function($super, target){
385                 $super('tplMediaPlayer', target);
386                 this.provider = new MediaPlayerProvider(this.show.bind(this));
387         },
388
389         command: function(command){
390                 this.provider.simpleResultQuery(
391                                 URL.mediaplayercmd,
392                                 {'command' : command},
393                                 this.simpleResultCallback.bind(this)
394                         );
395         },
396
397         playFile: function(file){
398                 this.provider.simpleResultQuery(
399                                 URL.mediaplayerplay,
400                                 {'file' : file},
401                                 this.simpleResultCallback.bind(this)
402                         );
403         },
404
405         addFile: function(file){
406                 this.provider.simpleResultQuery(
407                                 URL.mediaplayeradd,
408                                 {'file' : file},
409                                 this.simpleResultCallback.bind(this)
410                         );
411         },
412
413         removeFile: function(file){
414                 this.provider.simpleResultQuery(
415                                 URL.mediaplayerremove,
416                                 {'file' : file},
417                                 function(data){
418                                         this.simpleResultCallback(data);
419                                         this.reload();
420                                 }.bind(this)
421                         );
422         },
423
424         savePlaylist: function(filename){
425                 this.provider.simpleResultQuery(
426                                 URL.mediaplayerwrite,
427                                 {'filename' : filename},
428                                 this.simpleResultCallback.bind(this)
429                         );
430         }
431
432 });
433
434 var MovieListHandler  = Class.create(AbstractContentHandler, {
435         initialize: function($super, target){
436                 $super('tplMovieList', target);
437                 this.provider = new MovieListProvider(this.show.bind(this));
438                 this.ajaxload = true;
439         },
440
441         getData: function(element){
442                 /*<table
443                         class="mListItem"
444                         data-servicereference="${movie.servicereference}"
445                         data-servicename="${movie.servicename}"
446                         data-title="${movie.title}"
447                         data-description="${movie.description}">
448                 */
449                 var parent = element.up('.mListItem');
450                 var m = {
451                                 servicereference : unescape(parent.readAttribute('data-servicereference')),
452                                 servicename : unescape(parent.readAttribute('data-servicename')),
453                                 title : unescape(parent.readAttribute('data-title')),
454                                 description : unescape(parent.readAttribute('data-description'))
455                 };
456
457                 return m;
458         },
459
460         /**
461          * del
462          * Deletes a movie
463          * Parameters:
464          * @servicereference - the servicereference of the movie that should be deleted
465          * @servicename - the name of the service the movie was recorded from
466          * @title - the title of the movie
467          * @description - the description of the movie
468          */
469         del: function(element){
470                 movie = this.getData(element);
471
472                 var result = confirm( "Are you sure want to delete the Movie?\n" +
473                                 "Servicename: " + movie.servicename + "\n" +
474                                 "Title: " + movie.title + "\n" +
475                                 "Description: " + movie.description + "\n");
476
477                 if(result){
478                         debug("[MovieListProvider.del] ok confirm panel");
479                         this.provider.simpleResultQuery(URL.moviedelete, {sRef : movie.servicereference}, this.onDeleted.bind(this));
480                 }
481                 else{
482                         debug("[MovieListProvider.del] cancel confirm panel");
483                         result = false;
484                 }
485
486                 this.refresh = result;
487                 return result;
488         },
489
490         /**
491          * del
492          * Display the del result and reloads the movielist
493          */
494         onDeleted: function(transport){
495                 this.simpleResultCallback(transport);
496                 this.reload();
497         }
498 });
499
500 var MovieNavHandler = Class.create(AbstractContentHandler,{
501         initialize: function($super, tagTarget, locTarget){
502                 $super('tplMovieTags', tagTarget);
503                 this.targetLocations = locTarget;
504                 this.tplLocations = 'tplMovieLocations';
505         },
506
507         load: function(locations, tags){
508                 data = { 'locations' : locations, 'tags' : tags};
509                 this.show(data);
510                 this.showLocations(data);
511         },
512
513         showLocations: function(data){
514                 templateEngine.process(this.tplLocations, data, this.targetLocations);
515         }
516 });
517
518 var MultiEpgHandler  = Class.create(AbstractContentHandler, {
519         initialize: function($super, showMultiEpgFnc){
520                 $super('tplMultiEpg', null);
521                 this.provider = new MultiEpgProvider(this.show.bind(this));
522                 this.ajaxload = false;
523                 this.showEpg = showMultiEpgFnc;
524         },
525
526         show : function(data){
527                 this.data = data;
528                 templateEngine.fetch(
529                         this.tpl,
530                         function(){
531                                 var html = templateEngine.templates[this.tpl].process(this.data);
532                                 this.showEpg(html);
533                         }.bind(this)
534                 );
535         }
536 });
537
538 var ScreenshotHandler = Class.create(AbstractContentHandler, {
539         initialize: function($super, target){
540                 $super('tplGrab', target);
541                 this.provider = new ScreenshotProvider(this.show.bind(this));
542                 this.ajaxload = true;
543         }
544 });
545
546 var SimpleRequestHandler = Class.create(AbstractContentHandler,{
547         initialize: function(){
548                 this.provider = new SimpleRequestProvider();
549         },
550
551         load: function(url, parms){
552                 this.provider.simpleResultQuery(
553                                 url,
554                                 parms,
555                                 this.simpleResultCallback.bind(this)
556                         );
557         }
558 });
559
560 var RemoteControlHandler = Class.create(SimpleRequestHandler,{
561         sendKey: function(parms){
562                 this.load(URL.remotecontrol, parms);
563         },
564
565         showSimpleResult: function(result){
566                 if(!result.getState())
567                         this.notify(result.getStateText(), result.getState());
568         }
569 });
570
571 var TimerListHandler  = Class.create(AbstractContentHandler, {
572         initialize: function($super, target){
573                 $super('tplTimerList', target);
574                 this.provider = new TimerListProvider(this.show.bind(this));
575                 this.ajaxload = true;
576         },
577
578         cleanup: function(){
579                 this.provider.simpleResultQuery(
580                                 URL.timercleanup, {},
581                                 function(transport, callback){
582                                         this.simpleResultCallback(transport, callback);
583                                         this.reload();
584                                 }.bind(this));
585         }
586 });
587
588 var TimerHandler = Class.create(AbstractContentHandler, {
589         ACTIONS: [{value : 0, txt : 'Record'},
590                         {value : 1, txt : 'Zap'}],
591
592         AFTEREVENTS: [{value : 0, txt : 'Nothing'},
593                                 {value : 1, txt : 'Standby'},
594                                 {value : 2, txt : 'Deepstandby/Shutdown'},
595                                 {value : 3, txt : 'Auto'}],
596
597         SELECTED : "selected",
598         CHECKED: "checked",
599
600         /**
601          * initialize
602          * See the description in AbstractContentProvider
603          */
604         initialize: function($super, target, reloadCallback, onFinished){
605                 $super('tplTimerEdit', target, onFinished);
606                 this.t = {};
607                 this.provider = new SimpleRequestProvider();
608                 this.bouquetListProvider = new SimpleServiceListProvider(this.onBouquetsReady.bind(this));
609                 this.serviceListProvider = new SimpleServiceListProvider(this.onServicesReady.bind(this));
610                 this.ajaxload = true;
611                 this.reloadCallback = reloadCallback;
612                 this.data = {};
613         },
614
615         simpleResultCallback: function(transport, callback){
616                 this.provider.simpleResultCallback(
617                                 transport,
618                                 function(result){
619                                         this.showSimpleResult(result, callback);
620                                 }.bind(this)
621                         );
622         },
623
624         showSimpleResult: function($super, result, callback){
625                 $super(result);
626                 if(callback){
627                         callback(result);
628                         return;
629                 } else if(this.reloadCallback){
630                         this.reloadCallback();
631                 }
632         },
633
634         toReadableDate: function(date){
635                 var dateString = "";
636                 dateString += date.getFullYear();
637                 dateString += "-" + addLeadingZero(date.getMonth()+1);
638                 dateString += "-" + addLeadingZero(date.getDate());
639
640                 return dateString;
641         },
642
643         /**
644          * getData
645          *
646          * Extracts the data of a timer from the .tListItem elements data-* attributes
647          *
648          * <tr class="tListItem"
649          *      data-servicereference="${t.servicereference}"
650          *      data-servicename="${t.servicename}"
651          *      data-description="${t.description}"
652          *      data-name="${t.name}"
653          *      data-eventid="${t.eventid}"
654          *      data-begin="${t.begin}"
655          *      data-end="${t.end}"
656          *      data-repeated="${t.repeated}"
657          *      data-justplay="${t.justplay}"
658          *      data-dirname="${t.dirname}"
659          *      data-tags="${t.tags}"
660          *      data-afterevent="${t.afterevent}"
661          *      data-disabled="${t.disabled}"
662          * >
663          *
664          * Parameters:
665          * @element - the html element calling the load function ( onclick="TimerProvider.load(this)" )
666          */
667         getData: function(element, setOld){
668                 var parent = element.up('.tListItem');
669                 var t = {};
670
671                 if(parent){
672                         var begin = unescape(parent.readAttribute('data-begin'));
673                         var end = unescape(parent.readAttribute('data-end'));
674                         var beginD = new Date(begin * 1000);
675                         var endD = new Date(end * 1000);
676                         t = {
677                                 servicereference : decodeURIComponent(parent.readAttribute('data-servicereference')),
678                                 servicename : unescape(parent.readAttribute('data-servicename')),
679                                 description : unescape(parent.readAttribute('data-description')),
680                                 name : unescape(parent.readAttribute('data-name')),
681                                 eventid : unescape(parent.readAttribute('data-eventid')),
682                                 begin : begin,
683                                 beginDate : this.toReadableDate(beginD),
684                                 end : end,
685                                 endDate : this.toReadableDate(endD),
686                                 repeated : unescape(parent.readAttribute('data-repeated')),
687                                 justplay : unescape(parent.readAttribute('data-justplay')),
688                                 dirname : unescape(parent.readAttribute('data-dirname')),
689                                 tags : unescape(parent.readAttribute('data-tags')),
690                                 afterevent : unescape(parent.readAttribute('data-afterevent')),
691                                 disabled : unescape(parent.readAttribute('data-disabled'))
692                         };
693
694                         if(setOld){
695                                 t['servicereferenceOld'] = decodeURIComponent(parent.readAttribute('data-servicereference'));
696                                 t['beginOld'] = t.begin;
697                                 t['endOld'] = t.end;
698                                 t['deleteOldOnSave'] = 1;
699                         } else {
700                                 t['deleteOldOnSave'] = 0;
701                         }
702                 }
703                 return t;
704         },
705
706         getDataFromEvent: function(element){
707                 var parent = element.up('.epgListItem');
708                 var t = {};
709
710                 if(parent){
711                         var begin = unescape(parent.readAttribute('data-start'));
712                         var end = unescape(parent.readAttribute('data-end'));
713                         var beginD = new Date(begin * 1000);
714                         var endD = new Date(end * 1000);
715                         t = {
716                                 servicereference : decodeURIComponent(parent.readAttribute('data-servicereference')),
717                                 servicename : unescape(parent.readAttribute('data-servicename')),
718                                 description : unescape(parent.readAttribute('data-description')),
719                                 name : unescape(parent.readAttribute('data-title')),
720                                 eventid : unescape(parent.readAttribute('data-eventid')),
721                                 begin : begin,
722                                 beginDate : this.toReadableDate(beginD),
723                                 end : end,
724                                 endDate : this.toReadableDate(endD),
725                                 repeated : "0",
726                                 justplay : "0",
727                                 dirname : "",
728                                 tags : "",
729                                 afterevent : "3",
730                                 disabled : "0",
731                                 deleteOldOnSave : "0"
732                         };
733                 }
734                 return t;
735         },
736
737
738         /**
739          * @override
740          * load
741          * When handling timers the whole loading-sequence is entirely different.
742          * Most of the data is already there or has to be created.
743          *
744          * Parameters:
745          * @element - the html element calling the load function ( onclick="TimerProvider.load(this)" )
746          */
747         load: function(element, setOld, initial, fromEvent){
748                 var t = {};
749                 var begin = new Date();
750                 var end = new Date();
751
752                 if(initial){
753                         end.setHours(end.getHours() + 1);
754                         t = {
755                                 servicereference : "",
756                                 servicename : "",
757                                 description : "",
758                                 name : "",
759                                 eventid : "0",
760                                 begin : "0",
761                                 beginDate : this.toReadableDate(begin),
762                                 end : "0",
763                                 endDate : this.toReadableDate(end),
764                                 repeated : "0",
765                                 justplay : "0",
766                                 dirname : "",
767                                 tags : "",
768                                 afterevent : "3",
769                                 disabled : "0"
770                         };
771                 } else {
772                         if(fromEvent){
773                                 t = this.getDataFromEvent(element);
774                         } else {
775                                 t = this.getData(element, setOld);
776                         }
777                         begin = new Date(t.begin * 1000);
778                         end = new Date(t.end * 1000);
779                 }
780
781
782                 var bHours = this.numericalOptionList(0, 23, begin.getHours());
783                 var bMinutes = this.numericalOptionList(0, 59, begin.getMinutes());
784                 var eHours = this.numericalOptionList(0, 23, end.getHours());
785                 var eMinutes = this.numericalOptionList(0, 59, end.getMinutes());
786
787                 var actions = this.ACTIONS;
788                 actions[t.justplay].selected = this.SELECTED;
789
790                 var afterevents = this.AFTEREVENTS;
791                 afterevents[t.afterevent].selected = this.SELECTED;
792
793                 var repeated = this.repeatedDaysList(t.repeated);
794
795                 var data = {
796                                 shour : bHours,
797                                 smin : bMinutes,
798                                 ehour : eHours,
799                                 emin : eMinutes,
800                                 action : actions,
801                                 channel : [],
802                                 afterEvent : afterevents,
803                                 repeated : repeated,
804                                 timer : t };
805                 var _this = this;
806                 core.lt.getLocationsAndTags(function(currentLocation, locations, tags){
807                         _this.onLocationsAndTagsReady(data, currentLocation, locations, tags, initial);
808                 });
809         },
810
811         onLocationsAndTagsReady: function(data, currentLocation, locations, tags, initial){
812                 var dirname = data.timer.dirname;
813                 if(dirname == "")
814                         dirname = currentLocation;
815                 var l = toOptionList(locations, dirname);
816                 var t = toOptionList(tags, data.timer.tags, " ");
817                 t.shift();
818                 l.shift();
819
820                 data['dirname'] = l;
821                 data['tags'] = t;
822                 if(initial){
823                         data.timer.dirname = currentLocation;
824                 }
825                 this.data = data;
826                 this.bouquetListProvider.load({'sRef' : bouquetsTv});
827         },
828
829         onBouquetsReady: function(data){
830                 this.data['bouquets'] = data.services;
831                 this.serviceListProvider.load({'sRef' : unescape(data.services[0].servicereference)});
832         },
833
834         onServicesReady: function(data){
835                 var services = data.services;
836                 var serviceFound = false;
837                 var timer = this.data.timer;
838                 services.each(function(service){
839                         if(decodeURIComponent(service.servicereference) == timer.servicereference){
840                                 service['selected'] = 'selected';
841                                 serviceFound = true;
842                         }else{
843                                 service['selected'] = '';
844                         }
845                 }.bind(this));
846                 if(!serviceFound){
847                         services.push( {'servicereference' : timer.servicereference, 'servicename' : timer.servicename, 'selected' : 'selected'});
848                 }
849
850                 this.data['services'] = services;
851                 this.show(this.data);
852         },
853
854         onBouquetChanged: function(bRef, callback){
855                 var _this = this;
856                 var fnc = function(data){
857                         callback(data, _this.data.timer);
858                 };
859                 var prov = new SimpleServiceListProvider(fnc);
860                 prov.load({'sRef' : bRef});
861         },
862
863         recordNow: function(type, callback){
864                 this.provider.simpleResultQuery(
865                         URL.recordnow,
866                         {
867                                 'recordnow' : type
868                         },
869                         function(result){
870                                 if(!callback)
871                                         callback = function(){}; //Avoid automatic reload
872                                 this.simpleResultCallback(result, callback);
873                         }.bind(this));
874         },
875
876         addByEventId: function(sRef, id, justplay){
877                 this.provider.simpleResultQuery(
878                         URL.timeraddbyeventid,
879                         {
880                                 'sRef' : sRef,
881                                 'eventid' : id,
882                                 'justplay' : justplay
883                         },
884                         this.simpleResultCallback.bind(this));
885         },
886
887         change: function(t, old){
888                 var parms = {
889                         'sRef' : t.servicereference,
890                         'begin' : t.begin,
891                         'end' : t.end,
892                         'name' : t.name,
893                         'description' : t.description,
894                         'dirname' : t.dirname,
895                         'tags' : t.tags,
896                         'afterevent' : t.afterevent,
897                         'eit' : t.eventid,
898                         'disabled' : t.disabled,
899                         'justplay' : t.justplay,
900                         'repeated' : t.repeated
901                 };
902
903                 if(old){
904                         Object.extend(parms, {
905                                 'channelOld' : old.servicereference,
906                                 'beginOld' : old.begin,
907                                 'endOld' : old.end,
908                                 'deleteOldOnSave' : old.deleteOldOnSave
909                         });
910                 } else {
911                         parms['deleteOldOnSave'] = 0;
912                 }
913
914                 this.provider.simpleResultQuery(
915                         URL.timerchange,
916                         parms,
917                         this.simpleResultCallback.bind(this)
918                 );
919         },
920
921         del: function(element){
922                 var t = this.getData(element);
923                 var result = confirm("Selected timer:\n" + "Channel: " + t.servicename + "\n" +
924                                 "Name: " + t.name + "\n" + "Description: " + t.description + "\n" +
925                                 "Are you sure that you want to delete the Timer?");
926                 if (result) {
927                         debug("[TimerListProvider].del ok confirm panel");
928                         this.refresh = true;
929                         this.provider.simpleResultQuery(
930                                         URL.timerdelete,
931                                         {'sRef' : t.servicereference, 'begin' : t.begin, 'end' : t.end},
932                                         this.simpleResultCallback.bind(this)
933                                 );
934                 }
935                 return result;
936         },
937
938         toggleDisabled: function(element){
939                 var t = this.getData(element, true);
940                 var old = t;
941                 if(t.disabled == '0')
942                         t.disabled = '1';
943                 else
944                         t.disabled = '0';
945                 this.change(t, old);
946         },
947
948         /**
949          * repeatedDaysList
950          *
951          * Parameters:
952          * @num - the decimal value to apply as bitmask
953          * @return - a list of {id : dayid, value : dayvalue, txt : daytext, long : daylong}
954          **/
955         repeatedDaysList: function(num){
956                 var days = [{id : 'mo', value : 1, txt : 'Mo', long : 'Monday'},
957                                         {id : 'tu', value : 2, txt : 'Tu', long : 'Tuesday'},
958                                         {id : 'we', value : 4, txt : 'We', long : 'Wednesday'},
959                                         {id : 'th', value : 8, txt : 'Th', long : 'Thursday'},
960                                         {id : 'fr', value : 16, txt : 'Fr', long : 'Friday'},
961                                         {id : 'sa', value : 32, txt : 'Sa', long : 'Saturday'},
962                                         {id : 'su', value : 64, txt : 'Su', long : 'Sunday'},
963                                         {id : 'mf', value : 31, txt : 'Mo-Fr', long : 'Monday to Friday'},
964                                         {id : 'ms', value : 127, txt : 'Mo-Su', long : 'Monday to Sunday'}
965                                         ];
966                 var orgNum = num;
967                 // num is the decimal value of the bitmask for checked days
968                 for(var i = 0; i < days.length; i++){
969                         days[i].checked = "";
970
971                         //set checked when most right bit is 1
972                         if(num &1 == 1){
973                                 days[i].checked = this.CHECKED;
974                         }
975
976                         // shift one bit to the right
977                         num = num >> 1;
978                 }
979
980                 //check for special cases (Mo-Fr & Mo-Su)
981                 if(orgNum == 31){
982                         days[7].checked = this.CHECKED;
983                 } else if (orgNum == 127){
984                         days[8].checked = this.CHECKED;
985                 }
986
987                 return days;
988         },
989
990         /**
991          * numericalOptionList
992          * Create a List of numerical-based options
993          * Entry.value is being extended to at least 2 digits (9 => 09)
994          *
995          * Parameters:
996          * @lowerBound - Number to start at
997          * @upperBound - Number to stop at
998          * @selectedValue - entry.selected is set to this.SELECTED if number == selectedValue ("" else)
999          **/
1000         numericalOptionList: function(lowerBound, upperBound, selectedValue, offset){
1001                 var list = [];
1002                 var idx = 0;
1003                 if(offset == undefined){
1004                         offset = 0;
1005                 }
1006
1007                 for(var i = lowerBound; i <= upperBound; i++){
1008                         var t = i + offset;
1009                         var txt = t < 10 ? "0" + t : t;
1010                         var selected = "";
1011                         if(i == selectedValue){
1012                                 selected = this.SELECTED;
1013                         }
1014                         list[idx] = {value : i, txt : txt, selected : selected};
1015                         idx++;
1016                 }
1017                 return list;
1018         },
1019
1020         /**
1021          * daysOptionList
1022          *
1023          * Determines how many Days a month has an builds an
1024          * numericalOptionsList for that number of Days
1025          */
1026         daysOptionList: function(date){
1027                 var days = 32 - new Date(date.getYear(), date.getMonth(), 32).getDate();
1028                 return this.numericalOptionList(1, days, date.getDate());
1029         },
1030
1031         /**
1032          * commitForm
1033          *
1034          * Commit the Timer Form by serializing it, generating the correct paramteters and then executing the change Method
1035          * @id - id of the Form
1036          */
1037         commitForm : function(id){
1038                 debug("TimerHandler.commitForm");
1039                 var values = $(id).serialize(true);
1040
1041                 var tags = [];
1042                 $$('.tEditTag').each(function(element){
1043                         var selected = element.readAttribute('data-selected');
1044                         if(selected == "selected"){
1045                                 var value = element.readAttribute('data-value');
1046                                 tags.push(value);
1047                         }
1048                 });
1049
1050                 var repeated = 0;
1051                 $$('.tEditRepeated').each(function(element){
1052                         if(element.checked){
1053                                 if(element.value != 31 && element.value != 127){
1054                                         repeated += Number(element.value);
1055                                 }
1056                         }
1057                 });
1058
1059                 var begin = 0;
1060                 var end = 0;
1061
1062                 var startDate = $('sdate').value.split('-');
1063                 var sDate = new Date();
1064                 sDate.setFullYear(startDate[0], startDate[1] - 1, startDate[2]);
1065                 sDate.setHours( $('shour').value );
1066                 sDate.setMinutes( $('smin').value );
1067                 sDate.setSeconds(0);
1068                 begin = Math.floor(sDate.getTime() / 1000);
1069
1070                 var endDate = $('edate').value.split('-');
1071                 var eDate = new Date();
1072                 eDate.setFullYear(endDate[0], endDate[1] - 1, endDate[2]);
1073                 eDate.setHours( $('ehour').value );
1074                 eDate.setMinutes( $('emin').value );
1075                 eDate.setSeconds(0);
1076                 end = Math.floor(eDate.getTime() / 1000);
1077
1078                 timer = {
1079                         'servicereference' : decodeURIComponent(values.service),
1080                         'begin' : begin,
1081                         'end' : end,
1082                         'name' : values.name,
1083                         'eventid' : values.eventid,
1084                         'description' : values.description,
1085                         'dirname' : values.dirname,
1086                         'tags' : tags.join(" "),
1087                         'afterevent' : values.afterevent,
1088                         'eit' : 0,
1089                         'disabled' : values.disabled,
1090                         'justplay' : values.justplay,
1091                         'repeated' : repeated
1092                 };
1093                 var old = null;
1094                 if(values.deleteOldOnSave == "1"){
1095                         old = {
1096                                 'servicereference' : decodeURIComponent(values.servicereferenceOld),
1097                                 'begin' : values.beginOld,
1098                                 'end' : values.endOld,
1099                                 'deleteOldOnSave' : values.deleteOldOnSave
1100                         };
1101                 }
1102
1103                 debug(timer);
1104                 debug(old);
1105                 this.change(timer, old);
1106         },
1107
1108         /**
1109          * renderXML
1110          * See the description in AbstractContentProvider
1111          */
1112         renderXML: function(xml){
1113                 var list = new TimerList(xml).getArray();
1114                 return {timer : list};
1115         }
1116 });
1117
1118
1119 var VolumeHandler  = Class.create(AbstractContentHandler, {
1120         initialize: function($super, target){
1121                 $super('tplVolume', target);
1122                 this.provider = new VolumeProvider(this.show.bind(this));
1123                 this.ajaxload = false;
1124         }
1125 });