├── .github └── dependabot.yml ├── .gitignore ├── LICENSE ├── README.md ├── demo-2.html ├── demo-files ├── 1 │ ├── 2 │ │ └── construction-work-carpenter-tools.jpg │ └── city-houses-village-buildings.jpg ├── So Much Trouble In The World.mp3 ├── animals │ ├── animal-brown-horse.jpg │ ├── nature-animal-fur-dangerous.jpg │ └── nature-animal-wolf-wilderness.jpg ├── archive-document.zip ├── art-creative-metal-creativity.jpg ├── blue-abstract-glass-balls.jpg ├── books-magazines-building-school.jpg ├── cipher-core.js ├── city-houses-village-buildings.jpg ├── construction-work-carpenter-tools.jpg ├── folder test │ └── black-and-white-art-building-window.jpeg ├── nature │ ├── dawn-nature-sunset-trees.jpg │ ├── forest │ │ ├── bench-forest-trees-path.jpeg │ │ ├── nature-forest-ground-dangerous.jpg │ │ ├── nature-forest-trees-environment.jpg │ │ ├── wood-nature-forest-bridge.jpg │ │ ├── wood-nature-forest-trees.jpg │ │ ├── wood-nature-sun-forest.jpg │ │ └── wood-nature-sunny-forest.jpg │ ├── landing-stage-sea-nature-beach.jpg │ ├── landscape-mountains-nature-hills.jpeg │ ├── landscape-nature-man-person.jpeg │ ├── landscape-nature-sky-sunset.jpg │ ├── nature-plant-leaf-drop-of-water.jpeg │ ├── nature-sky-sunset-sun.jpg │ ├── pexels-photo (1).jpeg │ ├── pexels-photo (2).jpeg │ ├── pexels-photo.jpeg │ ├── pexels-photo.jpg │ ├── snow-mountains-nature-summer.jpg │ ├── streets-landscape-mountains-nature.jpg │ ├── water-summer-island-vibes.jpg │ └── water-sunrise.jpg ├── open-office-document.odt ├── pdf-document.pdf ├── unknown file.url ├── web-page.html └── word-document.doc ├── dist ├── ajax │ └── move-file.php ├── connectors │ └── connector.php ├── icons │ ├── fonts │ │ ├── file-tree-icons.eot │ │ ├── file-tree-icons.svg │ │ ├── file-tree-icons.ttf │ │ └── file-tree-icons.woff │ └── style.css ├── js │ ├── file-tree-browser.js │ └── file-tree-browser.js.map ├── lib │ ├── crypto-js │ │ ├── crypto-js.js │ │ └── crypto-js.min.js │ └── html5sortable │ │ ├── html5sortable.js │ │ ├── html5sortable.min.js │ │ └── html5sortable.min.js.map └── templates │ ├── bootstrap4.css │ └── bootstrap4.html ├── file-tree-generator-preview.png ├── gulpfile.js ├── index.html ├── package-lock.json ├── package.json ├── src ├── ajax │ └── move-file.php ├── connectors │ └── connector.php ├── icons │ ├── Read Me.txt │ ├── demo-files │ │ ├── demo.css │ │ └── demo.js │ ├── demo.html │ ├── fonts │ │ ├── file-tree-icons.eot │ │ ├── file-tree-icons.svg │ │ ├── file-tree-icons.ttf │ │ └── file-tree-icons.woff │ ├── selection.json │ └── style.css ├── lib │ ├── crypto-js │ │ ├── crypto-js.js │ │ └── crypto-js.min.js │ └── html5sortable │ │ ├── html5sortable.js │ │ ├── html5sortable.min.js │ │ └── html5sortable.min.js.map ├── templates │ ├── bootstrap4.css │ └── bootstrap4.html └── ts │ └── file-tree-browser.ts └── tsconfig.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MEMO.txt 2 | .vscode 3 | .htaccess 4 | apple-touch-icon.png 5 | browserconfig.xml 6 | favicon-16x16.png 7 | favicon-32x32.png 8 | favicon.ico 9 | manifest.json 10 | mstile-150x150.png 11 | node_modules 12 | safari-pinned-tab.svg 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # File Tree Browser 2 | 3 | ## Demo 4 | 5 | 6 | 7 | [![File Tree Generator](file-tree-generator-preview.png)](https://www.file-tree-generator.miglisoft.com) 8 | 9 | ## Table of contents 10 | 11 | * [Overview](#overview) 12 | * [Quick start](#quick-start) 13 | * [Options](#options) 14 | * [How to customize the HTML/ CSS](#how-to-customize-the-html-css) 15 | * [Connnectors](#connnectors) 16 | * [Contribute](#contribute) 17 | * [Versionning](#versionning) 18 | * [Authors](#authors) 19 | * [License](#license) 20 | 21 | ## Overview 22 | 23 | **File Tree Browser** is a Javascript plugin built to **browse folders** and **select files**. 24 | 25 | It retrieves directories and files recursively with Ajax from a main directory and displays the tree structure. You can browse and select, move files from folder to folder, do any stuff with the choosen file. 26 | 27 | File Tree Browser is programmed in **Vanilla Javascript** (compiled TypeScript) and **doesn't require any dependency**. 28 | 29 | a **PHP connector** is provided to retrieve the main directory content, you can write your own in any server language (NodeJS, ASP, ...). 30 | 31 | The default template is built with Bootstrap 4, but Bootstrap is **not required** at all. You can easily **add your own HTML/CSS template** and change markup to fit your needs. 32 | 33 | ## Installation 34 | 35 | Clone / download or install with npm 36 | 37 | ```bash 38 | npm install @migliori/file-tree-browser@1.1.1 39 | ``` 40 | 41 | ## Quick start 42 | 43 | * Upload the *dist* folder on your server 44 | * add the HTML markup on your page: 45 | 46 | ```html 47 | 53 |
54 |
55 |
56 |
57 | ``` 58 | 59 | * add the Javascript code: 60 | 61 | ```javascript 62 | 63 | 82 | ``` 83 | 84 | ## Options 85 | 86 | Name | type | Default Value | Description 87 | ---- | ---- | ----- | ------- 88 | connector | string | 'php' | connector file extension in `dist/connectors/connector.[ext]` 89 | dragAndDrop | boolean | true | allow or disallow to drag files from folder to folder 90 | explorerMode | string | 'list' | 'list' or 'grid' 91 | extensions | array | ['.*'] | Array with the authorized file extensions 92 | mainDir | string | 'demo-files' | main directory id 93 | maxDeph | number | 3 | deph of the folders to browse from the main directory 94 | cancelBtn | boolean | true | add a cancel button or not 95 | cancelBtnText | string | 'Cancel' | text for the *Cancel* button 96 | okBtn | boolean | true | add an OK button or not 97 | okBtnText | string | 'Ok' | text for the *Ok* button 98 | template | string | 'bootstrap4' | name of the HTML/CSS template files in *dist/templates/* 99 | elementClick | function | `function (filePath, fileName) {console.log(filePath); console.log(fileName);}` | callback function called when the user clicks any file in the explorer 100 | cancelBtnClick | function | `function () { console.log('Cancel'); }` | callback function called when the user clicks the explorer *cancel* button 101 | okBtnClick | function | `function (filePath, fileName) {console.log(filePath); console.log(fileName);}` | callback function called when the user clicks the explorer *OK* button 102 | 103 | ## How to customize the HTML/ CSS 104 | 105 | The template files are used to generate the File Explorer html code. 106 | 107 | They are located in *dist/templates/* 108 | 109 | ### To create your own templates 110 | 111 | * Create your HTML file + your css file with the same name for both in *dist/templates/* 112 | * Your HTML template **MUST**: 113 | * include exactly the same *<template>* tags with the exact IDs as the default Bootstrap 4 template. 114 | ie: 115 | 116 | ```html 117 | 118 | ``` 119 | 120 | * Each *<template>* tag MUST include elements having the prefixed CSS classes `ft-` 121 | 122 | * Load your template using the *template* option: 123 | 124 | ```javascript 125 | 136 | ``` 137 | 138 | You can use any HTML structure, any element, as long as the templates are all present with their respective IDs, and all the necessary prefixed classes are present in each of them. 139 | 140 | **WARNING**: if there's a missing *<template>* tag or a missing prefixed class, Javascript will throw the following console error: 141 | 142 | ```javascript 143 | 'Augh, there was an error!' 144 | ``` 145 | 146 | ## Connnectors 147 | 148 | The default connector is written in PHP. 149 | You can write your own in any server language (nodeJs, ASP, ...). ie: 150 | 151 | * create your connector file named *dist/connectors.connector.asp* 152 | * Load it using the *connector* option: 153 | 154 | ```javascript 155 | 166 | ``` 167 | 168 | ## Contribute 169 | 170 | Any new connector or cool template is welcome! 171 | 172 | ## Versioning 173 | 174 | We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/migliori/file-tree-browser/tags). 175 | 176 | ## Authors 177 | 178 | * **Gilles Migliori** - _Initial work_ - [Migliori](https://github.com/migliori) 179 | 180 | ## License 181 | 182 | This project is licensed under the GNU GENERAL PUBLIC LICENSE - see the [LICENSE](LICENSE) file for details 183 | -------------------------------------------------------------------------------- /demo-2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | File Tree Browser Demo 2 - Bootstrap modal Image Picker 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

File Tree Browser Demo 2 - Bootstrap modal Image Picker

17 | 18 |
19 | Demo 1 20 | Demo 2 21 |
22 | 23 |

Documentation & Download: https://github.com/migliori/file-tree-browser

24 | 25 |
26 | 27 |
28 | 29 | 30 |
31 | 32 | 33 | 54 | 55 |

@miglisoft

56 | 57 | 58 | 59 | 60 | 61 | 62 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /demo-files/1/2/construction-work-carpenter-tools.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/1/2/construction-work-carpenter-tools.jpg -------------------------------------------------------------------------------- /demo-files/1/city-houses-village-buildings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/1/city-houses-village-buildings.jpg -------------------------------------------------------------------------------- /demo-files/So Much Trouble In The World.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/So Much Trouble In The World.mp3 -------------------------------------------------------------------------------- /demo-files/animals/animal-brown-horse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/animals/animal-brown-horse.jpg -------------------------------------------------------------------------------- /demo-files/animals/nature-animal-fur-dangerous.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/animals/nature-animal-fur-dangerous.jpg -------------------------------------------------------------------------------- /demo-files/animals/nature-animal-wolf-wilderness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/animals/nature-animal-wolf-wilderness.jpg -------------------------------------------------------------------------------- /demo-files/archive-document.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/archive-document.zip -------------------------------------------------------------------------------- /demo-files/art-creative-metal-creativity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/art-creative-metal-creativity.jpg -------------------------------------------------------------------------------- /demo-files/blue-abstract-glass-balls.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/blue-abstract-glass-balls.jpg -------------------------------------------------------------------------------- /demo-files/books-magazines-building-school.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/books-magazines-building-school.jpg -------------------------------------------------------------------------------- /demo-files/cipher-core.js: -------------------------------------------------------------------------------- 1 | ;(function (root, factory, undef) { 2 | if (typeof exports === "object") { 3 | // CommonJS 4 | module.exports = exports = factory(require("./core"), require("./evpkdf")); 5 | } 6 | else if (typeof define === "function" && define.amd) { 7 | // AMD 8 | define(["./core", "./evpkdf"], factory); 9 | } 10 | else { 11 | // Global (browser) 12 | factory(root.CryptoJS); 13 | } 14 | }(this, function (CryptoJS) { 15 | 16 | /** 17 | * Cipher core components. 18 | */ 19 | CryptoJS.lib.Cipher || (function (undefined) { 20 | // Shortcuts 21 | var C = CryptoJS; 22 | var C_lib = C.lib; 23 | var Base = C_lib.Base; 24 | var WordArray = C_lib.WordArray; 25 | var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm; 26 | var C_enc = C.enc; 27 | var Utf8 = C_enc.Utf8; 28 | var Base64 = C_enc.Base64; 29 | var C_algo = C.algo; 30 | var EvpKDF = C_algo.EvpKDF; 31 | 32 | /** 33 | * Abstract base cipher template. 34 | * 35 | * @property {number} keySize This cipher's key size. Default: 4 (128 bits) 36 | * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits) 37 | * @property {number} _ENC_XFORM_MODE A constant representing encryption mode. 38 | * @property {number} _DEC_XFORM_MODE A constant representing decryption mode. 39 | */ 40 | var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({ 41 | /** 42 | * Configuration options. 43 | * 44 | * @property {WordArray} iv The IV to use for this operation. 45 | */ 46 | cfg: Base.extend(), 47 | 48 | /** 49 | * Creates this cipher in encryption mode. 50 | * 51 | * @param {WordArray} key The key. 52 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 53 | * 54 | * @return {Cipher} A cipher instance. 55 | * 56 | * @static 57 | * 58 | * @example 59 | * 60 | * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray }); 61 | */ 62 | createEncryptor: function (key, cfg) { 63 | return this.create(this._ENC_XFORM_MODE, key, cfg); 64 | }, 65 | 66 | /** 67 | * Creates this cipher in decryption mode. 68 | * 69 | * @param {WordArray} key The key. 70 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 71 | * 72 | * @return {Cipher} A cipher instance. 73 | * 74 | * @static 75 | * 76 | * @example 77 | * 78 | * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray }); 79 | */ 80 | createDecryptor: function (key, cfg) { 81 | return this.create(this._DEC_XFORM_MODE, key, cfg); 82 | }, 83 | 84 | /** 85 | * Initializes a newly created cipher. 86 | * 87 | * @param {number} xformMode Either the encryption or decryption transormation mode constant. 88 | * @param {WordArray} key The key. 89 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 90 | * 91 | * @example 92 | * 93 | * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray }); 94 | */ 95 | init: function (xformMode, key, cfg) { 96 | // Apply config defaults 97 | this.cfg = this.cfg.extend(cfg); 98 | 99 | // Store transform mode and key 100 | this._xformMode = xformMode; 101 | this._key = key; 102 | 103 | // Set initial values 104 | this.reset(); 105 | }, 106 | 107 | /** 108 | * Resets this cipher to its initial state. 109 | * 110 | * @example 111 | * 112 | * cipher.reset(); 113 | */ 114 | reset: function () { 115 | // Reset data buffer 116 | BufferedBlockAlgorithm.reset.call(this); 117 | 118 | // Perform concrete-cipher logic 119 | this._doReset(); 120 | }, 121 | 122 | /** 123 | * Adds data to be encrypted or decrypted. 124 | * 125 | * @param {WordArray|string} dataUpdate The data to encrypt or decrypt. 126 | * 127 | * @return {WordArray} The data after processing. 128 | * 129 | * @example 130 | * 131 | * var encrypted = cipher.process('data'); 132 | * var encrypted = cipher.process(wordArray); 133 | */ 134 | process: function (dataUpdate) { 135 | // Append 136 | this._append(dataUpdate); 137 | 138 | // Process available blocks 139 | return this._process(); 140 | }, 141 | 142 | /** 143 | * Finalizes the encryption or decryption process. 144 | * Note that the finalize operation is effectively a destructive, read-once operation. 145 | * 146 | * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt. 147 | * 148 | * @return {WordArray} The data after final processing. 149 | * 150 | * @example 151 | * 152 | * var encrypted = cipher.finalize(); 153 | * var encrypted = cipher.finalize('data'); 154 | * var encrypted = cipher.finalize(wordArray); 155 | */ 156 | finalize: function (dataUpdate) { 157 | // Final data update 158 | if (dataUpdate) { 159 | this._append(dataUpdate); 160 | } 161 | 162 | // Perform concrete-cipher logic 163 | var finalProcessedData = this._doFinalize(); 164 | 165 | return finalProcessedData; 166 | }, 167 | 168 | keySize: 128/32, 169 | 170 | ivSize: 128/32, 171 | 172 | _ENC_XFORM_MODE: 1, 173 | 174 | _DEC_XFORM_MODE: 2, 175 | 176 | /** 177 | * Creates shortcut functions to a cipher's object interface. 178 | * 179 | * @param {Cipher} cipher The cipher to create a helper for. 180 | * 181 | * @return {Object} An object with encrypt and decrypt shortcut functions. 182 | * 183 | * @static 184 | * 185 | * @example 186 | * 187 | * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES); 188 | */ 189 | _createHelper: (function () { 190 | function selectCipherStrategy(key) { 191 | if (typeof key == 'string') { 192 | return PasswordBasedCipher; 193 | } else { 194 | return SerializableCipher; 195 | } 196 | } 197 | 198 | return function (cipher) { 199 | return { 200 | encrypt: function (message, key, cfg) { 201 | return selectCipherStrategy(key).encrypt(cipher, message, key, cfg); 202 | }, 203 | 204 | decrypt: function (ciphertext, key, cfg) { 205 | return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg); 206 | } 207 | }; 208 | }; 209 | }()) 210 | }); 211 | 212 | /** 213 | * Abstract base stream cipher template. 214 | * 215 | * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits) 216 | */ 217 | var StreamCipher = C_lib.StreamCipher = Cipher.extend({ 218 | _doFinalize: function () { 219 | // Process partial blocks 220 | var finalProcessedBlocks = this._process(!!'flush'); 221 | 222 | return finalProcessedBlocks; 223 | }, 224 | 225 | blockSize: 1 226 | }); 227 | 228 | /** 229 | * Mode namespace. 230 | */ 231 | var C_mode = C.mode = {}; 232 | 233 | /** 234 | * Abstract base block cipher mode template. 235 | */ 236 | var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({ 237 | /** 238 | * Creates this mode for encryption. 239 | * 240 | * @param {Cipher} cipher A block cipher instance. 241 | * @param {Array} iv The IV words. 242 | * 243 | * @static 244 | * 245 | * @example 246 | * 247 | * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words); 248 | */ 249 | createEncryptor: function (cipher, iv) { 250 | return this.Encryptor.create(cipher, iv); 251 | }, 252 | 253 | /** 254 | * Creates this mode for decryption. 255 | * 256 | * @param {Cipher} cipher A block cipher instance. 257 | * @param {Array} iv The IV words. 258 | * 259 | * @static 260 | * 261 | * @example 262 | * 263 | * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words); 264 | */ 265 | createDecryptor: function (cipher, iv) { 266 | return this.Decryptor.create(cipher, iv); 267 | }, 268 | 269 | /** 270 | * Initializes a newly created mode. 271 | * 272 | * @param {Cipher} cipher A block cipher instance. 273 | * @param {Array} iv The IV words. 274 | * 275 | * @example 276 | * 277 | * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words); 278 | */ 279 | init: function (cipher, iv) { 280 | this._cipher = cipher; 281 | this._iv = iv; 282 | } 283 | }); 284 | 285 | /** 286 | * Cipher Block Chaining mode. 287 | */ 288 | var CBC = C_mode.CBC = (function () { 289 | /** 290 | * Abstract base CBC mode. 291 | */ 292 | var CBC = BlockCipherMode.extend(); 293 | 294 | /** 295 | * CBC encryptor. 296 | */ 297 | CBC.Encryptor = CBC.extend({ 298 | /** 299 | * Processes the data block at offset. 300 | * 301 | * @param {Array} words The data words to operate on. 302 | * @param {number} offset The offset where the block starts. 303 | * 304 | * @example 305 | * 306 | * mode.processBlock(data.words, offset); 307 | */ 308 | processBlock: function (words, offset) { 309 | // Shortcuts 310 | var cipher = this._cipher; 311 | var blockSize = cipher.blockSize; 312 | 313 | // XOR and encrypt 314 | xorBlock.call(this, words, offset, blockSize); 315 | cipher.encryptBlock(words, offset); 316 | 317 | // Remember this block to use with next block 318 | this._prevBlock = words.slice(offset, offset + blockSize); 319 | } 320 | }); 321 | 322 | /** 323 | * CBC decryptor. 324 | */ 325 | CBC.Decryptor = CBC.extend({ 326 | /** 327 | * Processes the data block at offset. 328 | * 329 | * @param {Array} words The data words to operate on. 330 | * @param {number} offset The offset where the block starts. 331 | * 332 | * @example 333 | * 334 | * mode.processBlock(data.words, offset); 335 | */ 336 | processBlock: function (words, offset) { 337 | // Shortcuts 338 | var cipher = this._cipher; 339 | var blockSize = cipher.blockSize; 340 | 341 | // Remember this block to use with next block 342 | var thisBlock = words.slice(offset, offset + blockSize); 343 | 344 | // Decrypt and XOR 345 | cipher.decryptBlock(words, offset); 346 | xorBlock.call(this, words, offset, blockSize); 347 | 348 | // This block becomes the previous block 349 | this._prevBlock = thisBlock; 350 | } 351 | }); 352 | 353 | function xorBlock(words, offset, blockSize) { 354 | var block; 355 | 356 | // Shortcut 357 | var iv = this._iv; 358 | 359 | // Choose mixing block 360 | if (iv) { 361 | block = iv; 362 | 363 | // Remove IV for subsequent blocks 364 | this._iv = undefined; 365 | } else { 366 | block = this._prevBlock; 367 | } 368 | 369 | // XOR blocks 370 | for (var i = 0; i < blockSize; i++) { 371 | words[offset + i] ^= block[i]; 372 | } 373 | } 374 | 375 | return CBC; 376 | }()); 377 | 378 | /** 379 | * Padding namespace. 380 | */ 381 | var C_pad = C.pad = {}; 382 | 383 | /** 384 | * PKCS #5/7 padding strategy. 385 | */ 386 | var Pkcs7 = C_pad.Pkcs7 = { 387 | /** 388 | * Pads data using the algorithm defined in PKCS #5/7. 389 | * 390 | * @param {WordArray} data The data to pad. 391 | * @param {number} blockSize The multiple that the data should be padded to. 392 | * 393 | * @static 394 | * 395 | * @example 396 | * 397 | * CryptoJS.pad.Pkcs7.pad(wordArray, 4); 398 | */ 399 | pad: function (data, blockSize) { 400 | // Shortcut 401 | var blockSizeBytes = blockSize * 4; 402 | 403 | // Count padding bytes 404 | var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes; 405 | 406 | // Create padding word 407 | var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes; 408 | 409 | // Create padding 410 | var paddingWords = []; 411 | for (var i = 0; i < nPaddingBytes; i += 4) { 412 | paddingWords.push(paddingWord); 413 | } 414 | var padding = WordArray.create(paddingWords, nPaddingBytes); 415 | 416 | // Add padding 417 | data.concat(padding); 418 | }, 419 | 420 | /** 421 | * Unpads data that had been padded using the algorithm defined in PKCS #5/7. 422 | * 423 | * @param {WordArray} data The data to unpad. 424 | * 425 | * @static 426 | * 427 | * @example 428 | * 429 | * CryptoJS.pad.Pkcs7.unpad(wordArray); 430 | */ 431 | unpad: function (data) { 432 | // Get number of padding bytes from last byte 433 | var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff; 434 | 435 | // Remove padding 436 | data.sigBytes -= nPaddingBytes; 437 | } 438 | }; 439 | 440 | /** 441 | * Abstract base block cipher template. 442 | * 443 | * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits) 444 | */ 445 | var BlockCipher = C_lib.BlockCipher = Cipher.extend({ 446 | /** 447 | * Configuration options. 448 | * 449 | * @property {Mode} mode The block mode to use. Default: CBC 450 | * @property {Padding} padding The padding strategy to use. Default: Pkcs7 451 | */ 452 | cfg: Cipher.cfg.extend({ 453 | mode: CBC, 454 | padding: Pkcs7 455 | }), 456 | 457 | reset: function () { 458 | var modeCreator; 459 | 460 | // Reset cipher 461 | Cipher.reset.call(this); 462 | 463 | // Shortcuts 464 | var cfg = this.cfg; 465 | var iv = cfg.iv; 466 | var mode = cfg.mode; 467 | 468 | // Reset block mode 469 | if (this._xformMode == this._ENC_XFORM_MODE) { 470 | modeCreator = mode.createEncryptor; 471 | } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { 472 | modeCreator = mode.createDecryptor; 473 | // Keep at least one block in the buffer for unpadding 474 | this._minBufferSize = 1; 475 | } 476 | 477 | if (this._mode && this._mode.__creator == modeCreator) { 478 | this._mode.init(this, iv && iv.words); 479 | } else { 480 | this._mode = modeCreator.call(mode, this, iv && iv.words); 481 | this._mode.__creator = modeCreator; 482 | } 483 | }, 484 | 485 | _doProcessBlock: function (words, offset) { 486 | this._mode.processBlock(words, offset); 487 | }, 488 | 489 | _doFinalize: function () { 490 | var finalProcessedBlocks; 491 | 492 | // Shortcut 493 | var padding = this.cfg.padding; 494 | 495 | // Finalize 496 | if (this._xformMode == this._ENC_XFORM_MODE) { 497 | // Pad data 498 | padding.pad(this._data, this.blockSize); 499 | 500 | // Process final blocks 501 | finalProcessedBlocks = this._process(!!'flush'); 502 | } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ { 503 | // Process final blocks 504 | finalProcessedBlocks = this._process(!!'flush'); 505 | 506 | // Unpad data 507 | padding.unpad(finalProcessedBlocks); 508 | } 509 | 510 | return finalProcessedBlocks; 511 | }, 512 | 513 | blockSize: 128/32 514 | }); 515 | 516 | /** 517 | * A collection of cipher parameters. 518 | * 519 | * @property {WordArray} ciphertext The raw ciphertext. 520 | * @property {WordArray} key The key to this ciphertext. 521 | * @property {WordArray} iv The IV used in the ciphering operation. 522 | * @property {WordArray} salt The salt used with a key derivation function. 523 | * @property {Cipher} algorithm The cipher algorithm. 524 | * @property {Mode} mode The block mode used in the ciphering operation. 525 | * @property {Padding} padding The padding scheme used in the ciphering operation. 526 | * @property {number} blockSize The block size of the cipher. 527 | * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string. 528 | */ 529 | var CipherParams = C_lib.CipherParams = Base.extend({ 530 | /** 531 | * Initializes a newly created cipher params object. 532 | * 533 | * @param {Object} cipherParams An object with any of the possible cipher parameters. 534 | * 535 | * @example 536 | * 537 | * var cipherParams = CryptoJS.lib.CipherParams.create({ 538 | * ciphertext: ciphertextWordArray, 539 | * key: keyWordArray, 540 | * iv: ivWordArray, 541 | * salt: saltWordArray, 542 | * algorithm: CryptoJS.algo.AES, 543 | * mode: CryptoJS.mode.CBC, 544 | * padding: CryptoJS.pad.PKCS7, 545 | * blockSize: 4, 546 | * formatter: CryptoJS.format.OpenSSL 547 | * }); 548 | */ 549 | init: function (cipherParams) { 550 | this.mixIn(cipherParams); 551 | }, 552 | 553 | /** 554 | * Converts this cipher params object to a string. 555 | * 556 | * @param {Format} formatter (Optional) The formatting strategy to use. 557 | * 558 | * @return {string} The stringified cipher params. 559 | * 560 | * @throws Error If neither the formatter nor the default formatter is set. 561 | * 562 | * @example 563 | * 564 | * var string = cipherParams + ''; 565 | * var string = cipherParams.toString(); 566 | * var string = cipherParams.toString(CryptoJS.format.OpenSSL); 567 | */ 568 | toString: function (formatter) { 569 | return (formatter || this.formatter).stringify(this); 570 | } 571 | }); 572 | 573 | /** 574 | * Format namespace. 575 | */ 576 | var C_format = C.format = {}; 577 | 578 | /** 579 | * OpenSSL formatting strategy. 580 | */ 581 | var OpenSSLFormatter = C_format.OpenSSL = { 582 | /** 583 | * Converts a cipher params object to an OpenSSL-compatible string. 584 | * 585 | * @param {CipherParams} cipherParams The cipher params object. 586 | * 587 | * @return {string} The OpenSSL-compatible string. 588 | * 589 | * @static 590 | * 591 | * @example 592 | * 593 | * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams); 594 | */ 595 | stringify: function (cipherParams) { 596 | var wordArray; 597 | 598 | // Shortcuts 599 | var ciphertext = cipherParams.ciphertext; 600 | var salt = cipherParams.salt; 601 | 602 | // Format 603 | if (salt) { 604 | wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext); 605 | } else { 606 | wordArray = ciphertext; 607 | } 608 | 609 | return wordArray.toString(Base64); 610 | }, 611 | 612 | /** 613 | * Converts an OpenSSL-compatible string to a cipher params object. 614 | * 615 | * @param {string} openSSLStr The OpenSSL-compatible string. 616 | * 617 | * @return {CipherParams} The cipher params object. 618 | * 619 | * @static 620 | * 621 | * @example 622 | * 623 | * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString); 624 | */ 625 | parse: function (openSSLStr) { 626 | var salt; 627 | 628 | // Parse base64 629 | var ciphertext = Base64.parse(openSSLStr); 630 | 631 | // Shortcut 632 | var ciphertextWords = ciphertext.words; 633 | 634 | // Test for salt 635 | if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) { 636 | // Extract salt 637 | salt = WordArray.create(ciphertextWords.slice(2, 4)); 638 | 639 | // Remove salt from ciphertext 640 | ciphertextWords.splice(0, 4); 641 | ciphertext.sigBytes -= 16; 642 | } 643 | 644 | return CipherParams.create({ ciphertext: ciphertext, salt: salt }); 645 | } 646 | }; 647 | 648 | /** 649 | * A cipher wrapper that returns ciphertext as a serializable cipher params object. 650 | */ 651 | var SerializableCipher = C_lib.SerializableCipher = Base.extend({ 652 | /** 653 | * Configuration options. 654 | * 655 | * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL 656 | */ 657 | cfg: Base.extend({ 658 | format: OpenSSLFormatter 659 | }), 660 | 661 | /** 662 | * Encrypts a message. 663 | * 664 | * @param {Cipher} cipher The cipher algorithm to use. 665 | * @param {WordArray|string} message The message to encrypt. 666 | * @param {WordArray} key The key. 667 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 668 | * 669 | * @return {CipherParams} A cipher params object. 670 | * 671 | * @static 672 | * 673 | * @example 674 | * 675 | * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key); 676 | * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv }); 677 | * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL }); 678 | */ 679 | encrypt: function (cipher, message, key, cfg) { 680 | // Apply config defaults 681 | cfg = this.cfg.extend(cfg); 682 | 683 | // Encrypt 684 | var encryptor = cipher.createEncryptor(key, cfg); 685 | var ciphertext = encryptor.finalize(message); 686 | 687 | // Shortcut 688 | var cipherCfg = encryptor.cfg; 689 | 690 | // Create and return serializable cipher params 691 | return CipherParams.create({ 692 | ciphertext: ciphertext, 693 | key: key, 694 | iv: cipherCfg.iv, 695 | algorithm: cipher, 696 | mode: cipherCfg.mode, 697 | padding: cipherCfg.padding, 698 | blockSize: cipher.blockSize, 699 | formatter: cfg.format 700 | }); 701 | }, 702 | 703 | /** 704 | * Decrypts serialized ciphertext. 705 | * 706 | * @param {Cipher} cipher The cipher algorithm to use. 707 | * @param {CipherParams|string} ciphertext The ciphertext to decrypt. 708 | * @param {WordArray} key The key. 709 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 710 | * 711 | * @return {WordArray} The plaintext. 712 | * 713 | * @static 714 | * 715 | * @example 716 | * 717 | * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL }); 718 | * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL }); 719 | */ 720 | decrypt: function (cipher, ciphertext, key, cfg) { 721 | // Apply config defaults 722 | cfg = this.cfg.extend(cfg); 723 | 724 | // Convert string to CipherParams 725 | ciphertext = this._parse(ciphertext, cfg.format); 726 | 727 | // Decrypt 728 | var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext); 729 | 730 | return plaintext; 731 | }, 732 | 733 | /** 734 | * Converts serialized ciphertext to CipherParams, 735 | * else assumed CipherParams already and returns ciphertext unchanged. 736 | * 737 | * @param {CipherParams|string} ciphertext The ciphertext. 738 | * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext. 739 | * 740 | * @return {CipherParams} The unserialized ciphertext. 741 | * 742 | * @static 743 | * 744 | * @example 745 | * 746 | * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format); 747 | */ 748 | _parse: function (ciphertext, format) { 749 | if (typeof ciphertext == 'string') { 750 | return format.parse(ciphertext, this); 751 | } else { 752 | return ciphertext; 753 | } 754 | } 755 | }); 756 | 757 | /** 758 | * Key derivation function namespace. 759 | */ 760 | var C_kdf = C.kdf = {}; 761 | 762 | /** 763 | * OpenSSL key derivation function. 764 | */ 765 | var OpenSSLKdf = C_kdf.OpenSSL = { 766 | /** 767 | * Derives a key and IV from a password. 768 | * 769 | * @param {string} password The password to derive from. 770 | * @param {number} keySize The size in words of the key to generate. 771 | * @param {number} ivSize The size in words of the IV to generate. 772 | * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly. 773 | * 774 | * @return {CipherParams} A cipher params object with the key, IV, and salt. 775 | * 776 | * @static 777 | * 778 | * @example 779 | * 780 | * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32); 781 | * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt'); 782 | */ 783 | execute: function (password, keySize, ivSize, salt) { 784 | // Generate random salt 785 | if (!salt) { 786 | salt = WordArray.random(64/8); 787 | } 788 | 789 | // Derive key and IV 790 | var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt); 791 | 792 | // Separate key and IV 793 | var iv = WordArray.create(key.words.slice(keySize), ivSize * 4); 794 | key.sigBytes = keySize * 4; 795 | 796 | // Return params 797 | return CipherParams.create({ key: key, iv: iv, salt: salt }); 798 | } 799 | }; 800 | 801 | /** 802 | * A serializable cipher wrapper that derives the key from a password, 803 | * and returns ciphertext as a serializable cipher params object. 804 | */ 805 | var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({ 806 | /** 807 | * Configuration options. 808 | * 809 | * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL 810 | */ 811 | cfg: SerializableCipher.cfg.extend({ 812 | kdf: OpenSSLKdf 813 | }), 814 | 815 | /** 816 | * Encrypts a message using a password. 817 | * 818 | * @param {Cipher} cipher The cipher algorithm to use. 819 | * @param {WordArray|string} message The message to encrypt. 820 | * @param {string} password The password. 821 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 822 | * 823 | * @return {CipherParams} A cipher params object. 824 | * 825 | * @static 826 | * 827 | * @example 828 | * 829 | * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password'); 830 | * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL }); 831 | */ 832 | encrypt: function (cipher, message, password, cfg) { 833 | // Apply config defaults 834 | cfg = this.cfg.extend(cfg); 835 | 836 | // Derive key and other params 837 | var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize); 838 | 839 | // Add IV to config 840 | cfg.iv = derivedParams.iv; 841 | 842 | // Encrypt 843 | var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg); 844 | 845 | // Mix in derived params 846 | ciphertext.mixIn(derivedParams); 847 | 848 | return ciphertext; 849 | }, 850 | 851 | /** 852 | * Decrypts serialized ciphertext using a password. 853 | * 854 | * @param {Cipher} cipher The cipher algorithm to use. 855 | * @param {CipherParams|string} ciphertext The ciphertext to decrypt. 856 | * @param {string} password The password. 857 | * @param {Object} cfg (Optional) The configuration options to use for this operation. 858 | * 859 | * @return {WordArray} The plaintext. 860 | * 861 | * @static 862 | * 863 | * @example 864 | * 865 | * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL }); 866 | * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL }); 867 | */ 868 | decrypt: function (cipher, ciphertext, password, cfg) { 869 | // Apply config defaults 870 | cfg = this.cfg.extend(cfg); 871 | 872 | // Convert string to CipherParams 873 | ciphertext = this._parse(ciphertext, cfg.format); 874 | 875 | // Derive key and other params 876 | var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt); 877 | 878 | // Add IV to config 879 | cfg.iv = derivedParams.iv; 880 | 881 | // Decrypt 882 | var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg); 883 | 884 | return plaintext; 885 | } 886 | }); 887 | }()); 888 | 889 | 890 | })); -------------------------------------------------------------------------------- /demo-files/city-houses-village-buildings.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/city-houses-village-buildings.jpg -------------------------------------------------------------------------------- /demo-files/construction-work-carpenter-tools.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/construction-work-carpenter-tools.jpg -------------------------------------------------------------------------------- /demo-files/folder test/black-and-white-art-building-window.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/folder test/black-and-white-art-building-window.jpeg -------------------------------------------------------------------------------- /demo-files/nature/dawn-nature-sunset-trees.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/dawn-nature-sunset-trees.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/bench-forest-trees-path.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/bench-forest-trees-path.jpeg -------------------------------------------------------------------------------- /demo-files/nature/forest/nature-forest-ground-dangerous.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/nature-forest-ground-dangerous.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/nature-forest-trees-environment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/nature-forest-trees-environment.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/wood-nature-forest-bridge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/wood-nature-forest-bridge.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/wood-nature-forest-trees.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/wood-nature-forest-trees.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/wood-nature-sun-forest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/wood-nature-sun-forest.jpg -------------------------------------------------------------------------------- /demo-files/nature/forest/wood-nature-sunny-forest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/forest/wood-nature-sunny-forest.jpg -------------------------------------------------------------------------------- /demo-files/nature/landing-stage-sea-nature-beach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/landing-stage-sea-nature-beach.jpg -------------------------------------------------------------------------------- /demo-files/nature/landscape-mountains-nature-hills.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/landscape-mountains-nature-hills.jpeg -------------------------------------------------------------------------------- /demo-files/nature/landscape-nature-man-person.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/landscape-nature-man-person.jpeg -------------------------------------------------------------------------------- /demo-files/nature/landscape-nature-sky-sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/landscape-nature-sky-sunset.jpg -------------------------------------------------------------------------------- /demo-files/nature/nature-plant-leaf-drop-of-water.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/nature-plant-leaf-drop-of-water.jpeg -------------------------------------------------------------------------------- /demo-files/nature/nature-sky-sunset-sun.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/nature-sky-sunset-sun.jpg -------------------------------------------------------------------------------- /demo-files/nature/pexels-photo (1).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/pexels-photo (1).jpeg -------------------------------------------------------------------------------- /demo-files/nature/pexels-photo (2).jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/pexels-photo (2).jpeg -------------------------------------------------------------------------------- /demo-files/nature/pexels-photo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/pexels-photo.jpeg -------------------------------------------------------------------------------- /demo-files/nature/pexels-photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/pexels-photo.jpg -------------------------------------------------------------------------------- /demo-files/nature/snow-mountains-nature-summer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/snow-mountains-nature-summer.jpg -------------------------------------------------------------------------------- /demo-files/nature/streets-landscape-mountains-nature.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/streets-landscape-mountains-nature.jpg -------------------------------------------------------------------------------- /demo-files/nature/water-summer-island-vibes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/water-summer-island-vibes.jpg -------------------------------------------------------------------------------- /demo-files/nature/water-sunrise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/nature/water-sunrise.jpg -------------------------------------------------------------------------------- /demo-files/open-office-document.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/open-office-document.odt -------------------------------------------------------------------------------- /demo-files/pdf-document.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/pdf-document.pdf -------------------------------------------------------------------------------- /demo-files/unknown file.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://www.phpcrudgenerator.com/ 3 | -------------------------------------------------------------------------------- /demo-files/web-page.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/web-page.html -------------------------------------------------------------------------------- /demo-files/word-document.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/demo-files/word-document.doc -------------------------------------------------------------------------------- /dist/ajax/move-file.php: -------------------------------------------------------------------------------- 1 | $value) { 5 | $$key = urldecode(stripslashes($_POST[$key])); 6 | } 7 | $ext = json_decode($ext); 8 | $authorized_ext = array_values($ext); 9 | 10 | if (!isset($filename)|| 11 | !isset($filepath) || 12 | !isset($destpath) || 13 | !isset($filehash) || 14 | !preg_match('`[a-z0-9]+`', $filehash) || 15 | preg_match('`\.\.|\*`', $filepath) || 16 | preg_match('`\.\.|\*`', $destpath)) { 17 | exit('1'); 18 | } 19 | 20 | $salt = '%t$qPP'; 21 | if (hash('sha256', $filepath . $salt) !== $filehash) { 22 | exit('2'); 23 | } 24 | 25 | $rootfilepath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $root . $filepath); 26 | $rootdestpath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $root . $destpath); 27 | 28 | if (!file_exists(($rootfilepath))) { 29 | exit('3'); 30 | } 31 | if(!is_authorized($filename, $authorized_ext)) { 32 | exit('4'); 33 | } 34 | 35 | // Security checks ok 36 | 37 | $out = array(); 38 | 39 | if (!@copy ($rootfilepath , $rootdestpath)) { 40 | $out = array( 41 | 'status' => 'danger', 42 | 'msg' => 'Failed to copy ' . $rootdestpath 43 | ); 44 | } else { 45 | if (file_exists($rootfilepath)) { 46 | if (!@unlink($rootfilepath)) { 47 | $out = array( 48 | 'status' => 'danger', 49 | 'msg' => 'Failed to delete ' . $rootfilepath 50 | ); 51 | } else { 52 | $out = array( 53 | 'status' => 'success', 54 | 'msg' => '' 55 | ); 56 | } 57 | } else { 58 | $out = array( 59 | 'status' => 'danger', 60 | 'msg' => 'file doesn\'t exist' 61 | ); 62 | } 63 | } 64 | 65 | echo json_encode($out); 66 | 67 | function is_authorized($file, $authorized_ext) { 68 | $ext = '.' . pathinfo($file, PATHINFO_EXTENSION); 69 | if ($authorized_ext[0] === '.*' || in_array($ext, $authorized_ext)) { 70 | return true; 71 | } 72 | 73 | return false; 74 | } 75 | -------------------------------------------------------------------------------- /dist/connectors/connector.php: -------------------------------------------------------------------------------- 1 | 0) && @is_dir($source_dir.$file)) { 49 | $filedata[$folder_prefix . $file] = scan_recursively($source_dir.$file.'/', $authorized_ext, $folder_prefix, $new_depth, $hidden); 50 | } else if(is_authorized($file, $authorized_ext)) { 51 | $filedata[] = array( 52 | 'ext' => pathinfo($file, PATHINFO_EXTENSION), 53 | 'name' => $file, 54 | 'size' => filesize($source_dir.$file) 55 | ); 56 | } 57 | } 58 | 59 | closedir($fp); 60 | return $filedata; 61 | } 62 | echo 'can not open dir'; 63 | return false; 64 | } 65 | 66 | function is_authorized($file, $authorized_ext) { 67 | $ext = '.' . pathinfo($file, PATHINFO_EXTENSION); 68 | if ($authorized_ext[0] === '.*' || in_array($ext, $authorized_ext)) { 69 | return true; 70 | } 71 | 72 | return false; 73 | } 74 | -------------------------------------------------------------------------------- /dist/icons/fonts/file-tree-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/dist/icons/fonts/file-tree-icons.eot -------------------------------------------------------------------------------- /dist/icons/fonts/file-tree-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /dist/icons/fonts/file-tree-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/dist/icons/fonts/file-tree-icons.ttf -------------------------------------------------------------------------------- /dist/icons/fonts/file-tree-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/dist/icons/fonts/file-tree-icons.woff -------------------------------------------------------------------------------- /dist/icons/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'file-tree-icons'; 3 | src: url('fonts/file-tree-icons.eot?117yyb'); 4 | src: url('fonts/file-tree-icons.eot?117yyb#iefix') format('embedded-opentype'), 5 | url('fonts/file-tree-icons.ttf?117yyb') format('truetype'), 6 | url('fonts/file-tree-icons.woff?117yyb') format('woff'), 7 | url('fonts/file-tree-icons.svg?117yyb#file-tree-icons') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | [class^="ft-icon-"], [class*=" ft-icon-"] { 14 | /* use !important to prevent issues with browser extensions that change fonts */ 15 | font-family: 'file-tree-icons' !important; 16 | speak: none; 17 | font-style: normal; 18 | font-weight: normal; 19 | font-variant: normal; 20 | text-transform: none; 21 | line-height: 1; 22 | 23 | /* Better Font Rendering =========== */ 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | } 27 | 28 | .ft-icon-grid:before { 29 | content: "\e900"; 30 | } 31 | .ft-icon-file-empty:before { 32 | content: "\e924"; 33 | } 34 | .ft-icon-file-text2:before { 35 | content: "\e926"; 36 | } 37 | .ft-icon-file-picture:before { 38 | content: "\e927"; 39 | } 40 | .ft-icon-file-music:before { 41 | content: "\e928"; 42 | } 43 | .ft-icon-file-video:before { 44 | content: "\e92a"; 45 | } 46 | .ft-icon-file-zip:before { 47 | content: "\e92b"; 48 | } 49 | .ft-icon-folder:before { 50 | content: "\e92f"; 51 | } 52 | .ft-icon-folder-open:before { 53 | content: "\e930"; 54 | } 55 | .ft-icon-list:before { 56 | content: "\e9ba"; 57 | } 58 | .ft-icon-blocked:before { 59 | content: "\ea0e"; 60 | } 61 | .ft-icon-checkmark:before { 62 | content: "\ea10"; 63 | } 64 | .ft-icon-file-pdf:before { 65 | content: "\eadf"; 66 | } 67 | .ft-icon-file-openoffice:before { 68 | content: "\eae0"; 69 | } 70 | .ft-icon-file-word:before { 71 | content: "\eae1"; 72 | } 73 | .ft-icon-file-excel:before { 74 | content: "\eae2"; 75 | } 76 | .ft-icon-html-five2:before { 77 | content: "\eae5"; 78 | } 79 | -------------------------------------------------------------------------------- /dist/js/file-tree-browser.js: -------------------------------------------------------------------------------- 1 | (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i { 68 | this.jsonTree = JSON.parse(data); 69 | if (this.jsonTree.error) { 70 | throw this.jsonTree.error; 71 | } 72 | this.buildTree(); 73 | if (this.options.dragAndDrop === true) { 74 | if (typeof (CryptoJS) === "undefined") { 75 | this.loadScript(this.scriptSrc + 'lib/crypto-js/crypto-js.min.js'); 76 | } 77 | if (typeof (sortable) === "undefined") { 78 | this.loadScript(this.scriptSrc + 'lib/html5sortable/html5sortable.min.js').then(() => { 79 | this.render(); 80 | }) 81 | .catch(() => { 82 | console.error('Script loading failed :( '); 83 | }); 84 | } 85 | else { 86 | this.render(); 87 | } 88 | } 89 | else { 90 | this.render(); 91 | } 92 | }) 93 | .catch((err) => { 94 | console.error('Augh, there was an error!', err); 95 | }); 96 | } 97 | render() { 98 | const $targetId = document.getElementById(this.targetId); 99 | this.loadCss(); 100 | $targetId.querySelectorAll('.ft-tree')[0].innerHTML = this.treeMarkup; 101 | const folders = $targetId.querySelectorAll('.ft-tree .ft-folder-container'); 102 | Array.prototype.forEach.call(folders, (el) => { 103 | el.addEventListener('click', (e) => { 104 | e.preventDefault(); 105 | e.stopPropagation(); 106 | // get all the parent folders 107 | const parents = this.parentsUntil(el, 'ft-folder-container', 'ft-' + this.targetId + '-root'); 108 | // open all the parent folders, close the others 109 | Array.prototype.forEach.call(folders, (folder) => { 110 | const ic = folder.querySelector('i'); 111 | if (parents.indexOf(folder) > -1) { 112 | folder.classList.add('ft-folder-open'); 113 | ic.classList.remove(this.icons.folder); 114 | ic.classList.add(this.icons.folderOpen); 115 | } 116 | else { 117 | folder.classList.remove('ft-folder-open'); 118 | ic.classList.add(this.icons.folder); 119 | ic.classList.remove(this.icons.folderOpen); 120 | } 121 | }); 122 | this.currentFolderId = el.getAttribute('id'); 123 | this.loadFolder(this.currentFolderId); 124 | return false; 125 | }); 126 | }); 127 | // load the root folder explorer content 128 | this.currentFolderId = 'ft-' + this.targetId + '-root'; 129 | this.loadFolder(this.currentFolderId); 130 | } 131 | /** 132 | * Load js-tree + icon lib CSS 133 | */ 134 | loadCss() { 135 | const ftIcons = document.getElementById('ft-icons'); 136 | if (ftIcons == undefined) { 137 | const linkElement = document.createElement('link'); 138 | linkElement.setAttribute('id', 'ft-icons'); 139 | linkElement.setAttribute('rel', 'stylesheet'); 140 | linkElement.setAttribute('type', 'text/css'); 141 | linkElement.setAttribute('href', this.scriptSrc + 'icons/style.css'); 142 | document.getElementsByTagName('head')[0].appendChild(linkElement); 143 | } 144 | const ftCss = document.getElementById('ft-styles'); 145 | if (ftCss == undefined) { 146 | const linkElement = document.createElement('link'); 147 | linkElement.setAttribute('id', 'ft-styles'); 148 | linkElement.setAttribute('rel', 'stylesheet'); 149 | linkElement.setAttribute('type', 'text/css'); 150 | linkElement.setAttribute('href', this.scriptSrc + 'templates/' + this.options.template + '.css'); 151 | document.getElementsByTagName('head')[0].appendChild(linkElement); 152 | } 153 | } 154 | loadScript(src) { 155 | const script = document.createElement('script'); 156 | script.setAttribute('src', src); 157 | document.body.appendChild(script); 158 | return new Promise((res, rej) => { 159 | script.onload = function () { 160 | res(null); 161 | }; 162 | script.onerror = function (e) { 163 | rej(e); 164 | }; 165 | }); 166 | } 167 | buildFolderContent(jst, url, deph) { 168 | const folderContent = { 169 | folders: [], 170 | files: [] 171 | }; 172 | for (let key in jst) { 173 | let value = jst[key]; 174 | if (typeof (value.ext) === 'undefined') { 175 | // directory 176 | let data = jst[key]; 177 | const folderName = key.replace(this.options.folderPrefix, ''); 178 | folderContent.folders.push({ 179 | parent: data.parent, 180 | dataRefId: this.sanitizeFolderOrFile(key, 'folder') + '-' + (deph + 1).toString(), 181 | name: folderName, 182 | url: url + folderName + '/' 183 | }); 184 | } 185 | else { 186 | // file 187 | const filedata = value; 188 | Object.assign(filedata, { type: this.getFileType(filedata.ext) }); 189 | const icon = this.icons[filedata.type]; 190 | if (filedata.type === 'image') { 191 | folderContent.files.push({ 192 | name: filedata.name, 193 | icon: icon, 194 | type: filedata.type, 195 | url: url + filedata.name, 196 | width: null, 197 | height: null 198 | }); 199 | } 200 | else { 201 | folderContent.files.push({ 202 | name: filedata.name, 203 | icon: icon, 204 | size: filedata.size, 205 | type: filedata.type, 206 | url: url + filedata.name 207 | }); 208 | } 209 | } 210 | } 211 | return folderContent; 212 | } 213 | buildTree(jst = this.jsonTree, url = this.options.mainDir + '/', deph = 0) { 214 | if (deph === 0) { 215 | const rootId = 'ft-' + this.targetId + '-root'; 216 | this.treeMarkup = ``; 236 | } 237 | } 238 | enableDrag() { 239 | let explorerContainerSelector = '.ft-explorer-list-container'; 240 | if (this.options.explorerMode === 'grid') { 241 | explorerContainerSelector = '.ft-explorer-grid-container'; 242 | } 243 | let folders = document.getElementById(this.targetId).querySelectorAll('.ft-folder-container'); 244 | sortable(explorerContainerSelector, { 245 | items: '.ft-file-container', 246 | acceptFrom: false 247 | }); 248 | folders.forEach((folder) => { 249 | const folderId = folder.getAttribute('id'); 250 | // console.warn(folderId + ' => ' + this.currentFolderId); 251 | if (this.listeningFolders.indexOf(folderId) === -1 || folderId.match(/^explorer-/)) { 252 | if (folderId !== this.currentFolderId) { 253 | sortable('#' + folderId, { 254 | acceptFrom: '.ft-explorer-list-container, .ft-explorer-grid-container' 255 | }); 256 | this.listeningFolders.push(folderId); 257 | // console.log('listening #' + folderId); 258 | sortable('#' + folderId)[0].addEventListener('sortupdate', this.moveFile.bind(this)); 259 | } 260 | else { 261 | // console.log('skip #' + folderId); 262 | } 263 | } 264 | else if (folderId === this.currentFolderId) { 265 | sortable('#' + folderId, 'disable'); 266 | // console.log('disable #' + folderId); 267 | } 268 | else { 269 | sortable('#' + folderId, 'enable'); 270 | // console.log('enable #' + folderId); 271 | } 272 | }); 273 | } 274 | moveFile(e) { 275 | for (let index = 0; index < e.detail.item.children.length; index++) { 276 | const element = e.detail.item.children[index]; 277 | if (element.dataset.filename !== undefined && element.dataset.href !== undefined) { 278 | const salt = '%t$qPP'; 279 | const filehash = encodeURIComponent(CryptoJS.SHA256(element.dataset.href + salt).toString()); 280 | const filename = encodeURIComponent(element.dataset.filename); 281 | const filepath = encodeURIComponent(element.dataset.href); 282 | const ext = encodeURIComponent(JSON.stringify(this.options.extensions)); 283 | let destpath = this.options.mainDir; 284 | if (e.detail.destination.container.id !== 'ft-' + this.targetId + '-root') { 285 | destpath = document.getElementById(e.detail.destination.container.id.replace(/^explorer-/, '')).querySelector('div[draggable="true"] > a').getAttribute('data-url'); 286 | } 287 | destpath += '/' + element.dataset.filename; 288 | destpath = encodeURIComponent(destpath); 289 | if (destpath !== filepath) { 290 | const data = `filename=${filename}&filepath=${filepath}&destpath=${destpath}&filehash=${filehash}&ext=${ext}`; 291 | index = e.detail.item.children.length - 1; 292 | // move the file on server 293 | const request = new XMLHttpRequest(); 294 | request.open('POST', this.scriptSrc + 'ajax/move-file.php', true); 295 | request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 296 | request.onload = () => { 297 | if (request.status >= 200 && request.status < 400) { 298 | // Success! 299 | const resp = JSON.parse(request.response); 300 | if (resp.status === 'success') { 301 | const container = document.getElementById(e.detail.destination.container.id); 302 | const itemIndex = e.detail.destination.index; 303 | container.children[itemIndex].parentNode.removeChild(container.children[itemIndex]); 304 | // rebuild tree 305 | this.getFiles() 306 | .then((responsedata) => { 307 | this.jsonTree = JSON.parse(responsedata); 308 | if (this.jsonTree.error) { 309 | throw this.jsonTree.error; 310 | } 311 | this.buildTree(); 312 | }) 313 | .catch((err) => { 314 | console.error('Augh, there was an error!', err); 315 | }); 316 | } 317 | else { 318 | console.error(resp); 319 | } 320 | } 321 | else { 322 | console.error('Ajax query failed'); 323 | } 324 | }; 325 | request.onerror = function () { 326 | console.error('There was a connection error of some sort'); 327 | }; 328 | request.send(data); 329 | } 330 | } 331 | } 332 | } 333 | getFileType(ext) { 334 | const x = this.extTypes; 335 | for (let key in x) { 336 | let value = x[key]; 337 | if (value.indexOf(ext) !== -1) { 338 | return key; 339 | } 340 | } 341 | return 'default'; 342 | } 343 | getFiles() { 344 | return new Promise((resolve, reject) => { 345 | let xhr = new XMLHttpRequest(); 346 | xhr.open('POST', this.scriptSrc + 'connectors/connector.' + this.options.connector, true); 347 | xhr.onload = function () { 348 | if (this.status >= 200 && this.status < 300) { 349 | resolve(xhr.response); 350 | } 351 | else { 352 | reject({ 353 | status: this.status, 354 | statusText: xhr.statusText 355 | }); 356 | } 357 | }; 358 | xhr.onerror = function () { 359 | reject({ 360 | status: this.status, 361 | statusText: xhr.statusText 362 | }); 363 | }; 364 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 365 | xhr.send('dir=' + encodeURI(this.options.mainDir) + '&ext=' + JSON.stringify(this.options.extensions) + '&folder_prefix=' + this.options.folderPrefix); 366 | }); 367 | } 368 | getScriptScr() { 369 | const sc = document.getElementsByTagName("script"); 370 | for (let idx = 0; idx < sc.length; idx++) { 371 | const s = sc.item(idx); 372 | if (s.src && s.src.match(/file-tree-browser(\.min)?\.js$/)) { 373 | return s.src.replace(/js\/file-tree-browser(\.min)?\.js$/, ''); 374 | } 375 | } 376 | } 377 | humanFileSize(bytes, si) { 378 | const thresh = si ? 1000 : 1024; 379 | if (Math.abs(bytes) < thresh) { 380 | return bytes + ' B'; 381 | } 382 | const units = si 383 | ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 384 | : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; 385 | let u = -1; 386 | do { 387 | bytes /= thresh; 388 | ++u; 389 | } while (Math.abs(bytes) >= thresh && u < units.length - 1); 390 | return bytes.toFixed(1) + ' ' + units[u]; 391 | } 392 | loadFolder(folderId) { 393 | const $targetId = document.getElementById(this.targetId); 394 | const folderContent = this.foldersContent[folderId]; 395 | let clone; 396 | let output; 397 | this.loadTemplates().then((template) => { 398 | this.template = template; 399 | const folders = folderContent.folders; 400 | const files = folderContent.files; 401 | let explorerContainer; 402 | let explorerFile; 403 | let explorerFolder; 404 | let explorerImage; 405 | let explorerActionBtns; 406 | let explorerMode; 407 | explorerActionBtns = document.querySelector('#explorer-action-btns'); 408 | const explorerActionBtnsClone = explorerActionBtns.content.cloneNode(true); 409 | explorerMode = document.querySelector('#explorer-mode'); 410 | const explorerModeClone = explorerMode.content.cloneNode(true); 411 | switch (this.options.explorerMode) { 412 | case 'list': 413 | explorerContainer = document.querySelector('#explorer-list'); 414 | explorerFile = document.querySelector('#explorer-list-file'); 415 | explorerFolder = document.querySelector('#explorer-list-folder'); 416 | explorerImage = document.querySelector('#explorer-list-image'); 417 | output = explorerContainer.content.querySelector('.ft-explorer-list-container').cloneNode(true); 418 | break; 419 | case 'grid': 420 | explorerContainer = document.querySelector('#explorer-grid'); 421 | explorerFile = document.querySelector('#explorer-grid-file'); 422 | explorerFolder = document.querySelector('#explorer-grid-folder'); 423 | explorerImage = document.querySelector('#explorer-grid-image'); 424 | output = explorerContainer.content.querySelector('.ft-explorer-grid-container').cloneNode(true); 425 | break; 426 | default: 427 | break; 428 | } 429 | for (let key in folders) { 430 | let folder = folders[key]; 431 | clone = explorerFolder.content.cloneNode(true); 432 | clone.querySelector('li').setAttribute('id', 'explorer-' + folder.dataRefId); 433 | clone.querySelector('.ft-folder').setAttribute('data-href', folder.dataRefId); 434 | clone.querySelector('.ft-folder i').classList.add(this.icons.folder); 435 | clone.querySelector('.ft-foldername').innerHTML = folder.name; 436 | output.appendChild(clone); 437 | } 438 | for (let key in files) { 439 | let file = files[key]; 440 | if (file.type === 'image') { 441 | let cloneId = Math.random().toString(36).substr(2, 9); 442 | clone = explorerImage.content.cloneNode(true); 443 | clone.querySelector('.ft-imagedesc').setAttribute('id', cloneId); 444 | clone.querySelector('.ft-image').setAttribute('data-href', file.url); 445 | clone.querySelector('.ft-image').setAttribute('data-filename', file.name); 446 | clone.querySelector('.ft-image img').setAttribute('src', file.url); 447 | clone.querySelector('.ft-imagename').innerHTML = file.name; 448 | output.appendChild(clone); 449 | let img = new Image(); 450 | img.src = file.url; 451 | img.onload = () => { 452 | let el = document.getElementById(cloneId); 453 | if (el !== null) { 454 | el.querySelector('.ft-image-size').innerHTML = img.width.toString() + 'x' + img.height.toString() + 'px'; 455 | } 456 | }; 457 | } 458 | else { 459 | clone = explorerFile.content.cloneNode(true); 460 | clone.querySelector('.ft-file').setAttribute('data-href', file.url); 461 | clone.querySelector('.ft-file').setAttribute('data-filename', file.name); 462 | clone.querySelector('.ft-file i').classList.add(file.icon); 463 | clone.querySelector('.ft-filename').innerHTML = file.name; 464 | clone.querySelector('.ft-filesize').innerHTML = this.humanFileSize(file.size, true); 465 | output.appendChild(clone); 466 | } 467 | } 468 | $targetId.querySelector('.ft-explorer').innerHTML = ''; 469 | $targetId.querySelector('.ft-explorer').appendChild(explorerModeClone); 470 | $targetId.querySelector('.ft-explorer').appendChild(output); 471 | if (this.options.okBtn === true || this.options.cancelBtn === true) { 472 | $targetId.querySelector('.ft-explorer').appendChild(explorerActionBtnsClone); 473 | if (this.options.okBtn !== true) { 474 | $targetId.querySelector('.explorer-ok-btn').remove(); 475 | } 476 | else { 477 | // translate 478 | $targetId.querySelector('.explorer-ok-btn').textContent = this.options.okBtnText; 479 | } 480 | if (this.options.cancelBtn !== true) { 481 | $targetId.querySelector('.explorer-cancel-btn').remove(); 482 | } 483 | else { 484 | // translate 485 | $targetId.querySelector('.explorer-cancel-btn').textContent = this.options.cancelBtnText; 486 | } 487 | if (this.options.okBtn === true) { 488 | $targetId.querySelector('.explorer-ok-btn').addEventListener('click', (e) => { 489 | e.preventDefault(); 490 | const target = $targetId.querySelector('.ft-file-container.active a'); 491 | if (target !== null) { 492 | const targetFilename = target.getAttribute('data-filename'); 493 | const targetHref = target.getAttribute('data-href'); 494 | this.options.okBtnClick(targetHref, targetFilename); 495 | } 496 | else { 497 | alert('Nothing selected'); 498 | } 499 | return false; 500 | }, false); 501 | } 502 | if (this.options.cancelBtn === true) { 503 | $targetId.querySelector('.explorer-cancel-btn').addEventListener('click', (e) => { 504 | e.preventDefault(); 505 | this.options.cancelBtnClick(); 506 | return false; 507 | }, false); 508 | } 509 | } 510 | const modeBtns = Array.from($targetId.querySelectorAll('.ft-explorer-mode .explorer-mode-btn')); 511 | /* add explorer mode buttons events & activate the current btn */ 512 | modeBtns.forEach(m => { 513 | if (m.getAttribute('value') === this.options.explorerMode) { 514 | m.classList.add('active'); 515 | } 516 | m.addEventListener('click', (e) => { 517 | this.switchMode(); 518 | this.loadFolder(folderId); 519 | }); 520 | }); 521 | /* add explorer elements events */ 522 | const elements = Array.from($targetId.querySelectorAll('.ft-explorer a[data-href]')); 523 | const elementContainers = Array.from($targetId.querySelectorAll('.ft-explorer .ft-file-container')); 524 | elements.forEach(el => { 525 | el.addEventListener('click', (e) => { 526 | e.preventDefault(); 527 | elementContainers.forEach(elContainer => { 528 | elContainer.classList.remove('active'); 529 | }); 530 | const target = e.target.closest('a'); 531 | if (target.closest('.ft-file-container') !== null) { 532 | target.closest('.ft-file-container').classList.add('active'); 533 | const targetFilename = target.getAttribute('data-filename'); 534 | const targetHref = target.getAttribute('data-href'); 535 | this.options.elementClick(targetHref, targetFilename, e); 536 | } 537 | return false; 538 | }, false); 539 | }); 540 | /* add explorer folder events */ 541 | const links = Array.from($targetId.querySelectorAll('.ft-explorer a.ft-folder')); 542 | links.forEach(l => { 543 | l.addEventListener('click', (e) => { 544 | e.preventDefault(); 545 | const target = e.target.closest('a'); 546 | const targetId = target.getAttribute('data-href'); 547 | if (targetId !== null) { 548 | let event = document.createEvent('HTMLEvents'); 549 | event.initEvent('click', true, false); 550 | document.getElementById(targetId).dispatchEvent(event); 551 | } 552 | return false; 553 | }, false); 554 | }); 555 | // enable files / folders drag & drop 556 | if (this.options.dragAndDrop === true) { 557 | this.enableDrag(); 558 | } 559 | }) 560 | .catch((err) => { 561 | console.error('Augh, there was an error!', err); 562 | }); 563 | } 564 | loadTemplates() { 565 | return new Promise((resolve, reject) => { 566 | if (this.template !== null) { 567 | resolve(this.template); 568 | } 569 | else { 570 | const ftMode = this.options.explorerMode; 571 | let xhr = new XMLHttpRequest(); 572 | xhr.open('GET', this.scriptSrc + 'templates/' + this.options.template + '.html', true); 573 | xhr.onload = function () { 574 | // console.log(xhr.response); 575 | if (this.status >= 200 && this.status < 300) { 576 | if (document.querySelectorAll('#explorer-' + ftMode).length < 1) { 577 | const div = document.createElement('div'); 578 | div.innerHTML = xhr.response; 579 | while (div.children.length > 0) { 580 | document.body.appendChild(div.children[0]); 581 | } 582 | } 583 | resolve(xhr.response); 584 | } 585 | else { 586 | reject({ 587 | status: this.status, 588 | statusText: xhr.statusText 589 | }); 590 | } 591 | }; 592 | xhr.onerror = function () { 593 | reject({ 594 | status: this.status, 595 | statusText: xhr.statusText 596 | }); 597 | }; 598 | xhr.send(); 599 | } 600 | }); 601 | } 602 | parentsUntil(el, searchClass, stopElementId) { 603 | const Parents = new Array(); 604 | while (el.parentNode) { 605 | if (el.classList.contains(searchClass)) { 606 | Parents.push(el); 607 | } 608 | el = el.parentNode; 609 | if (el.id === stopElementId) { 610 | Parents.push(el); 611 | return Parents; 612 | } 613 | } 614 | return Parents; 615 | } 616 | /** 617 | * @description Sanitizes a folder or file name to work with #name of legacy system 618 | * Legacy system unknown 619 | * @author BM67 620 | * @param {String} name The string to sanitize 621 | * @param {String} type Optional "file" or default is assumed "folder" 622 | * @return {String} The sanitized name 623 | */ 624 | sanitizeFolderOrFile(name, type) { 625 | var parts, ext = ""; 626 | if (type === "file") { 627 | parts = name.split("."); 628 | ext = "." + parts.pop(); 629 | name = parts.join("_"); 630 | } 631 | name = name.toLowerCase(); 632 | const items = [ 633 | [/[+\&]/g, "u"], 634 | [/ä/g, "ae"], 635 | [/ö/g, "oe"], 636 | [/ü/g, "ue"], 637 | [/ß/g, "ss"], 638 | [/[ \`\´\?\(\)\[\]\{\}\/\\$\§\"\'\!\=\-\.\,\;\:<>\|\^\°\*\+\~\%]/g, "_"] 639 | ]; 640 | items.forEach(item => name = name.replace(item[0], item[1])); 641 | return name + ext; 642 | } 643 | switchMode() { 644 | if (this.options.explorerMode === 'list') { 645 | this.options.explorerMode = 'grid'; 646 | } 647 | else { 648 | this.options.explorerMode = 'list'; 649 | } 650 | for (let index = 0; index < this.listeningFolders.length; index++) { 651 | if (this.listeningFolders[index].match(/^explorer-/)) { 652 | this.listeningFolders.splice(index, 1); 653 | } 654 | } 655 | } 656 | } 657 | Object.assign(window, { FileTreeBrowser }); 658 | 659 | },{}]},{},[1]) 660 | 661 | //# sourceMappingURL=file-tree-browser.js.map 662 | -------------------------------------------------------------------------------- /dist/lib/html5sortable/html5sortable.min.js: -------------------------------------------------------------------------------- 1 | var sortable=function(){"use strict";function c(e,t,n){if(void 0===n)return e&&e.h5s&&e.h5s.data&&e.h5s.data[t];e.h5s=e.h5s||{},e.h5s.data=e.h5s.data||{},e.h5s.data[t]=n}var v=function(e,t){if(!(e instanceof NodeList||e instanceof HTMLCollection||e instanceof Array))throw new Error("You must provide a nodeList/HTMLCollection/Array of elements to be filtered.");return"string"!=typeof t?Array.from(e):Array.from(e).filter(function(e){return 1===e.nodeType&&e.matches(t)})},w=new Map,t=function(){function e(){this._config=new Map,this._placeholder=void 0,this._data=new Map}return Object.defineProperty(e.prototype,"config",{get:function(){var n={};return this._config.forEach(function(e,t){n[t]=e}),n},set:function(e){if("object"!=typeof e)throw new Error("You must provide a valid configuration object to the config setter.");var t=Object.assign({},e);this._config=new Map(Object.entries(t))},enumerable:!0,configurable:!0}),e.prototype.setConfig=function(e,t){if(!this._config.has(e))throw new Error("Trying to set invalid configuration item: "+e);this._config.set(e,t)},e.prototype.getConfig=function(e){if(!this._config.has(e))throw new Error("Invalid configuration item requested: "+e);return this._config.get(e)},Object.defineProperty(e.prototype,"placeholder",{get:function(){return this._placeholder},set:function(e){if(!(e instanceof HTMLElement)&&null!==e)throw new Error("A placeholder must be an html element or null.");this._placeholder=e},enumerable:!0,configurable:!0}),e.prototype.setData=function(e,t){if("string"!=typeof e)throw new Error("The key must be a string.");this._data.set(e,t)},e.prototype.getData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.get(e)},e.prototype.deleteData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.delete(e)},e}(),y=function(e){if(!(e instanceof HTMLElement))throw new Error("Please provide a sortable to the store function.");return w.has(e)||w.set(e,new t),w.get(e)};function a(e,t,n){if(e instanceof Array)for(var r=0;r':t=document.createElement("div")),"string"==typeof n&&(r=t.classList).add.apply(r,n.split(" ")),t},C=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return["height","padding-top","padding-bottom"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},M=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return["width","padding-left","padding-right"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},s=function(e,t){if(!(e instanceof Array))throw new Error("You must provide a Array of HTMLElements to be filtered.");return"string"!=typeof t?e:e.filter(function(e){return e.querySelector(t)instanceof HTMLElement||e.shadowRoot&&e.shadowRoot.querySelector(t)instanceof HTMLElement}).map(function(e){return e.querySelector(t)||e.shadowRoot&&e.shadowRoot.querySelector(t)})},p=function(e){return e.composedPath&&e.composedPath()[0]||e.target},m=function(e,t,n){return{element:e,posX:n.pageX-t.left,posY:n.pageY-t.top}},h=function(e,t,n){if(!(e instanceof Event))throw new Error("setDragImage requires a DragEvent as the first argument.");if(!(t instanceof HTMLElement))throw new Error("setDragImage requires the dragged element as the second argument.");if(n||(n=m),e.dataTransfer&&e.dataTransfer.setDragImage){var r=n(t,E(t),e);if(!(r.element instanceof HTMLElement)||"number"!=typeof r.posX||"number"!=typeof r.posY)throw new Error("The customDragImage function you provided must return and object with the properties element[string], posX[integer], posY[integer].");e.dataTransfer.effectAllowed="copyMove",e.dataTransfer.setData("text/plain",p(e).id),e.dataTransfer.setDragImage(r.element,r.posX,r.posY)}},x=function(e,t){if(!0===e.isSortable){var n=y(e).getConfig("acceptFrom");if(null!==n&&!1!==n&&"string"!=typeof n)throw new Error('HTML5Sortable: Wrong argument, "acceptFrom" must be "null", "false", or a valid selector string.');if(null!==n)return!1!==n&&0=parseInt(r.maxItems)&&H.parentElement!==n||(e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect=!0===y(n).getConfig("copy")?"copy":"move",o(n,t,e.pageX,e.pageY))}};a(t.concat(s),"dragover",r),a(t.concat(s),"dragenter",r)}),e)}return k.destroy=function(e){var t,n,r,o;n=c(t=e,"opts")||{},r=v(t.children,n.items),o=s(r,n.handle),i(t,"dragover"),i(t,"dragenter"),i(t,"dragstart"),i(t,"dragend"),i(t,"drop"),j(t),i(o,"mousedown"),g(r),F(r),t.isSortable=!1},k.enable=function(e){X(e)},k.disable=function(e){var t,n,r,o;n=c(t=e,"opts"),r=v(t.children,n.items),o=s(r,n.handle),l(t,"aria-dropeffect","none"),c(t,"_disabled","true"),l(o,"draggable","false"),i(o,"mousedown")},k.__testing={_data:c,_removeItemEvents:g,_removeItemData:F,_removeSortableData:j},k}(); 2 | //# sourceMappingURL=html5sortable.min.js.map 3 | -------------------------------------------------------------------------------- /dist/templates/bootstrap4.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --active-background: #dee2e6; 3 | --active-color: #007BFF; 4 | --folder-color: #ffc107; 5 | --text-color: #212529; 6 | } 7 | 8 | /*============================================= 9 | = File Tree Browser = 10 | =============================================*/ 11 | 12 | .ft-tree .ft-folder-container ul { 13 | display: none; 14 | } 15 | 16 | .ft-tree .ft-folder-container.ft-folder-open>ul { 17 | display: block; 18 | } 19 | 20 | .ft-tree ul { 21 | list-style-type: none; 22 | padding-left: 1.66rem; 23 | } 24 | 25 | .ft-tree .ft-folder-container i { 26 | color: var(--folder-color); 27 | margin-right: .5rem; 28 | } 29 | 30 | .ft-tree .ft-folder-container a { 31 | color: var(--text-color); 32 | } 33 | 34 | /*============================================= 35 | = Explorer - common properties = 36 | =============================================*/ 37 | 38 | .ft-explorer .explorer-mode-btn.active { 39 | color: var(--active-color); 40 | } 41 | 42 | .ft-explorer .ft-folder, 43 | .ft-explorer .ft-file { 44 | font-size: 1.5rem; 45 | } 46 | 47 | .ft-explorer .ft-folder i { 48 | color: var(--folder-color); 49 | } 50 | 51 | .ft-explorer .ft-filename, 52 | .ft-explorer .ft-foldername, 53 | .ft-explorer .ft-imagename, 54 | .ft-explorer .ft-file:hover, 55 | .ft-explorer .ft-folder:hover, 56 | .ft-explorer .ft-image:hover { 57 | color: var(--text-color); 58 | text-decoration: none !important; 59 | } 60 | 61 | .ft-explorer .ft-file-container.active { 62 | background: var(--active-background); 63 | border-color: var(--active-background); 64 | } 65 | 66 | /*============================================= 67 | = Explorer list = 68 | =============================================*/ 69 | 70 | .ft-explorer-list-container .media>a { 71 | min-width: 100px; 72 | } 73 | 74 | .ft-explorer-list-container .media-body { 75 | font-size: 0.8125rem; 76 | } 77 | 78 | /*============================================= 79 | = Explorer grid = 80 | =============================================*/ 81 | 82 | /* responsive list groups 83 | https://codepen.io/migli/pen/gOOmYLb 84 | -------------------------------------------------- */ 85 | 86 | .ft-explorer-grid-container .list-group-item { 87 | width: 95%; 88 | margin: 1% !important; 89 | } 90 | 91 | .ft-explorer-grid-container .list-group-item h6 { 92 | font-size: 13px; 93 | } 94 | 95 | .ft-explorer-grid-container .list-group-item p { 96 | font-size: 12px; 97 | } 98 | 99 | @media (min-width: 576px) { 100 | .ft-explorer-grid-container .list-group-item { 101 | width: 47%; 102 | margin: 5px 1.5% !important; 103 | } 104 | } 105 | 106 | @media (min-width: 768px) { 107 | .ft-explorer-grid-container .list-group-item { 108 | width: 31.333%; 109 | margin: 5px 1% !important; 110 | } 111 | } 112 | 113 | @media (min-width: 992px) { 114 | .ft-explorer-grid-container .list-group-item { 115 | width: 23%; 116 | margin: 5px 1% !important; 117 | } 118 | } 119 | 120 | @media (min-width: 1200px) { 121 | .ft-explorer-grid-container .list-group-item { 122 | width: 19%; 123 | margin: 5px .5% !important; 124 | } 125 | } 126 | 127 | /*============================================= 128 | = file icon colors = 129 | =============================================*/ 130 | 131 | i.ft-icon-file-zip { 132 | color: #ffc107; 133 | } 134 | 135 | i.ft-icon-file-excel { 136 | color: #0C6C36; 137 | } 138 | 139 | i.ft-icon-html-five2 { 140 | color: #DE4B25; 141 | } 142 | 143 | i.ft-icon-file-picture { 144 | color: #F83A12; 145 | } 146 | 147 | i.ft-icon-file-music { 148 | color: #6759AA; 149 | } 150 | 151 | i.ft-icon-file-openoffice { 152 | color: #0E81C7; 153 | } 154 | 155 | i.ft-icon-file-pdf { 156 | color: #DF0A0A; 157 | } 158 | 159 | i.ft-icon-file-text2 { 160 | color: #212529; 161 | } 162 | 163 | i.ft-icon-file-video { 164 | color: #AAAA87; 165 | } 166 | 167 | i.ft-icon-file-word { 168 | color: #2A5592; 169 | } 170 | 171 | i.ft-icon-file-empty { 172 | color: #a1a7ac; 173 | } 174 | 175 | /*============ End of file icon colors =============*/ 176 | -------------------------------------------------------------------------------- /dist/templates/bootstrap4.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 21 | 22 | 23 | 24 | 27 | 28 | 31 | 32 | 40 | 41 | 52 | 53 | 64 | 65 | 66 | 67 | 70 | 71 | 74 | 75 | 83 | 84 | 93 | 94 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /file-tree-generator-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/file-tree-generator-preview.png -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 2 | const gulp = require('gulp'); 3 | const browserify = require('browserify'); 4 | const source = require('vinyl-source-stream'); 5 | const watchify = require('watchify'); 6 | const tsify = require('tsify'); 7 | const fancy_log = require('fancy-log'); 8 | const uglify = require('gulp-uglify'); 9 | const sourcemaps = require('gulp-sourcemaps'); 10 | const buffer = require('vinyl-buffer'); 11 | const paths = { 12 | files: ['src/ajax/*.*', 'src/connectors/*.*', 'src/lib/*?/*.*', 'src/templates/*.*', 'src/icons/fonts/*.*', 'src/icons/style.css'] 13 | }; 14 | 15 | const watchedBrowserify = watchify(browserify({ 16 | basedir: '.', 17 | debug: true, 18 | entries: ['src/ts/file-tree-browser.ts'], 19 | cache: {}, 20 | packageCache: {} 21 | }).plugin(tsify)); 22 | 23 | function bundle () { 24 | return watchedBrowserify 25 | /* .transform('babelify', { 26 | presets: ['es2015'], 27 | extensions: ['.ts'] 28 | }) */ 29 | .bundle() 30 | .on('error', fancy_log) 31 | .pipe(source('js/file-tree-browser.js')) 32 | .pipe(buffer()) 33 | .pipe(sourcemaps.init({ loadMaps: true })) 34 | .pipe(sourcemaps.write('./')) 35 | .pipe(gulp.dest('dist')); 36 | } 37 | 38 | gulp.task('copy-files', function () { 39 | return gulp.src(paths.files, { base: 'src' }) 40 | .pipe(gulp.dest('dist/')); 41 | }); 42 | 43 | gulp.task('default', gulp.series(gulp.parallel('copy-files'), bundle)); 44 | 45 | watchedBrowserify.on('update', gulp.series(gulp.parallel('copy-files'), bundle)); 46 | watchedBrowserify.on('log', fancy_log); 47 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | File Tree Browser Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

File Tree Browser Demo

17 | 18 |
19 | Demo 1 20 | Demo 2 21 |
22 |
23 |

This script scans a directory recursively and allows to navigate inside it like a file explorer.
It normally allows to drag and drop files from one directory to another.
This feature is disabled in the demo.

24 |

Documentation & Download: https://github.com/migliori/file-tree-browser

25 |
26 |
27 |

 
 

28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |

@miglisoft

37 | 38 | 39 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "file-tree-browser", 3 | "version": "1.1.1", 4 | "description": "Recovers directories and files recursively with Ajax from a main directory and displays the tree structure. The script called with Ajax is provided in several server languages: PHP, ASP, Node.js, .…", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "test" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/migliori/file-tree-browser.git" 12 | }, 13 | "keywords": [ 14 | "file", 15 | "tree", 16 | "javascript", 17 | "bootstrap" 18 | ], 19 | "author": "Gilles Migliori", 20 | "license": "GNU General Public License v3.0", 21 | "bugs": { 22 | "url": "https://github.com/migliori/file-tree-browser/issues" 23 | }, 24 | "homepage": "https://github.com/migliori/file-tree-browser#readme", 25 | "dependencies": { 26 | "babel-core": "^6.26.3", 27 | "babel-preset-es2015": "^6.24.1", 28 | "browserify": "^17.0.0", 29 | "fancy-log": "^2.0.0", 30 | "gulp": "^5.0.0", 31 | "gulp-sourcemaps": "^3.0.0", 32 | "gulp-typescript": "^5.0.1", 33 | "gulp-uglify": "^3.0.2", 34 | "tsify": "^5.0.4", 35 | "typescript": "^5.3.3", 36 | "vinyl-buffer": "^1.0.1", 37 | "vinyl-source-stream": "^2.0.0", 38 | "watchify": "^4.0.0" 39 | }, 40 | "devDependencies": { 41 | "babelify": "^10.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/ajax/move-file.php: -------------------------------------------------------------------------------- 1 | $value) { 5 | $$key = urldecode(stripslashes($_POST[$key])); 6 | } 7 | $ext = json_decode($ext); 8 | $authorized_ext = array_values($ext); 9 | 10 | if (!isset($filename)|| 11 | !isset($filepath) || 12 | !isset($destpath) || 13 | !isset($filehash) || 14 | !preg_match('`[a-z0-9]+`', $filehash) || 15 | preg_match('`\.\.|\*`', $filepath) || 16 | preg_match('`\.\.|\*`', $destpath)) { 17 | exit('1'); 18 | } 19 | 20 | $salt = '%t$qPP'; 21 | if (hash('sha256', $filepath . $salt) !== $filehash) { 22 | exit('2'); 23 | } 24 | 25 | $rootfilepath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $root . $filepath); 26 | $rootdestpath = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $root . $destpath); 27 | 28 | if (!file_exists(($rootfilepath))) { 29 | exit('3'); 30 | } 31 | if(!is_authorized($filename, $authorized_ext)) { 32 | exit('4'); 33 | } 34 | 35 | // Security checks ok 36 | 37 | $out = array(); 38 | 39 | if (!@copy ($rootfilepath , $rootdestpath)) { 40 | $out = array( 41 | 'status' => 'danger', 42 | 'msg' => 'Failed to copy ' . $rootdestpath 43 | ); 44 | } else { 45 | if (file_exists($rootfilepath)) { 46 | if (!@unlink($rootfilepath)) { 47 | $out = array( 48 | 'status' => 'danger', 49 | 'msg' => 'Failed to delete ' . $rootfilepath 50 | ); 51 | } else { 52 | $out = array( 53 | 'status' => 'success', 54 | 'msg' => '' 55 | ); 56 | } 57 | } else { 58 | $out = array( 59 | 'status' => 'danger', 60 | 'msg' => 'file doesn\'t exist' 61 | ); 62 | } 63 | } 64 | 65 | echo json_encode($out); 66 | 67 | function is_authorized($file, $authorized_ext) { 68 | $ext = '.' . pathinfo($file, PATHINFO_EXTENSION); 69 | if ($authorized_ext[0] === '.*' || in_array($ext, $authorized_ext)) { 70 | return true; 71 | } 72 | 73 | return false; 74 | } 75 | -------------------------------------------------------------------------------- /src/connectors/connector.php: -------------------------------------------------------------------------------- 1 | 0) && @is_dir($source_dir.$file)) { 49 | $filedata[$folder_prefix . $file] = scan_recursively($source_dir.$file.'/', $authorized_ext, $folder_prefix, $new_depth, $hidden); 50 | } else if(is_authorized($file, $authorized_ext)) { 51 | $filedata[] = array( 52 | 'ext' => pathinfo($file, PATHINFO_EXTENSION), 53 | 'name' => $file, 54 | 'size' => filesize($source_dir.$file) 55 | ); 56 | } 57 | } 58 | 59 | closedir($fp); 60 | return $filedata; 61 | } 62 | echo 'can not open dir'; 63 | return false; 64 | } 65 | 66 | function is_authorized($file, $authorized_ext) { 67 | $ext = '.' . pathinfo($file, PATHINFO_EXTENSION); 68 | if ($authorized_ext[0] === '.*' || in_array($ext, $authorized_ext)) { 69 | return true; 70 | } 71 | 72 | return false; 73 | } 74 | -------------------------------------------------------------------------------- /src/icons/Read Me.txt: -------------------------------------------------------------------------------- 1 | Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. 2 | 3 | To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/#docs/local-fonts 4 | 5 | You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. 6 | 7 | You can import *selection.json* back to the IcoMoon app using the *Import Icons* button (or via Main Menu → Manage Projects) to retrieve your icon selection. 8 | -------------------------------------------------------------------------------- /src/icons/demo-files/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0; 3 | margin: 0; 4 | font-family: sans-serif; 5 | font-size: 1em; 6 | line-height: 1.5; 7 | color: #555; 8 | background: #fff; 9 | } 10 | h1 { 11 | font-size: 1.5em; 12 | font-weight: normal; 13 | } 14 | small { 15 | font-size: .66666667em; 16 | } 17 | a { 18 | color: #e74c3c; 19 | text-decoration: none; 20 | } 21 | a:hover, a:focus { 22 | box-shadow: 0 1px #e74c3c; 23 | } 24 | .bshadow0, input { 25 | box-shadow: inset 0 -2px #e7e7e7; 26 | } 27 | input:hover { 28 | box-shadow: inset 0 -2px #ccc; 29 | } 30 | input, fieldset { 31 | font-family: sans-serif; 32 | font-size: 1em; 33 | margin: 0; 34 | padding: 0; 35 | border: 0; 36 | } 37 | input { 38 | color: inherit; 39 | line-height: 1.5; 40 | height: 1.5em; 41 | padding: .25em 0; 42 | } 43 | input:focus { 44 | outline: none; 45 | box-shadow: inset 0 -2px #449fdb; 46 | } 47 | .glyph { 48 | font-size: 16px; 49 | width: 15em; 50 | padding-bottom: 1em; 51 | margin-right: 4em; 52 | margin-bottom: 1em; 53 | float: left; 54 | overflow: hidden; 55 | } 56 | .liga { 57 | width: 80%; 58 | width: calc(100% - 2.5em); 59 | } 60 | .talign-right { 61 | text-align: right; 62 | } 63 | .talign-center { 64 | text-align: center; 65 | } 66 | .bgc1 { 67 | background: #f1f1f1; 68 | } 69 | .fgc1 { 70 | color: #999; 71 | } 72 | .fgc0 { 73 | color: #000; 74 | } 75 | p { 76 | margin-top: 1em; 77 | margin-bottom: 1em; 78 | } 79 | .mvm { 80 | margin-top: .75em; 81 | margin-bottom: .75em; 82 | } 83 | .mtn { 84 | margin-top: 0; 85 | } 86 | .mtl, .mal { 87 | margin-top: 1.5em; 88 | } 89 | .mbl, .mal { 90 | margin-bottom: 1.5em; 91 | } 92 | .mal, .mhl { 93 | margin-left: 1.5em; 94 | margin-right: 1.5em; 95 | } 96 | .mhmm { 97 | margin-left: 1em; 98 | margin-right: 1em; 99 | } 100 | .mls { 101 | margin-left: .25em; 102 | } 103 | .ptl { 104 | padding-top: 1.5em; 105 | } 106 | .pbs, .pvs { 107 | padding-bottom: .25em; 108 | } 109 | .pvs, .pts { 110 | padding-top: .25em; 111 | } 112 | .unit { 113 | float: left; 114 | } 115 | .unitRight { 116 | float: right; 117 | } 118 | .size1of2 { 119 | width: 50%; 120 | } 121 | .size1of1 { 122 | width: 100%; 123 | } 124 | .clearfix:before, .clearfix:after { 125 | content: " "; 126 | display: table; 127 | } 128 | .clearfix:after { 129 | clear: both; 130 | } 131 | .hidden-true { 132 | display: none; 133 | } 134 | .textbox0 { 135 | width: 3em; 136 | background: #f1f1f1; 137 | padding: .25em .5em; 138 | line-height: 1.5; 139 | height: 1.5em; 140 | } 141 | #testDrive { 142 | display: block; 143 | padding-top: 24px; 144 | line-height: 1.5; 145 | } 146 | .fs0 { 147 | font-size: 16px; 148 | } 149 | .fs1 { 150 | font-size: 32px; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /src/icons/demo-files/demo.js: -------------------------------------------------------------------------------- 1 | if (!('boxShadow' in document.body.style)) { 2 | document.body.setAttribute('class', 'noBoxShadow'); 3 | } 4 | 5 | document.body.addEventListener("click", function(e) { 6 | var target = e.target; 7 | if (target.tagName === "INPUT" && 8 | target.getAttribute('class').indexOf('liga') === -1) { 9 | target.select(); 10 | } 11 | }); 12 | 13 | (function() { 14 | var fontSize = document.getElementById('fontSize'), 15 | testDrive = document.getElementById('testDrive'), 16 | testText = document.getElementById('testText'); 17 | function updateTest() { 18 | testDrive.innerHTML = testText.value || String.fromCharCode(160); 19 | if (window.icomoonLiga) { 20 | window.icomoonLiga(testDrive); 21 | } 22 | } 23 | function updateSize() { 24 | testDrive.style.fontSize = fontSize.value + 'px'; 25 | } 26 | fontSize.addEventListener('change', updateSize, false); 27 | testText.addEventListener('input', updateTest, false); 28 | testText.addEventListener('change', updateTest, false); 29 | updateSize(); 30 | }()); 31 | -------------------------------------------------------------------------------- /src/icons/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IcoMoon Demo 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Font Name: file-tree-icons (Glyphs: 17)

13 |
14 |
15 |

Grid Size: 16

16 |
17 |
18 | 19 | ft-icon-grid 20 |
21 |
22 | 23 | 24 |
25 |
26 | liga: 27 | 28 |
29 |
30 |
31 |
32 | 33 | ft-icon-file-empty 34 |
35 |
36 | 37 | 38 |
39 |
40 | liga: 41 | 42 |
43 |
44 |
45 |
46 | 47 | ft-icon-file-text2 48 |
49 |
50 | 51 | 52 |
53 |
54 | liga: 55 | 56 |
57 |
58 |
59 |
60 | 61 | ft-icon-file-picture 62 |
63 |
64 | 65 | 66 |
67 |
68 | liga: 69 | 70 |
71 |
72 |
73 |
74 | 75 | ft-icon-file-music 76 |
77 |
78 | 79 | 80 |
81 |
82 | liga: 83 | 84 |
85 |
86 |
87 |
88 | 89 | ft-icon-file-video 90 |
91 |
92 | 93 | 94 |
95 |
96 | liga: 97 | 98 |
99 |
100 |
101 |
102 | 103 | ft-icon-file-zip 104 |
105 |
106 | 107 | 108 |
109 |
110 | liga: 111 | 112 |
113 |
114 |
115 |
116 | 117 | ft-icon-folder 118 |
119 |
120 | 121 | 122 |
123 |
124 | liga: 125 | 126 |
127 |
128 |
129 |
130 | 131 | ft-icon-folder-open 132 |
133 |
134 | 135 | 136 |
137 |
138 | liga: 139 | 140 |
141 |
142 |
143 |
144 | 145 | ft-icon-list 146 |
147 |
148 | 149 | 150 |
151 |
152 | liga: 153 | 154 |
155 |
156 |
157 |
158 | 159 | ft-icon-blocked 160 |
161 |
162 | 163 | 164 |
165 |
166 | liga: 167 | 168 |
169 |
170 |
171 |
172 | 173 | ft-icon-checkmark 174 |
175 |
176 | 177 | 178 |
179 |
180 | liga: 181 | 182 |
183 |
184 |
185 |
186 | 187 | ft-icon-file-pdf 188 |
189 |
190 | 191 | 192 |
193 |
194 | liga: 195 | 196 |
197 |
198 |
199 |
200 | 201 | ft-icon-file-openoffice 202 |
203 |
204 | 205 | 206 |
207 |
208 | liga: 209 | 210 |
211 |
212 |
213 |
214 | 215 | ft-icon-file-word 216 |
217 |
218 | 219 | 220 |
221 |
222 | liga: 223 | 224 |
225 |
226 |
227 |
228 | 229 | ft-icon-file-excel 230 |
231 |
232 | 233 | 234 |
235 |
236 | liga: 237 | 238 |
239 |
240 |
241 |
242 | 243 | ft-icon-html-five2 244 |
245 |
246 | 247 | 248 |
249 |
250 | liga: 251 | 252 |
253 |
254 |
255 | 256 | 257 |
258 |

Font Test Drive

259 | 264 | 266 |
  267 |
268 |
269 | 270 |
271 |

Generated by IcoMoon

272 |
273 | 274 | 275 | 276 | 277 | -------------------------------------------------------------------------------- /src/icons/fonts/file-tree-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/src/icons/fonts/file-tree-icons.eot -------------------------------------------------------------------------------- /src/icons/fonts/file-tree-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/icons/fonts/file-tree-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/src/icons/fonts/file-tree-icons.ttf -------------------------------------------------------------------------------- /src/icons/fonts/file-tree-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/migliori/file-tree-browser/1d4a1f9291743d68f17e6d201d34456888dcb23a/src/icons/fonts/file-tree-icons.woff -------------------------------------------------------------------------------- /src/icons/selection.json: -------------------------------------------------------------------------------- 1 | {"IcoMoonType":"selection","icons":[{"icon":{"paths":["M224 384h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM192 544c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM224 0h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-46.304 32-64v-160c0-17.696-14.304-32-32-32zM192 160c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM224 768h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM192 928c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM608 384h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM576 544c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM608 768h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM576 928c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM992 384h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM960 544c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM992 0h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-46.304 32-64v-160c0-17.696-14.304-32-32-32zM960 160c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM608 0h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-46.304 32-64v-160c0-17.696-14.304-32-32-32zM576 160c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64zM992 768h-192c-17.696 0-32 14.304-32 32v192c0 17.696 14.304 32 32 32h192c17.696 0 32-14.304 32-32v-192c0-17.696-14.304-32-32-32zM960 928c0 17.696-14.304 32-32 32h-64c-17.696 0-32-14.304-32-32v-64c0-17.696 14.304-32 32-32h64c17.696 0 32 14.304 32 32v64z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["grid"],"grid":16},"attrs":[{}],"properties":{"order":1,"id":0,"prevSize":32,"code":59648,"name":"grid"},"setIdx":0,"setId":2,"iconIdx":0},{"icon":{"paths":["M917.806 229.076c-22.212-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.888 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.984 17.78 50.678 41.878 81.374 72.572zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.326 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-empty","file","document","paper","page","new","empty","blank"],"defaultCode":59684,"grid":16},"attrs":[],"properties":{"ligatures":"file-empty, file3","name":"file-empty","id":36,"order":4,"prevSize":32,"code":59684},"setIdx":1,"setId":1,"iconIdx":36},{"icon":{"paths":["M917.806 229.076c-22.212-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.888 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.984 17.78 50.678 41.878 81.374 72.572zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.326 32 32 32h224v624z","M736 832h-448c-17.672 0-32-14.326-32-32s14.328-32 32-32h448c17.674 0 32 14.326 32 32s-14.326 32-32 32z","M736 704h-448c-17.672 0-32-14.326-32-32s14.328-32 32-32h448c17.674 0 32 14.326 32 32s-14.326 32-32 32z","M736 576h-448c-17.672 0-32-14.326-32-32s14.328-32 32-32h448c17.674 0 32 14.326 32 32s-14.326 32-32 32z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-text","file","document","list","paper","page"],"defaultCode":59686,"grid":16},"attrs":[],"properties":{"ligatures":"file-text2, file4","name":"file-text2","id":38,"order":5,"prevSize":32,"code":59686},"setIdx":1,"setId":1,"iconIdx":38},{"icon":{"paths":["M832 896h-640v-128l192-320 263 320 185-128v256z","M832 480c0 53.020-42.98 96-96 96-53.022 0-96-42.98-96-96s42.978-96 96-96c53.020 0 96 42.98 96 96z","M917.806 229.076c-22.212-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.888 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.984 17.78 50.678 41.878 81.374 72.572zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.326 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-picture","file","document","file-image"],"defaultCode":59687,"grid":16},"attrs":[],"properties":{"ligatures":"file-picture, file5","name":"file-picture","id":39,"order":6,"prevSize":32,"code":59687},"setIdx":1,"setId":1,"iconIdx":39},{"icon":{"paths":["M917.806 229.076c-22.21-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.886 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.982 17.78 50.678 41.878 81.374 72.572v0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.324 32 32 32h224v624z","M756.288 391.252c-7.414-6.080-17.164-8.514-26.562-6.632l-320 64c-14.958 2.994-25.726 16.126-25.726 31.38v236.876c-18.832-8.174-40.678-12.876-64-12.876-70.692 0-128 42.98-128 96s57.308 96 128 96 128-42.98 128-96v-229.766l256-51.202v133.842c-18.832-8.174-40.678-12.876-64-12.876-70.692 0-128 42.98-128 96s57.308 96 128 96 128-42.98 128-96v-319.998c0-9.586-4.298-18.668-11.712-24.748z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-music","file","document","file-song","file-audio"],"defaultCode":59688,"grid":16},"attrs":[],"properties":{"ligatures":"file-music, file6","name":"file-music","id":40,"order":7,"prevSize":32,"code":59688},"setIdx":1,"setId":1,"iconIdx":40},{"icon":{"paths":["M917.806 229.076c-22.208-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.594-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.882 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0 0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.98 17.78 50.678 41.878 81.374 72.572v0 0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.32 32 32 32h224v624z","M256 512h320v320h-320v-320z","M576 640l192-128v320l-192-128z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-video","file","document","file-camera"],"defaultCode":59690,"grid":16},"attrs":[],"properties":{"ligatures":"file-video, file8","name":"file-video","id":42,"order":8,"prevSize":32,"code":59690},"setIdx":1,"setId":1,"iconIdx":42},{"icon":{"paths":["M917.806 229.076c-22.208-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.884 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0 0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.98 17.78 50.678 41.878 81.374 72.572v0 0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.322 32 32 32h224v624z","M256 64h128v64h-128v-64z","M384 128h128v64h-128v-64z","M256 192h128v64h-128v-64z","M384 256h128v64h-128v-64z","M256 320h128v64h-128v-64z","M384 384h128v64h-128v-64z","M256 448h128v64h-128v-64z","M384 512h128v64h-128v-64z","M256 848c0 26.4 21.6 48 48 48h160c26.4 0 48-21.6 48-48v-160c0-26.4-21.6-48-48-48h-80v-64h-128v272zM448 768v64h-128v-64h128z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-zip","file","document","file-compressed","file-type","file-format"],"defaultCode":59691,"grid":16},"attrs":[],"properties":{"ligatures":"file-zip, file9","name":"file-zip","id":43,"order":9,"prevSize":32,"code":59691},"setIdx":1,"setId":1,"iconIdx":43},{"icon":{"paths":["M448 128l128 128h448v704h-1024v-832z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["folder","directory","category","browse"],"defaultCode":59695,"grid":16},"attrs":[],"properties":{"ligatures":"folder, directory","name":"folder","id":47,"order":2,"prevSize":32,"code":59695},"setIdx":1,"setId":1,"iconIdx":47},{"icon":{"paths":["M832 960l192-512h-832l-192 512zM128 384l-128 576v-832h288l128 128h416v128z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["folder-open","directory","category","browse"],"defaultCode":59696,"grid":16},"attrs":[],"properties":{"ligatures":"folder-open, directory2","name":"folder-open","id":48,"order":3,"prevSize":32,"code":59696},"setIdx":1,"setId":1,"iconIdx":48},{"icon":{"paths":["M0 0h256v256h-256zM384 64h640v128h-640zM0 384h256v256h-256zM384 448h640v128h-640zM0 768h256v256h-256zM384 832h640v128h-640z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["list","todo","bullet","menu","options"],"defaultCode":59834,"grid":16},"attrs":[],"properties":{"ligatures":"list, todo","name":"list","id":186,"order":15,"prevSize":32,"code":59834},"setIdx":1,"setId":1,"iconIdx":186},{"icon":{"paths":["M874.040 149.96c-96.706-96.702-225.28-149.96-362.040-149.96s-265.334 53.258-362.040 149.96c-96.702 96.706-149.96 225.28-149.96 362.040s53.258 265.334 149.96 362.040c96.706 96.702 225.28 149.96 362.040 149.96s265.334-53.258 362.040-149.96c96.702-96.706 149.96-225.28 149.96-362.040s-53.258-265.334-149.96-362.040zM896 512c0 82.814-26.354 159.588-71.112 222.38l-535.266-535.268c62.792-44.758 139.564-71.112 222.378-71.112 211.738 0 384 172.262 384 384zM128 512c0-82.814 26.354-159.586 71.112-222.378l535.27 535.268c-62.794 44.756-139.568 71.11-222.382 71.11-211.738 0-384-172.262-384-384z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["blocked","forbidden","denied","banned"],"defaultCode":59918,"grid":16},"attrs":[],"properties":{"ligatures":"blocked, forbidden","name":"blocked","id":270,"order":18,"prevSize":32,"code":59918},"setIdx":1,"setId":1,"iconIdx":270},{"icon":{"paths":["M864 128l-480 480-224-224-160 160 384 384 640-640z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["checkmark","tick","correct","accept","ok"],"defaultCode":59920,"grid":16},"attrs":[],"properties":{"ligatures":"checkmark, tick","name":"checkmark","id":272,"order":17,"prevSize":32,"code":59920},"setIdx":1,"setId":1,"iconIdx":272},{"icon":{"paths":["M842.012 589.48c-13.648-13.446-43.914-20.566-89.972-21.172-31.178-0.344-68.702 2.402-108.17 7.928-17.674-10.198-35.892-21.294-50.188-34.658-38.462-35.916-70.568-85.772-90.576-140.594 1.304-5.12 2.414-9.62 3.448-14.212 0 0 21.666-123.060 15.932-164.666-0.792-5.706-1.276-7.362-2.808-11.796l-1.882-4.834c-5.894-13.592-17.448-27.994-35.564-27.208l-10.916-0.344c-20.202 0-36.664 10.332-40.986 25.774-13.138 48.434 0.418 120.892 24.98 214.738l-6.288 15.286c-17.588 42.876-39.63 86.060-59.078 124.158l-2.528 4.954c-20.46 40.040-39.026 74.028-55.856 102.822l-17.376 9.188c-1.264 0.668-31.044 16.418-38.028 20.644-59.256 35.38-98.524 75.542-105.038 107.416-2.072 10.17-0.53 23.186 10.014 29.212l16.806 8.458c7.292 3.652 14.978 5.502 22.854 5.502 42.206 0 91.202-52.572 158.698-170.366 77.93-25.37 166.652-46.458 244.412-58.090 59.258 33.368 132.142 56.544 178.142 56.544 8.168 0 15.212-0.78 20.932-2.294 8.822-2.336 16.258-7.368 20.792-14.194 8.926-13.432 10.734-31.932 8.312-50.876-0.72-5.622-5.21-12.574-10.068-17.32zM211.646 814.048c7.698-21.042 38.16-62.644 83.206-99.556 2.832-2.296 9.808-8.832 16.194-14.902-47.104 75.124-78.648 105.066-99.4 114.458zM478.434 199.686c13.566 0 21.284 34.194 21.924 66.254s-6.858 54.56-16.158 71.208c-7.702-24.648-11.426-63.5-11.426-88.904 0 0-0.566-48.558 5.66-48.558v0zM398.852 637.494c9.45-16.916 19.282-34.756 29.33-53.678 24.492-46.316 39.958-82.556 51.478-112.346 22.91 41.684 51.444 77.12 84.984 105.512 4.186 3.542 8.62 7.102 13.276 10.65-68.21 13.496-127.164 29.91-179.068 49.862v0zM828.902 633.652c-4.152 2.598-16.052 4.1-23.708 4.1-24.708 0-55.272-11.294-98.126-29.666 16.468-1.218 31.562-1.838 45.102-1.838 24.782 0 32.12-0.108 56.35 6.072 24.228 6.18 24.538 18.734 20.382 21.332v0z","M917.806 229.076c-22.21-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.886 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.982 17.78 50.678 41.878 81.374 72.572v0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.324 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-pdf","file","file-format"],"defaultCode":60127,"grid":16},"attrs":[],"properties":{"ligatures":"file-pdf, file10","name":"file-pdf","id":479,"order":10,"prevSize":32,"code":60127},"setIdx":1,"setId":1,"iconIdx":479},{"icon":{"paths":["M690.22 471.682c-60.668-28.652-137.97-34.42-194.834 6.048 69.14-6.604 144.958 4.838 195.106 57.124 48-55.080 124.116-65.406 192.958-59.732-57.488-38.144-133.22-33.024-193.23-3.44v0zM665.646 605.75c-68.376-1.578-134.434 23.172-191.1 60.104-107.176-45.588-242.736-37.124-334.002 38.982 26.33-0.934 52.006-7.446 78.056-10.792 95.182-9.488 196.588 14.142 268.512 79.824 29.772-43.542 71.644-78.242 119.652-99.922 63.074-30.52 134.16-33.684 202.82-34.52-41.688-28.648-94.614-33.954-143.938-33.676z","M917.806 229.076c-22.21-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.886 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.982 17.78 50.678 41.878 81.374 72.572v0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.324 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-openoffice","file","file-format"],"defaultCode":60128,"grid":16},"attrs":[],"properties":{"ligatures":"file-openoffice, file11","name":"file-openoffice","id":480,"order":11,"prevSize":32,"code":60128},"setIdx":1,"setId":1,"iconIdx":480},{"icon":{"paths":["M639.778 475.892h44.21l-51.012 226.178-66.324-318.010h-106.55l-77.114 318.010-57.816-318.010h-111.394l113.092 511.88h108.838l76.294-302.708 68.256 302.708h100.336l129.628-511.88h-170.446v91.832z","M917.806 229.076c-22.21-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.886 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.982 17.78 50.678 41.878 81.374 72.572v0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.324 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-word","file","file-format","word","docx"],"defaultCode":60129,"grid":16},"attrs":[],"properties":{"ligatures":"file-word, file12","name":"file-word","id":481,"order":12,"prevSize":32,"code":60129},"setIdx":1,"setId":1,"iconIdx":481},{"icon":{"paths":["M743.028 384h-135.292l-95.732 141.032-95.742-141.032h-135.29l162.162 242.464-182.972 269.536h251.838v-91.576h-50.156l50.156-74.994 111.396 166.57h140.444l-182.976-269.536 162.164-242.464z","M917.806 229.076c-22.21-30.292-53.174-65.7-87.178-99.704s-69.412-64.964-99.704-87.178c-51.574-37.82-76.592-42.194-90.924-42.194h-496c-44.112 0-80 35.888-80 80v864c0 44.112 35.886 80 80 80h736c44.112 0 80-35.888 80-80v-624c0-14.332-4.372-39.35-42.194-90.924v0zM785.374 174.626c30.7 30.7 54.8 58.398 72.58 81.374h-153.954v-153.946c22.982 17.78 50.678 41.878 81.374 72.572v0zM896 944c0 8.672-7.328 16-16 16h-736c-8.672 0-16-7.328-16-16v-864c0-8.672 7.328-16 16-16 0 0 495.956-0.002 496 0v224c0 17.672 14.324 32 32 32h224v624z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["file-excel","file","file-format","xlc"],"defaultCode":60130,"grid":16},"attrs":[],"properties":{"ligatures":"file-excel, file13","name":"file-excel","id":482,"order":13,"prevSize":32,"code":60130},"setIdx":1,"setId":1,"iconIdx":482},{"icon":{"paths":["M60.538 0l82.144 921.63 368.756 102.37 369.724-102.524 82.3-921.476h-902.924zM810.762 862.824l-297.226 82.376v0.466l-0.776-0.234-0.782 0.234v-0.466l-297.222-82.376-70.242-787.486h736.496l-70.248 787.486zM650.754 530.204l-13.070 146.552-126.21 34.070-125.862-33.916-8.050-90.234h-113.49l15.83 177.512 232.076 64.176 231.342-64.176 31.040-347.012h-411.966l-10.302-115.748h432.534l10.112-113.026h-566.218l30.498 341.802z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"tags":["html-five","w3c"],"defaultCode":60133,"grid":16},"attrs":[],"properties":{"ligatures":"html-five2, w3c2","name":"html-five2","id":485,"order":14,"prevSize":32,"code":60133},"setIdx":1,"setId":1,"iconIdx":485}],"height":1024,"metadata":{"name":"file-tree-icons"},"preferences":{"showGlyphs":true,"showCodes":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"ft-icon-","metadata":{"fontFamily":"file-tree-icons","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"showSelector":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"name":"icomoon","classSelector":".icon"},"historySize":50}} -------------------------------------------------------------------------------- /src/icons/style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'file-tree-icons'; 3 | src: url('fonts/file-tree-icons.eot?117yyb'); 4 | src: url('fonts/file-tree-icons.eot?117yyb#iefix') format('embedded-opentype'), 5 | url('fonts/file-tree-icons.ttf?117yyb') format('truetype'), 6 | url('fonts/file-tree-icons.woff?117yyb') format('woff'), 7 | url('fonts/file-tree-icons.svg?117yyb#file-tree-icons') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | font-display: block; 11 | } 12 | 13 | [class^="ft-icon-"], [class*=" ft-icon-"] { 14 | /* use !important to prevent issues with browser extensions that change fonts */ 15 | font-family: 'file-tree-icons' !important; 16 | speak: none; 17 | font-style: normal; 18 | font-weight: normal; 19 | font-variant: normal; 20 | text-transform: none; 21 | line-height: 1; 22 | 23 | /* Better Font Rendering =========== */ 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | } 27 | 28 | .ft-icon-grid:before { 29 | content: "\e900"; 30 | } 31 | .ft-icon-file-empty:before { 32 | content: "\e924"; 33 | } 34 | .ft-icon-file-text2:before { 35 | content: "\e926"; 36 | } 37 | .ft-icon-file-picture:before { 38 | content: "\e927"; 39 | } 40 | .ft-icon-file-music:before { 41 | content: "\e928"; 42 | } 43 | .ft-icon-file-video:before { 44 | content: "\e92a"; 45 | } 46 | .ft-icon-file-zip:before { 47 | content: "\e92b"; 48 | } 49 | .ft-icon-folder:before { 50 | content: "\e92f"; 51 | } 52 | .ft-icon-folder-open:before { 53 | content: "\e930"; 54 | } 55 | .ft-icon-list:before { 56 | content: "\e9ba"; 57 | } 58 | .ft-icon-blocked:before { 59 | content: "\ea0e"; 60 | } 61 | .ft-icon-checkmark:before { 62 | content: "\ea10"; 63 | } 64 | .ft-icon-file-pdf:before { 65 | content: "\eadf"; 66 | } 67 | .ft-icon-file-openoffice:before { 68 | content: "\eae0"; 69 | } 70 | .ft-icon-file-word:before { 71 | content: "\eae1"; 72 | } 73 | .ft-icon-file-excel:before { 74 | content: "\eae2"; 75 | } 76 | .ft-icon-html-five2:before { 77 | content: "\eae5"; 78 | } 79 | -------------------------------------------------------------------------------- /src/lib/html5sortable/html5sortable.min.js: -------------------------------------------------------------------------------- 1 | var sortable=function(){"use strict";function c(e,t,n){if(void 0===n)return e&&e.h5s&&e.h5s.data&&e.h5s.data[t];e.h5s=e.h5s||{},e.h5s.data=e.h5s.data||{},e.h5s.data[t]=n}var v=function(e,t){if(!(e instanceof NodeList||e instanceof HTMLCollection||e instanceof Array))throw new Error("You must provide a nodeList/HTMLCollection/Array of elements to be filtered.");return"string"!=typeof t?Array.from(e):Array.from(e).filter(function(e){return 1===e.nodeType&&e.matches(t)})},w=new Map,t=function(){function e(){this._config=new Map,this._placeholder=void 0,this._data=new Map}return Object.defineProperty(e.prototype,"config",{get:function(){var n={};return this._config.forEach(function(e,t){n[t]=e}),n},set:function(e){if("object"!=typeof e)throw new Error("You must provide a valid configuration object to the config setter.");var t=Object.assign({},e);this._config=new Map(Object.entries(t))},enumerable:!0,configurable:!0}),e.prototype.setConfig=function(e,t){if(!this._config.has(e))throw new Error("Trying to set invalid configuration item: "+e);this._config.set(e,t)},e.prototype.getConfig=function(e){if(!this._config.has(e))throw new Error("Invalid configuration item requested: "+e);return this._config.get(e)},Object.defineProperty(e.prototype,"placeholder",{get:function(){return this._placeholder},set:function(e){if(!(e instanceof HTMLElement)&&null!==e)throw new Error("A placeholder must be an html element or null.");this._placeholder=e},enumerable:!0,configurable:!0}),e.prototype.setData=function(e,t){if("string"!=typeof e)throw new Error("The key must be a string.");this._data.set(e,t)},e.prototype.getData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.get(e)},e.prototype.deleteData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.delete(e)},e}(),y=function(e){if(!(e instanceof HTMLElement))throw new Error("Please provide a sortable to the store function.");return w.has(e)||w.set(e,new t),w.get(e)};function a(e,t,n){if(e instanceof Array)for(var r=0;r':t=document.createElement("div")),"string"==typeof n&&(r=t.classList).add.apply(r,n.split(" ")),t},C=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return["height","padding-top","padding-bottom"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},M=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return["width","padding-left","padding-right"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},s=function(e,t){if(!(e instanceof Array))throw new Error("You must provide a Array of HTMLElements to be filtered.");return"string"!=typeof t?e:e.filter(function(e){return e.querySelector(t)instanceof HTMLElement||e.shadowRoot&&e.shadowRoot.querySelector(t)instanceof HTMLElement}).map(function(e){return e.querySelector(t)||e.shadowRoot&&e.shadowRoot.querySelector(t)})},p=function(e){return e.composedPath&&e.composedPath()[0]||e.target},m=function(e,t,n){return{element:e,posX:n.pageX-t.left,posY:n.pageY-t.top}},h=function(e,t,n){if(!(e instanceof Event))throw new Error("setDragImage requires a DragEvent as the first argument.");if(!(t instanceof HTMLElement))throw new Error("setDragImage requires the dragged element as the second argument.");if(n||(n=m),e.dataTransfer&&e.dataTransfer.setDragImage){var r=n(t,E(t),e);if(!(r.element instanceof HTMLElement)||"number"!=typeof r.posX||"number"!=typeof r.posY)throw new Error("The customDragImage function you provided must return and object with the properties element[string], posX[integer], posY[integer].");e.dataTransfer.effectAllowed="copyMove",e.dataTransfer.setData("text/plain",p(e).id),e.dataTransfer.setDragImage(r.element,r.posX,r.posY)}},x=function(e,t){if(!0===e.isSortable){var n=y(e).getConfig("acceptFrom");if(null!==n&&!1!==n&&"string"!=typeof n)throw new Error('HTML5Sortable: Wrong argument, "acceptFrom" must be "null", "false", or a valid selector string.');if(null!==n)return!1!==n&&0=parseInt(r.maxItems)&&H.parentElement!==n||(e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect=!0===y(n).getConfig("copy")?"copy":"move",o(n,t,e.pageX,e.pageY))}};a(t.concat(s),"dragover",r),a(t.concat(s),"dragenter",r)}),e)}return k.destroy=function(e){var t,n,r,o;n=c(t=e,"opts")||{},r=v(t.children,n.items),o=s(r,n.handle),i(t,"dragover"),i(t,"dragenter"),i(t,"dragstart"),i(t,"dragend"),i(t,"drop"),j(t),i(o,"mousedown"),g(r),F(r),t.isSortable=!1},k.enable=function(e){X(e)},k.disable=function(e){var t,n,r,o;n=c(t=e,"opts"),r=v(t.children,n.items),o=s(r,n.handle),l(t,"aria-dropeffect","none"),c(t,"_disabled","true"),l(o,"draggable","false"),i(o,"mousedown")},k.__testing={_data:c,_removeItemEvents:g,_removeItemData:F,_removeSortableData:j},k}(); 2 | //# sourceMappingURL=html5sortable.min.js.map 3 | -------------------------------------------------------------------------------- /src/templates/bootstrap4.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --active-background: #dee2e6; 3 | --active-color: #007BFF; 4 | --folder-color: #ffc107; 5 | --text-color: #212529; 6 | } 7 | 8 | /*============================================= 9 | = File Tree Browser = 10 | =============================================*/ 11 | 12 | .ft-tree .ft-folder-container ul { 13 | display: none; 14 | } 15 | 16 | .ft-tree .ft-folder-container.ft-folder-open>ul { 17 | display: block; 18 | } 19 | 20 | .ft-tree ul { 21 | list-style-type: none; 22 | padding-left: 1.66rem; 23 | } 24 | 25 | .ft-tree .ft-folder-container i { 26 | color: var(--folder-color); 27 | margin-right: .5rem; 28 | } 29 | 30 | .ft-tree .ft-folder-container a { 31 | color: var(--text-color); 32 | } 33 | 34 | /*============================================= 35 | = Explorer - common properties = 36 | =============================================*/ 37 | 38 | .ft-explorer .explorer-mode-btn.active { 39 | color: var(--active-color); 40 | } 41 | 42 | .ft-explorer .ft-folder, 43 | .ft-explorer .ft-file { 44 | font-size: 1.5rem; 45 | } 46 | 47 | .ft-explorer .ft-folder i { 48 | color: var(--folder-color); 49 | } 50 | 51 | .ft-explorer .ft-filename, 52 | .ft-explorer .ft-foldername, 53 | .ft-explorer .ft-imagename, 54 | .ft-explorer .ft-file:hover, 55 | .ft-explorer .ft-folder:hover, 56 | .ft-explorer .ft-image:hover { 57 | color: var(--text-color); 58 | text-decoration: none !important; 59 | } 60 | 61 | .ft-explorer .ft-file-container.active { 62 | background: var(--active-background); 63 | border-color: var(--active-background); 64 | } 65 | 66 | /*============================================= 67 | = Explorer list = 68 | =============================================*/ 69 | 70 | .ft-explorer-list-container .media>a { 71 | min-width: 100px; 72 | } 73 | 74 | .ft-explorer-list-container .media-body { 75 | font-size: 0.8125rem; 76 | } 77 | 78 | /*============================================= 79 | = Explorer grid = 80 | =============================================*/ 81 | 82 | /* responsive list groups 83 | https://codepen.io/migli/pen/gOOmYLb 84 | -------------------------------------------------- */ 85 | 86 | .ft-explorer-grid-container .list-group-item { 87 | width: 95%; 88 | margin: 1% !important; 89 | } 90 | 91 | .ft-explorer-grid-container .list-group-item h6 { 92 | font-size: 13px; 93 | } 94 | 95 | .ft-explorer-grid-container .list-group-item p { 96 | font-size: 12px; 97 | } 98 | 99 | @media (min-width: 576px) { 100 | .ft-explorer-grid-container .list-group-item { 101 | width: 47%; 102 | margin: 5px 1.5% !important; 103 | } 104 | } 105 | 106 | @media (min-width: 768px) { 107 | .ft-explorer-grid-container .list-group-item { 108 | width: 31.333%; 109 | margin: 5px 1% !important; 110 | } 111 | } 112 | 113 | @media (min-width: 992px) { 114 | .ft-explorer-grid-container .list-group-item { 115 | width: 23%; 116 | margin: 5px 1% !important; 117 | } 118 | } 119 | 120 | @media (min-width: 1200px) { 121 | .ft-explorer-grid-container .list-group-item { 122 | width: 19%; 123 | margin: 5px .5% !important; 124 | } 125 | } 126 | 127 | /*============================================= 128 | = file icon colors = 129 | =============================================*/ 130 | 131 | i.ft-icon-file-zip { 132 | color: #ffc107; 133 | } 134 | 135 | i.ft-icon-file-excel { 136 | color: #0C6C36; 137 | } 138 | 139 | i.ft-icon-html-five2 { 140 | color: #DE4B25; 141 | } 142 | 143 | i.ft-icon-file-picture { 144 | color: #F83A12; 145 | } 146 | 147 | i.ft-icon-file-music { 148 | color: #6759AA; 149 | } 150 | 151 | i.ft-icon-file-openoffice { 152 | color: #0E81C7; 153 | } 154 | 155 | i.ft-icon-file-pdf { 156 | color: #DF0A0A; 157 | } 158 | 159 | i.ft-icon-file-text2 { 160 | color: #212529; 161 | } 162 | 163 | i.ft-icon-file-video { 164 | color: #AAAA87; 165 | } 166 | 167 | i.ft-icon-file-word { 168 | color: #2A5592; 169 | } 170 | 171 | i.ft-icon-file-empty { 172 | color: #a1a7ac; 173 | } 174 | 175 | /*============ End of file icon colors =============*/ 176 | -------------------------------------------------------------------------------- /src/templates/bootstrap4.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 21 | 22 | 23 | 24 | 27 | 28 | 31 | 32 | 40 | 41 | 52 | 53 | 64 | 65 | 66 | 67 | 70 | 71 | 74 | 75 | 83 | 84 | 93 | 94 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "src/ts/file-tree-browser-browser.ts" 4 | ], 5 | "compilerOptions": { 6 | "noImplicitAny": true, 7 | "target": "es2015" 8 | } 9 | } 10 | --------------------------------------------------------------------------------