1/** 2 * Copyright �� Mnemosyne LLC 3 * 4 * This file is licensed under the GPLv2. 5 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 6 */ 7 8function TorrentRendererHelper() 9{ 10} 11 12TorrentRendererHelper.getProgressInfo = function(controller, t) 13{ 14 var pct, extra, 15 s = t.getStatus(), 16 seed_ratio_limit = t.seedRatioLimit(controller); 17 18 if (t.needsMetaData()) 19 pct = t.getMetadataPercentComplete() * 100; 20 else if (!t.isDone()) 21 pct = Math.round(t.getPercentDone() * 100); 22 else if (seed_ratio_limit > 0 && t.isSeeding()) // don't split up the bar if paused or queued 23 pct = Math.round(t.getUploadRatio() * 100 / seed_ratio_limit); 24 else 25 pct = 100; 26 27 if (s === Torrent._StatusStopped) 28 extra = 'paused'; 29 else if (s === Torrent._StatusDownloadWait) 30 extra = 'leeching queued'; 31 else if (t.needsMetaData()) 32 extra = 'magnet'; 33 else if (s === Torrent._StatusDownload) 34 extra = 'leeching'; 35 else if (s === Torrent._StatusSeedWait) 36 extra = 'seeding queued'; 37 else if (s === Torrent._StatusSeed) 38 extra = 'seeding'; 39 else 40 extra = ''; 41 42 return { 43 percent: pct, 44 complete: [ 'torrent_progress_bar', 'complete', extra ].join(' '), 45 incomplete: [ 'torrent_progress_bar', 'incomplete', extra ].join(' ') 46 }; 47}; 48 49TorrentRendererHelper.createProgressbar = function(classes) 50{ 51 var complete, incomplete, progressbar; 52 53 complete = document.createElement('div'); 54 complete.className = 'torrent_progress_bar complete'; 55 56 incomplete = document.createElement('div'); 57 incomplete.className = 'torrent_progress_bar incomplete'; 58 59 progressbar = document.createElement('div'); 60 progressbar.className = 'torrent_progress_bar_container ' + classes; 61 progressbar.appendChild(complete); 62 progressbar.appendChild(incomplete); 63 64 return { 'element': progressbar, 'complete': complete, 'incomplete': incomplete }; 65}; 66 67TorrentRendererHelper.renderProgressbar = function(controller, t, progressbar) 68{ 69 var e, style, width, display, 70 info = TorrentRendererHelper.getProgressInfo(controller, t); 71 72 // update the complete progressbar 73 e = progressbar.complete; 74 style = e.style; 75 width = '' + info.percent + '%'; 76 display = info.percent > 0 ? 'block' : 'none'; 77 if (style.width!==width || style.display!==display) 78 $(e).css({ width: ''+info.percent+'%', display: display }); 79 if (e.className !== info.complete) 80 e.className = info.complete; 81 82 // update the incomplete progressbar 83 e = progressbar.incomplete; 84 display = (info.percent < 100) ? 'block' : 'none'; 85 if (e.style.display !== display) 86 e.style.display = display; 87 if (e.className !== info.incomplete) 88 e.className = info.incomplete; 89}; 90 91TorrentRendererHelper.formatUL = function(t) 92{ 93 return '��� ' + Transmission.fmt.speedBps(t.getUploadSpeed()); 94}; 95 96TorrentRendererHelper.formatDL = function(t) 97{ 98 return '��� ' + Transmission.fmt.speedBps(t.getDownloadSpeed()); 99}; 100 101/**** 102***** 103***** 104****/ 105 106function TorrentRendererFull() 107{ 108} 109TorrentRendererFull.prototype = 110{ 111 createRow: function() 112 { 113 var root, name, peers, progressbar, details, image, button; 114 115 root = document.createElement('li'); 116 root.className = 'torrent'; 117 118 name = document.createElement('div'); 119 name.className = 'torrent_name'; 120 121 peers = document.createElement('div'); 122 peers.className = 'torrent_peer_details'; 123 124 progressbar = TorrentRendererHelper.createProgressbar('full'); 125 126 details = document.createElement('div'); 127 details.className = 'torrent_progress_details'; 128 129 image = document.createElement('div'); 130 button = document.createElement('a'); 131 button.appendChild(image); 132 133 root.appendChild(name); 134 root.appendChild(peers); 135 root.appendChild(button); 136 root.appendChild(progressbar.element); 137 root.appendChild(details); 138 139 root._name_container = name; 140 root._peer_details_container = peers; 141 root._progress_details_container = details; 142 root._progressbar = progressbar; 143 root._pause_resume_button_image = image; 144 root._toggle_running_button = button; 145 146 return root; 147 }, 148 149 getPeerDetails: function(t) 150 { 151 var err, 152 peer_count, 153 webseed_count, 154 fmt = Transmission.fmt; 155 156 if ((err = t.getErrorMessage())) 157 return err; 158 159 if (t.isDownloading()) 160 { 161 peer_count = t.getPeersConnected(); 162 webseed_count = t.getWebseedsSendingToUs(); 163 164 if (webseed_count && peer_count) 165 { 166 // Downloading from 2 of 3 peer(s) and 2 webseed(s) 167 return [ 'Downloading from', 168 t.getPeersSendingToUs(), 169 'of', 170 fmt.countString('peer','peers',peer_count), 171 'and', 172 fmt.countString('web seed','web seeds',webseed_count) ].join(' '); 173 } 174 else if (webseed_count) 175 { 176 // Downloading from 2 webseed(s) 177 return [ 'Downloading from', 178 fmt.countString('web seed','web seeds',webseed_count) ].join(' '); 179 } 180 else 181 { 182 // Downloading from 2 of 3 peer(s) 183 return [ 'Downloading from', 184 t.getPeersSendingToUs(), 185 'of', 186 fmt.countString('peer','peers',peer_count) ].join(' '); 187 } 188 } 189 190 if (t.isSeeding()) 191 return [ 'Seeding to', 192 t.getPeersGettingFromUs(), 193 'of', 194 fmt.countString ('peer','peers',t.getPeersConnected()), 195 '-', 196 TorrentRendererHelper.formatUL(t) ].join(' '); 197 198 if (t.isChecking()) 199 return [ 'Verifying local data (', 200 Transmission.fmt.percentString(100.0 * t.getRecheckProgress()), 201 '% tested)' ].join(''); 202 203 return t.getStateString(); 204 }, 205 206 getProgressDetails: function(controller, t) 207 { 208 if (t.needsMetaData()) { 209 var percent = 100 * t.getMetadataPercentComplete(); 210 return [ "Magnetized transfer - retrieving metadata (", 211 Transmission.fmt.percentString(percent), 212 "%)" ].join(''); 213 } 214 215 var c, 216 sizeWhenDone = t.getSizeWhenDone(), 217 totalSize = t.getTotalSize(), 218 is_done = t.isDone() || t.isSeeding(); 219 220 if (is_done) { 221 if (totalSize === sizeWhenDone) // seed: '698.05 MiB' 222 c = [ Transmission.fmt.size(totalSize) ]; 223 else // partial seed: '127.21 MiB of 698.05 MiB (18.2%)' 224 c = [ Transmission.fmt.size(sizeWhenDone), 225 ' of ', 226 Transmission.fmt.size(t.getTotalSize()), 227 ' (', t.getPercentDoneStr(), '%)' ]; 228 // append UL stats: ', uploaded 8.59 GiB (Ratio: 12.3)' 229 c.push(', uploaded ', 230 Transmission.fmt.size(t.getUploadedEver()), 231 ' (Ratio ', 232 Transmission.fmt.ratioString(t.getUploadRatio()), 233 ')'); 234 } else { // not done yet 235 c = [ Transmission.fmt.size(sizeWhenDone - t.getLeftUntilDone()), 236 ' of ', Transmission.fmt.size(sizeWhenDone), 237 ' (', t.getPercentDoneStr(), '%)' ]; 238 } 239 240 // maybe append eta 241 if (!t.isStopped() && (!is_done || t.seedRatioLimit(controller)>0)) { 242 c.push(' - '); 243 var eta = t.getETA(); 244 if (eta < 0 || eta >= (999*60*60) /* arbitrary */) 245 c.push('remaining time unknown'); 246 else 247 c.push(Transmission.fmt.timeInterval(t.getETA()), 248 ' remaining'); 249 } 250 251 return c.join(''); 252 }, 253 254 render: function(controller, t, root) 255 { 256 // name 257 setTextContent(root._name_container, t.getName()); 258 259 // progressbar 260 TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar); 261 262 // peer details 263 var has_error = t.getError() !== Torrent._ErrNone; 264 var e = root._peer_details_container; 265 $(e).toggleClass('error',has_error); 266 setTextContent(e, this.getPeerDetails(t)); 267 268 // progress details 269 e = root._progress_details_container; 270 setTextContent(e, this.getProgressDetails(controller, t)); 271 272 // pause/resume button 273 var is_stopped = t.isStopped(); 274 e = root._pause_resume_button_image; 275 e.alt = is_stopped ? 'Resume' : 'Pause'; 276 e.className = is_stopped ? 'torrent_resume' : 'torrent_pause'; 277 } 278}; 279 280/**** 281***** 282***** 283****/ 284 285function TorrentRendererCompact() 286{ 287} 288TorrentRendererCompact.prototype = 289{ 290 createRow: function() 291 { 292 var progressbar, details, name, root; 293 294 progressbar = TorrentRendererHelper.createProgressbar('compact'); 295 296 details = document.createElement('div'); 297 details.className = 'torrent_peer_details compact'; 298 299 name = document.createElement('div'); 300 name.className = 'torrent_name compact'; 301 302 root = document.createElement('li'); 303 root.appendChild(progressbar.element); 304 root.appendChild(details); 305 root.appendChild(name); 306 root.className = 'torrent compact'; 307 root._progressbar = progressbar; 308 root._details_container = details; 309 root._name_container = name; 310 return root; 311 }, 312 313 getPeerDetails: function(t) 314 { 315 var c; 316 if ((c = t.getErrorMessage())) 317 return c; 318 if (t.isDownloading()) { 319 var have_dn = t.getDownloadSpeed() > 0, 320 have_up = t.getUploadSpeed() > 0; 321 if (!have_up && !have_dn) 322 return 'Idle'; 323 var s = ''; 324 if (have_dn) 325 s += TorrentRendererHelper.formatDL(t); 326 if (have_dn && have_up) 327 s += ' ' 328 if (have_up) 329 s += TorrentRendererHelper.formatUL(t); 330 return s; 331 } 332 if (t.isSeeding()) 333 return [ 'Ratio: ', 334 Transmission.fmt.ratioString(t.getUploadRatio()), 335 ', ', 336 TorrentRendererHelper.formatUL(t) ].join(''); 337 return t.getStateString(); 338 }, 339 340 render: function(controller, t, root) 341 { 342 // name 343 var is_stopped = t.isStopped(); 344 var e = root._name_container; 345 $(e).toggleClass('paused', is_stopped); 346 setTextContent(e, t.getName()); 347 348 // peer details 349 var has_error = t.getError() !== Torrent._ErrNone; 350 e = root._details_container; 351 $(e).toggleClass('error', has_error); 352 setTextContent(e, this.getPeerDetails(t)); 353 354 // progressbar 355 TorrentRendererHelper.renderProgressbar(controller, t, root._progressbar); 356 } 357}; 358 359/**** 360***** 361***** 362****/ 363 364function TorrentRow(view, controller, torrent) 365{ 366 this.initialize(view, controller, torrent); 367} 368TorrentRow.prototype = 369{ 370 initialize: function(view, controller, torrent) { 371 var row = this; 372 this._view = view; 373 this._torrent = torrent; 374 this._element = view.createRow(); 375 this.render(controller); 376 $(this._torrent).bind('dataChanged.torrentRowListener',function(){row.render(controller);}); 377 378 }, 379 getElement: function() { 380 return this._element; 381 }, 382 render: function(controller) { 383 var tor = this.getTorrent(); 384 if (tor) 385 this._view.render(controller, tor, this.getElement()); 386 }, 387 isSelected: function() { 388 return this.getElement().className.indexOf('selected') !== -1; 389 }, 390 setSelected: function(flag) { 391 $(this.getElement()).toggleClass('selected', flag); 392 }, 393 394 getToggleRunningButton: function() { 395 return this.getElement()._toggle_running_button; 396 }, 397 398 getTorrent: function() { 399 return this._torrent; 400 }, 401 getTorrentId: function() { 402 return this.getTorrent().getId(); 403 } 404}; 405