WebUI: Use Map instead of Mootools Hash in Torrents table
[qBittorrent.git] / src / webui / www / private / scripts / file-tree.js
blob7ccc46513f148c4a99c22828446a11f737f00760
1 /*
2  * Bittorrent Client using Qt and libtorrent.
3  * Copyright (C) 2019  Thomas Piccirello <thomas.piccirello@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  *
19  * In addition, as a special exception, the copyright holders give permission to
20  * link this program with the OpenSSL project's "OpenSSL" library (or with
21  * modified versions of it that use the same license as the "OpenSSL" library),
22  * and distribute the linked executables. You must obey the GNU General Public
23  * License in all respects for all of the code used other than "OpenSSL".  If you
24  * modify file(s), you may extend this exception to your version of the file(s),
25  * but you are not obligated to do so. If you do not wish to do so, delete this
26  * exception statement from your version.
27  */
29 "use strict";
31 window.qBittorrent ??= {};
32 window.qBittorrent.FileTree ??= (() => {
33     const exports = () => {
34         return {
35             FilePriority: FilePriority,
36             TriState: TriState,
37             FileTree: FileTree,
38             FileNode: FileNode,
39             FolderNode: FolderNode,
40         };
41     };
43     const FilePriority = {
44         "Ignored": 0,
45         "Normal": 1,
46         "High": 6,
47         "Maximum": 7,
48         "Mixed": -1
49     };
50     Object.freeze(FilePriority);
52     const TriState = {
53         "Unchecked": 0,
54         "Checked": 1,
55         "Partial": 2
56     };
57     Object.freeze(TriState);
59     const FileTree = new Class({
60         root: null,
61         nodeMap: {},
63         setRoot: function(root) {
64             this.root = root;
65             this.generateNodeMap(root);
67             if (this.root.isFolder)
68                 this.root.calculateSize();
69         },
71         getRoot: function() {
72             return this.root;
73         },
75         generateNodeMap: function(node) {
76             // don't store root node in map
77             if (node.root !== null)
78                 this.nodeMap[node.rowId] = node;
80             node.children.each((child) => {
81                 this.generateNodeMap(child);
82             });
83         },
85         getNode: function(rowId) {
86             return (this.nodeMap[rowId] === undefined)
87                 ? null
88                 : this.nodeMap[rowId];
89         },
91         getRowId: function(node) {
92             return node.rowId;
93         },
95         /**
96          * Returns the nodes in dfs order
97          */
98         toArray: function() {
99             const nodes = [];
100             this.root.children.each((node) => {
101                 this._getArrayOfNodes(node, nodes);
102             });
103             return nodes;
104         },
106         _getArrayOfNodes: function(node, array) {
107             array.push(node);
108             node.children.each((child) => {
109                 this._getArrayOfNodes(child, array);
110             });
111         }
112     });
114     const FileNode = new Class({
115         name: "",
116         path: "",
117         rowId: null,
118         size: 0,
119         checked: TriState.Unchecked,
120         remaining: 0,
121         progress: 0,
122         priority: FilePriority.Normal,
123         availability: 0,
124         depth: 0,
125         root: null,
126         data: null,
127         isFolder: false,
128         children: [],
129     });
131     const FolderNode = new Class({
132         Extends: FileNode,
134         /**
135          * Will automatically tick the checkbox for a folder if all subfolders and files are also ticked
136          */
137         autoCheckFolders: true,
139         initialize: function() {
140             this.isFolder = true;
141         },
143         addChild(node) {
144             this.children.push(node);
145         },
147         /**
148          * Recursively calculate size of node and its children
149          */
150         calculateSize: function() {
151             let size = 0;
152             let remaining = 0;
153             let progress = 0;
154             let availability = 0;
155             let checked = TriState.Unchecked;
156             let priority = FilePriority.Normal;
158             let isFirstFile = true;
160             this.children.each((node) => {
161                 if (node.isFolder)
162                     node.calculateSize();
164                 size += node.size;
166                 if (isFirstFile) {
167                     priority = node.priority;
168                     checked = node.checked;
169                     isFirstFile = false;
170                 }
171                 else {
172                     if (priority !== node.priority)
173                         priority = FilePriority.Mixed;
174                     if (checked !== node.checked)
175                         checked = TriState.Partial;
176                 }
178                 const isIgnored = (node.priority === FilePriority.Ignored);
179                 if (!isIgnored) {
180                     remaining += node.remaining;
181                     progress += (node.progress * node.size);
182                     availability += (node.availability * node.size);
183                 }
184             });
186             this.size = size;
187             this.remaining = remaining;
188             this.checked = this.autoCheckFolders ? checked : TriState.Checked;
189             this.progress = (progress / size);
190             this.priority = priority;
191             this.availability = (availability / size);
192         }
193     });
195     return exports();
196 })();
197 Object.freeze(window.qBittorrent.FileTree);