Changeset 389

Show
Ignore:
Timestamp:
06/27/08 06:29:30 (2 months ago)
Author:
charles
Message:

Move a few steps forward to having Clutch served directly by Transmission. torrent lists, sorting, filtering, and maybe start/stop work... adding torrents doesn't work yet, and probably some retweaking needs to be done for iPhone and Safari

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/rpc/web/javascript/common.js

    r388 r389  
    115115 */ 
    116116Array.prototype.inArray = function (obj) { 
    117         var i; 
    118         for (i=0; i < this.length; i++) { 
    119                 if (this[i] === obj) { 
    120                         return true; 
    121                 } 
    122         } 
    123         return false; 
     117        return this.indexOf( obj ) != -1; 
    124118}; 
    125119 
     
    293287} 
    294288 
     289 
     290/* 
     291 *   Given a numerator and denominator, return a ratio string 
     292 */ 
     293Math.ratio = function( numerator, denominator ) 
     294{ 
     295        var result = Math.roundWithPrecision((numerator / denominator), 2); 
     296 
     297        // check for special cases 
     298        if (isNaN(result)) result = 0; 
     299        if (result=="Infinity") result = "&infin;"; 
     300 
     301        // Add the decimals if this is an integer 
     302        if ((result % 1) == 0) 
     303                result = result + '.00'; 
     304 
     305        return result; 
     306} 
     307 
    295308/* 
    296309 * Trim whitespace from a string 
    297310 */ 
    298311String.prototype.trim = function () { 
    299     return this.replace(/^\s*/, "").replace(/\s*$/, ""); 
    300 
    301  
     312        return this.replace(/^\s*/, "").replace(/\s*$/, ""); 
     313
     314 
     315 
     316 
     317/*** 
     318****  Preferences 
     319***/ 
     320 
     321function Prefs() { } 
     322Prefs.prototype = { } 
     323 
     324Prefs._RefreshRate        = 'refresh_rate'; 
     325 
     326Prefs._ShowFilter         = 'show_filter'; 
     327 
     328Prefs._ShowInspector      = 'show_inspector'; 
     329 
     330Prefs._FilterMode         = 'filter'; 
     331Prefs._FilterAll          = 'all'; 
     332Prefs._FilterSeeding      = 'seeding'; 
     333Prefs._FilterDownloading  = 'downloading'; 
     334Prefs._FilterPaused       = 'paused'; 
     335 
     336Prefs._SortDirection      = 'sort_direction'; 
     337Prefs._SortAscending      = 'ascending'; 
     338Prefs._SortDescending     = 'descending'; 
     339 
     340Prefs._SortMethod         = 'sort_method'; 
     341Prefs._SortByAge          = 'age'; 
     342Prefs._SortByActivity     = 'activity'; 
     343Prefs._SortByQueue        = 'queue_order'; 
     344Prefs._SortByName         = 'name'; 
     345Prefs._SortByProgress     = 'percent_completed'; 
     346Prefs._SortByState        = 'state'; 
     347Prefs._SortByTracker      = 'tracker'; 
     348 
     349 
     350Prefs._Defaults = 
     351
     352        'filter': 'all', 
     353        'refresh_rate' : 5, 
     354        'show_filter': true, 
     355        'show_inspector': false, 
     356        'sort_direction': 'ascending', 
     357        'sort_method': 'name' 
     358}; 
     359 
     360/* 
     361 * Set a preference option 
     362 */ 
     363Prefs.setValue = function( key, val ) 
     364
     365        if( Prefs._Defaults[key] == undefined ) 
     366                console.warn( "unrecognized preference key '%s'", key ); 
     367 
     368        var days = 30; 
     369        var date = new Date(); 
     370        date.setTime(date.getTime()+(days*24*60*60*1000)); 
     371        document.cookie = key+"="+val+"; expires="+date.toGMTString()+"; path=/"; 
     372
     373 
     374/** 
     375 * Get a preference option 
     376 * 
     377 * @param key the preference's key 
     378 * @param fallback if the option isn't set, return this instead 
     379 */ 
     380Prefs.getValue = function( key, fallback ) 
     381
     382        var val; 
     383 
     384        if( Prefs._Defaults[key] == undefined ) 
     385                console.warn( "unrecognized preference key '%s'", key ); 
     386 
     387        var lines = document.cookie.split( ';' ); 
     388        for( var i=0, len=lines.length; !val && i<len; ++i ) { 
     389                var line = lines[i].trim( ); 
     390                var delim = line.indexOf( '=' ); 
     391                if( ( delim == key.length ) && line.indexOf( key ) == 0 ) 
     392                        val = line.substring( delim + 1 ); 
     393        } 
     394 
     395        // FIXME: we support strings and booleans... add number support too? 
     396        if( !val ) val = fallback; 
     397        else if( val == 'true' ) val = true; 
     398        else if( val == 'false' ) val = false; 
     399        return val; 
     400
     401 
     402/** 
     403 * Get an object with all the Clutch preferences set 
     404 * 
     405 * @pararm o object to be populated (optional) 
     406 */ 
     407Prefs.getClutchPrefs = function( o ) 
     408
     409        if( o == null ) 
     410                o = new Object( ); 
     411        for( var key in Prefs._Defaults ) 
     412                o[key] = Prefs.getValue( key, Prefs._Defaults[key] ); 
     413        return o; 
     414
  • branches/rpc/web/javascript/torrent.js

    r385 r389  
    22 *      Copyright © Dave Perrett and Malcolm Jarvis 
    33 *      This code is licensed under the GPL version 2. 
    4  *      For more details, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 
     4 *      For details, see http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 
    55 * 
    6  * Class Torrent 
     6 *     Class Torrent 
    77 */ 
    88 
    9 function Torrent(data) { 
    10     // Constants 
    11         this._StatusDownloading     = 'downloading'; 
    12         this._StatusSeeding         = 'seeding';  
    13         this._StatusStopping        = 'stopping';  
    14         this._StatusPaused          = 'paused';  
    15         this._StatusChecking        = 'checking'; 
    16         this._StatusWaitingToCheck  = 'waiting to checking'; 
    17         this._InfiniteTimeRemaining = 215784000; // 999 Hours - may as well be infinite 
    18         this._MaxProgressBarWidth   = 100; // reduce this to make the progress bar shorter (%) 
    19  
    20     this.initialize(data); 
     9function Torrent(controller,data) { 
     10    this.initialize(controller,data); 
    2111}  
    2212 
    23 Torrent.prototype = { 
    24  
    25     /* 
    26      * Constructor 
    27      */ 
    28     initialize: function(data) { 
    29                  
     13// Constants 
     14Torrent._StatusSeeding         = 'seeding'; 
     15Torrent._StatusDownloading     = 'downloading'; 
     16Torrent._StatusPaused          = 'paused'; 
     17Torrent._StatusChecking        = 'verifying local data'; 
     18Torrent._StatusWaitingToCheck  =  'waiting to verify'; 
     19Torrent._InfiniteTimeRemaining = 215784000; // 999 Hours - may as well be infinite 
     20Torrent._MaxProgressBarWidth   = 100; // reduce this to make the progress bar shorter (%) 
     21 
     22Torrent.prototype = 
     23
     24        /* 
     25         * Constructor 
     26         */ 
     27        initialize: function(controller,data) 
     28        { 
    3029                // Create a new <li> element 
    3130                var element = $('<li/>'); 
    3231                element.addClass('torrent'); 
    3332                element[0].id = 'torrent_' + data.id; 
     33                element._torrent = this; 
    3434                this._element = element; 
     35                this._controller = controller; 
     36                controller._rows.push( element ); 
    3537                 
    3638                // Create the 'name' <div> 
    37                 this._name_container = $('<div/>'); 
    38                 this._name_container.addClass('torrent_name'); 
    39                 this._name_container[0].innerHTML= data.name
    40                 this._element.append(this._name_container)
     39                var e = $('<div/>'); 
     40                e.addClass('torrent_name'); 
     41                element.append( e )
     42                element._name_container = e
    4143                 
    4244                // Create the 'progress details' <div> 
    43                 this._progress_details_container = $('<div/>'); 
    44                 this._progress_details_container.addClass('torrent_progress_details'); 
    45                 this._element.append(this._progress_details_container); 
    46                          
     45                e = $('<div/>'); 
     46                e.addClass('torrent_progress_details'); 
     47                element.append(e); 
     48                element._progress_details_container = e; 
     49 
    4750                // Create the 'in progress' bar 
    48                 this._progress_complete_container = $('<div/>'); 
    49                 this._progress_complete_container.addClass('torrent_progress_bar'); 
    50                 this._progress_complete_container.addClass('incomplete'); 
    51                 this._progress_complete_container.css('width', '0%'); 
    52                 this._element.append(this._progress_complete_container)
     51                e = $('<div/>'); 
     52                e.addClass('torrent_progress_bar incomplete'); 
     53                e.css('width', '0%'); 
     54                element.append( e ); 
     55                element._progress_complete_container = e
    5356                         
    5457                // Create the 'incomplete' bar (initially hidden) 
    55                 this._progress_incomplete_container = $('<div/>'); 
    56                 this._progress_incomplete_container.addClass('torrent_progress_bar'); 
    57                 this._progress_incomplete_container.addClass('incomplete'); 
    58                 this._progress_incomplete_container.hide(); 
    59                 this._element.append(this._progress_incomplete_container); 
    60                  
    61                 // Add the pause/resume button - don't specify the image or alt text until  
    62                 // the 'refresh()' function (depends on torrent state) 
    63                 this._pause_resume_button = $('<a/>'); 
    64                 this._pause_resume_button_image = $('<div/>'); 
    65                 this._pause_resume_button_image.addClass('torrent_pause'); 
    66                 this._pause_resume_button.append(this._pause_resume_button_image); 
    67                 this._element.append(this._pause_resume_button); 
    68                          
    69                 // Set the pause button click observer (not shown on iPhone) 
    70                 if (!iPhone) this._pause_resume_button.bind('click', {torrent: this}, this.clickPauseResumeButton); 
     58                e = $('<div/>'); 
     59                e.addClass('torrent_progress_bar incomplete'); 
     60                e.hide(); 
     61                element.append( e ); 
     62                element._progress_incomplete_container = e; 
     63                 
     64                // Add the pause/resume button - don't specify the 
     65                // image or alt text until the 'refresh()' function 
     66                // (depends on torrent state) 
     67                var image = $('<div/>'); 
     68                image.addClass('torrent_pause'); 
     69                e = $('<a/>'); 
     70                e.append( image ); 
     71                element.append( e ); 
     72                element._pause_resume_button_image = image; 
     73                element._pause_resume_button = e; 
     74                if (!iPhone) e.bind('click', {element: element}, this.clickPauseResumeButton); 
    7175                 
    7276                // Create the 'peer details' <div> 
    73                 this._peer_details_container = $('<div/>'); 
    74                 this._peer_details_container.addClass('torrent_peer_details'); 
    75                 this._element.append(this._peer_details_container); 
     77                e = $('<div/>'); 
     78                e.addClass('torrent_peer_details'); 
     79                element.append( e ); 
     80                element._peer_details_container = e; 
    7681                         
    7782                // Set the torrent click observer 
    78                 this._element.bind('click', {torrent: this}, this.clickTorrent); 
    79                 if (!iPhone) this._element.bind('contextmenu', {torrent: this}, this.rightClickTorrent);               
     83                element.bind('click', {element: element}, this.clickTorrent); 
     84                if (!iPhone) element.bind('contextmenu', {element: element}, this.rightClickTorrent);          
    8085                 
    8186                // Safari hack - first torrent needs to be moved down for some reason. Seems to be ok when 
    8287                // using <li>'s in straight html, but adding through the DOM gets a bit odd. 
    83                 if ($.browser.safari) { 
     88                if ($.browser.safari) 
    8489                        this._element.css('margin-top', '7px'); 
    85                 } 
    8690                 
    8791                // insert the element 
     
    9195                this.refresh(data); 
    9296        }, 
    93  
    9497 
    9598 
     
    99102         *  
    100103         *--------------------------------------------*/ 
    101                  
    102104         
    103         /* 
    104          * Set the main transmission controller 
    105          */ 
    106         setController: function(controller) { 
    107                 this._controller = controller; 
    108         }, 
    109          
    110         /* 
    111          * Return the id of this torrent 
    112          */ 
    113         id: function() { 
    114                 return parseInt(this._id); 
    115         }, 
    116          
    117         /* 
    118          * Return the DOM element for this torrent (a <LI> element) 
    119          */ 
     105        /* Return the DOM element for this torrent (a <LI> element) */ 
    120106        element: function() { 
    121107                return this._element; 
    122108        }, 
    123          
    124         /* 
    125          * Return the torrent before this in the list 
    126          */ 
    127         previousTorrent: function() { 
    128                 return this._previous_torrent; 
    129         }, 
    130          
    131         /* 
    132          * Set the torrent before this in the list 
    133          */ 
    134         setPreviousTorrent: function(torrent) { 
    135                 this._previous_torrent = torrent; 
    136         }, 
    137          
    138         /* 
    139          * Return the torrent after this in the list 
    140          */ 
    141         nextTorrent: function() { 
    142                 return this._next_torrent; 
    143         }, 
    144          
    145         /* 
    146          * Set the torrent after this in the list 
    147          */ 
    148         setNextTorrent: function(torrent) { 
    149                 this._next_torrent = torrent; 
    150         }, 
    151          
    152         /* 
    153          * Return the position of this torrent in the list 
    154          */ 
    155         position: function() { 
    156                 return this._position; 
    157         }, 
    158          
    159         /* 
    160          * Set the position of this torrent in the list 
    161          */ 
    162         setPosition: function(position) { 
    163                 return this._position = position; 
    164         }, 
    165          
    166         /* 
    167          * Return the state of this torrent 
    168          */ 
    169         isActive: function() { 
    170                 return this._state == this._StatusSeeding || !(this._state == this._StatusStopping || this._state == this._StatusPaused); 
    171         }, 
    172          
    173         /* 
    174          * Return the name of this torrent 
    175          */ 
    176         name: function() { 
    177                 return this._name; 
    178         }, 
    179          
    180         /* 
    181          * Return the error message for this torrent 
    182          */ 
    183         errorMessage: function() { 
    184                 return this._error_message; 
    185         }, 
    186          
    187         /* 
    188          * Return the creator of this torrent 
    189          */ 
    190         creator: function() { 
    191                 return this._creator; 
    192         }, 
    193          
    194         /* 
    195          * Return the comment for this torrent 
    196          */ 
    197         comment: function() { 
    198                 return this._comment; 
    199         }, 
    200          
    201         /* 
    202          * Return the swarm speed of this torrent 
    203          */ 
    204         swarmSpeed: function() { 
    205                 return this._swarm_speed; 
    206         }, 
    207          
    208         /* 
    209          * Return the size of this torrent 
    210          */ 
    211         size: function() { 
    212                 return this._size; 
    213         }, 
    214          
    215         /* 
    216          * Return the hash of this torrent 
    217          */ 
    218         hash: function() { 
    219                 return this._hash; 
    220         }, 
    221          
    222         /* 
    223          * Return the state of this torrent 
    224          */ 
    225         state: function() { 
    226                 return this._state; 
    227         }, 
    228          
    229         /* 
    230          * Return the download speed of this torrent 
    231          */ 
    232         downloadSpeed: function() { 
    233                 return this._download_speed; 
    234         }, 
    235          
    236         /* 
    237          * Return the upload speed of this torrent 
    238          */ 
    239         uploadSpeed: function() { 
    240                 return this._upload_speed; 
    241         }, 
    242          
    243         /* 
    244          * Return the download total of this torrent 
    245          */ 
    246         downloadTotal: function() { 
    247                 return this._download_total; 
    248         }, 
    249          
    250         /* 
    251          * Return the bytes completed of this torrent 
    252          */ 
    253         completed: function() { 
    254                 return this._completed; 
    255         }, 
    256          
    257         /* 
    258          * Return the percent completed of this torrent 
    259          */ 
    260         percentCompleted: function() { 
    261                 return this._percent_completed; 
    262         }, 
    263          
    264         /* 
    265          * Return the upload total of this torrent 
    266          */ 
    267         uploadTotal: function() { 
    268                 return this._upload_total; 
    269         }, 
    270          
    271         /* 
    272          * Return the total number of seeders for this torrent 
    273          */ 
    274         totalSeeders: function() { 
    275                 return ((this._total_seeders == '') ? 0 : this._total_seeders); 
    276         }, 
    277          
    278         /* 
    279          * Return the total number of leechers for this torrent 
    280          */ 
    281         totalLeechers: function() { 
    282                 return ((this._total_leechers == '') ? 0 : this._total_leechers); 
    283         }, 
    284          
    285         /* 
    286          * Return the total number of peers downloading for this torrent 
    287          */ 
    288         peersDownloading: function() { 
    289                 return ((this._peers_downloading == '') ? 0 : this._peers_downloading); 
    290         }, 
    291          
    292         /* 
    293          * Return the total number of peers uploading for this torrent 
    294          */ 
    295         peersUploading: function() { 
    296                 return ((this._peers_uploading == '') ? 0 : this._peers_uploading); 
    297         }, 
    298          
    299         /* 
    300          * Return the ratio for this torrent 
    301          */ 
    302         ratio: function() { 
    303                 var result = Math.roundWithPrecision((this._upload_total / this._download_total), 2); 
    304          
    305                 // check for special cases 
    306         if (isNaN(result)) result = 0; 
    307         if (result=="Infinity") result = "&infin;"; 
    308  
    309         // Add the decimals if this is an integer 
    310         if ((result % 1) == 0) { 
    311                 result = result + '.00'; 
    312         } 
    313          
    314         return result; 
    315         }, 
    316  
    317  
     109 
     110        setElement: function( element ) { 
     111                if( this._element != element ) { 
     112                        this._element = element; 
     113                        element._torrent = this; 
     114                        this.refreshHTML( ); 
     115                } 
     116        }, 
     117 
     118        activity: function() { return this._download_speed + this._upload_speed; }, 
     119        comment: function() { return this._comment; }, 
     120        completed: function() { return this._completed; }, 
     121        creator: function() { return this._creator; }, 
     122        dateAdded: function() { return this._date; }, 
     123        downloadSpeed: function() { return this._download_speed; }, 
     124        downloadTotal: function() { return this._download_total; }, 
     125        errorMessage: function() { return this._error_message; }, 
     126        hash: function() { return this._hashString; }, 
     127        id: function() { return this._id; }, 
     128        isActive: function() { return this.state() != Torrent._StatusPaused; }, 
     129        isDownloading: function() { return this.state() == Torrent._StatusDownloading; }, 
     130        isSeeding: function() { return this.state() == Torrent._StatusSeeding; }, 
     131        name: function() { return this._name; }, 
     132        peersDownloading: function() { return this._peers_downloading; }, 
     133        peersUploading: function() { return this._peers_uploading; }, 
     134        percentCompleted: function() { return this._percent_completed; }, 
     135        size: function() { return this._size; }, 
     136        state: function() { return this._state; }, 
     137        swarmSpeed: function() { return this._swarm_speed; }, 
     138        totalLeechers: function() { return this._total_leechers; }, 
     139        totalSeeders: function() { return this._total_seeders; }, 
     140        uploadSpeed: function() { return this._upload_speed; }, 
     141        uploadTotal: function() { return this._upload_total; }, 
    318142 
    319143        /*-------------------------------------------- 
     
    321145         *  E V E N T   F U N C T I O N S 
    322146         *  
    323          *--------------------------------------------*/        
     147         *--------------------------------------------*/ 
    324148         
    325149        /* 
     
    328152        rightClickTorrent: function(event) { 
    329153                 
    330                 var torrent = event.data.torrent; 
     154                var torrent = event.data.element._torrent; 
    331155                 
    332156                // Don't stop the event! need it for the right-click menu 
     
    344168                // which deselects all on click 
    345169                event.stopPropagation(); 
    346                 var torrent = event.data.torrent; 
    347                         
     170                var torrent = event.data.element._torrent; 
     171                 
    348172                // 'Apple' button emulation on PC : 
    349173                // Need settable meta-key and ctrl-key variables for mac emulation 
     
    355179                } 
    356180                 
     181                var selectionChanged = false; 
     182                 
    357183                // Shift-Click - Highlight a range between this torrent and the last-clicked torrent 
    358184                if (iPhone) { 
    359185                        torrent._controller.deselectAll(); 
    360                         torrent.select(); 
     186                        torrent.select( ); 
     187                        selectionChanged = true; 
     188                 
    361189                } else if (event.shiftKey) { 
    362                         torrent._controller.selectRange(torrent); 
     190                        torrent._controller.selectRange(torrent, true ); 
    363191                        // Need to deselect any selected text 
    364192                        window.focus(); 
     
    366194                // Apple-Click, not selected 
    367195                } else if (!torrent.isSelected() && meta_key) { 
    368                         torrent.select(); 
     196                        torrent.select( ); 
     197                        selectionChanged = true; 
    369198                         
    370199                // Regular Click, not selected 
    371200                } else if (!torrent.isSelected()) { 
    372201                        torrent._controller.deselectAll(); 
    373                         torrent.select(); 
     202                        torrent.select( ); 
     203                        selectionChanged = true; 
    374204                 
    375205                // Apple-Click, selected         
    376206                } else if (torrent.isSelected() && meta_key) { 
    377                         torrent.deselect(); 
     207                        torrent.deselect( ); 
     208                        selectionChanged = true; 
    378209                         
    379210                // Regular Click, selected 
    380211                } else if (torrent.isSelected()) { 
    381212                        torrent._controller.deselectAll(); 
    382                         torrent.select(); 
     213                        torrent.select( ); 
     214                        selectionChanged = true; 
    383215                } 
    384216                 
    385217                torrent._controller.setLastTorrentClicked(torrent); 
    386         }, 
    387          
     218                 
     219                if( selectionChanged ) 
     220                        torrent._controller.selectionChanged( ); 
     221        }, 
    388222 
    389223        /* 
     
    393227                // Prevents click event resulting in selection of torrent 
    394228                event.stopPropagation(); 
    395                 var torrent = event.data.torrent; 
    396                  
    397                 var action;      
    398                 if (torrent._state == torrent._StatusPaused) { 
     229                var torrent = event.data.element._torrent; 
     230                 
     231                var action; 
     232                var name; 
     233                if( torrent.isActive( ) ) { 
     234                        name = "torrent_pause"; 
     235                        action = 'pauseTorrents'; 
     236                } else { 
     237                        name = "torrent_resume"; 
    399238                        action = 'resumeTorrents'; 
    400                         torrent._pause_resume_button_image[0].style.className = "torrent_resume"; 
    401                 } else { 
    402                         action = 'pauseTorrents'; 
    403                         torrent._pause_resume_button_image[0].style.className = "torrent_pause"; 
    404                 } 
    405                  
     239                } 
     240                 
     241                torrent._element._pause_resume_button_image[0].style.className = name; 
    406242                // Send an ajax request to perform the action 
    407243                torrent._controller.remote.request(action, $.toJSON([torrent._id])); 
    408244        }, 
    409  
    410  
    411245 
    412246        /*-------------------------------------------- 
     
    416250         *--------------------------------------------*/ 
    417251         
     252        refresh: function(data) { 
     253                this.refreshData( data ); 
     254                this.refreshHTML( ); 
     255        }, 
     256 
    418257        /* 
    419258         * Refresh display 
    420259         */ 
    421         refresh: function(data) { 
     260        refreshData: function(data) 
     261        { 
     262                // These variables never change after the inital load 
     263                if (data.name)         this._name         = data.name; 
     264                if (data.isPrivate)    this._is_private   = data.isPrivate; 
     265                if (data.hashString)   this._hashString   = data.hashString; 
     266                if (data.addedDate)    this._date         = data.addedDate; 
     267                if (data.totalSize)    this._size         = data.totalSize; 
     268                if (data.announceURL)  this._tracker      = data.announceURL; 
     269                if (data.comment)      this._comment      = data.comment; 
     270                if (data.creator)      this._creator      = data.creator; 
     271                if (data.dateCreated)  this._creator_date = data.dateCreated; 
     272                if (data.path)         this._torrent_file = data.path;//FIXME 
     273                 
     274                // Set the regularly-changing torrent variables 
     275                this._id                = data.id; 
     276                this._completed         = data.haveUnchecked + data.haveValid; 
     277                this._verified          = data.haveValid; 
     278                this._percent_completed = 100 * this._completed / this._size; 
     279                this._download_total    = data.downloadedEver; 
     280                this._upload_total      = data.uploadedEver; 
     281                this._download_speed    = data.rateDownload; 
     282                this._upload_speed      = data.rateUpload; 
     283                this._peers_downloading = data.peersGettingFromUs; 
     284                this._peers_uploading   = data.peersSendingToUs; 
     285                this._peers_total       = data.peersKnown; 
     286                this._error             = data.error; 
     287                this._error_message     = data.errorString; 
     288                this._eta               = data.eta; 
     289                this._swarm_speed       = data.swarm_speed; 
     290                this._total_leechers    = data.leechers; 
     291                this._total_seeders     = data.seeders; 
     292                 
     293                switch( data.status ) { 
     294                        case 1: this._state = Torrent._StatusWaitingToCheck; break; 
     295                        case 2: this._state = Torrent._StatusChecking; break; 
     296                        case 4: this._state = Torrent._StatusDownloading; break; 
     297                        case 8: this._state = Torrent._StatusSeeding; break; 
     298                        case 16: this._state = Torrent._StatusPaused; break; 
     299                } 
     300                 
     301                this._is_running = this._state != Torrent._StatusPaused; 
     302                 
     303                // Get -1 returned sometimes (maybe torrents with errors?) 
     304                if( this._total_leechers < 0 ) 
     305                    this._total_leechers = 0; 
     306                if( this._total_seeders < 0 ) 
     307                    this._total_seeders = 0; 
     308        }, 
     309 
     310        refreshHTML: function() 
     311        { 
    422312                var progress_details; 
    423313                var peer_details; 
    424                  
    425                 // These variables never change after the inital load    
    426                 if (data.name)          this._name                      = data.name; 
    427                 if (data.hash)          this._hash                      = data.hash; 
    428                 if (data.date)          this._date                      = data.date; 
    429                 if (data.size)          this._size                      = data.size; 
    430                 if (data.position)      this._position          = data.position; 
    431                 if (data.tracker)       this._tracker           = data.tracker; 
    432                 if (data.comment)       this._comment           = data.comment; 
    433                 if (data.creator)       this._creator           = data.creator; 
    434                 if (data.date)          this._creator_date      = data.date; 
    435                 if (data.path)          this._torrent_file      = data.path; 
    436                  
    437                 // Set the regularly-changing torrent variables 
    438                 this._id                    = data.id; 
    439                 this._completed             = data.completed; 
    440                 this._percent_completed     = data.percent_completed; 
    441                 this._download_total        = data.download_total; 
    442                 this._upload_total          = data.upload_total; 
    443                 this._download_speed        = data.download_speed; 
    444                 this._upload_speed          = data.upload_speed; 
    445                 this._peers_downloading     = data.peers_downloading; 
    446                 this._peers_uploading       = data.peers_uploading; 
    447                 // Don't *think* we need this anywhere 
    448                 this._peers_from            = data.peers_from;  
    449                 this._peers_total           = data.peers_total; 
    450                 this._error                 = data.error; 
    451                 this._error_message         = data.error_message; 
    452                 this._state                 = data.state; 
    453                 this._eta                   = data.eta; 
    454                 this._running               = data.running;      
    455                 this._swarm_speed           = data.swarm_speed;  
    456                 this._total_leechers            = data.scrape_leechers;  
    457                 this._total_seeders             = data.scrape_seeders; 
    458          
    459                 // Get -1 returned sometimes (maybe torrents with errors?) 
    460                 if (this._total_leechers < 0) { 
    461                         this._total_leechers = 0; 
    462                 } 
    463                 if (this._total_seeders < 0) { 
    464                         this._total_seeders = 0; 
    465                 } 
     314                var root = this._element; 
     315                 
     316                root._name_container[0].innerHTML = this._name; 
    466317                 
    467318                // Figure out the percent completed 
    468                 var css_percent_completed = Math.floor(this._percent_completed * this._MaxProgressBarWidth / 100); 
     319                var css_percent_completed = Math.floor(this._percent_completed * Torrent._MaxProgressBarWidth / 100); 
    469320                var int_percent_completed = Math.floor(this._percent_completed); 
    470321                 
    471322                // Sometimes get figures greater that the max 
    472                 if (css_percent_completed > this._MaxProgressBarWidth) { 
    473                     css_percent_completed = this._MaxProgressBarWidth; 
     323                if (css_percent_completed > Torrent._MaxProgressBarWidth) { 
     324                    css_percent_completed = Torrent._MaxProgressBarWidth; 
    474325                } 
    475326                 
    476327                // Add the progress bar 
    477                 if (int_percent_completed < 100 && this.state() != "seeding") { 
    478                  
    479            // Add the decimals if the percentage is an integer 
    480               if ((this._percent_completed % 1) == 0) { 
    481                       this._percent_completed = this._percent_completed + '.00'; 
    482               } 
     328                if (int_percent_completed < 100 && this.state() != "seeding") 
     329                { 
     330                       // Add the decimals if the percentage is an integer 
     331                      if ((this._percent_completed % 1) == 0) { 
     332                              this._percent_completed = this._percent_completed + '.00'; 
     333                      } 
    483334                        // Create the 'progress details' label 
    484335                        // Eg: '101 MB of 631 MB (16.02%) - 2 hr 30 min remaining' 
     
    486337                        progress_details += Math.formatBytes(this._size) + ' ('; 
    487338                        progress_details += this._percent_completed + '%)'; 
    488                         if ((this._eta < 0 || this._eta >= this._InfiniteTimeRemaining) && this.isActive()) { 
     339                        if ((this._eta < 0 || this._eta >= Torrent._InfiniteTimeRemaining) && this.isActive()) { 
    489340                                progress_details += ' - remaining time unknown'; 
    490341                        } else if (this.isActive()) { 
     
    494345                        // Update the 'in progress' bar 
    495346                        var class_name = (this.isActive()) ? 'in_progress' : 'incomplete_stopped'; 
    496                         this._progress_complete_container.removeClass(); 
    497                         this._progress_complete_container.addClass('torrent_progress_bar'); 
    498                         this._progress_complete_container.addClass(class_name); 
    499                         this._progress_complete_container.css('width', css_percent_completed + '%'); 
     347                        root._progress_complete_container.removeClass(); 
     348                        root._progress_complete_container.addClass('torrent_progress_bar'); 
     349                        root._progress_complete_container.addClass(class_name); 
     350                        root._progress_complete_container.css('width', css_percent_completed + '%'); 
    500351                         
    501352                        // Update the 'incomplete' bar 
    502                 if (! this._progress_incomplete_container.is('.incomplete')) { 
    503                                 this._progress_incomplete_container.removeClass(); 
    504                                 this._progress_incomplete_container.addClass('torrent_progress_bar'); 
    505                                 this._progress_incomplete_container.addClass('in_progress'); 
     353                        if (! root._progress_incomplete_container.is('.incomplete')) { 
     354                                root._progress_incomplete_container.removeClass(); 
     355                                root._progress_incomplete_container.addClass('torrent_progress_bar in_progress'); 
    506356                        } 
    507                         this._progress_incomplete_container.css('width', (this._MaxProgressBarWidth - css_percent_completed) + '%'); 
    508                         this._progress_incomplete_container.show(); 
     357                        root._progress_incomplete_container.css('width', (Torrent._MaxProgressBarWidth - css_percent_completed) + '%'); 
     358                        root._progress_incomplete_container.show(); 
    509359                         
    510360                        // Create the 'peer details' label 
    511361                        // Eg: 'Downloading from 36 of 40 peers - DL: 60.2 KB/s UL: 4.3 KB/s' 
    512 &nbs