Changeset 13523


Ignore:
Timestamp:
Sep 23, 2012, 10:05:21 PM (9 years ago)
Author:
jordan
Message:

(trunk web) #5013 "WebUI Inspector file tree" -- possible reimplementation.

Location:
trunk/web/javascript
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/web/javascript/file-row.js

    r13522 r13523  
    66 */
    77
    8 function FileRow(torrent, i)
     8function FileRow(torrent, depth, name, indices, even)
    99{
    1010        var fields = {
    1111                have: 0,
    12                 index: 0,
    13                 isDirty: false,
     12                indices: [],
    1413                isWanted: true,
    15                 priority: 0,
     14                priorityLow: false,
     15                priorityNormal: true,
     16                priorityHigh: false,
    1617                me: this,
    1718                size: 0,
     
    2728        },
    2829
    29         initialize = function(torrent, i) {
     30        initialize = function(torrent, depth, name, indices, even) {
    3031                fields.torrent = torrent;
    31                 fields.index = i;
    32                 createRow(torrent, i);
    33         },
    34 
    35         readAttributes = function(file) {
    36                 if (fields.have !== file.bytesCompleted) {
    37                         fields.have = file.bytesCompleted;
    38                         fields.isDirty = true;
    39                 }
    40                 if (fields.size !== file.length) {
    41                         fields.size = file.length;
    42                         fields.isDirty = true;
    43                 }
    44                 if (fields.priority !== file.priority) {
    45                         fields.priority = file.priority;
    46                         fields.isDirty = true;
    47                 }
    48                 if (fields.isWanted !== file.wanted) {
    49                         fields.isWanted = file.wanted;
    50                         fields.isDirty = true;
    51                 }
     32                fields.indices = indices;
     33                createRow(torrent, depth, name, even);
    5234        },
    5335
     
    5840                e.toggleClass('complete', isDone());
    5941                $(e[0].checkbox).prop('checked', fields.isWanted);
    60         },
    61         refreshPriorityHTML = function()
    62         {
    63                 $(elements.priority_high_button  ).toggleClass('selected', fields.priority ===  1 );
    64                 $(elements.priority_normal_button).toggleClass('selected', fields.priority ===  0 );
    65                 $(elements.priority_low_button   ).toggleClass('selected', fields.priority === -1 );
    6642        },
    6743        refreshProgressHTML = function()
     
    7652                setTextContent(elements.progress, c);
    7753        },
    78         refreshHTML = function() {
    79                 if (fields.isDirty) {
    80                         fields.isDirty = false;
     54        refreshImpl = function() {
     55                var i,
     56                    file,
     57                    have = 0,
     58                    size = 0,
     59                    wanted = false,
     60                    low = false,
     61                    normal = false,
     62                    high = false;
     63
     64                // loop through the file_indices that affect this row
     65                for (i=0; i<fields.indices.length; ++i) {
     66                        file = fields.torrent.getFile (fields.indices[i]);
     67                        have += file.bytesCompleted;
     68                        size += file.length;
     69                        wanted |= file.wanted;
     70                        switch (file.priority) {
     71                                case -1: low = true; break;
     72                                case  0: normal = true; break;
     73                                case  1: high = true; break;
     74                        }
     75                }
     76
     77                if ((fields.have != have) || (fields.size != size)) {
     78                        fields.have = have;
     79                        fields.size = size;
    8180                        refreshProgressHTML();
     81                }
     82
     83                if (fields.isWanted !== wanted) {
     84                        fields.isWanted = wanted;
    8285                        refreshWantedHTML();
    83                         refreshPriorityHTML();
    8486                }
    85         },
    86         refresh = function() {
    87                 readAttributes(fields.torrent.getFile(fields.index));
    88                 refreshHTML();
     87
     88                if (fields.priorityLow !== low) {
     89                        fields.priorityLow = low;
     90                        $(elements.priority_low_button).toggleClass('selected', low);
     91                }
     92
     93                if (fields.priorityNormal !== normal) {
     94                        fields.priorityNormal = normal;
     95                        $(elements.priority_normal_button).toggleClass('selected', normal);
     96                }
     97
     98                if (fields.priorityHigh !== high) {
     99                        fields.priorityHigh = high;
     100                        $(elements.priority_high_button).toggleClass('selected', high);
     101                }
    89102        },
    90103
     
    93106        },
    94107
    95         createRow = function(torrent, i) {
    96                 var file = torrent.getFile(i), e, name, root, box;
     108        createRow = function(torrent, depth, name, even) {
     109                var e, root, box;
    97110
    98111                root = document.createElement('li');
    99                 root.id = 't' + fields.torrent.getId() + 'f' + fields.index;
    100                 root.className = 'inspector_torrent_file_list_entry ' + ((i%2)?'odd':'even');
     112                root.className = 'inspector_torrent_file_list_entry' + (even?'even':'odd');
    101113                elements.root = root;
    102114
     
    136148                root.appendChild(box);
    137149
    138                 name = file.name || 'Unknown';
    139                 name = name.substring(name.lastIndexOf('/')+1);
    140                 name = name.replace(/([\/_\.])/g, "$1​");
    141150                e = document.createElement('div');
    142151                e.className = "inspector_torrent_file_list_entry_name";
    143152                setTextContent(e, name);
     153                $(e).click(function(){ fireNameClicked(-1); });
    144154                root.appendChild(e);
    145155
     
    147157                e.className = "inspector_torrent_file_list_entry_progress";
    148158                root.appendChild(e);
     159                $(e).click(function(){ fireNameClicked(-1); });
    149160                elements.progress = e;
    150161
    151                 refresh();
     162                $(root).css('margin-left', '' + (depth*16) + 'px');
     163
     164                refreshImpl();
    152165                return root;
    153166        },
    154167
    155168        fireWantedChanged = function(do_want) {
    156                 $(fields.me).trigger('wantedToggled',[ fields.me, do_want ]);
     169                $(fields.me).trigger('wantedToggled',[ fields.indices, do_want ]);
    157170        },
    158171        firePriorityChanged = function(priority) {
    159                 $(fields.me).trigger('priorityToggled',[ fields.me, priority ]);
     172                $(fields.me).trigger('priorityToggled',[ fields.indices, priority ]);
     173        },
     174        fireNameClicked = function() {
     175                $(fields.me).trigger('nameClicked',[ fields.me, fields.indices ]);
    160176        };
    161177
     
    167183                return elements.root;
    168184        };
    169         this.getIndex = function() {
    170                 return fields.index;
    171         };
    172185        this.isEditable = function () {
    173186                return (fields.torrent.getFileCount()>1) && !isDone();
    174187        };
    175         this.getPath = function () {
    176                 var file = torrent.getFile(i);
    177                 var path = file.name.replace(/\/\/+/g,'/');
    178                 path = path.split('/').slice(0,-1);
    179                 path.push('t' + fields.torrent.getId() + 'f' + fields.index);
    180                 return path;
     188        this.refresh = function() {
     189                refreshImpl();
    181190        };
    182191
    183         initialize(torrent, i);
     192        initialize(torrent, depth, name, indices, even);
    184193};
  • trunk/web/javascript/inspector.js

    r13522 r13523  
    223223            d = u = 0;
    224224            if(torrents.length == 1) {
    225                                 d = torrents[0].getDownloadedEver();
    226                                 u = torrents[0].getUploadedEver();
    227                                
    228                                 if (d == 0)
    229                                         d = torrents[0].getHaveValid();
     225                d = torrents[0].getDownloadedEver();
     226                u = torrents[0].getUploadedEver();
     227                               
     228                if (d == 0)
     229                    d = torrents[0].getHaveValid();
    230230            }
    231231            else {
    232                                 for(i=0; t=torrents[i]; ++i) {
    233                                         d += t.getDownloadedEver();
    234                                         u += t.getUploadedEver();
    235                                 }
    236                         }
     232                for(i=0; t=torrents[i]; ++i) {
     233                    d += t.getDownloadedEver();
     234                    u += t.getUploadedEver();
     235                }
     236            }
    237237            str = fmt.size(u) + ' (Ratio: ' + fmt.ratioString( Math.ratio(u,d))+')';
    238238        }
     
    457457    ****/
    458458
    459     changeFileCommand = function(rows, command) {
     459    changeFileCommand = function(fileIndices, command) {
    460460        var torrentId = data.file_torrent.getId();
    461         var rowIndices = $.map(rows.slice(0),function (row) {return row.getIndex();});
    462         data.controller.changeFileCommand(torrentId, rowIndices, command);
    463     },
    464 
    465     selectAllFiles = function() {
    466         changeFileCommand([], 'files-wanted');
    467     },
    468 
    469     deselectAllFiles = function() {
    470         changeFileCommand([], 'files-unwanted');
    471     },
    472 
    473     onFileWantedToggled = function(ev, row, want) {
    474         changeFileCommand([row], want?'files-wanted':'files-unwanted');
    475     },
    476 
    477     onFilePriorityToggled = function(ev, row, priority) {
     461        data.controller.changeFileCommand(torrentId, fileIndices, command);
     462    },
     463
     464    onFileWantedToggled = function(ev, fileIndices, want) {
     465        changeFileCommand(fileIndices, want?'files-wanted':'files-unwanted');
     466    },
     467
     468    onFilePriorityToggled = function(ev, fileIndices, priority) {
    478469        var command;
    479470        switch(priority) {
     
    482473            default: command = 'priority-normal'; break;
    483474        }
    484         changeFileCommand([row], command);
     475        changeFileCommand(fileIndices, command);
     476    },
     477
     478    onNameClicked = function(ev, fileRow, fileIndices) {
     479        $(fileRow.getElement()).siblings().slideToggle();
    485480    },
    486481
     
    488483        $(data.elements.file_list).empty();
    489484        delete data.file_torrent;
     485        delete data.file_torrent_n;
    490486        delete data.file_rows;
    491487    },
    492488
     489    createFileTreeModel = function (tor) {
     490        var i, j, n, name, tokens, walk, tree, token, sub,
     491            leaves = [ ],
     492            tree = { children: { }, file_indices: [ ] };
     493
     494        n = tor.getFileCount();
     495        for (i=0; i<n; ++i) {
     496            name = tor.getFile(i).name;
     497            tokens = name.split('/');
     498            walk = tree;
     499            for (j=0; j<tokens.length; ++j) {
     500                token = tokens[j];
     501                sub = walk.children[token];
     502                if (!sub) {
     503                    walk.children[token] = sub = {
     504                      name: token,
     505                      parent: walk,
     506                      children: { },
     507                      file_indices: [ ],
     508                      depth: j
     509                    };
     510                }
     511                walk = sub;
     512            }
     513            walk.file_index = i;
     514            delete walk.children;
     515            leaves.push (walk);
     516        }
     517
     518        for (i=0; i<leaves.length; ++i) {
     519            walk = leaves[i];
     520            j = walk.file_index;
     521            do {
     522                walk.file_indices.push (j);
     523                walk = walk.parent;
     524            } while (walk);
     525        }
     526
     527        return tree;
     528    },
     529
     530    addNodeToView = function (tor, parent, sub, i) {
     531        var row;
     532        row = new FileRow(tor, sub.depth, sub.name, sub.file_indices, i%2);
     533        data.file_rows.push(row);
     534        parent.appendChild(row.getElement());
     535        $(row).bind('wantedToggled',onFileWantedToggled);
     536        $(row).bind('priorityToggled',onFilePriorityToggled);
     537        $(row).bind('nameClicked',onNameClicked);
     538    }
     539
     540    addSubtreeToView = function (tor, parent, sub, i) {
     541        var key, div;
     542        div = document.createElement('div');
     543        if (sub.parent)
     544            addNodeToView (tor, div, sub, i++);
     545        if (sub.children)
     546            for (key in sub.children)
     547                i = addSubtreeToView (tor, div, sub.children[key]); 
     548        parent.appendChild(div);
     549        return i;
     550    },
     551               
    493552    updateFilesPage = function() {
    494         var i, j, n, sel, row, tor, fragment,
    495             box, complete, conn, connections, e, from, heirarchy, item,
    496                     matches, parents, parentid, path, sum, subheirarchy, to, inner,
     553        var i, n, tor, fragment, tree,
    497554            file_list = data.elements.file_list,
    498555            torrents = data.torrents;
    499556
     557        // only show one torrent at a time
    500558        if (torrents.length !== 1) {
    501559            clearFileList();
     
    503561        }
    504562
    505         // build the file list
    506563        tor = torrents[0];
    507 
    508         for (parentid in data.parents) {
    509             data.parents[parentid] = $('#'+parentid).children('li').css('display')
    510         }
    511         clearFileList();
    512         data.file_torrent = tor;
    513         n = tor.getFileCount();
    514         data.file_rows = [];
    515         fragment = document.createDocumentFragment();
    516         heirarchy = {'/':[]}
    517        
    518         for (i=0; i<n; ++i) {
    519             row = data.file_rows[i] = new FileRow(tor, i);
    520             fragment.appendChild(row.getElement());
    521                     $(row).bind('wantedToggled',onFileWantedToggled);
    522                     $(row).bind('priorityToggled',onFilePriorityToggled);
    523             path = row.getPath();
    524             if (path.length == 1) {
    525                 heirarchy['/'].push(path[0]);
    526             } else {
    527                 subheirarchy = heirarchy;
    528                 for (j=0; j<path.length; j++) {
    529                     if (j<(path.length-1)) {
    530                         subheirarchy[path[j]] = (subheirarchy[path[j]] == undefined) ? {'/':[]} : subheirarchy[path[j]];
    531                         subheirarchy[path[j]]['PARENT'] = (path[j-1] == undefined) ? [undefined] : [path[j-1].replace(/[\[\] ().]/g,'_')]
    532                         subheirarchy = subheirarchy[path[j]];
    533                     } else {
    534                         parentid  = (path[j-1] == undefined) ? [undefined] : [path[j-1].replace(/[\[\] ().]/g,'_')]
    535                         subheirarchy['/'].push([path[j],parentid]);
    536                     }
    537                 }
    538             }
    539         }
    540         console.log(heirarchy);
    541         /*
    542         At this point we have a single object containing the whole
    543         torrent heirarchy. The '/' key is file element ids as assigned above
    544         for the current level. Any other keys are array objects which are
    545         directories in the torrent heirarchy, this will also contain a '/'
    546         key and potentially more keys for nested directories.
    547         */
    548         connections = [];
    549         parents = {};
    550         var recursiveCreate = function(key,val) {
    551             if (key == "PARENT") { return; }
    552             if (typeof(val) == "object" &&! Array.isArray(val)) {
    553                 row = document.createElement('li');
    554                 row.id = key.replace(/[\[\] ().]/g,'_');
    555                 row.classname = 'inspector_torrent_file_list_entry odd';
    556 
    557                 e = document.createElement('input');
    558                 e.type = 'checkbox';
    559                 e.className = "file_wanted_control";
    560                 e.title = 'Download file';
    561                 e.checked = true;
    562                 $(e).change(function() { $($(this).parent()).children('li').children('input').click() });
    563                 row.appendChild(e);
    564 
    565                 e = document.createElement('div');
    566                 e.className = 'file-priority-radiobox';
    567                 box = e;
    568 
    569                         e = document.createElement('div');
    570                         e.className = 'low';
    571                         e.title = 'Low Priority';
    572                         $(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.low').click() });
    573                         box.appendChild(e);
    574 
    575                         e = document.createElement('div');
    576                         e.className = 'normal';
    577                         e.title = 'Normal Priority';
    578                         $(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.normal').click() });
    579                         box.appendChild(e);
    580 
    581                         e = document.createElement('div');
    582                         e.title = 'High Priority';
    583                         e.className = 'high';
    584                         $(e).click(function(){ $($(this).parent().parent()).children('li').children('div').children('.high').click() });
    585                         box.appendChild(e);
    586 
    587                 row.appendChild(box);
    588 
    589                 inner = document.createElement('div');
    590                 inner.className = "inspector_torrent_file_list_entry_name";
    591                 inner.innerHTML = key;
    592                 row.appendChild(inner);
    593 
    594                 complete = document.createElement('div');
    595                 complete.className = "inspector_torrent_file_list_entry_progress";
    596                 complete.innerHTML = "&nbsp;"
    597                 row.appendChild(complete)
    598 
    599                 fragment.appendChild(row);
    600                 connections.push([key.replace(/[\[\] ().]/g,'_'),val['PARENT'][0]])
    601             } else {
    602                 for (item in val) {
    603                     parents[val[item][1][0]] = ""
    604                 }
    605                 connections.push.apply(connections,val)
    606             }
    607             if (!Array.isArray(val)) {
    608                 $.each(val,function(key,val) { recursiveCreate(key,val) })
    609             }
    610         }
    611         $.each(heirarchy,function(key,val) { recursiveCreate(key,val) })
    612         file_list.appendChild(fragment);
    613         for (conn in connections) {
    614             from = connections[conn][0];
    615             to = connections[conn][1];
    616             if (to == undefined) { continue; }
    617             $('#'+from).appendTo($('#'+to));
    618             $('#'+from).css('margin-left','20px')
    619         }
    620         for (parentid in parents) {
    621             $($('.inspector_torrent_file_list_entry_name',$('#'+parentid))[0]).click(function() { $($(this).parent()).children('li').toggle(); })
    622 
    623             sum = 0;
    624             matches = $('#'+parentid).children('li').text().match(/\([^\.]+\)/g)
    625             if (matches == null) { continue; }
    626             matches.map(function(word) {return parseFloat(word.slice(1,-2)) }).map(function(perc) {sum+=perc})
    627             count = $('#'+parentid).children('li').text().match(/\([^\.]+\)/g).length
    628             totalcomplete = (sum/count).toFixed(1)
    629 
    630             $($('.inspector_torrent_file_list_entry_progress',$('#'+parentid))[0]).text('('+totalcomplete+'%)')
    631         }
    632         for (parentid in data.parents) {
    633             $('#'+parentid).children('li').css('display',data.parents[parentid])
    634         }
    635         data.parents = parents;
     564        n = tor ? tor.getFileCount() : 0;
     565        if (tor!=data.file_torrent || n==data.file_torrent_n) {
     566            // rebuild the file list...
     567            clearFileList();
     568            data.file_torrent = tor;
     569            data.file_torrent_n = n;
     570            data.file_rows = [ ];
     571            fragment = document.createDocumentFragment();
     572            tree = createFileTreeModel (tor);
     573            addSubtreeToView (tor, fragment, tree, 0);
     574            file_list.appendChild (fragment);
     575        } else {
     576            // ...refresh the already-existing file list
     577            for (i=0, n=data.file_rows.length; i<n; ++i)
     578                data.file_rows[i].refresh();
     579        }
    636580    },
    637581
     
    831775        data.elements.trackers_list  = $('#inspector_trackers_list')[0];
    832776
    833         data.elements.have_lb           = $('#inspector-info-have')[0];
    834         data.elements.availability_lb   = $('#inspector-info-availability')[0];
    835         data.elements.downloaded_lb     = $('#inspector-info-downloaded')[0];
    836         data.elements.uploaded_lb       = $('#inspector-info-uploaded')[0];
    837         data.elements.state_lb          = $('#inspector-info-state')[0];
    838         data.elements.running_time_lb   = $('#inspector-info-running-time')[0];
    839         data.elements.remaining_time_lb = $('#inspector-info-remaining-time')[0];
    840         data.elements.last_activity_lb  = $('#inspector-info-last-activity')[0];
    841         data.elements.error_lb          = $('#inspector-info-error')[0];
    842         data.elements.size_lb           = $('#inspector-info-size')[0];
    843         data.elements.foldername_lb     = $('#inspector-info-location')[0];
    844         data.elements.hash_lb           = $('#inspector-info-hash')[0];
    845         data.elements.privacy_lb        = $('#inspector-info-privacy')[0];
    846         data.elements.origin_lb         = $('#inspector-info-origin')[0];
    847         data.elements.comment_lb        = $('#inspector-info-comment')[0];
     777        data.elements.have_lb           = $('#inspector-info-have')[0];
     778        data.elements.availability_lb   = $('#inspector-info-availability')[0];
     779        data.elements.downloaded_lb     = $('#inspector-info-downloaded')[0];
     780        data.elements.uploaded_lb       = $('#inspector-info-uploaded')[0];
     781        data.elements.state_lb          = $('#inspector-info-state')[0];
     782        data.elements.running_time_lb   = $('#inspector-info-running-time')[0];
     783        data.elements.remaining_time_lb = $('#inspector-info-remaining-time')[0];
     784        data.elements.last_activity_lb  = $('#inspector-info-last-activity')[0];
     785        data.elements.error_lb          = $('#inspector-info-error')[0];
     786        data.elements.size_lb           = $('#inspector-info-size')[0];
     787        data.elements.foldername_lb     = $('#inspector-info-location')[0];
     788        data.elements.hash_lb           = $('#inspector-info-hash')[0];
     789        data.elements.privacy_lb        = $('#inspector-info-privacy')[0];
     790        data.elements.origin_lb         = $('#inspector-info-origin')[0];
     791        data.elements.comment_lb        = $('#inspector-info-comment')[0];
    848792        data.elements.name_lb           = $('#torrent_inspector_name')[0];
    849 
    850         // file page's buttons
    851         $('#select-all-files').click(selectAllFiles);
    852         $('#deselect-all-files').click(deselectAllFiles);
    853793
    854794        // force initial 'N/A' updates on all the pages
Note: See TracChangeset for help on using the changeset viewer.