root/trunk/common/List.js

Revision 209, 29.4 kB (checked in by ddavis, 2 years ago)

Allow radio buttons or checkboxes in lists. BugzID: 50196

  • Property svn:keywords set to Id
Line 
1/*
2List Controller Component
3$Id$
4
5Copyright (c) 2005, Six Apart, Ltd.
6All rights reserved.
7
8Redistribution and use in source and binary forms, with or without
9modification, are permitted provided that the following conditions are
10met:
11
12    * Redistributions of source code must retain the above copyright
13notice, this list of conditions and the following disclaimer.
14
15    * Redistributions in binary form must reproduce the above
16copyright notice, this list of conditions and the following disclaimer
17in the documentation and/or other materials provided with the
18distribution.
19
20    * Neither the name of "Six Apart" nor the names of its
21contributors may be used to endorse or promote products derived from
22this software without specific prior written permission.
23
24THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35*/
36
37
38List = new Class( Component, {
39   
40    /* options that can be set with setOption() */
41   /* TODO document these
42    * Options for list:
43    * - disableUnSelect
44    * - viewMode
45    * - magnifierElement
46    * - enableMagnifier
47    * - magnifyDelay
48    * - singleselect
49    * - updateCache
50    * - cacheObject
51    * - perPage
52    * - noClickSelection
53    * - hoverDelay
54    * - checkboxSelection
55    * - selectLimit
56    */
57    disableUnSelect: false,
58    viewMode: "tile",
59    enableMagnifier: false,
60    magnifierElement: null,
61    magnifyDelay: 100,
62    singleSelect: false,
63    updateCache: false,
64    cacheObject: null,
65    perPage: 30,
66    noClickSelection: false,
67    hoverDelay: 100,
68    checkboxSelection: false,
69    selectLimit: 0, /* no limit */
70   
71   
72    activatable: true,
73    flyoutClasses: [
74        "flyout-left",
75        "flyout-right",
76        "flyout-top",
77        "flyout-bottom"
78    ],
79       
80
81    initObject: function( element, templateName ) {
82        arguments.callee.applySuper( this, arguments );
83       
84        this.content = DOM.getElement( element + "-content" );
85       
86        if ( !this.content )
87            this.content = this.element;
88       
89        if ( !templateName )
90            throw "List now takes an element, and a template as arguments";
91
92        this.templateName = templateName;
93        /* list of items assigned ids */
94        this.selected = [];
95        this.focused = false;
96        /* list of ids to item list position */
97        this.itempos = {};
98        /* ordered list of dom elements */
99        this.items = [];
100        /* ids that shouldn't be selected visibly */
101        this.unselectable = {};
102        this.lastselected = null;
103        /* Used for hover-effect delay functionality */
104        this.hoverElement = null;
105        this.hoveredElement = null;
106        this.hoverTimer = null;
107
108        this.cacheObject = null;
109
110        this.currentPage = 1;
111    },
112   
113   
114    destroyObject: function() {
115        this.selected.length = 0;
116        this.selected = null;
117        this.items.length = 0;
118        this.items = null;
119        this.unselectable = null;
120        this.content = null;
121        this.hoverElement = null;
122        this.hoveredElement = null;
123        this.magnifierElement = null;
124        this.magnifierElementContent = null;
125        this.cacheObject = null;
126        arguments.callee.applySuper( this, arguments );
127    },
128
129   
130    initEventListeners: function() {
131        arguments.callee.applySuper( this, arguments );
132       
133        /* enable mouse scroll */
134        this.addEventListener( this.element, "DOMMouseScroll", "eventDOMMouseScroll" );
135
136        /* stop ie text selection */
137        /* moz uses a css tag */
138        DOM.addEventListener( this.element, "selectstart", Event.stop );
139    },
140
141
142    clearHover: function() { 
143        if ( this.hoverElement ) 
144            DOM.removeClassName( this.hoverElement, "list-item-hover" );
145        this.hoverElement = null;
146        if ( this.hoverTimer ) 
147            this.hoverTimer.destroy();
148        this.hoverTimer = null;
149    },
150
151
152    clearHovered: function() { 
153        if ( this.hoveredElement ) 
154            DOM.removeClassName( this.hoveredElement, "list-item-hover" );     
155    },
156
157
158    /**
159     * This method invokes the superclass method of the same name, and removes any active hover effects.
160     */
161    deactivate: function() {
162        arguments.callee.applySuper( this, arguments );
163        this.clearHover();
164    },
165
166
167    setOption: function( opt, value ) {
168        switch ( opt ) {
169            case "magnifierElement":
170                if ( !value )
171                    break;
172                   
173                this.magnifierElement = $( value );
174                if( !this.magnifierElement )
175                    break;
176               
177                this.magnifierElementContent = $( value + '-content' );
178                if ( !this.magnifierElementContent )
179                    this.magnifierElementContent = this.magnifierElement;
180               
181                /* mouse over hides the magnifier */
182                if ( !this.magnifierElement.mouseOverSet ) {
183                    var el = this.magnifierElement;
184                    DOM.addEventListener( this.magnifierElementContent, "mouseover",
185                        function() { DOM.addClassName( el, "hidden" ); } );
186                    this.magnifierElement.mouseOverSet = true;
187                }
188           
189                break;
190
191            case "enableMagnifier":
192               
193                /* force the magnifier to be hidden */
194                if ( !value )
195                    DOM.addClassName( this.magnifierElement, "hidden" );
196               
197                this[ opt ] = value;
198               
199                break;
200            case "viewMode":
201                DOM.removeClassName( this.element, /^mode-.*/ );
202                DOM.addClassName( this.element, "mode-" + value );
203                this[ opt ] = value;
204
205                break;
206            case "singleselect":
207                /* backwards compatable */
208                opt = "singleSelect";
209               
210                /* this needs to fall through here */
211            default:
212                this[ opt ] = value;
213        }
214    },
215
216   
217    setModel: function( model ) {
218        /* clean up the old model */
219        if ( this.model )
220            this.model.removeObserver( this );
221        this.model = model;
222        this.model.addObserver( this );
223        this.retrieveItems();
224    },
225
226   
227    getSelectedLength: function() {
228        return this.selected.length;
229    },
230   
231
232    getSelectedIDs: function() {
233        return this.selected;
234    },
235
236
237    getFirstSelected: function() {
238        return this.selected.length ? this.selected[ 0 ] : null;
239    },
240   
241   
242    getSelectedItems: function() {
243        var selected = [];
244        for ( var i = 0; i < this.selected.length; i++ )
245            selected.push( this.items[ this.itempos[ this.selected[ i ] ] ] );
246        return selected;
247    },
248   
249
250    getFirstItem: function() {
251        return this.items.length ? this.items[ 0 ] : null;
252    },
253   
254   
255    getItem: function( id ) {
256        if ( !defined( this.itempos[ id ] ) )
257            return null;
258        else
259            return this.items[ this.itempos[ id ] ];
260    },
261
262
263    getItems: function() {
264        return this.items;
265    },
266
267   
268    getItemIds: function() {
269        var ids = [];
270        for ( var i = 0; i < this.items.length; i++ )
271            ids.push( this.items[ i ].itemId );
272       
273        return ids;
274    },
275
276
277    replaceItems: function ( items ) {
278        /* keep selected items list to re-set those */
279        var current = this.selected;
280       
281        this.resetView();
282       
283        for ( var i = 0; i < items.length; i++ )
284            this.addItem( items[ i ], ( current.indexOf( items[ i ].id ) != -1 ) ? true : false );
285
286        this.broadcastToObservers( "listItemsUpdated", this, false, items );
287    },
288   
289
290    updateItems: function ( items, classes ) {
291        /* keep selected items list to re-set those */
292        for ( var i = 0; i < items.length; i++ ) {
293            var id = items[ i ].id;
294            var pos = this.itempos[ id ];
295            var zebra = ( pos % 2 ) ? "even" : "odd";
296           
297            /* xxx add item if it doesn't exist? */
298            if ( !defined( pos ) )
299                continue;
300           
301            var selected = ( this.selected.indexOf( id ) != -1 ) ? true : false;
302
303            /* create element, and process the template */
304            var div = document.createElement( "div" );
305            div.className = defined( classes ) ? classes : "list-item " + zebra;
306            div.innerHTML = Template.process( this.templateName, {
307                div: div,
308                item: items[ i ],
309                is: {
310                    selected: selected
311                },
312                list: this,
313                index: pos
314            } );
315            div.itemId = items[ i ].id;
316           
317            /* add the class before the replace, and avoid a split second flash */
318            if ( selected ) {
319                DOM.addClassName( div, "selected" );
320                if ( this.checkboxSelection )
321                    this.toggleCheckbox( div, true );
322            }
323           
324            this.content.replaceChild( div, this.items[ pos ] );
325            this.items[ pos ] = div;
326       
327            if ( this.updateCache && this.cacheObject )
328                this.cacheObject.setItem( items[ i ].id, items[ i ] );
329        }
330       
331        if ( this.items.length )
332            this.setListEmpty( false );
333       
334        this.broadcastToObservers( "listItemsUpdated", this, true, items );
335    },
336
337
338    addItem: function( item, selected, classes ) {
339/*        if ( this.items.indexOf( item ) != -1 )
340            return;
341*/
342       
343        this.setListEmpty( false );
344
345        var pos = this.items.length;
346        var zebra = ( pos % 2 ) ? "even" : "odd";
347
348        var div = document.createElement( "div" );
349        div.className = defined( classes ) ? classes : "list-item " + zebra;
350        div.innerHTML = Template.process( this.templateName, {
351            div: div,
352            item: item,
353            is: {
354                selected: selected
355            },
356            list: this,
357            index: pos 
358        } );
359        div.itemId = item.id;
360
361        /* fixme special case for chooser, lets fix this */
362        if ( defined( item.type ) )
363            div.type = item.type;
364
365        /* todo lets do this another way */
366        if ( defined( item.unselectable ) && item.unselectable )
367            this.unselectable[ item.id ] = true;
368       
369        this.content.appendChild( div );
370
371        this.items.push( div );
372        this.itempos[ item.id ] = pos;
373       
374        if ( this.updateCache && this.cacheObject )
375            this.cacheObject.setItem( item.id, item );
376       
377        if ( selected ) {
378            DOM.addClassName( div, "selected" );
379            if ( this.checkboxSelection )
380                this.toggleCheckbox( div, true );
381            this.selected.add( item.id );
382        }
383    },
384   
385
386    /* xxx this should accept an itemId or dom element */
387    removeItem: function( itemid ) {
388        if ( !defined( this.itempos[ itemid ] ) )
389            return;
390       
391        log("remove item " + itemid);
392       
393        this.removeItems( [ itemid ] );
394    },
395
396
397    removeItems: function( items ) {
398        var itemids = [];
399        for ( var i = 0; i < items.length; i++ ) {
400            var idx = this.itempos[ items[ i ] ];
401            if ( !defined( idx ) )
402                continue;
403           
404            /* extra check */
405            if ( this.items[ idx ].itemId != items[ i ] )
406                continue;
407           
408            this.content.removeChild( this.items[ idx ] );
409
410            if ( this.lastselected == items[ i ] )
411                this.lastselected = null;
412       
413            // recalculate the position index
414            var len = this.items.length;
415            for ( var j = idx + 1; j < len; j++ )
416                this.itempos[ this.items[ j ].itemId ] = ( j - 1 );
417       
418            this.selected.remove( items[ i ] );
419            delete this.itempos[ items[ i ] ];
420            this.items.splice( idx, 1 );
421       
422            if ( this.items.length == 0 )
423                this.setListEmpty( true );
424           
425            itemids.push( items[ i ] );
426           
427            if ( this.updateCache && this.cacheObject )
428                this.cacheObject.deleteItem( items[ i ] );
429        }
430       
431        if ( itemids.length )
432            this.broadcastToObservers( "listItemsRemoved", this, itemids );
433    },
434
435
436    reset: function() {
437        this.resetView();
438        DOM.addClassName( this.element, "list-empty" ); 
439    },
440
441   
442    resetView: function() {
443        this.selected = [];
444        this.itempos = {};
445        var len = this.items.length;
446        for( var i = 0; i < len; i++ )
447            this.content.removeChild( this.items[ i ] );
448        this.items = [];
449        this.lastselected = null;
450        this.unselectable = {};
451        //this.broadcastToObservers( "listViewReset", this );
452        //this.setListEmpty( true );
453    },
454
455 
456    /* accepts an array of ids */
457    setSelection: function( ids, nobcast ) {
458        var startlen = this.selected.length;
459        var idx;
460        var selected = [];
461        var e;
462
463        for ( var i = 0; i < ids.length; i++ ) {
464            /* you can set selection on items not in the list yet */
465            this.selected.add( ids[ i ] );
466            idx = this.itempos[ ids[ i ] ];
467            if ( defined( idx ) ) {
468                e = this.items[ idx ];
469                selected.push( e.itemId );
470                DOM.addClassName( e, "selected" );
471                if ( this.checkboxSelection )
472                    this.toggleCheckbox( e, true );
473            }
474        }
475       
476        if ( nobcast )
477            return;
478       
479        //this.lastselected = ids[ ( ids.length - 1 ) ];
480        // if there are any new selections, then tell the observers
481        if ( startlen < this.selected.length && selected.length )
482            this.broadcastToObservers( "listItemsSelected", this, selected );
483    },
484
485
486    /* XXX how can we avoid this code duplication? */
487    unsetSelection: function( ids ) {
488        var startlen = this.selected.length;
489        var selected = [];
490        var idx;
491        var e;
492
493        for ( var i = 0; i < ids.length; i++ ) {
494            this.selected.remove( ids[ i ] );
495            idx = this.itempos[ ids[ i ] ];
496            if ( !defined( idx ) )
497                continue;
498               
499            e = this.items[ idx ];
500            selected.push( e.itemId );
501            DOM.removeClassName( e, "selected" );
502            if ( this.checkboxSelection )
503                this.toggleCheckbox( e, false );
504        }
505       
506        if ( startlen > this.selected.length && selected.length )
507            this.broadcastToObservers( "listItemsUnSelected", this, selected );
508    },
509
510
511    resetSelection: function() {
512        // no need to refire if the selected list is empty
513        if ( this.selected.length == 0 )
514            return;
515
516        var selected = [];
517        var idx;
518        var e;
519
520        for ( var i = 0; i < this.selected.length; i++ ) {
521            idx = this.itempos[ this.selected[ i ] ];
522            if ( !defined( idx ) )
523                continue;
524            e = this.items[ idx ];
525            selected.push( this.selected[ i ] );
526            DOM.removeClassName( e, "selected" );
527            if ( this.checkboxSelection )
528                this.toggleCheckbox( e, false );
529        }
530
531        this.selected = [];
532       
533        if ( selected.length )
534            this.broadcastToObservers( "listItemsUnSelected", this, selected );
535    },
536
537
538    getListElementFromTarget: function( target ) {
539        return DOM.getFirstAncestorByClassName( target, "list-item", true );
540    },
541
542
543    getItemIdFromTarget: function( target ) {
544        var item = this.getListElementFromTarget( target );
545        if ( item )
546            return item.itemId;
547        else
548            return undefined; 
549    },
550   
551
552    /* events */
553   
554    eventDOMMouseScroll: function( event ) {
555        var delta = 0;
556        if ( event.wheelDelta ) {
557            delta = ( event.wheelDelta * -0.5 );
558        } else if ( event.detail ) {
559            delta = ( event.detail * 10 );
560        }
561        var scrollt = this.content.scrollTop;
562        this.content.scrollTop += delta;
563        /* only trigger reflow if this scroll affects the list */
564        if ( scrollt != this.content.scrollTop ) {
565            this.reflow();
566            event.stop();
567        }
568    },
569   
570
571    eventMouseDown: function( event ) {
572        arguments.callee.applySuper( this, arguments );
573        var ancestor = this.getListElementFromTarget( event.target );
574        if ( ancestor )
575            return;
576       
577        // xxx can add drag select box code here
578    },
579
580   
581    eventDoubleClick: function( event ) {
582        var ancestor = this.getListElementFromTarget( event.target );
583        if ( !ancestor )
584            return;
585       
586        if ( this.selected.length )
587            this.broadcastToObservers( "listItemsDoubleClicked", this, this.selected );
588    },
589 
590 
591    eventMouseOver: function( event ) {
592        var element = this.getListElementFromTarget( event.target );
593       
594        /* TODO convert this from a dom ref to an ID */
595        if ( element !== this.hoverElement ) {
596       
597            this.hoverElement = element; // Delay before hover effect:
598           
599            if ( this.hoverTimer )
600                this.hoverTimer.destroy();
601       
602            this.hoverTimer = new Timer( this.getIndirectMethod( "timedMouseover" ), this.hoverDelay, 1 ); 
603       
604            if ( !this.enableMagnifier || !element )
605                return;
606        }
607       
608        if ( !this.enableMagnifier )
609            return;
610       
611        if ( this.magnifierAttribute ) {
612             var target = DOM.getMouseEventAttribute( event, this.magnifierAttribute );
613             /* mouse over an item with an attribute, then show the magnifier */
614             if ( !target )
615                 return;
616        }
617        /* auto use assetCache if available */
618        if ( !this.cacheObject && window.app && app.assetCache )
619            this.cacheObject = app.assetCache;
620               
621        /* don't reset the timer on remouse over */
622        if ( this.magnifyItemId && this.magnifyItemId == element.itemId )
623            return;
624       
625        this.magnifyItemId = element.itemId;
626       
627        var item = this.cacheObject.getItem( this.magnifyItemId );
628        if ( !item )
629            return;
630       
631        /* preload the div */
632        this.magnifierElementContent.innerHTML = Template.process( this.magnifierTemplate, { item: item, list: this } );
633       
634        /* stop any other timer */
635        if ( this.magnifyTimer )
636            this.magnifyTimer.destroy();
637       
638        this.magnifyTimer = new Timer( this.getIndirectMethod( "showMagnifier" ), this.magnifyDelay, 1 );
639           
640        var cli = DOM.getClientDimensions();
641        /* get half client dimensions */
642        this.clientHX = cli.x / 2;
643        this.clientHY = cli.y / 2;
644       
645        this.positionMagnifier( event );
646    },
647
648
649    showMagnifier: function() {
650        if ( !defined( this.magnifyItemId ) )
651            return;
652         
653        /* show magnifier */
654        DOM.removeClassName( this.magnifierElement, "hidden" );
655    },
656   
657   
658    eventMouseMove: function( event ) {
659        if ( !this.enableMagnifier || !defined( this.magnifyItemId ) || !this.getListElementFromTarget( event.target ) )
660            return;
661
662        this.positionMagnifier( event );
663    },
664
665
666    positionMagnifier: function( event ) {
667        var m = DOM.getAbsoluteCursorPosition( event );
668       
669        var classX = ( m.x > this.clientHX ) ? 0 : 1;
670        var classY = ( m.y > this.clientHY ) ? 2 : 3;
671       
672        /* avoid resetting the classes if not needed */
673        if ( classX != this.magClassX || classY != this.magClassY ) {
674            for ( var i = 0; i < this.flyoutClasses.length; i++ ) {
675                if ( i == classX || i == classY )
676                    continue;
677                DOM.removeClassName( this.magnifierElement, this.flyoutClasses[ i ] );
678            }
679       
680            DOM.addClassName( this.magnifierElement, this.flyoutClasses[ classX ] );
681            DOM.addClassName( this.magnifierElement, this.flyoutClasses[ classY ] );
682
683            this.magClassX = classX;
684            this.magClassY = classY;
685        }
686       
687        /* offset the magnifier so it doesn't cause a 'mouse out, hide, mouse over, repeat' */
688        m.x += 10;
689        m.y += 15;
690       
691        /* set inital position */
692        DOM.setLeft( this.magnifierElement, m.x );
693        DOM.setTop( this.magnifierElement, m.y );
694    },
695
696
697    eventMouseOut: function( event ) { // We don't get the mouseout on the hoverElement here for some reason.
698        var element;
699        if ( this.magnifierAttribute ) {
700             var target = DOM.getMouseEventAttribute( event, this.magnifierAttribute );
701             /* mouse over an item with an attribute, then show the magnifier */
702             if ( !target )
703                return;
704        } else {
705            element = this.getListElementFromTarget( event.relatedTarget );
706            if ( event.relatedTarget && !element )
707                this.clearHover(); // So we use 'relatedTarget' instead of 'target'.
708        }
709       
710        if ( this.enableMagnifier && !element ) {
711            if ( this.magnifyTimer )
712                this.magnifyTimer.destroy();
713            DOM.addClassName( this.magnifierElement, "hidden" );
714            this.magnifyItemId = undefined;
715            event.stop();
716        }
717    },
718
719
720
721    eventClick: function( event ) {
722        if ( this.noClickSelection )
723            return;
724       
725        var command = this.getMouseEventCommand( event );
726        if ( command )
727            return;
728       
729        var ancestor = this.getListElementFromTarget( event.target );
730        if ( !ancestor ) {
731            /* deselect everything only if no modifier keys are being used */
732            if ( event.ctrlKey || event.metaKey || event.shiftKey )
733                return;
734            if ( !this.disableUnSelect )
735                this.resetSelection();
736            return;
737        }
738        var itemId = ancestor.itemId;
739
740        if ( !this.singleSelect && event.shiftKey ) {
741            var sel = [];
742           
743            /* lastselected is an id
744             * using the itempos list, we find the position
745             * of the item in our list
746             */
747           
748            // locate start and end of selection in list
749            var start = this.itempos[ this.lastselected ] || 0
750            //var end = this.items.indexOf( ancestor );
751            var end = this.itempos[ itemId ];
752           
753            if ( start > end ) {
754                var tmp = end;
755                end = start;
756                start = tmp;
757            }
758           
759            /* only select items that are not already selected
760             * this cuts down on the number of selected items
761             * sent back to the watchers
762             */
763            for ( var i = start; i <= end; i++ ) {
764                if ( this.selectLimit && ( this.selected.length + sel.length ) >= this.selectLimit ) {
765                    this.unsetSelection( [ this.items[ i ].itemId ] );
766                    continue;
767                }
768                if ( this.selected.indexOf( this.items[ i ].itemId ) == -1 
769                    && !this.unselectable[ this.items[ i ].itemId ] )
770                    sel.push( this.items[ i ].itemId );
771            }
772           
773            this.setSelection( sel );
774           
775            return;
776        } else if ( !this.singleSelect && ( event.ctrlKey || event.metaKey ) ) {
777            if ( this.selected.indexOf( itemId ) != -1 && !this.unselectable[ itemId ] ) {
778                this.lastselected = itemId;
779                this.unsetSelection( [ itemId ] );
780                return;
781            }
782        } else {
783            if ( this.selected.length == 1 && this.selected[ 0 ] == itemId ) {
784                /* selected item that is already selected */
785                this.lastselected = itemId;
786                if ( this.toggleSelect )
787                    this.unsetSelection( [ itemId ] );
788                return;
789            } else {
790                if ( !this.toggleSelect && !this.disableUnSelect )
791                    this.resetSelection();
792            }
793        }
794        if ( defined( this.unselectable[ itemId ] ) )
795            return;
796
797        this.lastselected = itemId;
798        if ( this.toggleSelect ) {
799            if ( this.selected.indexOf( itemId ) != -1 ) {
800                log("unselecting " + itemId);
801                this.unsetSelection( [ itemId ] );
802                return;
803            }
804        }
805       
806        if ( this.selectLimit && this.selected.length >= this.selectLimit )
807            return this.unsetSelection( [ itemId ] );
808       
809        log("selecting " + itemId);
810        this.setSelection( [ itemId ] );
811    },
812
813
814    timedMouseover: function( timer ) { 
815        if ( this.hoveredElement ) 
816            this.clearHovered();
817        if ( this.hoverElement ) {
818            DOM.addClassName( this.hoverElement, "list-item-hover" );
819            this.hoveredElement = this.hoverElement;
820        }
821    },
822
823       
824    /* emitted by the list model */
825
826    listModelItems: function( modelobj, items, update, total, offset, count ) {
827
828        this.length = total;
829
830        this.broadcastToObservers( "listTotal", this, total, this.currentPage, this.perPage, items.length );
831
832        if ( update ) {
833            this.updateItems( items );
834            return;
835        }
836
837        DOM.removeClassName( this.element, "list-loading" );
838
839        if ( modelobj.filteredEmpty )
840            this.setListEmpty( true, true );
841        else if ( modelobj.empty )
842            this.setListEmpty( true );
843        else if ( items.length )
844            this.setListEmpty( false );
845        else if ( !items.length )
846            this.setListEmpty( true );
847        else
848            this.setListEmpty( false );
849           
850        this.replaceItems( items );
851    },
852
853
854    setListEmpty: function( empty, filtered ) {
855        if ( empty ) {
856            if ( filtered )
857                DOM.addClassName( this.element, "list-empty-filtered" );
858            else
859                DOM.removeClassName( this.element, "list-empty-filtered" );
860            /*
861            var es = DOM.getElementsByClassName( this.element, "list-empty-message" );
862            for ( var i = 0; i < es.length; i++ )
863                DOM.removeClassName( es[ i ], "hidden" );
864            */ 
865            DOM.addClassName( this.element, "list-no-results" );
866        } else {
867            DOM.removeClassName( this.element, "list-no-results" );
868            DOM.removeClassName( this.element, "list-empty-filtered" );
869        }
870       
871        DOM.removeClassName( this.element, "list-empty" ); 
872         
873        this.broadcastToObservers( "listEmpty", this, empty, filtered );
874    },
875
876   
877    retrieveItems: function() {
878        this.model.getItems( ( ( this.currentPage - 1 ) * this.perPage ), this.perPage );
879    },
880 
881
882    setPerPage: function( perPage ) {
883        this.perPage = perPage;
884    },
885   
886   
887    setCurrentPage: function( currentPage ) {
888        this.currentPage = currentPage;
889    },
890
891   
892    /* observer called methods */
893   
894    listModelChanged: function( modelobj ) {
895        this.retrieveItems();
896    },
897   
898   
899    pagerPageChange: function( pagerobj, page ) {
900        this.setCurrentPage( page );
901        this.retrieveItems();
902    },
903
904   
905    componentActivated: function( comp ) {
906        /* XXX doesn't get called? */
907        if ( !this.enableMagnifier )
908            return;
909       
910        DOM.addClassName( this.magnifierElement, "hidden" );
911    },
912
913
914    componentDeactivated: function( comp ) {
915        /* XXX doesn't get called? */
916        if ( !this.enableMagnifier )
917            return;
918           
919        DOM.addClassName( this.magnifierElement, "hidden" );
920    },
921
922   
923    toggleCheckbox: function( e, value ) {
924        var es = e.getElementsByTagName( "input" );
925        if ( !es )
926            return;
927        var type;
928        for ( var i = 0; i < es.length; i++ ) {
929            type = es[ i ].getAttribute( "type" );
930            type = type ? type.toLowerCase() : "";
931            if ( type == "checkbox" || type == "radio" )
932                es[ i ].checked = value;
933        }
934    }
935} );
936
937
938ListModel = new Class( Observable, {
939    init: function() {
940        arguments.callee.applySuper( this, arguments );
941        if( arguments[ 0 ] instanceof Array )
942            this.source = arguments[ 0 ];
943        app.c.addObserver( this );
944    },
945
946   
947    getItems: function( start, end, callback ) {
948        if ( !start )
949            start = 0;
950        if ( !end || end > this.source.length )
951            end = this.source.length;
952       
953        this.broadcastToObservers( "listModelItems", this, this.source.slice( start, end ) );
954    },
955
956   
957    /* observer called methods */
958    assetsDeleted: function( cobj, ids ) {
959        this.broadcastToObservers( "listModelChanged", this );
960    },
961
962   
963    assetsUpdated: function( cobj, ids ) {
964        this.broadcastToObservers( "listModelChanged", this );
965    }             
966} );
967
968   
Note: See TracBrowser for help on using the browser.