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