Subversion Repositories Applications.papyrus

Rev

Blame | Last modification | View Log | RSS feed

if(!dojo._hasResource["dojox.widget.SortList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.widget.SortList"] = true;
dojo.provide("dojox.widget.SortList");
dojo.experimental("dojox.widget.SortList"); // level: prototype, designed for dijit.chat.demo

dojo.require("dijit.layout._LayoutWidget");
dojo.require("dijit._Templated");

dojo.declare("dojox.widget.SortList",
        [dijit.layout._LayoutWidget, dijit._Templated],
        {
        // summary: a sortable <ul> with a fixed header for use in dijit.demos.chat
        //      for demonstration purposes only for now. feel free to make API suggestions
        //      or fixes. 
        //
        // title: String 
        //      the title in the header
        title: "",
        
        // heading: String
        //      in the event a parent container is expecting a title="" attribute, set it for the parent 
        //      via title, and the title of this widget via heading="" ... assuming you want different 
        //      titles for each. eg: TabContainer, AccordionContainer, etc. 
        heading: "",

        // descending: Boolean
        //      toggle sort order based on this value. 
        descending: true,

        // selected: Array
        //      a list of the selected <li> nodes at any given time.
        selected: null,


        // sortable: Boolean
        //      toggle to enable/disable sorting
        sortable: true,

        // FIXME: this is really simple store support
        store: "",
        key: "name",

        templateString:"<div class=\"sortList\" id=\"${id}\">\n\t\t<div class=\"sortListTitle\" dojoAttachPoint=\"titleNode\">\n\t\t<div class=\"sortListIcon\"></div>\n\t\t<span dojoAttachPoint=\"focusNode\">${title}</span>\n\t\t</div>\n\t\t<div class=\"sortListBodyWrapper\" dojoAttachEvent=\"onmouseover: _set, onmouseout: _unset, onclick:_handleClick\" dojoAttachPoint=\"bodyWrapper\">\n\t\t<ul dojoAttachPoint=\"containerNode\" class=\"sortListBody\"></ul>\n\t</div>\n</div>\n",

        _addItem: function(item){
                var node = document.createElement("li");
                var text = this.store.getValue(item,this.key);
                node.innerHTML = text;
                this.containerNode.appendChild(node);
        },

        postCreate: function(){
                if (this.store){
                        // FIXME: is this right?
                        this.store = eval(this.store);
                        var props = {
                                onItem: dojo.hitch(this,"_addItem"),
                                onComplete: dojo.hitch(this,"onSort")
                        };
                        this.store.fetch(props);        
                }else{ this.onSort(); }
                this.inherited("postCreate",arguments);
        },

        startup: function(){
                this.inherited("startup",arguments);
                if(this.heading){ 
                        this.setTitle(this.heading); this.title=this.heading; 
                }
                // we cheat, and give the browser just enough time so we know our height
                setTimeout(dojo.hitch(this,"resize"),5);
                if (this.sortable){ this.connect(this.titleNode,"onclick", "onSort"); }
        },

        resize: function(){
                // summary: do our additional calculations when resize() is called by or in a parent
                this.inherited("resize",arguments);
                // FIXME: 
                // the 10 comes from the difference between the contentBox and calculated height
                // because of badding and border extents. this shouldn't be done this way, a theme change will 
                // break it: but we also don't want to run getComputedStyle or dojo.coords() every time resize() 
                // is fired.
                var offset = ((this._contentBox.h) - (dojo.style(this.titleNode,"height")))-10;
                this.bodyWrapper.style.height = Math.abs(offset) + "px"; 
        },
        
        onSort: function(/* Event */e){
                // summary: sort the data, and style the nodes.

                var arr = dojo.query("li",this.domNode);
                if (this.sortable){
                        this.descending = !this.descending;
                        dojo.addClass(this.titleNode,((this.descending)?"sortListDesc":"sortListAsc"));
                        dojo.removeClass(this.titleNode,((this.descending)?"sortListAsc":"sortListDesc"));
                        arr.sort(this._sorter);
                        if(this.descending){ arr.reverse(); }
                }
                var i=0;
                dojo.forEach(arr,function(item){
                        dojo[(((i++)%2)===0)?"addClass":"removeClass"](item,"sortListItemOdd");
                        this.containerNode.appendChild(item); 
                },this);
        },
        
        _set: function(/* Event */e){
                // summary: set hover state 
                if (e.target != this.bodyWrapper){
                        dojo.addClass(e.target,"sortListItemHover");
                }
        },

        _unset: function(/* Event */e){
                // summary: remove hover state (FIXME: combine with _set?) 
                dojo.removeClass(e.target,"sortListItemHover"); 
        },

        _handleClick: function(/* Event */e){
                // summary: click listener for data portion of widget. toggle selected state
                //      of node, and update this.selected array accordingly
                dojo.toggleClass(e.target,"sortListItemSelected");
                e.target.focus();
                this._updateValues(e.target.innerHTML);
        },

        _updateValues: function(){
                this._selected = dojo.query("li.sortListItemSelected",this.containerNode);
                this.selected = [];
                dojo.forEach(this._selected,function(node){
                        this.selected.push(node.innerHTML);
                },this);
                this.onChanged(arguments);
        },

        _sorter: function(a,b){
                // summary: a basic sort function, use query sort, or keep this?
                var aStr = a.innerHTML;
                var bStr = b.innerHTML;
                if(aStr>bStr){ return 1; }
                if(aStr<bStr){ return -1; }
                return 0;
        },

        setTitle: function(/* String */title){
                // summary: Sets the widget title to a String
                this.focusNode.innerHTML = title;
        },

        onChanged: function(){
                // summary: stub function, passes the last changed item, and is fired after current state 
        }
});

}