Skip to main content
Rollback to Revision 2
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Edit: Hoping to bump this a little as I never got any feedback.

Edit: Hoping to bump this a little as I never got any feedback.

added 69 characters in body
Source Link

Edit: Hoping to bump this a little as I never got any feedback.

Edit: Hoping to bump this a little as I never got any feedback.

Tweeted twitter.com/#!/StackCodeReview/status/233928600229920768
improves formatting; added 2 characters in body; edited title
Source Link
palacsint
  • 30.4k
  • 9
  • 82
  • 157

Jquery jQuery list widget code review

this is my first post here, so Hello :)

I have been writing a jQuery widget for a couple of days now. Originally I needed this functionality for something I am writing at work, but I felt like I could abstract it a little more so here I am. I think it's about finished for now, I may add some features depending on how It gets used (if it does).

This is my first jQuery widget and I have been programming in javascriptJavaScript for just over a month now, so I don't think the code will be particularly great, but I've tried my hardest.

I would just like some feedback on my coding, how to improve/ dodo it better, now and in the future. It's quite a big chunk of code but I didn't see anything in the FAQ about length of code.

I've also attatchedattached a jsFiddle so you can mess with it. : http://jsfiddle.net/jCVzp/2/ I've

I've tried to comment as best as I can and have noted all the options in the file description, and more guidance needed, just ask.

Any time and help is greatly appreciated, thanks!.

(function($) {
            /* 
            *   Document   : list-widget-0.1
            *   Created on : 06-Aug-2012, 20:53:49
            *   Author     : aydin hassan
            *   Description:
            *       This widget is designed to be attatched to a div
            *       
            *       Using the options you can specify one of three list types:
            *           1.) a normal list if items (normal)
            *           2.) a list of items with a cross/tick img depending on its status (act-deact)
            *               ---Clicking the image will toggle its status (change the img and class) and run a provided callback
            *           3.) a list of items with a trash can icon (remove)
            *               ---Click the image will run a supplied calback and then remove the item
            *
            *       Each of the lists has various callbacks:
            *           1.) The global click callback (selectabble.clickCallBack), if passed, will launch on clicked an element for any list type
            *           2.) The global click off callback (selectable.clickOffCallBack), if passed, will launch when an item is clicked off.
            *               ---Works in conjuction with selectable.sticky - if this is set to true elements will stay higlighted until they are clicked off
            *               ---NOTE: click off callback will not be processed if selectable.sticky is set to true
            *           3.) The act-deact callback, if passed, will run after a user has clicked the img, or, if there is no global click callback (selectabble.clickCallBack) it will 
            *               run when the li element is clicked
            *           4.) The remove callback, if passed, will run after the user clicks on the trash-can icon
            *           5.) The add button callback, if passed, will run when a user clicks the add button
            *
            *       List data:
            *           The list data must be an object of the following form:
            *               act-deact:
            *               var data = {
            *                   "0":{"name":"list item 1","activated":true},
            *                   "1":{"name":"list item 2","activated":true},
            *                   "2":{"name":"list item 3","activated":false}
            *               };
            *               
            *               normal/remove:
            *               var data = {
            *                   "0":{"name":"list item 1"},
            *                   "1":{"name":"list item 2"},
            *                   "2":{"name":"list item 3"}
            *               };
            *       
            *       Other options:
            *           title:          ---The title of the list box
            *           description:    ---Some description of the data
            *           searchBar:      ---BOOL - To display a filter box
            *           addButton:      ---BOOL - To display an add button
            *           idStyle:        ---A string to prepend to the id of the item id in the data object to use as the li element id attribute
            *           
            */      
            
          $.widget( "widgets.adminList", {


            // These options will be used as defaults

            options: { 
              list: null,
              title: "Title",
              description: "Some description",
              searchBar: true,
              addButton: false,
 
              addCallBack: null,
              listType: "normal",
              idStyle: "li-id-",
              removeCallBack: null,
              toggleCallBack: null,
              selectable: null    
              
            },


            // Set up the widget
            _create: function() {
                                    
            },
            
            _init: function() {
                var options = this.options;
                //Build the container elements
                this._buildTableHead();

                //switch type of list and run setup function for specified type
                switch (options.listType) {
                    case "normal": this._setUpNormal();
                        break;
                    case "act-deact": this._setUpActDeact();
                        break;
                    case "remove": this._setUpRemove();
                        break;
                }
                
                                
                //If the selectable options are configured then we may want sticky elements (hover css stays until clciked again, or another elements is clicked)
                //And there may also be click on and click off callbacks
                if(options.selectable != null) {
                    $(".list-widget-list-container .list-widget-list li a").live('click',(function(e) {
                        //prevent the href("") from being followed, href is needed for IE to display hover
                        e.preventDefault();
                        //If we want elements to stick
                        if(options.selectable.stick) {
                            //If this element is stuck already
                            //unstick it and run click off call back if supplied
                            if($(this).hasClass("selected")) {
                                $(this).removeClass("selected");
                                if(options.selectable.clickOffCallBack != null){
                                    options.selectable.clickOffCallBack(this);
                                }
                            //Else unstick any other elements
                            //Stick this element
                            //and run click callback
                            } else {
                                $(".list-widget-list-container .list-widget-list").find(".selected").removeClass("selected");
                                $(this).addClass("selected");
                                if(options.selectable.clickCallBack != null){
                                    options.selectable.clickCallBack(this);
                                }
                            }
                        //If we don't want to stick just run click on callback if supplied
                        } else {
                            if(options.selectable.clickCallBack != null){
                                options.selectable.clickCallBack(this);
                            }
                        }
                    }));
                }
                
                //If add callback is supplied
                //create click event
                if(options.addButton && options.addCallBack != null) {
                    $(".list-widget-head-div .header-table .add-but").click(function() {
                        options.addCallBack(this);
                    });
                }
                
                
                //create event for filter box
                var that = this;                    
                $(".list-widget-head-div .header-table .list-search-box").bind("keyup",function(){
                    that._listFilter(this);
                });
                
                //Add the list elements
                this.add(options.list);
            },
            
            _listFilter:function(e){
                var filter = $(e).val(); // get the value of the input, which we filter on
                var list = $(".list-widget-list-container .list-widget-list");

                //only filter if value exists
                if(!filter || filter.length < 1 ){
                    list.find("li").show();
                }
                else{
                    list.find("li").each(function(){
                        //if a element text contains the filter value, hide it
                        if($("a", this).text().toLowerCase().indexOf(filter.toLowerCase()) == -1  ){
                            $(this).hide();
                        }
                        else{
                            //else show it
                            $(this).show();
                        }
                    });
                }
            },
                            
            _buildTableHead:function(){
                //get the current options
                var options = this.options;
                //get the div the widget has been attatched to
                var self = this.element;
                
                //build table header
                var headCells = $("<tr />")
                        .append($('<td  />')
                            .attr("width","33%")
                            .attr("height","45px")
                            .append($('<p />')
                                .addClass("title")
                                .text(options.title)
                            )
                        );
                
                //depending on the options;
                //add a search bar and add button
                
                //if we want searchbar and add button..
                if(options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .attr("text-align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    )
                    .append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                //if we only want add button
                } else if (!options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .attr("align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    );
                //if we only want search bar
                } else if (options.searchBar && !options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                }
                
                //Build the tables and append the cells
                self.append($('<div />')
                        .addClass("list-widget-head-div")
                        .addClass("ui-corner-top")
                        .append($('<table />')
                            .addClass("header-table")
                            .append(headCells)
                        )
                        //Add the description if present
                        .append($("<p />")
                            .addClass("descript")
                            .text(options.description)
                    )
                );
                
                //Add the actual list element
                self.append($("<div />")
                    .addClass("list-widget-list-container")
                    .addClass("ui-corner-bottom")
                        .append($("<ul />")
                        .addClass("list-widget-list")
                    )
                );
            },
            
            _setUpNormal:function(){
                //get the current options
                var options = this.options;

            },
            _setUpActDeact:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the item image
                //Changes the status and can be provided with a call back
                //which has access to the clicked element
                
                
                //If there is no clickCallBack supplied, we apply the toggle action to the whole li element
                if(options.selectable.clickCallBack == null) {
                    $(".list-widget-list-container .list-widget-list li").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this).find("img.list-img");
                        //var to store status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled)
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                //if there is a clickCallBack then we just apply the toggle event to the image
                } else {
                    $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this);
                        //var to stored status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                }
            },
            _setUpRemove:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the delete image
                //runs a provided callback and the removes item
                $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                    //if callback has been provided, run it
                    if(options.removeCallBack != null) {
                        options.removeCallBack(this)
                    }
                    //remove element
                    $(this).parent().remove();
                });
            },
            
            // Use the _setOption method to respond to changes to options

            _setOption: function( key, value ) {

              switch( key ) {

                case "clear":
                  // handle changes to clear option

                  break;

              }

              // In $ UI 1.8, you have to manually invoke the _setOption method from the base widget

              $.Widget.prototype._setOption.apply( this, arguments );
              // In $ UI 1.9 and above, you use the _super method instead
              this._super( "_setOption", key, value );

            },

            // Use the destroy method to clean up any modifications your widget has made to the DOM

            destroy: function() {

              // In $ UI 1.8, you must invoke the destroy method from the base widget

              $.Widget.prototype.destroy.call( this );
              // In $ UI 1.9 and above, you would define _destroy instead of destroy and not call the base method

            },
            
            /* This fuction when presented with an object in the following format
             * var data = {
             *      "0":{"name":"list item 1","activated":true},
             *      "1":{"name":"list item 2","activated":true},
             *      "2":{"name":"list item 3","activated":false}
             *  };
             * Will append the items to the bottom of the list
             */ 
            
            add: function(list) {
                //Pick add function depending on listType
                switch(this.options.listType) {
                    case "normal":this._addNormal(list);
                        break;
                    case "act-deact":this._addActDeact(list);
                        break;
                    case "remove":this._addRemove(list);
                        break;
                }
            },
            
            _addNormal: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                            .text(val.name)
                        )
                    );
                });
            },
            
            _addActDeact: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");

                //For each list item
                $.each(list, function(key,val){
                    //creat li element
                    var li = $("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<img />")
                                .addClass("list-img")
                            )
                            .append($("<a />")
                                .text(val.name)
                                .attr("href","")
                                .addClass("actdeact")
                        );
                    //add activated/deactivated class
                    //depending on item status 
                    if(val.activated === true) {
                        li.find("img").addClass("activated");
                        li.find("img").attr("src","tick.png");
                    } else {
                        li.find("img").addClass("deactivated");
                        li.find("img").attr("src","cross.png");
                    }
                    //Append the list item to the list
                    ulElem.append(li);
                });
                
            },
            
            _addRemove: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .append($("<img />")
                                .addClass("list-img")
                                .attr("src","trash_can.png")
                            )
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                                .text(val.name)
                                .addClass("remove")
                        )
                    );
                });
            },
            
            //Function to empty the list
            empty: function() {
                $(".list-widget-list-container .list-widget-list").empty();
            }
            
        });

Jquery list widget code review

this is my first post here, so Hello :)

I have been writing a jQuery widget for a couple of days now. Originally I needed this functionality for something I am writing at work, but I felt like I could abstract it a little more so here I am. I think it's about finished for now, I may add some features depending on how It gets used (if it does)

This is my first jQuery widget and I have been programming in javascript for just over a month now, so I don't think the code will be particularly great, but I've tried my hardest.

I would just like some feedback on my coding, how to improve/ do it better, now and in the future. It's quite a big chunk of code but I didn't see anything in the FAQ about length of code.

I've also attatched a jsFiddle so you can mess with it. http://jsfiddle.net/jCVzp/2/ I've tried to comment as best as I can and have noted all the options in the file description, and more guidance needed, just ask.

Any time and help is greatly appreciated, thanks!

(function($) {
            /* 
            *   Document   : list-widget-0.1
            *   Created on : 06-Aug-2012, 20:53:49
            *   Author     : aydin hassan
            *   Description:
            *       This widget is designed to be attatched to a div
            *       
            *       Using the options you can specify one of three list types:
            *           1.) a normal list if items (normal)
            *           2.) a list of items with a cross/tick img depending on its status (act-deact)
            *               ---Clicking the image will toggle its status (change the img and class) and run a provided callback
            *           3.) a list of items with a trash can icon (remove)
            *               ---Click the image will run a supplied calback and then remove the item
            *
            *       Each of the lists has various callbacks:
            *           1.) The global click callback (selectabble.clickCallBack), if passed, will launch on clicked an element for any list type
            *           2.) The global click off callback (selectable.clickOffCallBack), if passed, will launch when an item is clicked off.
            *               ---Works in conjuction with selectable.sticky - if this is set to true elements will stay higlighted until they are clicked off
            *               ---NOTE: click off callback will not be processed if selectable.sticky is set to true
            *           3.) The act-deact callback, if passed, will run after a user has clicked the img, or, if there is no global click callback (selectabble.clickCallBack) it will 
            *               run when the li element is clicked
            *           4.) The remove callback, if passed, will run after the user clicks on the trash-can icon
            *           5.) The add button callback, if passed, will run when a user clicks the add button
            *
            *       List data:
            *           The list data must be an object of the following form:
            *               act-deact:
            *               var data = {
            *                   "0":{"name":"list item 1","activated":true},
            *                   "1":{"name":"list item 2","activated":true},
            *                   "2":{"name":"list item 3","activated":false}
            *               };
            *               
            *               normal/remove:
            *               var data = {
            *                   "0":{"name":"list item 1"},
            *                   "1":{"name":"list item 2"},
            *                   "2":{"name":"list item 3"}
            *               };
            *       
            *       Other options:
            *           title:          ---The title of the list box
            *           description:    ---Some description of the data
            *           searchBar:      ---BOOL - To display a filter box
            *           addButton:      ---BOOL - To display an add button
            *           idStyle:        ---A string to prepend to the id of the item id in the data object to use as the li element id attribute
            *           
            */      
            
          $.widget( "widgets.adminList", {


            // These options will be used as defaults

            options: { 
              list: null,
              title: "Title",
              description: "Some description",
              searchBar: true,
              addButton: false,
              addCallBack: null,
              listType: "normal",
              idStyle: "li-id-",
              removeCallBack: null,
              toggleCallBack: null,
              selectable: null    
              
            },


            // Set up the widget
            _create: function() {
                                    
            },
            
            _init: function() {
                var options = this.options;
                //Build the container elements
                this._buildTableHead();

                //switch type of list and run setup function for specified type
                switch (options.listType) {
                    case "normal": this._setUpNormal();
                        break;
                    case "act-deact": this._setUpActDeact();
                        break;
                    case "remove": this._setUpRemove();
                        break;
                }
                
                                
                //If the selectable options are configured then we may want sticky elements (hover css stays until clciked again, or another elements is clicked)
                //And there may also be click on and click off callbacks
                if(options.selectable != null) {
                    $(".list-widget-list-container .list-widget-list li a").live('click',(function(e) {
                        //prevent the href("") from being followed, href is needed for IE to display hover
                        e.preventDefault();
                        //If we want elements to stick
                        if(options.selectable.stick) {
                            //If this element is stuck already
                            //unstick it and run click off call back if supplied
                            if($(this).hasClass("selected")) {
                                $(this).removeClass("selected");
                                if(options.selectable.clickOffCallBack != null){
                                    options.selectable.clickOffCallBack(this);
                                }
                            //Else unstick any other elements
                            //Stick this element
                            //and run click callback
                            } else {
                                $(".list-widget-list-container .list-widget-list").find(".selected").removeClass("selected");
                                $(this).addClass("selected");
                                if(options.selectable.clickCallBack != null){
                                    options.selectable.clickCallBack(this);
                                }
                            }
                        //If we don't want to stick just run click on callback if supplied
                        } else {
                            if(options.selectable.clickCallBack != null){
                                options.selectable.clickCallBack(this);
                            }
                        }
                    }));
                }
                
                //If add callback is supplied
                //create click event
                if(options.addButton && options.addCallBack != null) {
                    $(".list-widget-head-div .header-table .add-but").click(function() {
                        options.addCallBack(this);
                    });
                }
                
                
                //create event for filter box
                var that = this;                    
                $(".list-widget-head-div .header-table .list-search-box").bind("keyup",function(){
                    that._listFilter(this);
                });
                
                //Add the list elements
                this.add(options.list);
            },
            
            _listFilter:function(e){
                var filter = $(e).val(); // get the value of the input, which we filter on
                var list = $(".list-widget-list-container .list-widget-list");

                //only filter if value exists
                if(!filter || filter.length < 1 ){
                    list.find("li").show();
                }
                else{
                    list.find("li").each(function(){
                        //if a element text contains the filter value, hide it
                        if($("a", this).text().toLowerCase().indexOf(filter.toLowerCase()) == -1  ){
                            $(this).hide();
                        }
                        else{
                            //else show it
                            $(this).show();
                        }
                    });
                }
            },
                            
            _buildTableHead:function(){
                //get the current options
                var options = this.options;
                //get the div the widget has been attatched to
                var self = this.element;
                
                //build table header
                var headCells = $("<tr />")
                        .append($('<td  />')
                            .attr("width","33%")
                            .attr("height","45px")
                            .append($('<p />')
                                .addClass("title")
                                .text(options.title)
                            )
                        );
                
                //depending on the options;
                //add a search bar and add button
                
                //if we want searchbar and add button..
                if(options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .attr("text-align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    )
                    .append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                //if we only want add button
                } else if (!options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .attr("align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    );
                //if we only want search bar
                } else if (options.searchBar && !options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                }
                
                //Build the tables and append the cells
                self.append($('<div />')
                        .addClass("list-widget-head-div")
                        .addClass("ui-corner-top")
                        .append($('<table />')
                            .addClass("header-table")
                            .append(headCells)
                        )
                        //Add the description if present
                        .append($("<p />")
                            .addClass("descript")
                            .text(options.description)
                    )
                );
                
                //Add the actual list element
                self.append($("<div />")
                    .addClass("list-widget-list-container")
                    .addClass("ui-corner-bottom")
                        .append($("<ul />")
                        .addClass("list-widget-list")
                    )
                );
            },
            
            _setUpNormal:function(){
                //get the current options
                var options = this.options;

            },
            _setUpActDeact:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the item image
                //Changes the status and can be provided with a call back
                //which has access to the clicked element
                
                
                //If there is no clickCallBack supplied, we apply the toggle action to the whole li element
                if(options.selectable.clickCallBack == null) {
                    $(".list-widget-list-container .list-widget-list li").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this).find("img.list-img");
                        //var to store status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled)
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                //if there is a clickCallBack then we just apply the toggle event to the image
                } else {
                    $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this);
                        //var to stored status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                }
            },
            _setUpRemove:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the delete image
                //runs a provided callback and the removes item
                $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                    //if callback has been provided, run it
                    if(options.removeCallBack != null) {
                        options.removeCallBack(this)
                    }
                    //remove element
                    $(this).parent().remove();
                });
            },
            
            // Use the _setOption method to respond to changes to options

            _setOption: function( key, value ) {

              switch( key ) {

                case "clear":
                  // handle changes to clear option

                  break;

              }

              // In $ UI 1.8, you have to manually invoke the _setOption method from the base widget

              $.Widget.prototype._setOption.apply( this, arguments );
              // In $ UI 1.9 and above, you use the _super method instead
              this._super( "_setOption", key, value );

            },

            // Use the destroy method to clean up any modifications your widget has made to the DOM

            destroy: function() {

              // In $ UI 1.8, you must invoke the destroy method from the base widget

              $.Widget.prototype.destroy.call( this );
              // In $ UI 1.9 and above, you would define _destroy instead of destroy and not call the base method

            },
            
            /* This fuction when presented with an object in the following format
             * var data = {
             *      "0":{"name":"list item 1","activated":true},
             *      "1":{"name":"list item 2","activated":true},
             *      "2":{"name":"list item 3","activated":false}
             *  };
             * Will append the items to the bottom of the list
             */ 
            
            add: function(list) {
                //Pick add function depending on listType
                switch(this.options.listType) {
                    case "normal":this._addNormal(list);
                        break;
                    case "act-deact":this._addActDeact(list);
                        break;
                    case "remove":this._addRemove(list);
                        break;
                }
            },
            
            _addNormal: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                            .text(val.name)
                        )
                    );
                });
            },
            
            _addActDeact: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");

                //For each list item
                $.each(list, function(key,val){
                    //creat li element
                    var li = $("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<img />")
                                .addClass("list-img")
                            )
                            .append($("<a />")
                                .text(val.name)
                                .attr("href","")
                                .addClass("actdeact")
                        );
                    //add activated/deactivated class
                    //depending on item status 
                    if(val.activated === true) {
                        li.find("img").addClass("activated");
                        li.find("img").attr("src","tick.png");
                    } else {
                        li.find("img").addClass("deactivated");
                        li.find("img").attr("src","cross.png");
                    }
                    //Append the list item to the list
                    ulElem.append(li);
                });
                
            },
            
            _addRemove: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .append($("<img />")
                                .addClass("list-img")
                                .attr("src","trash_can.png")
                            )
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                                .text(val.name)
                                .addClass("remove")
                        )
                    );
                });
            },
            
            //Function to empty the list
            empty: function() {
                $(".list-widget-list-container .list-widget-list").empty();
            }
            
        });

jQuery list widget

I have been writing a jQuery widget for a couple of days now. Originally I needed this functionality for something I am writing at work, but I felt like I could abstract it a little more so here I am. I think it's about finished for now, I may add some features depending on how It gets used (if it does).

This is my first jQuery widget and I have been programming in JavaScript for just over a month now, so I don't think the code will be particularly great, but I've tried my hardest.

I would just like some feedback on my coding, how to improve/do it better, now and in the future. It's quite a big chunk of code but I didn't see anything in the FAQ about length of code.

I've also attached a jsFiddle so you can mess with it: http://jsfiddle.net/jCVzp/2/

I've tried to comment as best as I can and have noted all the options in the file description, and more guidance needed, just ask.

Any time and help is greatly appreciated.

(function($) {
            /* 
            *   Document   : list-widget-0.1
            *   Created on : 06-Aug-2012, 20:53:49
            *   Author     : aydin hassan
            *   Description:
            *       This widget is designed to be attatched to a div
            *       
            *       Using the options you can specify one of three list types:
            *           1.) a normal list if items (normal)
            *           2.) a list of items with a cross/tick img depending on its status (act-deact)
            *               ---Clicking the image will toggle its status (change the img and class) and run a provided callback
            *           3.) a list of items with a trash can icon (remove)
            *               ---Click the image will run a supplied calback and then remove the item
            *
            *       Each of the lists has various callbacks:
            *           1.) The global click callback (selectabble.clickCallBack), if passed, will launch on clicked an element for any list type
            *           2.) The global click off callback (selectable.clickOffCallBack), if passed, will launch when an item is clicked off.
            *               ---Works in conjuction with selectable.sticky - if this is set to true elements will stay higlighted until they are clicked off
            *               ---NOTE: click off callback will not be processed if selectable.sticky is set to true
            *           3.) The act-deact callback, if passed, will run after a user has clicked the img, or, if there is no global click callback (selectabble.clickCallBack) it will 
            *               run when the li element is clicked
            *           4.) The remove callback, if passed, will run after the user clicks on the trash-can icon
            *           5.) The add button callback, if passed, will run when a user clicks the add button
            *
            *       List data:
            *           The list data must be an object of the following form:
            *               act-deact:
            *               var data = {
            *                   "0":{"name":"list item 1","activated":true},
            *                   "1":{"name":"list item 2","activated":true},
            *                   "2":{"name":"list item 3","activated":false}
            *               };
            *               
            *               normal/remove:
            *               var data = {
            *                   "0":{"name":"list item 1"},
            *                   "1":{"name":"list item 2"},
            *                   "2":{"name":"list item 3"}
            *               };
            *       
            *       Other options:
            *           title:          ---The title of the list box
            *           description:    ---Some description of the data
            *           searchBar:      ---BOOL - To display a filter box
            *           addButton:      ---BOOL - To display an add button
            *           idStyle:        ---A string to prepend to the id of the item id in the data object to use as the li element id attribute
            *           
            */      
            
          $.widget( "widgets.adminList", {


            // These options will be used as defaults

            options: { 
              list: null,
              title: "Title",
              description: "Some description",
              searchBar: true,
              addButton: false,
 
              addCallBack: null,
              listType: "normal",
              idStyle: "li-id-",
              removeCallBack: null,
              toggleCallBack: null,
              selectable: null    
              
            },


            // Set up the widget
            _create: function() {
                                    
            },
            
            _init: function() {
                var options = this.options;
                //Build the container elements
                this._buildTableHead();

                //switch type of list and run setup function for specified type
                switch (options.listType) {
                    case "normal": this._setUpNormal();
                        break;
                    case "act-deact": this._setUpActDeact();
                        break;
                    case "remove": this._setUpRemove();
                        break;
                }
                
                                
                //If the selectable options are configured then we may want sticky elements (hover css stays until clciked again, or another elements is clicked)
                //And there may also be click on and click off callbacks
                if(options.selectable != null) {
                    $(".list-widget-list-container .list-widget-list li a").live('click',(function(e) {
                        //prevent the href("") from being followed, href is needed for IE to display hover
                        e.preventDefault();
                        //If we want elements to stick
                        if(options.selectable.stick) {
                            //If this element is stuck already
                            //unstick it and run click off call back if supplied
                            if($(this).hasClass("selected")) {
                                $(this).removeClass("selected");
                                if(options.selectable.clickOffCallBack != null){
                                    options.selectable.clickOffCallBack(this);
                                }
                            //Else unstick any other elements
                            //Stick this element
                            //and run click callback
                            } else {
                                $(".list-widget-list-container .list-widget-list").find(".selected").removeClass("selected");
                                $(this).addClass("selected");
                                if(options.selectable.clickCallBack != null){
                                    options.selectable.clickCallBack(this);
                                }
                            }
                        //If we don't want to stick just run click on callback if supplied
                        } else {
                            if(options.selectable.clickCallBack != null){
                                options.selectable.clickCallBack(this);
                            }
                        }
                    }));
                }
                
                //If add callback is supplied
                //create click event
                if(options.addButton && options.addCallBack != null) {
                    $(".list-widget-head-div .header-table .add-but").click(function() {
                        options.addCallBack(this);
                    });
                }
                
                
                //create event for filter box
                var that = this;                    
                $(".list-widget-head-div .header-table .list-search-box").bind("keyup",function(){
                    that._listFilter(this);
                });
                
                //Add the list elements
                this.add(options.list);
            },
            
            _listFilter:function(e){
                var filter = $(e).val(); // get the value of the input, which we filter on
                var list = $(".list-widget-list-container .list-widget-list");

                //only filter if value exists
                if(!filter || filter.length < 1 ){
                    list.find("li").show();
                }
                else{
                    list.find("li").each(function(){
                        //if a element text contains the filter value, hide it
                        if($("a", this).text().toLowerCase().indexOf(filter.toLowerCase()) == -1  ){
                            $(this).hide();
                        }
                        else{
                            //else show it
                            $(this).show();
                        }
                    });
                }
            },
                            
            _buildTableHead:function(){
                //get the current options
                var options = this.options;
                //get the div the widget has been attatched to
                var self = this.element;
                
                //build table header
                var headCells = $("<tr />")
                        .append($('<td  />')
                            .attr("width","33%")
                            .attr("height","45px")
                            .append($('<p />')
                                .addClass("title")
                                .text(options.title)
                            )
                        );
                
                //depending on the options;
                //add a search bar and add button
                
                //if we want searchbar and add button..
                if(options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .attr("text-align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    )
                    .append($('<td  />')
                        .attr("width","33%")
                        .attr("height","45px")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                //if we only want add button
                } else if (!options.searchBar && options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .attr("align","center")
                        .append($('<img />')
                            .addClass("add-but")
                            .attr("src","add-image.png")
                        )
                    );
                //if we only want search bar
                } else if (options.searchBar && !options.addButton) {
                    headCells.append($('<td  />')
                        .attr("width","50%")
                        .append($('<input />')
                            .attr("type","text")
                            .addClass("list-search-box")
                        )
                    );
                }
                
                //Build the tables and append the cells
                self.append($('<div />')
                        .addClass("list-widget-head-div")
                        .addClass("ui-corner-top")
                        .append($('<table />')
                            .addClass("header-table")
                            .append(headCells)
                        )
                        //Add the description if present
                        .append($("<p />")
                            .addClass("descript")
                            .text(options.description)
                    )
                );
                
                //Add the actual list element
                self.append($("<div />")
                    .addClass("list-widget-list-container")
                    .addClass("ui-corner-bottom")
                        .append($("<ul />")
                        .addClass("list-widget-list")
                    )
                );
            },
            
            _setUpNormal:function(){
                //get the current options
                var options = this.options;

            },
            _setUpActDeact:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the item image
                //Changes the status and can be provided with a call back
                //which has access to the clicked element
                
                
                //If there is no clickCallBack supplied, we apply the toggle action to the whole li element
                if(options.selectable.clickCallBack == null) {
                    $(".list-widget-list-container .list-widget-list li").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this).find("img.list-img");
                        //var to store status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled)
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                //if there is a clickCallBack then we just apply the toggle event to the image
                } else {
                    $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                        //get the clicked element
                        var imgElem = $(this);
                        //var to stored status
                        var active;
                        //get status of item
                        //and remove the class
                        if(imgElem.hasClass("deactivated")) {
                            active = false;
                            imgElem.removeClass("deactivated");
                        } else {
                            active = true;
                            imgElem.removeClass("activated");
                        }
                        //add the loading class
                        imgElem.addClass("loading");
                        imgElem.attr("src","ajax-loader.gif")
                        //if callback has been provided, run it
                        if(options.toggleCallBack != null) {
                            options.toggleCallBack(this)
                        }
                        //remove loading class
                        imgElem.removeClass("loading");
                        //add the oposite class(item has been toggled
                        if(active) {
                            imgElem.addClass("deactivated");
                            imgElem.attr("src","cross.png")
                        } else {
                            imgElem.addClass("activated");
                            imgElem.attr("src","tick.png")
                        }
                    });
                }
            },
            _setUpRemove:function(){
                //get the current options
                var options = this.options;
                
                //click event upon clicking the delete image
                //runs a provided callback and the removes item
                $(".list-widget-list-container .list-widget-list li img.list-img").live('click',function(e){
                    //if callback has been provided, run it
                    if(options.removeCallBack != null) {
                        options.removeCallBack(this)
                    }
                    //remove element
                    $(this).parent().remove();
                });
            },
            
            // Use the _setOption method to respond to changes to options

            _setOption: function( key, value ) {

              switch( key ) {

                case "clear":
                  // handle changes to clear option

                  break;

              }

              // In $ UI 1.8, you have to manually invoke the _setOption method from the base widget

              $.Widget.prototype._setOption.apply( this, arguments );
              // In $ UI 1.9 and above, you use the _super method instead
              this._super( "_setOption", key, value );

            },

            // Use the destroy method to clean up any modifications your widget has made to the DOM

            destroy: function() {

              // In $ UI 1.8, you must invoke the destroy method from the base widget

              $.Widget.prototype.destroy.call( this );
              // In $ UI 1.9 and above, you would define _destroy instead of destroy and not call the base method

            },
            
            /* This fuction when presented with an object in the following format
             * var data = {
             *      "0":{"name":"list item 1","activated":true},
             *      "1":{"name":"list item 2","activated":true},
             *      "2":{"name":"list item 3","activated":false}
             *  };
             * Will append the items to the bottom of the list
             */ 
            
            add: function(list) {
                //Pick add function depending on listType
                switch(this.options.listType) {
                    case "normal":this._addNormal(list);
                        break;
                    case "act-deact":this._addActDeact(list);
                        break;
                    case "remove":this._addRemove(list);
                        break;
                }
            },
            
            _addNormal: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                            .text(val.name)
                        )
                    );
                });
            },
            
            _addActDeact: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");

                //For each list item
                $.each(list, function(key,val){
                    //creat li element
                    var li = $("<li />")
                        .attr("id",options.idStyle + key)
                            .append($("<img />")
                                .addClass("list-img")
                            )
                            .append($("<a />")
                                .text(val.name)
                                .attr("href","")
                                .addClass("actdeact")
                        );
                    //add activated/deactivated class
                    //depending on item status 
                    if(val.activated === true) {
                        li.find("img").addClass("activated");
                        li.find("img").attr("src","tick.png");
                    } else {
                        li.find("img").addClass("deactivated");
                        li.find("img").attr("src","cross.png");
                    }
                    //Append the list item to the list
                    ulElem.append(li);
                });
                
            },
            
            _addRemove: function(list) {
                var options = this.options;
                
                //Get the list elemenent
                var ulElem = $(".list-widget-list-container .list-widget-list");
                
                //For each list item
                $.each(list, function(key,val){
                    //Append the item to the list
                    ulElem.append($("<li />")
                        .append($("<img />")
                                .addClass("list-img")
                                .attr("src","trash_can.png")
                            )
                        .attr("id",options.idStyle + key)
                            .append($("<a />")
                                .text(val.name)
                                .addClass("remove")
                        )
                    );
                });
            },
            
            //Function to empty the list
            empty: function() {
                $(".list-widget-list-container .list-widget-list").empty();
            }
            
        });
Source Link
Loading