├── artwork ├── plus.png ├── blue_cloud.png ├── open_arrow.png ├── fileexplorer_arrows.psd ├── fileexplorer_checkmark.psd ├── fileexplorer_menu_arrow.psd ├── pngs │ ├── fileexplorer_open_icon.png │ ├── fileexplorer_path_icon.png │ ├── fileexplorer_arrow_up_icon.png │ ├── fileexplorer_collapsed_icon.png │ ├── fileexplorer_expanded_icon.png │ ├── fileexplorer_item_file_icon.png │ ├── fileexplorer_menu_back_icon.png │ ├── fileexplorer_tool_copy_icon.png │ ├── fileexplorer_tool_cut_icon.png │ ├── fileexplorer_arrow_left_icon.png │ ├── fileexplorer_arrow_right_icon.png │ ├── fileexplorer_item_folder_icon.png │ ├── fileexplorer_menu_check_icon.png │ ├── fileexplorer_path_cloud_icon.png │ ├── fileexplorer_tool_delete_icon.png │ ├── fileexplorer_tool_paste_icon.png │ ├── fileexplorer_tool_upload_icon.png │ ├── fileexplorer_arrow_up_icon_hover.png │ ├── fileexplorer_expanded_icon_hover.png │ ├── fileexplorer_menu_forward_icon.png │ ├── fileexplorer_tool_checked_icon.png │ ├── fileexplorer_tool_download_icon.png │ ├── fileexplorer_tool_new_file_icon.png │ ├── fileexplorer_tool_unchecked_icon.png │ ├── fileexplorer_arrow_left_icon_hover.png │ ├── fileexplorer_collapsed_icon_hover.png │ ├── fileexplorer_tool_new_folder_icon.png │ └── fileexplorer_arrow_right_icon_hover.png ├── fileexplorer_tool_download_icon.png ├── uploads_in_progress2.svg ├── uploads_done2.svg ├── upload_errors2.svg ├── fileexplorer_arrow.svg ├── uploads_queued2.svg ├── fileexplorer_checkbox.svg ├── fileexplorer_file.svg ├── texturepacker_export.css ├── fileexplorer_file_new_file.svg ├── fileexplorer_file_copy.svg ├── fileexplorer_folder.svg ├── fileexplorer_folder_open.svg ├── fileexplorer_upload_download.svg ├── fileexplorer_file_paste.svg ├── fileexplorer_file_new_folder.svg ├── fileexplorer_file_delete.svg └── main_sprite_sheet.tps ├── file-explorer ├── fileexplorer_actions.woff └── fileexplorer_sprites.png ├── package.json ├── docs ├── debounce_attributes.md ├── image_loader.md ├── prepare_xhr.md ├── textarea_overlay.md ├── popup_menu.md ├── folder.md └── file_explorer.md ├── server-side-helpers ├── crc32_stream.php ├── deflate_stream.php └── file_upload_helper.php ├── demo.html └── README.md /artwork/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/plus.png -------------------------------------------------------------------------------- /artwork/blue_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/blue_cloud.png -------------------------------------------------------------------------------- /artwork/open_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/open_arrow.png -------------------------------------------------------------------------------- /artwork/fileexplorer_arrows.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/fileexplorer_arrows.psd -------------------------------------------------------------------------------- /artwork/fileexplorer_checkmark.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/fileexplorer_checkmark.psd -------------------------------------------------------------------------------- /artwork/fileexplorer_menu_arrow.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/fileexplorer_menu_arrow.psd -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_open_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_open_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_path_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_path_icon.png -------------------------------------------------------------------------------- /file-explorer/fileexplorer_actions.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/file-explorer/fileexplorer_actions.woff -------------------------------------------------------------------------------- /file-explorer/fileexplorer_sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/file-explorer/fileexplorer_sprites.png -------------------------------------------------------------------------------- /artwork/fileexplorer_tool_download_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/fileexplorer_tool_download_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_up_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_up_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_collapsed_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_collapsed_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_expanded_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_expanded_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_item_file_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_item_file_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_menu_back_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_menu_back_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_copy_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_copy_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_cut_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_cut_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_left_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_left_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_right_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_right_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_item_folder_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_item_folder_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_menu_check_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_menu_check_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_path_cloud_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_path_cloud_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_delete_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_delete_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_paste_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_paste_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_upload_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_upload_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_up_icon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_up_icon_hover.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_expanded_icon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_expanded_icon_hover.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_menu_forward_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_menu_forward_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_checked_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_checked_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_download_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_download_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_new_file_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_new_file_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_unchecked_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_unchecked_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_left_icon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_left_icon_hover.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_collapsed_icon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_collapsed_icon_hover.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_tool_new_folder_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_tool_new_folder_icon.png -------------------------------------------------------------------------------- /artwork/pngs/fileexplorer_arrow_right_icon_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/js-fileexplorer/master/artwork/pngs/fileexplorer_arrow_right_icon_hover.png -------------------------------------------------------------------------------- /artwork/uploads_in_progress2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /artwork/uploads_done2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /artwork/upload_errors2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /artwork/fileexplorer_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /artwork/uploads_queued2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /artwork/fileexplorer_checkbox.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-fileexplorer", 3 | "version": "1.0.0", 4 | "description": "A zero dependencies, customizable, pure Javascript widget for navigating, managing (move, copy, delete), uploading, and downloading files and folders or other hierarchical object structures on any modern web browser.", 5 | "organization": "CubicleSoft", 6 | "main": "file-explorer/file-explorer.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/cubiclesoft/js-fileexplorer.git" 13 | }, 14 | "bugs": "https://github.com/cubiclesoft/js-fileexplorer/issues", 15 | "github": "https://github.com/cubiclesoft/js-fileexplorer", 16 | "keywords": [ 17 | "file-explorer", 18 | "widget", 19 | "filemanager", 20 | "file-manager", 21 | "file-uploader", 22 | "file-download", 23 | "folder-viewer" 24 | ], 25 | "author": "CubicleSoft", 26 | "license": "MIT or LGPL (your choice)", 27 | "bugs": { 28 | "url": "https://github.com/cubiclesoft/js-fileexplorer/issues" 29 | }, 30 | "homepage": "https://github.com/cubiclesoft/js-fileexplorer", 31 | "files": [ 32 | "file-explorer/file-explorer.css", 33 | "file-explorer/file-explorer.js", 34 | "file-explorer/fileexplorer_actions.woff", 35 | "file-explorer/fileexplorer_sprites.png", 36 | "server-side-helpers/crc32_stream.php", 37 | "server-side-helpers/deflate_stream.php", 38 | "server-side-helpers/file_explorer_fs_helper.php", 39 | "server-side-helpers/file_upload_helper.php", 40 | "server-side-helpers/zip_stream_writer.php" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/debounce_attributes.md: -------------------------------------------------------------------------------- 1 | DebounceAttributes Class 2 | ======================== 3 | 4 | The DebounceAttributes class debounces/throttles based on changing attribute values instead of debouncing/throttling DOM events. The result is a cleaner, more performant solution. 5 | 6 | Example usage: 7 | 8 | ```js 9 | var statusbarresizewatch = new DebounceAttributes({ 10 | watchers: [ 11 | { elem: elems.mainwrap, attr: 'offsetWidth', val: -1 } 12 | ], 13 | interval: 50, 14 | stopsame: 5, 15 | callback: CalculateUpdateMultilineStatus, 16 | intervalcallback: CalculateUpdateMultilineStatus 17 | }); 18 | 19 | window.addEventListener('resize', statusbarresizewatch.Start, true); 20 | ``` 21 | 22 | DebounceAttributes(options) 23 | --------------------------- 24 | 25 | Category: Constructor 26 | 27 | Parameters: 28 | 29 | * options - An object of options to use to initialize the class. 30 | 31 | Returns: A Javascript function hierarchy. 32 | 33 | This function sets up a new DebounceAttributes class instance, which efficiently watches one or more element attributes for changes, and stops watching when the changes stop. A better alternative to traditional debouncing. The 'new' keyword is required in order to use it correctly. 34 | 35 | The options object accepts these options: 36 | 37 | * watchers - An array of objects each containing an element and attribute name to watch and an initial value (Default is []). 38 | * interval - An integer containing the number of milliseconds in between value checks (Default is 50). 39 | * stopsame - An integer containing the number of sequential identical values of the attribute before the watcher clears the interval (Default is 1). 40 | * callback - A function to call when the interval is cleared. 41 | * intervalcallback - A function to call each interval. 42 | 43 | DebounceAttributes.Start() 44 | -------------------------- 45 | 46 | Category: Actions 47 | 48 | Parameters: None. 49 | 50 | Returns: Nothing. 51 | 52 | This function starts the interval timer if it isn't already started to begin watching for attribute changes. 53 | 54 | DebounceAttributes.Stop() 55 | ------------------------- 56 | 57 | Category: Actions 58 | 59 | Parameters: None. 60 | 61 | Returns: Nothing. 62 | 63 | This function stops the interval timer. 64 | 65 | DebounceAttributes.Destroy() 66 | ---------------------------- 67 | 68 | Category: Destructor 69 | 70 | Parameters: None. 71 | 72 | Returns: Nothing. 73 | 74 | This function destroys the DebounceAttributes instance. 75 | -------------------------------------------------------------------------------- /artwork/texturepacker_export.css: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------------- 2 | created with https://www.codeandweb.com/texturepacker 3 | ----------------------------------------------------- 4 | $TexturePacker:SmartUpdate:3d63a344f597624cc50262f980d290ee:3e53d0e35e4e13e7188d2e87a76f1465:8f4ee330d84e56b65b32ddff57a8b78e$ 5 | ----------------------------------------------------- 6 | 7 | usage: 8 | 9 | replace {-spritename-} with the sprite you like to use 10 | 11 | */ 12 | 13 | .sprite {display:inline-block; overflow:hidden; background-repeat: no-repeat;background-image:url(file-explorer-sprites.png);} 14 | 15 | .fileexplorer_arrow_left_icon {width:32px; height:24px; background-position: -0px -0px} 16 | .fileexplorer_arrow_left_icon_hover {width:32px; height:24px; background-position: -32px -0px} 17 | .fileexplorer_arrow_right_icon {width:32px; height:24px; background-position: -64px -0px} 18 | .fileexplorer_arrow_right_icon_hover {width:32px; height:24px; background-position: -96px -0px} 19 | .fileexplorer_arrow_up_icon {width:24px; height:24px; background-position: -0px -24px} 20 | .fileexplorer_arrow_up_icon_hover {width:24px; height:24px; background-position: -24px -24px} 21 | .fileexplorer_collapsed_icon {width:18px; height:24px; background-position: -48px -24px} 22 | .fileexplorer_collapsed_icon_hover {width:18px; height:24px; background-position: -66px -24px} 23 | .fileexplorer_expanded_icon {width:18px; height:24px; background-position: -84px -24px} 24 | .fileexplorer_expanded_icon_hover {width:18px; height:24px; background-position: -102px -24px} 25 | .fileexplorer_item_file_icon {width:48px; height:48px; background-position: -0px -48px} 26 | .fileexplorer_item_folder_icon {width:48px; height:48px; background-position: -48px -48px} 27 | .fileexplorer_menu_back_icon {width:24px; height:24px; background-position: -96px -48px} 28 | .fileexplorer_menu_check_icon {width:24px; height:24px; background-position: -0px -96px} 29 | .fileexplorer_menu_forward_icon {width:24px; height:24px; background-position: -24px -96px} 30 | .fileexplorer_open_icon {width:24px; height:24px; background-position: -48px -96px} 31 | .fileexplorer_path_cloud_icon {width:24px; height:24px; background-position: -72px -96px} 32 | .fileexplorer_path_icon {width:24px; height:24px; background-position: -96px -96px} 33 | .fileexplorer_tool_checked_icon {width:24px; height:24px; background-position: -0px -120px} 34 | .fileexplorer_tool_copy_icon {width:24px; height:24px; background-position: -24px -120px} 35 | .fileexplorer_tool_cut_icon {width:24px; height:24px; background-position: -48px -120px} 36 | .fileexplorer_tool_delete_icon {width:24px; height:24px; background-position: -72px -120px} 37 | .fileexplorer_tool_download_icon {width:24px; height:24px; background-position: -96px -120px} 38 | .fileexplorer_tool_new_file_icon {width:24px; height:24px; background-position: -0px -144px} 39 | .fileexplorer_tool_new_folder_icon {width:24px; height:24px; background-position: -24px -144px} 40 | .fileexplorer_tool_paste_icon {width:24px; height:24px; background-position: -48px -144px} 41 | .fileexplorer_tool_unchecked_icon {width:24px; height:24px; background-position: -72px -144px} 42 | .fileexplorer_tool_upload_icon {width:24px; height:24px; background-position: -96px -144px} 43 | -------------------------------------------------------------------------------- /docs/image_loader.md: -------------------------------------------------------------------------------- 1 | ImageLoader Class 2 | ================= 3 | 4 | The ImageLoader class is a multi-queue delayed image loader that only loads images when it is told to. 5 | 6 | Example usage: 7 | 8 | ```js 9 | function ImageLoadResult(opts, success) 10 | { 11 | console.log(opts); 12 | console.log(success); 13 | } 14 | 15 | var imageloader = new ImageLoader(); 16 | 17 | imageloader.AddToQueue({ 18 | src: 'https://picsum.photos/300/200', 19 | callback: ImageLoadResult, 20 | info: { id: 'cool' } 21 | }); 22 | 23 | imageloader.AddToQueue({ 24 | src: 'https://picsum.photos/150/400', 25 | callback: ImageLoadResult, 26 | info: { id: 'cool2' } 27 | }); 28 | 29 | imageload.ProcessQueue(); 30 | ``` 31 | 32 | ImageLoader(options) 33 | -------------------- 34 | 35 | Category: Consstructor 36 | 37 | Parameters: 38 | 39 | * options - An object of options to use to initialize the class. 40 | 41 | Returns: A Javascript function hierarchy. 42 | 43 | This function sets up a new ImageLoader class instance. 44 | 45 | The options object accepts this option: 46 | 47 | * maxactive - An integer containing the maximum number of simultaneous requests to place in the active queue (Default is 10). 48 | 49 | ImageLoader.settings 50 | -------------------- 51 | 52 | Category: Settings 53 | 54 | The `settings` object contains the settings for the instance. 55 | 56 | ImageLoader.AddToQueue(opts) 57 | ---------------------------- 58 | 59 | Category: Queue actions 60 | 61 | Parameters: 62 | 63 | * opts - An object containing various options. 64 | 65 | Returns: Nothing. 66 | 67 | This function assigns an `id` and adds the opts object to the queue. 68 | 69 | The opts object accepts these options: 70 | 71 | * src - A string containing an image URL to retrieve. 72 | * width - An optional integer containing the width of the img tag. 73 | * height - An optional integer containing the height of the img tag. 74 | * callback - An optional callback function to call on success/failure. 75 | 76 | The following are reserved in the opts object for internal use: 77 | 78 | * id - An integer containing the ID of the queued item. 79 | * started - An integer containing a timestamp of when the item entered the active queue. 80 | * img - A DOM node containing an img tag. 81 | 82 | ImageLoader.ProcessQueue() 83 | -------------------------- 84 | 85 | Category: Queue actions 86 | 87 | Parameters: None. 88 | 89 | Returns: Nothing. 90 | 91 | This function starts processing the queue. It moves up to `maxactive` items into the active queue. 92 | 93 | ImageLoader.IsActive(id) 94 | ------------------------ 95 | 96 | Category: Queue information 97 | 98 | Parameters: 99 | 100 | * id - An integer containing an ID of a queued item. 101 | 102 | Returns: A boolean of true if the item is in the active queue, false otherwise. 103 | 104 | This function checks to see if the item with the specified ID is in the active queue. Useful when wanting to avoid cancelling images already being retrieved. 105 | 106 | ImageLoader.RemoveFromQueue(id) 107 | ------------------------------- 108 | 109 | Category: Queue actions 110 | 111 | Parameters: 112 | 113 | * id - An integer containing an ID of a queued item. 114 | 115 | Returns: Nothing. 116 | 117 | This function removes the item specified by the ID from whichever queue it is in. If it is in the active queue, it is cancelled first and then removed. 118 | 119 | ImageLoader.Destroy() 120 | --------------------- 121 | 122 | Category: Destructor 123 | 124 | Parameters: None. 125 | 126 | Returns: Nothing. 127 | 128 | This function destroys the ImageLoader instance. 129 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file_new_file.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file_copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /artwork/fileexplorer_folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /server-side-helpers/crc32_stream.php: -------------------------------------------------------------------------------- 1 | 0x04C11DB7, "start" => 0xFFFFFFFF, "xor" => 0xFFFFFFFF, "refdata" => 1, "refcrc" => 1); 14 | 15 | public function __construct() 16 | { 17 | $this->open = false; 18 | } 19 | 20 | public function Init($options = false) 21 | { 22 | if ($options === false && function_exists("hash_init")) $this->hash = hash_init("crc32b"); 23 | else 24 | { 25 | if ($options === false) $options = self::$default; 26 | 27 | $this->hash = false; 28 | $this->crctable = array(); 29 | $poly = $this->LIM32($options["poly"]); 30 | for ($x = 0; $x < 256; $x++) 31 | { 32 | $c = $this->SHL32($x, 24); 33 | for ($y = 0; $y < 8; $y++) $c = $this->SHL32($c, 1) ^ ($c & 0x80000000 ? $poly : 0); 34 | $this->crctable[$x] = $c; 35 | } 36 | 37 | $this->datareflect = $options["refdata"]; 38 | $this->crcreflect = $options["refcrc"]; 39 | $this->firstcrc = $options["start"]; 40 | $this->currcrc = $options["start"]; 41 | $this->finalxor = $options["xor"]; 42 | } 43 | 44 | $this->open = true; 45 | } 46 | 47 | public function AddData($data) 48 | { 49 | if (!$this->open) return false; 50 | 51 | if ($this->hash !== false) hash_update($this->hash, $data); 52 | else 53 | { 54 | $y = strlen($data); 55 | 56 | for ($x = 0; $x < $y; $x++) 57 | { 58 | if ($this->datareflect) $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ self::$revlookup[ord($data[$x])]]; 59 | else $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ ord($data[$x])]; 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | public function Finalize() 67 | { 68 | if (!$this->open) return false; 69 | 70 | if ($this->hash !== false) 71 | { 72 | $result = hexdec(hash_final($this->hash)); 73 | 74 | $this->hash = hash_init("crc32b"); 75 | } 76 | else 77 | { 78 | if ($this->crcreflect) 79 | { 80 | $tempcrc = $this->currcrc; 81 | $this->currcrc = self::$revlookup[$this->SHR32($tempcrc, 24)] | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 16) & 0xFF], 8) | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 8) & 0xFF], 16) | $this->SHL32(self::$revlookup[$this->LIM32($tempcrc & 0xFF)], 24); 82 | } 83 | $result = $this->currcrc ^ $this->finalxor; 84 | 85 | $this->currcrc = $this->firstcrc; 86 | } 87 | 88 | return $result; 89 | } 90 | 91 | // These functions are a hacky, but effective way of enforcing unsigned 32-bit integers onto a generic signed int. 92 | // Allow bitwise operations to work across platforms. Minimum integer size must be 32-bit. 93 | private function SHR32($num, $bits) 94 | { 95 | $num = (int)$num; 96 | if ($bits < 0) $bits = 0; 97 | 98 | if ($num < 0 && $bits) 99 | { 100 | $num = ($num >> 1) & 0x7FFFFFFF; 101 | $bits--; 102 | } 103 | 104 | return $this->LIM32($num >> $bits); 105 | } 106 | 107 | private function SHL32($num, $bits) 108 | { 109 | if ($bits < 0) $bits = 0; 110 | 111 | return $this->LIM32((int)$num << $bits); 112 | } 113 | 114 | private function LIM32($num) 115 | { 116 | return (int)((int)$num & 0xFFFFFFFF); 117 | } 118 | } 119 | ?> -------------------------------------------------------------------------------- /artwork/fileexplorer_folder_open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /artwork/fileexplorer_upload_download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/prepare_xhr.md: -------------------------------------------------------------------------------- 1 | PrepareXHR Class 2 | ================ 3 | 4 | The PrepareXHR class is a basic and convenient wrapper around a XMLHttpRequest (XHR) object. 5 | 6 | Example usage: 7 | 8 | ```js 9 | var xhr = new PrepareXHR({ 10 | url: '/filemanager/', 11 | params: { 12 | action: 'refresh', 13 | path: JSON.stringify(['/', 'some', 'dir']), 14 | xsrftoken: 'asdfasdf' 15 | }, 16 | onsuccess: function(e) { 17 | console.log(e.target.response); 18 | }, 19 | onerror: function(e) { 20 | console.log(e); 21 | } 22 | }); 23 | 24 | xhr.Send(); 25 | ``` 26 | 27 | PrepareXHR(options) 28 | ------------------- 29 | 30 | Category: Constructor 31 | 32 | Parameters: 33 | 34 | * options - An object of options to use to initialize the class. 35 | 36 | Returns: A Javascript function hierarchy. 37 | 38 | This function sets up a new PrepareXHR class instance. 39 | 40 | The options object accepts these options: 41 | 42 | * method - An optional string containing a HTTP method to use for the request. 43 | * url - A string containing the URL to use. Must be XHR-compatible (e.g. CORS headers or same domain). 44 | * headers - An optional object containing key-value pairs of custom HTTP headers to send. 45 | * params - An optional object or array or FormData instance containing POST parameters to send. Not compatible with the body option. 46 | * body - An optional string containing the body of the request to send. Not compatible with the params option. 47 | * onsuccess - An optional callback function that is run if the request completes successfully. 48 | * onerror - An optional callback function that is run if the request fails. 49 | * onload - An optional callback function that is run if the request completes successfully. 50 | * onabort - An optional callback function that is run if the request is aborted. 51 | * onloadstart - An optional callback function that is run when the request starts. 52 | * onprogress - An optional callback function that is periodically run as the response data arrives. 53 | * ontimeout - An optional callback function that is run if the request times out. 54 | * onloadend - An optional callback function that is run when the request ends (regardless if it succeeds or not). 55 | 56 | PrepareXHR.xhr 57 | -------------- 58 | 59 | Category: Variable 60 | 61 | This variable is the internal-ish XMLHttpRequest (XHR) object instance. 62 | 63 | PrepareXHR.upload.addEventListener(type, listener, options) 64 | ----------------------------------------------------------- 65 | 66 | Category: Events 67 | 68 | Parameters: 69 | 70 | * type - A string containing the XHR event type to listen to. 71 | * listener - A callback function to call when the XHR event fires. 72 | * options - A boolean or an object containing standard event listener options. 73 | 74 | Returns: Nothing. 75 | 76 | This function adds an event listener to the XHR object instance upload/request event handlers. 77 | 78 | PrepareXHR.upload.removeEventListener(type, listener, options) 79 | -------------------------------------------------------------- 80 | 81 | Category: Events 82 | 83 | Parameters: 84 | 85 | * type - A string containing the XHR event type to stop listening to. 86 | * listener - A callback function to remove. 87 | * options - A boolean or an object containing standard event listener options. 88 | 89 | Returns: Nothing. 90 | 91 | This function removes an event listener from the XHR object instance upload/request event handlers. 92 | 93 | PrepareXHR.addEventListener(type, listener, options) 94 | ---------------------------------------------------- 95 | 96 | Category: Events 97 | 98 | Parameters: 99 | 100 | * type - A string containing the XHR event type to listen to. 101 | * listener - A callback function to call when the XHR event fires. 102 | * options - A boolean or an object containing standard event listener options. 103 | 104 | Returns: Nothing. 105 | 106 | This function adds an event listener to the XHR object instance response event handlers. 107 | 108 | PrepareXHR.removeEventListener(type, listener, options) 109 | ------------------------------------------------------- 110 | 111 | Category: Events 112 | 113 | Parameters: 114 | 115 | * type - A string containing the XHR event type to stop listening to. 116 | * listener - A callback function to remove. 117 | * options - A boolean or an object containing standard event listener options. 118 | 119 | Returns: Nothing. 120 | 121 | This function removes an event listener from the XHR object instance response event handlers. 122 | 123 | PrepareXHR.GetMethod() 124 | ---------------------- 125 | 126 | Category: HTTP information 127 | 128 | Parameters: None. 129 | 130 | Returns: A string containing the HTTP method to use. 131 | 132 | This function returns the calculated HTTP method to use based on the input constructor options object. 133 | 134 | PrepareXHR.PrepareBody() 135 | ------------------------ 136 | 137 | Category: Actions 138 | 139 | Parameters: None. 140 | 141 | Returns: A value that can be passed to `Send()`. 142 | 143 | This function prepares the XHR body to send. It is automatically called if Send() is not passed anything. 144 | 145 | PrepareXHR.Send(xhrbody) 146 | ------------------------ 147 | 148 | Category: Actions 149 | 150 | Parameters: 151 | 152 | * xhrbody - Undefined or a value compatible with `XMLHttpRequest.send()`. 153 | 154 | Returns: Nothing. 155 | 156 | This function starts sending an asynchronous request to the server. If `xhrbody` is not defined, this function calls `PrepareBody()` to generate the value to send. 157 | 158 | PrepareXHR.Abort() 159 | ------------------ 160 | 161 | Category: Actions 162 | 163 | Parameters: None. 164 | 165 | Returns: Nothing. 166 | 167 | This function aborts a request/upload/response in progress. 168 | 169 | PrepareXHR.Destroy() 170 | -------------------- 171 | 172 | Category: Destructor 173 | 174 | Parameters: None. 175 | 176 | Returns: Nothing. 177 | 178 | This function destroys the PrepareXHR instance. 179 | -------------------------------------------------------------------------------- /docs/textarea_overlay.md: -------------------------------------------------------------------------------- 1 | TextareaOverlay Class 2 | ===================== 3 | 4 | The TextareaOverlay class displays a positionable textarea with optional text with text selection. Full keyboard, mouse, and touch support. 5 | 6 | Example usage: 7 | 8 | ```js 9 | options = { 10 | initvalue: 'hello.txt', 11 | initselstart: 0, 12 | initselend: 5, 13 | 14 | onposition: function(textelem) { 15 | textelem.style.left = 50 + 'px'; 16 | textelem.style.top = 40 + 'px'; 17 | textelem.style.width = 50 + 'px'; 18 | textelem.style.height = Math.min(elem.offsetHeight - 2, elem.scrollHeight - 42, textelem.scrollHeight + 2) + 'px'; 19 | }, 20 | 21 | ondone: function(val, lastelem) { 22 | if (lastelem) lastelem.focus(); 23 | console.log(val); 24 | 25 | this.Destroy(); 26 | }, 27 | 28 | oncancel: function(lastelem) { 29 | if (lastelem) lastelem.focus(); 30 | 31 | this.Destroy(); 32 | }, 33 | }; 34 | 35 | var textoverlaytest = new window.FileExplorer.TextareaOverlay(elem, options); 36 | ``` 37 | 38 | TextareaOverlay(parentelem, options) 39 | ------------------------------------ 40 | 41 | Category: Constructor 42 | 43 | Parameters: 44 | 45 | * parentelem - A DOM node to append the root of the TextareaOverlay widget to. 46 | * options - An object containing options to use to construct the widget. 47 | 48 | Returns: A Javascript function hierarchy. 49 | 50 | This function sets up a new TextareaOverlay widget instance. 51 | 52 | The options object accepts these options: 53 | 54 | * capturetab - A boolean indicating whether or not to capture the Tab key in the textarea and emit a tab (Default is false). 55 | * multiline - A boolean indicating whether or not to capture the Enter key in the textarea and emit a newline (Default is false). 56 | * initvalue - A string containing the initial value to use for the textarea (Default is ''). 57 | * initselstart - An integer specifying the start position of the selected text (Default is -1). If negative, the start position is at the end. 58 | * initselend - An integer specifying the end position of the selected text (Default is -1). If negative, the end position is at the end. 59 | * resizewatchers - An optional array of objects compatible with DebounceAttributes watchers. Useful for repositioning the popup menu during a resize operation. 60 | * onposition - An optional callback function to position and size the textarea. 61 | * ondone - An optional callback function to receive the new textarea value. Only sent if the value changed. 62 | * oncancel - An optional callback function to be notified if the overlay is cancelled or the value did not change. 63 | * ondestroy - An optional callback function to be notified when the widget is destroyed. 64 | 65 | TextareaOverlay.settings 66 | ------------------ 67 | 68 | Category: Settings 69 | 70 | The `settings` object contains the settings for the instance. Changing the settings after creating the instance will have little to no effect and changing them is not recommended. 71 | 72 | TextareaOverlay.addEventListener(eventname, callback) 73 | ----------------------------------------------------- 74 | 75 | Category: Events 76 | 77 | Parameters: 78 | 79 | * eventname - A string containing a name of a TextareaOverlay event to listen to. 80 | * callback - A function to call when the event fires. 81 | 82 | Returns: Nothing. 83 | 84 | This function presents a familiar function for registering for custom events emitted by TextareaOverlay. 85 | 86 | Known events: 87 | 88 | * position - Dispatched when the textarea should be positioned. 89 | * done - Dispatched when the textarea is done being edited and the value changed. 90 | * cancelled - Dispatched if the overlay is cancelled or the value did not change. 91 | * destroy - Dispatched when the Destroy() function is called. 92 | 93 | Most of these events have equivalents in the settings object and associated callbacks will automatically be registered as event listeners during initialization. 94 | 95 | TextareaOverlay.removeEventListener(eventname, callback) 96 | -------------------------------------------------------- 97 | 98 | Category: Events 99 | 100 | Parameters: 101 | 102 | * eventname - A string containing a name of a TextareaOverlay event to stop listening to. 103 | * callback - A function containing a registered callback to remove. 104 | 105 | Returns: Nothing. 106 | 107 | This function presents a familiar function for unregistering from custom events emitted by TextareaOverlay. 108 | 109 | TextareaOverlay.hasEventListener(eventname) 110 | ------------------------------------------- 111 | 112 | Category: Events 113 | 114 | Parameters: 115 | 116 | * eventname - A string containing a name of a TextareaOverlay event to check. 117 | 118 | Returns: A boolean of true if there are event listeners for the specified event, false otherwise. 119 | 120 | This function checks for the existence of an event and whether or not there are any listeners registered for the event. 121 | 122 | TextareaOverlay.UpdatePosition() 123 | -------------------------------- 124 | 125 | Category: Actions 126 | 127 | Parameters: None. 128 | 129 | Returns: Nothing. 130 | 131 | This function changes the height of the textarea to 1px and triggers a position update call. 132 | 133 | TextareaOverlay.Done(etype) 134 | --------------------------- 135 | 136 | Category: Actions 137 | 138 | Parameters: 139 | 140 | * etype - An optional string containing an event type. 141 | 142 | Returns: Nothing. 143 | 144 | This function makes the textarea read only and triggers the done event if it hasn't been disallowed and the text has been modified. Otherwise, it calls Cancel(). The etype value can be used to, for example, prevent another textarea from immediately appearing when clicking on a button that originally created the overlay. 145 | 146 | TextareaOverlay.Cancel(etype) 147 | ----------------------------- 148 | 149 | Category: Actions 150 | 151 | Parameters: 152 | 153 | * etype - An optional string containing an event type. 154 | 155 | Returns: Nothing. 156 | 157 | This function triggers the cancelled event if it hasn't been disallowed. The etype value can be used to, for example, prevent another textarea from immediately appearing when clicking on a button that originally created the overlay. 158 | 159 | TextareaOverlay.ResetAllowCancelDone() 160 | -------------------------------------- 161 | 162 | Category: Actions 163 | 164 | Parameters: None. 165 | 166 | Returns: Nothing. 167 | 168 | This function resets the textarea to be editable, sets keyboard focus to the textarea, and allows `Done()` and `Cancel()` to be called again in the future. 169 | 170 | TextareaOverlay.Destroy() 171 | ------------------------- 172 | 173 | Category: Destructor 174 | 175 | Parameters: None. 176 | 177 | Returns: Nothing. 178 | 179 | This function destroys the TextareaOverlay instance. Note that the focused element should be moved to another element prior to calling Destroy(). 180 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file_paste.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/popup_menu.md: -------------------------------------------------------------------------------- 1 | PopupMenu Class 2 | =============== 3 | 4 | The PopupMenu class displays a popup menu of items. Full keyboard, mouse, and touch support. 5 | 6 | Example usage: 7 | 8 | ```js 9 | options = { 10 | items: [ 11 | { id: 0, name: 'Test' }, 12 | { id: 1, name: 'Test 2', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 13 | 'split', 14 | { id: 2, name: '(Empty)', icon: 'fe_fileexplorer_popup_item_icon_folder', enabled: false }, 15 | 'split', 16 | { id: 3, name: 'Test 3', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 17 | { id: 4, name: 'Test 4', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 18 | { id: 5, name: 'Test 5', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 19 | { id: 6, name: 'Test 6', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 20 | { id: 7, name: 'Test 7', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 21 | { id: 8, name: 'Test 8', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 22 | { id: 9, name: 'Test 9', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 23 | { id: 10, name: 'Test 10', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 24 | { id: 11, name: 'Test 11', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 25 | { id: 12, name: 'Test 12', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 26 | { id: 13, name: 'Test 13', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 27 | { id: 14, name: 'Test 14', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 28 | { id: 15, name: 'Test 15', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 29 | { id: 16, name: 'Test 16', icon: 'fe_fileexplorer_popup_item_icon_folder' }, 30 | ], 31 | 32 | onposition: function(popupelem) { 33 | var maxleft = elem.offsetWidth - popupelem.offsetWidth; 34 | 35 | popupelem.style.left = (maxleft < 900 ? maxleft : 900) + 'px'; 36 | popupelem.style.top = (elem.offsetHeight - 25) + 'px'; 37 | }, 38 | 39 | onselected: function(id, item, lastelem, etype) { 40 | if (lastelem) lastelem.focus(); 41 | 42 | console.log(id); 43 | console.log(item); 44 | 45 | this.Destroy(); 46 | }, 47 | 48 | oncancel: function(lastelem, etype) { 49 | if (lastelem) lastelem.focus(); 50 | 51 | this.Destroy(); 52 | }, 53 | }; 54 | 55 | var popuptest = new window.FileExplorer.PopupMenu(elem, options); 56 | ``` 57 | 58 | PopupMenu(parentelem, options) 59 | ------------------------------ 60 | 61 | Category: Constructor 62 | 63 | Parameters: 64 | 65 | * parentelem - A DOM node to append the root of the PopupMenu widget to. 66 | * options - An object containing options to use to construct the widget. 67 | 68 | Returns: A Javascript function hierarchy. 69 | 70 | This function sets up a new PopupMenu widget instance. 71 | 72 | The options object accepts these options: 73 | 74 | * items - An array of objects and strings containing the items to show (Default is []). 75 | * resizewatchers - An optional array of objects compatible with DebounceAttributes watchers. Useful for repositioning the popup menu during a resize operation. 76 | * onposition - An optional callback function to position the popup menu. 77 | * onselchanged - An optional callback function to be notified whenever the selection is changed. 78 | * onselected - An optional callback function to receive the selected item. 79 | * oncancel - An optional callback function to be notified if the popup is cancelled. 80 | * onleft - An optional callback function to be notified if the user presses the left arrow key. 81 | * onright - An optional callback function to be notified if the user presses the right arrow key. 82 | * ondestroy - An optional callback function to be notified when the widget is destroyed. 83 | 84 | PopupMenu.settings 85 | ------------------ 86 | 87 | Category: Settings 88 | 89 | The `settings` object contains the settings for the instance. Changing the settings after creating the instance will have little to no effect and changing them is not recommended. 90 | 91 | PopupMenu.addEventListener(eventname, callback) 92 | ----------------------------------------------- 93 | 94 | Category: Events 95 | 96 | Parameters: 97 | 98 | * eventname - A string containing a name of a PopupMenu event to listen to. 99 | * callback - A function to call when the event fires. 100 | 101 | Returns: Nothing. 102 | 103 | This function presents a familiar function for registering for custom events emitted by PopupMenu. 104 | 105 | Known events: 106 | 107 | * position - Dispatched when the popup menu should be positioned. 108 | * selection_changed - Dispatched when the selection is changed. 109 | * selected - Dispatched when the user selects an item. 110 | * cancelled - Dispatched if the popup menu is cancelled. 111 | * left - Dispatched when the user presses the left arrow key. 112 | * right - Dispatched when the user presses the right arrow key. 113 | * destroy - Dispatched when the Destroy() function is called. 114 | 115 | Most of these events have equivalents in the settings object and associated callbacks will automatically be registered as event listeners during initialization. 116 | 117 | PopupMenu.removeEventListener(eventname, callback) 118 | -------------------------------------------------- 119 | 120 | Category: Events 121 | 122 | Parameters: 123 | 124 | * eventname - A string containing a name of a PopupMenu event to stop listening to. 125 | * callback - A function containing a registered callback to remove. 126 | 127 | Returns: Nothing. 128 | 129 | This function presents a familiar function for unregistering from custom events emitted by PopupMenu. 130 | 131 | PopupMenu.hasEventListener(eventname) 132 | ------------------------------------- 133 | 134 | Category: Events 135 | 136 | Parameters: 137 | 138 | * eventname - A string containing a name of a PopupMenu event to check. 139 | 140 | Returns: A boolean of true if there are event listeners for the specified event, false otherwise. 141 | 142 | This function checks for the existence of an event and whether or not there are any listeners registered for the event. 143 | 144 | PopupMenu.UpdatePosition() 145 | -------------------------- 146 | 147 | Category: Actions 148 | 149 | Parameters: None. 150 | 151 | Returns: Nothing. 152 | 153 | This function moves the popup menu off screen and triggers a position update call. 154 | 155 | PopupMenu.Cancel(etype) 156 | ----------------------- 157 | 158 | Category: Actions 159 | 160 | Parameters: 161 | 162 | * etype - An optional string containing an event type. 163 | 164 | Returns: Nothing. 165 | 166 | This function triggers the cancelled event if it hasn't been prevented. The etype value can be used to, for example, prevent another popup menu from immediately appearing when clicking on the original button that created the popup menu. 167 | 168 | PopupMenu.PreventCancel() 169 | ------------------------- 170 | 171 | Category: Actions 172 | 173 | Parameters: None. 174 | 175 | Returns: Nothing. 176 | 177 | This function prevents Cancel() from having any effect. Useful for moving focus to a specific element which would cause Cancel() to be called, which would trigger a callback, which would set focus to a different element. 178 | 179 | PopupMenu.Destroy() 180 | ------------------- 181 | 182 | Category: Destructor 183 | 184 | Parameters: None. 185 | 186 | Returns: Nothing. 187 | 188 | This function destroys the PopupMenu instance. Note that the focused element should be moved to another element prior to calling Destroy(). 189 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file_new_folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /artwork/fileexplorer_file_delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/folder.md: -------------------------------------------------------------------------------- 1 | Folder Class 2 | ============ 3 | 4 | The internal Folder class tracks the contents of a single folder in the mapped folders of the FileExplorer class. The Folder class cannot be instantiated except from within the FileExplorer but instances of this class can be accessed primarily via callbacks from FileExplorer. 5 | 6 | Folder(path) 7 | ------------ 8 | 9 | Category: Constructor 10 | 11 | Parameters: 12 | 13 | * path - An array of path segments to define the path for this Folder instance. 14 | 15 | Returns: Nothing. 16 | 17 | This function sets up a new Folder instance. Each path segment is an array consisting of `[id, value, attrs]`. Paths are validated via `FileExplorer.IsValidPath()`. 18 | 19 | Folder.addEventListener(eventname, callback) 20 | -------------------------------------------- 21 | 22 | Category: Events 23 | 24 | Parameters: 25 | 26 | * eventname - A string containing a name of a Folder event to listen to. 27 | * callback - A function to call when the event fires. 28 | 29 | Returns: Nothing. 30 | 31 | This function presents a familiar function for registering for custom events emitted by Folder. 32 | 33 | Known events: 34 | 35 | * set_attributes - Dispatched when SetAttributes()/SetAttribute() is called. 36 | * set_entries - Dispatched when SetEntries()/SetEntry() is called. 37 | * remove_entry - Dispatched when RemoveEntry() is called. 38 | * destroy - Dispatched when Destroy() is called. 39 | 40 | Folder.removeEventListener(eventname, callback) 41 | ----------------------------------------------- 42 | 43 | Category: Events 44 | 45 | Parameters: 46 | 47 | * eventname - A string containing a name of a Folder event to stop listening to. 48 | * callback - A function containing a registered callback to remove. 49 | 50 | Returns: Nothing. 51 | 52 | This function presents a familiar function for unregistering from custom events emitted by Folder. 53 | 54 | Folder.hasEventListener(eventname) 55 | ---------------------------------- 56 | 57 | Category: Events 58 | 59 | Parameters: 60 | 61 | * eventname - A string containing a name of a Folder event to check. 62 | 63 | Returns: A boolean of true if there are event listeners for the specified event, false otherwise. 64 | 65 | This function checks for the existence of an event and whether or not there are any listeners registered for the event. 66 | 67 | Folder.lastrefresh 68 | ------------------ 69 | 70 | Category: Internal variable 71 | 72 | This internal integer contains the last refresh timestamp. FileExplorer manages this value per Folder instance. 73 | 74 | Folder.waiting 75 | -------------- 76 | 77 | Category: Internal variable 78 | 79 | This internal boolean specifies whether or not the Folder is waiting for the first refresh callback to complete. The Folder instance sets this to true during a SetEntries() call. 80 | 81 | Folder.refs 82 | ----------- 83 | 84 | Category: Internal variable 85 | 86 | This internal integer tracks reference counts by the FileExplorer instance for folder map management. Do not use. 87 | 88 | Folder.SetBusyRef(newval) 89 | ------------------------- 90 | 91 | Category: Busy state 92 | 93 | Parameters: 94 | 95 | * newval - An integer containing the amount to add to the current busy state refcount. 96 | 97 | Returns: Nothing. 98 | 99 | This function adds the specified amount to the busy state refcount. If the refcount becomes <= 0, any queued busy callbacks are fired in the order they were added. Do not use. 100 | 101 | Folder.IsBusy() 102 | --------------- 103 | 104 | Category: Busy state 105 | 106 | Parameters: None. 107 | 108 | Returns: A boolean indicating whether or not the folder is busy. 109 | 110 | This function checks the busy status of the folder. Some operations enable the busy state. For example, when the mouse is used to start drawing a selection box, the busy state is enabled for the current folder so that the precalculated grid can't be modified by a SetEntries() call during the selection box operation, resulting in bizarre selections. When the mouse button is released, the busy state is cancelled and any queued callbacks fire. 111 | 112 | Folder.AddBusyQueueCallback(callback, callbackopts) 113 | --------------------------------------------------- 114 | 115 | Category: Busy state 116 | 117 | Parameters: 118 | 119 | * callback - A callback function to call when the busy state is complete. 120 | * callbackopts - An array of options to pass to the callback. 121 | 122 | Returns: Nothing. 123 | 124 | This function pushes the callback and callbackopts onto the busy queue and then calls `SetBusyRef(0)`. 125 | 126 | Folder.ClearBusyQueueCallbacks() 127 | -------------------------------- 128 | 129 | Category: Busy state 130 | 131 | Parameters: None. 132 | 133 | Returns: Nothing. 134 | 135 | This internal function clears the busy queue. Used by FileExplorer during `Destroy()`. Do not use. 136 | 137 | Folder.GetPath() 138 | ---------------- 139 | 140 | Category: Path information 141 | 142 | Parameters: None. 143 | 144 | Returns: The internal path array for the Folder instance. 145 | 146 | This function simply returns the internal Folder path array as-is. Do not modify. 147 | 148 | Folder.GetPathIDs() 149 | ------------------- 150 | 151 | Category: Path information 152 | 153 | Parameters: None. 154 | 155 | Returns: An array of path IDs. 156 | 157 | This function iterates over the path and constructs an array of path IDs. The return value is intended to be useful for sending the path of a folder to a server. 158 | 159 | Folder.SetAttributes(newattrs) 160 | ------------------------------ 161 | 162 | Category: Path attributes 163 | 164 | Parameters: 165 | 166 | * newattrs - An object containing new attributes to set for the current path. 167 | 168 | Returns: Nothing. 169 | 170 | This function overwrites the attributes of the current path item and dispatches the `set_attributes` event. 171 | 172 | Folder.SetAttribute(key, value) 173 | ------------------------------- 174 | 175 | Category: Path attributes 176 | 177 | Parameters: 178 | 179 | * key - A string containing the attribute key. 180 | * value - A value to assign to the attribute. 181 | 182 | Returns: Nothing. 183 | 184 | This function assigns an attribute of the current path item and dispatches the `set_attributes` event. 185 | 186 | Folder.GetAttributes() 187 | ---------------------- 188 | 189 | Category: Path attributes 190 | 191 | Parameters: None. 192 | 193 | Returns: The current attributes object for the path. 194 | 195 | This function returns the internal attributes object for the path. Do not modify directly. 196 | 197 | Folder.SetAutoSort(newautosort) 198 | ------------------------------- 199 | 200 | Category: Sorting 201 | 202 | Parameters: 203 | 204 | * newautosort - A boolean that specifies whether or not the Folder instance should automatically sort entries. 205 | 206 | Returns: Nothing. 207 | 208 | This function enables/disables automatic sorting of entries. 209 | 210 | Folder.SortEntries() 211 | -------------------- 212 | 213 | Category: Sorting 214 | 215 | Parameters: None. 216 | 217 | Returns: Nothing. 218 | 219 | This function sorts the entries using a locale-sensitive + numeric comparison function. Entries with a type of 'folder' also sort so they come before 'file' entries. 220 | 221 | Folder.SetEntries(newentries) 222 | ----------------------------- 223 | 224 | Category: Entries 225 | 226 | Parameters: 227 | 228 | * newentries - An array of objects containing the entries to set. 229 | 230 | Returns: Nothing. 231 | 232 | This function sets the new entries array, automatically sorts the entries (if enabled), rebuilds the entry ID map (ID to position in array), and dispatches the 'set_entries' event. 233 | 234 | Each entry consists of an object with the following required key-value pairs: 235 | 236 | * id - A unique string for the Folder instance that is DOM dataset compatible. This string should also be server compatible (e.g. map to a database). 237 | * name - A string to display to the user. Used by automatic sorting (if enabled). 238 | * type - A string containing one of 'folder' or 'file'. 239 | * hash - A string containing a hash or something uniquely identifiable to use during DOM updates that an item has NOT changed. 240 | 241 | Each entry consists of an object with the following optional key-value pairs: 242 | 243 | * attrs - An object containing key-value pairs. Currently, 'canmodify' is the only key-value recognized by FileExplorer. 244 | * size - An integer containing the size, in bytes, of the entry on disk. 245 | * tooltip - A string to use for the title to display as a tooltip when hovering. Most browsers natively support multi-line tooltips. 246 | * thumb - A string containing a URL to a thumbnail image to display. A standard icon is displayed while the thumbnail loads in the background. Thumbnails of large images should be scaled to no smaller than 196x196 to handle 4x pixel densities. 247 | * overlay - A string containing one or an array containing one or more class names to apply to the item in the DOM for purposes of displaying an overlay icon/text using CSS. 248 | 249 | Folder.UpdateEntries(updatedentries) 250 | ------------------------------------ 251 | 252 | Category: Entries 253 | 254 | Parameters: 255 | 256 | * updatedentries - An array of objects containing the entries to add/update. 257 | 258 | Returns: Nothing. 259 | 260 | This function adds/updates the entries array, automatically sorts the entries (if enabled), rebuilds the entry ID map (ID to position in array), and dispatches the 'set_entries' event. 261 | 262 | Folder.SetEntry(entry) 263 | ---------------------- 264 | 265 | Category: Entries 266 | 267 | Parameters: 268 | 269 | * entry - An object containing the entry to set. 270 | 271 | Returns: Nothing. 272 | 273 | This function sets a single entry, automatically sorts the entries (if enabled), rebuilds the entry ID map (ID to position in array), and dispatches the 'set_entries' event. 274 | 275 | This is an inefficient function to call repeatedly for setting a bunch of entries. It's designed for convenience to set a single entry. 276 | 277 | Folder.RemoveEntry(id) 278 | ---------------------- 279 | 280 | Category: Entries 281 | 282 | Parameters: 283 | 284 | * id - A string containing the ID of the entry to remove. 285 | 286 | Returns: Nothing. 287 | 288 | This function removes a single entry, adjusts the entry ID map (ID to position in array), and dispatches the 'remove_entry' event. 289 | 290 | This is an inefficient function to call for more than a couple of entries at one time. It's designed for convenience and performance for removing just one entry at a time. 291 | 292 | Folder.GetEntries() 293 | ------------------- 294 | 295 | Category: Entries 296 | 297 | Parameters: None. 298 | 299 | Returns: The array of entries. 300 | 301 | This function returns the internal array of entries for the Folder instance. 302 | 303 | Folder.GetEntryIDMap() 304 | ---------------------- 305 | 306 | Category: Entries 307 | 308 | Parameters: None. 309 | 310 | Returns: The object of entry IDs to positions into the entry array. 311 | 312 | This function returns the internal precalculated ID to position map for the Folder instance. This function is usually used in conjunction with GetEntries() for high-performance lookups by ID. 313 | 314 | Folder.Destroy() 315 | ---------------- 316 | 317 | Category: Destructor 318 | 319 | Parameters: None. 320 | 321 | Returns: Nothing. 322 | 323 | This function destroys the Folder instance. Should only be called by FileExplorer when the folder reference count reaches zero. 324 | -------------------------------------------------------------------------------- /server-side-helpers/deflate_stream.php: -------------------------------------------------------------------------------- 1 | open = false; 13 | } 14 | 15 | public function __destruct() 16 | { 17 | $this->Finalize(); 18 | } 19 | 20 | public static function IsSupported() 21 | { 22 | if (!is_bool(self::$supported)) 23 | { 24 | self::$supported = function_exists("stream_filter_append") && function_exists("stream_filter_remove") && function_exists("gzcompress"); 25 | if (self::$supported) 26 | { 27 | $data = self::Compress("test"); 28 | if ($data === false || $data === "") self::$supported = false; 29 | else 30 | { 31 | $data = self::Uncompress($data); 32 | if ($data === false || $data !== "test") self::$supported = false; 33 | } 34 | } 35 | } 36 | 37 | return self::$supported; 38 | } 39 | 40 | public static function Compress($data, $compresslevel = -1, $options = array()) 41 | { 42 | $ds = new DeflateStream; 43 | if (!$ds->Init("wb", $compresslevel, $options)) return false; 44 | if (!$ds->Write($data)) return false; 45 | if (!$ds->Finalize()) return false; 46 | $data = $ds->Read(); 47 | 48 | return $data; 49 | } 50 | 51 | public static function Uncompress($data, $options = array("type" => "auto")) 52 | { 53 | $ds = new DeflateStream; 54 | if (!$ds->Init("rb", -1, $options)) return false; 55 | if (!$ds->Write($data)) return false; 56 | if (!$ds->Finalize()) return false; 57 | $data = $ds->Read(); 58 | 59 | return $data; 60 | } 61 | 62 | public function Init($mode, $compresslevel = -1, $options = array()) 63 | { 64 | if ($mode !== "rb" && $mode !== "wb") return false; 65 | if ($this->open) $this->Finalize(); 66 | 67 | $this->fp = fopen("php://memory", "w+b"); 68 | if ($this->fp === false) return false; 69 | $this->compress = ($mode == "wb"); 70 | if (!isset($options["type"])) $options["type"] = "rfc1951"; 71 | 72 | if ($options["type"] == "rfc1950") $options["type"] = "zlib"; 73 | else if ($options["type"] == "rfc1952") $options["type"] = "gzip"; 74 | 75 | if ($options["type"] != "zlib" && $options["type"] != "gzip" && ($this->compress || $options["type"] != "auto")) $options["type"] = "raw"; 76 | $this->options = $options; 77 | 78 | // Add the deflate filter. 79 | if ($this->compress) $this->filter = stream_filter_append($this->fp, "zlib.deflate", STREAM_FILTER_WRITE, $compresslevel); 80 | else $this->filter = stream_filter_append($this->fp, "zlib.inflate", STREAM_FILTER_READ); 81 | 82 | $this->open = true; 83 | $this->indata = ""; 84 | $this->outdata = ""; 85 | 86 | if ($this->compress) 87 | { 88 | if ($this->options["type"] == "zlib") 89 | { 90 | $this->outdata .= "\x78\x9C"; 91 | $this->options["a"] = 1; 92 | $this->options["b"] = 0; 93 | } 94 | else if ($this->options["type"] == "gzip") 95 | { 96 | if (!class_exists("CRC32Stream", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/crc32_stream.php"; 97 | 98 | $this->options["crc32"] = new CRC32Stream(); 99 | $this->options["crc32"]->Init(); 100 | $this->options["bytes"] = 0; 101 | 102 | $this->outdata .= "\x1F\x8B\x08"; 103 | $flags = 0; 104 | if (isset($this->options["filename"])) $flags |= 0x08; 105 | if (isset($this->options["comment"])) $flags |= 0x10; 106 | $this->outdata .= chr($flags); 107 | $this->outdata .= "\x00\x00\x00\x00"; 108 | $this->outdata .= "\x00"; 109 | $this->outdata .= "\x03"; 110 | 111 | if (isset($this->options["filename"])) $this->outdata .= str_replace("\x00", " ", $this->options["filename"]) . "\x00"; 112 | if (isset($this->options["comment"])) $this->outdata .= str_replace("\x00", " ", $this->options["comment"]) . "\x00"; 113 | } 114 | } 115 | else 116 | { 117 | $this->options["header"] = false; 118 | } 119 | 120 | return true; 121 | } 122 | 123 | public function Read() 124 | { 125 | $result = $this->outdata; 126 | $this->outdata = ""; 127 | 128 | return $result; 129 | } 130 | 131 | public function Write($data) 132 | { 133 | if (!$this->open) return false; 134 | 135 | if ($this->compress) 136 | { 137 | if ($this->options["type"] == "zlib") 138 | { 139 | // Adler-32. 140 | $y = strlen($data); 141 | for ($x = 0; $x < $y; $x++) 142 | { 143 | $this->options["a"] = ($this->options["a"] + ord($data[$x])) % 65521; 144 | $this->options["b"] = ($this->options["b"] + $this->options["a"]) % 65521; 145 | } 146 | } 147 | else if ($this->options["type"] == "gzip") 148 | { 149 | $this->options["crc32"]->AddData($data); 150 | $this->options["bytes"] = $this->ADD32($this->options["bytes"], strlen($data)); 151 | } 152 | 153 | $this->indata .= $data; 154 | while (strlen($this->indata) >= 65536) 155 | { 156 | fwrite($this->fp, substr($this->indata, 0, 65536)); 157 | $this->indata = substr($this->indata, 65536); 158 | 159 | $this->ProcessOutput(); 160 | } 161 | } 162 | else 163 | { 164 | $this->indata .= $data; 165 | $this->ProcessInput(); 166 | } 167 | 168 | return true; 169 | } 170 | 171 | // Finalizes the stream. 172 | public function Finalize() 173 | { 174 | if (!$this->open) return false; 175 | 176 | if (!$this->compress) $this->ProcessInput(true); 177 | 178 | if (strlen($this->indata) > 0) 179 | { 180 | fwrite($this->fp, $this->indata); 181 | $this->indata = ""; 182 | } 183 | 184 | // Removing the filter pushes the last buffer into the stream. 185 | stream_filter_remove($this->filter); 186 | $this->filter = false; 187 | 188 | $this->ProcessOutput(); 189 | 190 | fclose($this->fp); 191 | 192 | if ($this->compress) 193 | { 194 | if ($this->options["type"] == "zlib") $this->outdata .= pack("N", $this->SHL32($this->options["b"], 16) | $this->options["a"]); 195 | else if ($this->options["type"] == "gzip") $this->outdata .= pack("V", $this->options["crc32"]->Finalize()) . pack("V", $this->options["bytes"]); 196 | } 197 | 198 | $this->open = false; 199 | 200 | return true; 201 | } 202 | 203 | private function ProcessOutput() 204 | { 205 | rewind($this->fp); 206 | 207 | // Hack! Because ftell() on a stream with a filter is still broken even under the latest PHP a mere 11 years later. 208 | // See: https://bugs.php.net/bug.php?id=49874 209 | ob_start(); 210 | fpassthru($this->fp); 211 | $this->outdata .= ob_get_contents(); 212 | ob_end_clean(); 213 | 214 | rewind($this->fp); 215 | ftruncate($this->fp, 0); 216 | } 217 | 218 | private function ProcessInput($final = false) 219 | { 220 | // Automatically determine the type of data based on the header signature. 221 | if ($this->options["type"] == "auto") 222 | { 223 | if (strlen($this->indata) >= 3) 224 | { 225 | $zlibtest = unpack("n", substr($this->indata, 0, 2)); 226 | 227 | if (substr($this->indata, 0, 3) === "\x1F\x8B\x08") $this->options["type"] = "gzip"; 228 | else if ((ord($this->indata[0]) & 0x0F) == 8 && ((ord($this->indata[0]) & 0xF0) >> 4) < 8 && $zlibtest[1] % 31 == 0) $this->options["type"] = "zlib"; 229 | else $this->options["type"] = "raw"; 230 | } 231 | else if ($final) $this->options["type"] = "raw"; 232 | } 233 | 234 | if ($this->options["type"] == "gzip") 235 | { 236 | if (!$this->options["header"]) 237 | { 238 | if (strlen($this->indata) >= 10) 239 | { 240 | $idcm = substr($this->indata, 0, 3); 241 | $flg = ord($this->indata[3]); 242 | 243 | if ($idcm !== "\x1F\x8B\x08") $this->options["type"] = "ignore"; 244 | else 245 | { 246 | // Calculate the number of bytes to skip. If flags are set, the size can be dynamic. 247 | $size = 10; 248 | $y = strlen($this->indata); 249 | 250 | // FLG.FEXTRA 251 | if ($size && ($flg & 0x04)) 252 | { 253 | if ($size + 2 >= $y) $size = 0; 254 | else 255 | { 256 | $xlen = unpack("v", substr($this->indata, $size, 2)); 257 | $size = ($size + 2 + $xlen <= $y ? $size + 2 + $xlen : 0); 258 | } 259 | } 260 | 261 | // FLG.FNAME 262 | if ($size && ($flg & 0x08)) 263 | { 264 | $pos = strpos($this->indata, "\x00", $size); 265 | $size = ($pos !== false ? $pos + 1 : 0); 266 | } 267 | 268 | // FLG.FCOMMENT 269 | if ($size && ($flg & 0x10)) 270 | { 271 | $pos = strpos($this->indata, "\x00", $size); 272 | $size = ($pos !== false ? $pos + 1 : 0); 273 | } 274 | 275 | // FLG.FHCRC 276 | if ($size && ($flg & 0x02)) $size = ($size + 2 <= $y ? $size + 2 : 0); 277 | 278 | if ($size) 279 | { 280 | $this->indata = substr($this->indata, $size); 281 | $this->options["header"] = true; 282 | } 283 | } 284 | } 285 | } 286 | 287 | if ($this->options["header"] && strlen($this->indata) > 8) 288 | { 289 | fwrite($this->fp, substr($this->indata, 0, -8)); 290 | $this->indata = substr($this->indata, -8); 291 | 292 | $this->ProcessOutput(); 293 | } 294 | 295 | if ($final) $this->indata = ""; 296 | } 297 | else if ($this->options["type"] == "zlib") 298 | { 299 | if (!$this->options["header"]) 300 | { 301 | if (strlen($this->indata) >= 2) 302 | { 303 | $cmf = ord($this->indata[0]); 304 | $flg = ord($this->indata[1]); 305 | $cm = $cmf & 0x0F; 306 | $cinfo = ($cmf & 0xF0) >> 4; 307 | 308 | // Compression method 'deflate' ($cm = 8), window size - 8 ($cinfo < 8), no preset dictionaries ($flg bit 5), checksum validates. 309 | if ($cm != 8 || $cinfo > 7 || ($flg & 0x20) || (($cmf << 8 | $flg) % 31) != 0) $this->options["type"] = "ignore"; 310 | else 311 | { 312 | $this->indata = substr($this->indata, 2); 313 | $this->options["header"] = true; 314 | } 315 | } 316 | } 317 | 318 | if ($this->options["header"] && strlen($this->indata) > 4) 319 | { 320 | fwrite($this->fp, substr($this->indata, 0, -4)); 321 | $this->indata = substr($this->indata, -4); 322 | 323 | $this->ProcessOutput(); 324 | } 325 | 326 | if ($final) $this->indata = ""; 327 | } 328 | 329 | if ($this->options["type"] == "raw") 330 | { 331 | fwrite($this->fp, $this->indata); 332 | $this->indata = ""; 333 | 334 | $this->ProcessOutput(); 335 | } 336 | 337 | // Only set when an unrecoverable header error has occurred for gzip or zlib. 338 | if ($this->options["type"] == "ignore") $this->indata = ""; 339 | } 340 | 341 | private function SHL32($num, $bits) 342 | { 343 | if ($bits < 0) $bits = 0; 344 | 345 | return $this->LIM32((int)$num << $bits); 346 | } 347 | 348 | private function LIM32($num) 349 | { 350 | return (int)((int)$num & 0xFFFFFFFF); 351 | } 352 | 353 | private function ADD32($num, $num2) 354 | { 355 | $num = (int)$num; 356 | $num2 = (int)$num2; 357 | $add = ((($num >> 30) & 0x03) + (($num2 >> 30) & 0x03)); 358 | $num = ((int)($num & 0x3FFFFFFF) + (int)($num2 & 0x3FFFFFFF)); 359 | if ($num & 0x40000000) $add++; 360 | $num = (int)(($num & 0x3FFFFFFF) | (($add & 0x03) << 30)); 361 | 362 | return $num; 363 | } 364 | } 365 | ?> -------------------------------------------------------------------------------- /server-side-helpers/file_upload_helper.php: -------------------------------------------------------------------------------- 1 | false, 52 | "error" => self::FHTranslate($msg), 53 | "errorcode" => $code 54 | ); 55 | } 56 | else if (!is_uploaded_file($currfiles["tmp_name"][$x])) 57 | { 58 | $entry = array( 59 | "success" => false, 60 | "error" => self::FHTranslate("The specified input filename was not uploaded to this server."), 61 | "errorcode" => "invalid_input_filename" 62 | ); 63 | } 64 | else 65 | { 66 | $currfiles["name"][$x] = self::FilenameSafe($currfiles["name"][$x]); 67 | $pos = strrpos($currfiles["name"][$x], "."); 68 | $fileext = ($pos !== false ? (string)substr($currfiles["name"][$x], $pos + 1) : ""); 69 | 70 | $entry = array( 71 | "success" => true, 72 | "file" => $currfiles["tmp_name"][$x], 73 | "name" => $currfiles["name"][$x], 74 | "ext" => $fileext, 75 | "type" => $currfiles["type"][$x], 76 | "size" => $currfiles["size"][$x] 77 | ); 78 | } 79 | 80 | $result[] = $entry; 81 | } 82 | } 83 | } 84 | 85 | return $result; 86 | } 87 | 88 | public static function GetMaxUploadFileSize() 89 | { 90 | $maxpostsize = floor(self::ConvertUserStrToBytes(ini_get("post_max_size")) * 3 / 4); 91 | if ($maxpostsize > 4096) $maxpostsize -= 4096; 92 | 93 | $maxuploadsize = self::ConvertUserStrToBytes(ini_get("upload_max_filesize")); 94 | if ($maxuploadsize < 1) $maxuploadsize = ($maxpostsize < 1 ? -1 : $maxpostsize); 95 | 96 | return ($maxpostsize < 1 ? $maxuploadsize : min($maxpostsize, $maxuploadsize)); 97 | } 98 | 99 | // Copy included for class self-containment. 100 | public static function ConvertUserStrToBytes($str) 101 | { 102 | $str = trim($str); 103 | $num = (double)$str; 104 | if (strtoupper(substr($str, -1)) == "B") $str = substr($str, 0, -1); 105 | switch (strtoupper(substr($str, -1))) 106 | { 107 | case "P": $num *= 1024; 108 | case "T": $num *= 1024; 109 | case "G": $num *= 1024; 110 | case "M": $num *= 1024; 111 | case "K": $num *= 1024; 112 | } 113 | 114 | return $num; 115 | } 116 | 117 | public static function GetChunkFilename() 118 | { 119 | if (isset($_SERVER["HTTP_CONTENT_DISPOSITION"])) 120 | { 121 | // Content-Disposition: attachment; filename="urlencodedstr" 122 | $str = $_SERVER["HTTP_CONTENT_DISPOSITION"]; 123 | if (strtolower(substr($str, 0, 11)) === "attachment;") 124 | { 125 | $pos = strpos($str, "\"", 11); 126 | $pos2 = strrpos($str, "\""); 127 | 128 | if ($pos !== false && $pos2 !== false && $pos < $pos2) 129 | { 130 | $str = self::FilenameSafe(rawurldecode(substr($str, $pos + 1, $pos2 - $pos - 1))); 131 | 132 | if ($str !== "") return $str; 133 | } 134 | } 135 | } 136 | 137 | return false; 138 | } 139 | 140 | public static function GetFileStartPosition() 141 | { 142 | if (isset($_SERVER["HTTP_CONTENT_RANGE"]) || isset($_SERVER["HTTP_RANGE"])) 143 | { 144 | // Content-Range: bytes (*|integer-integer)/(*|integer-integer) 145 | $vals = explode(" ", preg_replace('/\s+/', " ", str_replace(",", "", (isset($_SERVER["HTTP_CONTENT_RANGE"]) ? $_SERVER["HTTP_CONTENT_RANGE"] : $_SERVER["HTTP_RANGE"])))); 146 | if (count($vals) === 2 && strtolower($vals[0]) === "bytes") 147 | { 148 | $vals = explode("/", trim($vals[1])); 149 | if (count($vals) === 2) 150 | { 151 | $vals = explode("-", trim($vals[0])); 152 | 153 | if (count($vals) === 2) return (double)$vals[0]; 154 | } 155 | } 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | public static function HandleUpload($filekey, $options = array()) 162 | { 163 | if (!isset($_REQUEST["fileuploader"]) && !isset($_POST["fileuploader"])) return array("success" => false, "error" => "No upload or missing 'fileuploader'.", "errorcode" => "no_upload"); 164 | 165 | if (isset($options["allowed_exts"])) 166 | { 167 | $allowedexts = array(); 168 | 169 | if (is_string($options["allowed_exts"])) $options["allowed_exts"] = explode(",", $options["allowed_exts"]); 170 | 171 | foreach ($options["allowed_exts"] as $ext) 172 | { 173 | $ext = strtolower(trim(trim($ext), ".")); 174 | if ($ext !== "") $allowedexts[$ext] = true; 175 | } 176 | } 177 | 178 | $files = self::NormalizeFiles($filekey); 179 | if (!isset($files[0])) $result = array("success" => false, "error" => self::FHTranslate("File data was submitted but is missing."), "errorcode" => "bad_input"); 180 | else if (!$files[0]["success"]) $result = $files[0]; 181 | else if (isset($options["allowed_exts"]) && !isset($allowedexts[strtolower($files[0]["ext"])])) 182 | { 183 | $result = array( 184 | "success" => false, 185 | "error" => self::FHTranslate("Invalid file extension. Must be one of %s.", "'." . implode("', '.", array_keys($allowedexts)) . "'"), 186 | "errorcode" => "invalid_file_ext" 187 | ); 188 | } 189 | else 190 | { 191 | // For chunked file uploads, get the current filename and starting position from the incoming headers. 192 | $name = self::GetChunkFilename(); 193 | if ($name !== false) 194 | { 195 | $startpos = self::GetFileStartPosition(); 196 | 197 | $name = substr($name, 0, -(strlen($files[0]["ext"]) + 1)); 198 | 199 | if (isset($options["filename_callback"]) && is_callable($options["filename_callback"])) $filename = call_user_func_array($options["filename_callback"], array($name, strtolower($files[0]["ext"]), $files[0])); 200 | else if (isset($options["filename"])) $filename = (isset($options["fixed_filename"]) && $options["fixed_filename"] ? $options["filename"] : str_replace(array("{name}", "{ext}"), array($name, strtolower($files[0]["ext"])), $options["filename"])); 201 | else $filename = false; 202 | 203 | if (!is_string($filename)) $result = array("success" => false, "error" => self::FHTranslate("The server did not set a valid filename."), "errorcode" => "invalid_filename"); 204 | else if (isset($options["limit"]) && $options["limit"] > -1 && $startpos + filesize($files[0]["file"]) > $options["limit"]) $result = array("success" => false, "error" => self::FHTranslate("The server file size limit was exceeded."), "errorcode" => "file_too_large"); 205 | else 206 | { 207 | if (file_exists($filename) && $startpos === filesize($filename)) $fp = @fopen($filename, "ab"); 208 | else 209 | { 210 | $fp = @fopen($filename, ($startpos > 0 && file_exists($filename) ? "r+b" : "wb")); 211 | if ($fp !== false) @fseek($fp, $startpos, SEEK_SET); 212 | } 213 | 214 | $fp2 = @fopen($files[0]["file"], "rb"); 215 | 216 | if ($fp === false) $result = array("success" => false, "error" => self::FHTranslate("Unable to open a required file for writing."), "errorcode" => "open_failed", "info" => $filename); 217 | else if ($fp2 === false) $result = array("success" => false, "error" => self::FHTranslate("Unable to open a required file for reading."), "errorcode" => "open_failed", "info" => $files[0]["file"]); 218 | else 219 | { 220 | do 221 | { 222 | $data2 = @fread($fp2, 1048576); 223 | if ($data2 == "") break; 224 | 225 | @fwrite($fp, $data2); 226 | } while (1); 227 | 228 | fclose($fp2); 229 | fclose($fp); 230 | 231 | $result = array( 232 | "success" => true 233 | ); 234 | } 235 | } 236 | } 237 | else 238 | { 239 | $name = substr($files[0]["name"], 0, -(strlen($files[0]["ext"]) + 1)); 240 | 241 | if (isset($options["filename_callback"]) && is_callable($options["filename_callback"])) $filename = call_user_func_array($options["filename_callback"], array($name, strtolower($files[0]["ext"]), $files[0])); 242 | else if (isset($options["filename"])) $filename = (isset($options["fixed_filename"]) && $options["fixed_filename"] ? $options["filename"] : str_replace(array("{name}", "{ext}"), array($name, strtolower($files[0]["ext"])), $options["filename"])); 243 | else $filename = false; 244 | 245 | if (!is_string($filename)) $result = array("success" => false, "error" => self::FHTranslate("The server did not set a valid filename."), "errorcode" => "invalid_filename"); 246 | else if (isset($options["limit"]) && $options["limit"] > -1 && filesize($files[0]["file"]) > $options["limit"]) $result = array("success" => false, "error" => self::FHTranslate("The server file size limit was exceeded."), "errorcode" => "file_too_large"); 247 | else 248 | { 249 | @copy($files[0]["file"], $filename); 250 | 251 | $result = array( 252 | "success" => true 253 | ); 254 | } 255 | } 256 | } 257 | 258 | if ($result["success"] && isset($options["result_callback"]) && is_callable($options["result_callback"])) call_user_func_array($options["result_callback"], array(&$result, $filename, $name, strtolower($files[0]["ext"]), $files[0], (isset($options["result_callback_opts"]) ? $options["result_callback_opts"] : false))); 259 | 260 | if (isset($options["return_result"]) && $options["return_result"]) return $result; 261 | 262 | header("Content-Type: application/json"); 263 | 264 | echo json_encode($result, JSON_UNESCAPED_SLASHES); 265 | 266 | exit(); 267 | } 268 | 269 | public static function FHTranslate() 270 | { 271 | $args = func_get_args(); 272 | if (!count($args)) return ""; 273 | 274 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 275 | } 276 | } 277 | ?> -------------------------------------------------------------------------------- /artwork/main_sprite_sheet.tps: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | fileFormatVersion 5 | 4 6 | texturePackerVersion 7 | 5.3.0 8 | autoSDSettings 9 | 10 | 11 | scale 12 | 1 13 | extension 14 | 15 | spriteFilter 16 | 17 | acceptFractionalValues 18 | 19 | maxTextureSize 20 | 21 | width 22 | -1 23 | height 24 | -1 25 | 26 | 27 | 28 | allowRotation 29 | 30 | shapeDebug 31 | 32 | dpi 33 | 72 34 | dataFormat 35 | css-simple 36 | textureFileName 37 | ../file-explorer/file-explorer-sprites.png 38 | flipPVR 39 | 40 | pvrCompressionQuality 41 | PVR_QUALITY_NORMAL 42 | atfCompressData 43 | 44 | mipMapMinSize 45 | 32768 46 | etc1CompressionQuality 47 | ETC1_QUALITY_LOW_PERCEPTUAL 48 | etc2CompressionQuality 49 | ETC2_QUALITY_LOW_PERCEPTUAL 50 | dxtCompressionMode 51 | DXT_PERCEPTUAL 52 | jxrColorFormat 53 | JXR_YUV444 54 | jxrTrimFlexBits 55 | 0 56 | jxrCompressionLevel 57 | 0 58 | ditherType 59 | NearestNeighbour 60 | backgroundColor 61 | 0 62 | libGdx 63 | 64 | filtering 65 | 66 | x 67 | Linear 68 | y 69 | Linear 70 | 71 | 72 | shapePadding 73 | 0 74 | jpgQuality 75 | 80 76 | pngOptimizationLevel 77 | 0 78 | webpQualityLevel 79 | 101 80 | textureSubPath 81 | 82 | atfFormats 83 | 84 | textureFormat 85 | png 86 | borderPadding 87 | 0 88 | maxTextureSize 89 | 90 | width 91 | 2048 92 | height 93 | 2048 94 | 95 | fixedTextureSize 96 | 97 | width 98 | -1 99 | height 100 | -1 101 | 102 | algorithmSettings 103 | 104 | algorithm 105 | Basic 106 | freeSizeMode 107 | Best 108 | sizeConstraints 109 | AnySize 110 | forceSquared 111 | 112 | maxRects 113 | 114 | heuristic 115 | Best 116 | 117 | basic 118 | 119 | sortBy 120 | Best 121 | order 122 | Ascending 123 | 124 | polygon 125 | 126 | alignToGrid 127 | 1 128 | 129 | 130 | dataFileNames 131 | 132 | data 133 | 134 | name 135 | texturepacker_export.css 136 | 137 | 138 | multiPack 139 | 140 | forceIdenticalLayout 141 | 142 | outputFormat 143 | RGBA8888 144 | alphaHandling 145 | ClearTransparentPixels 146 | contentProtection 147 | 148 | key 149 | 150 | 151 | autoAliasEnabled 152 | 153 | trimSpriteNames 154 | 155 | prependSmartFolderName 156 | 157 | autodetectAnimations 158 | 159 | globalSpriteSettings 160 | 161 | scale 162 | 1 163 | scaleMode 164 | Smooth 165 | extrude 166 | 0 167 | trimThreshold 168 | 1 169 | trimMargin 170 | 1 171 | trimMode 172 | None 173 | tracerTolerance 174 | 200 175 | heuristicMask 176 | 177 | defaultPivotPoint 178 | 0.5,0.5 179 | writePivotPoints 180 | 181 | 182 | individualSpriteSettings 183 | 184 | pngs/fileexplorer_arrow_left_icon.png 185 | pngs/fileexplorer_arrow_left_icon_hover.png 186 | pngs/fileexplorer_arrow_right_icon.png 187 | pngs/fileexplorer_arrow_right_icon_hover.png 188 | 189 | pivotPoint 190 | 0.5,0.5 191 | spriteScale 192 | 1 193 | scale9Enabled 194 | 195 | scale9Borders 196 | 8,6,16,12 197 | scale9Paddings 198 | 8,6,16,12 199 | scale9FromFile 200 | 201 | 202 | pngs/fileexplorer_arrow_up_icon.png 203 | pngs/fileexplorer_arrow_up_icon_hover.png 204 | pngs/fileexplorer_menu_back_icon.png 205 | pngs/fileexplorer_menu_check_icon.png 206 | pngs/fileexplorer_menu_forward_icon.png 207 | pngs/fileexplorer_open_icon.png 208 | pngs/fileexplorer_path_cloud_icon.png 209 | pngs/fileexplorer_path_icon.png 210 | pngs/fileexplorer_tool_checked_icon.png 211 | pngs/fileexplorer_tool_copy_icon.png 212 | pngs/fileexplorer_tool_cut_icon.png 213 | pngs/fileexplorer_tool_delete_icon.png 214 | pngs/fileexplorer_tool_download_icon.png 215 | pngs/fileexplorer_tool_new_file_icon.png 216 | pngs/fileexplorer_tool_new_folder_icon.png 217 | pngs/fileexplorer_tool_paste_icon.png 218 | pngs/fileexplorer_tool_unchecked_icon.png 219 | pngs/fileexplorer_tool_upload_icon.png 220 | 221 | pivotPoint 222 | 0.5,0.5 223 | spriteScale 224 | 1 225 | scale9Enabled 226 | 227 | scale9Borders 228 | 6,6,12,12 229 | scale9Paddings 230 | 6,6,12,12 231 | scale9FromFile 232 | 233 | 234 | pngs/fileexplorer_collapsed_icon.png 235 | pngs/fileexplorer_collapsed_icon_hover.png 236 | pngs/fileexplorer_expanded_icon.png 237 | pngs/fileexplorer_expanded_icon_hover.png 238 | 239 | pivotPoint 240 | 0.5,0.5 241 | spriteScale 242 | 1 243 | scale9Enabled 244 | 245 | scale9Borders 246 | 5,6,9,12 247 | scale9Paddings 248 | 5,6,9,12 249 | scale9FromFile 250 | 251 | 252 | pngs/fileexplorer_item_file_icon.png 253 | pngs/fileexplorer_item_folder_icon.png 254 | 255 | pivotPoint 256 | 0.5,0.5 257 | spriteScale 258 | 1 259 | scale9Enabled 260 | 261 | scale9Borders 262 | 12,12,24,24 263 | scale9Paddings 264 | 12,12,24,24 265 | scale9FromFile 266 | 267 | 268 | 269 | fileList 270 | 271 | pngs 272 | 273 | ignoreFileList 274 | 275 | replaceList 276 | 277 | ignoredWarnings 278 | 279 | commonDivisorX 280 | 1 281 | commonDivisorY 282 | 1 283 | packNormalMaps 284 | 285 | autodetectNormalMaps 286 | 287 | normalMapFilter 288 | 289 | normalMapSuffix 290 | 291 | normalMapSheetFileName 292 | 293 | exporterProperties 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CubicleSoft File Explorer Demo 6 | 7 | 16 | 17 |

This is a fully functioning demo of CubicleSoft File Explorer.

18 |

Blah

19 |

Blah

20 |

Blah

21 |

Blah

22 | 23 | 24 | 25 | 26 |
27 | 28 | 435 | 436 |

Blah

437 |

Blah

438 |

Blah

439 |

Blah

440 |

Blah

441 |

Blah

442 |

Blah

443 |

Blah

444 |

Blah

445 |

Blah

446 |

Blah

447 |

Blah

448 |

Blah

449 |

Blah

450 | 451 | 452 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Folder and File Explorer 2 | ======================== 3 | 4 | A zero dependencies, customizable, pure Javascript widget for navigating, managing (move, copy, delete), uploading, and downloading files and folders or other hierarchical object structures on any modern web browser. Choose from a MIT or LGPL license. 5 | 6 | [![Screenshot of CubicleSoft File Explorer](https://user-images.githubusercontent.com/1432111/83955166-e3003a80-a804-11ea-806a-07b927297ccb.png)](https://cubiclesoft.com/demos/js-fileexplorer/demo.html) 7 | 8 | [Live Demo](https://cubiclesoft.com/demos/js-fileexplorer/demo.html) | [The making of this widget](https://cubicspot.blogspot.com/2020/06/building-complex-javascript-widgets.html) 9 | 10 | Experience a clean, elegant presentation of folders and files in a mobile-friendly layout that looks and feels great on all devices. CubicleSoft File Explorer is easily connected to any web application that needs to manage hierarchical objects (folders and files, database records, or even JSON, XML, etc). 11 | 12 | Check out a working product that uses this widget: [PHP File Manager and Editor](https://github.com/cubiclesoft/php-filemanager) 13 | 14 | [![Donate](https://cubiclesoft.com/res/donate-shield.png)](https://cubiclesoft.com/donate/) [![Discord](https://img.shields.io/discord/777282089980526602?label=chat&logo=discord)](https://cubiclesoft.com/product-support/github/) 15 | 16 | If you use this project, don't forget to donate to support its development! 17 | 18 | Features 19 | -------- 20 | 21 | * Clean, elegant presentation of folders and files in a mobile-friendly layout. 22 | * Zero dependencies. No other libraries required! 23 | * Can handle displaying thousands of files in a folder. 24 | * Full keyboard, mouse, and touch support. Secure from fake/simulated keyboard, mouse, and touch events. 25 | * Keyboard shortcuts. Lots of keyboard shortcuts. 26 | * Folder history tracking and navigation. Optionally navigate through folder history in the widget using the back and forward buttons on the mouse. 27 | * Customizable toolbar. 28 | * Create new files and folders. 29 | * Easily rename and delete/recycle files and folders. 30 | * Double-click/tap or press Enter to open items in your application-defined manner. 31 | * Powerful file and folder selection tools. Selection boxes with variable-speed scrolling on desktop browsers. 32 | * Multi-select checkboxes on touch devices. Can be enabled for non-touch devices too. 33 | * Cut/Copy/Paste items using: Keyboard shortcuts, mouse right-click menu, or toolbar buttons. 34 | * Cut/Copy/Paste items between compatible widget instances...even across different web browsers! 35 | * Drag-and-drop support between compatible widget instances. 36 | * Drag-and-drop bulk uploading support directly from the OS for both files and folders. 37 | * Drag-and-drop direct URL downloading support (Chromium only). 38 | * Chunked file upload support. 39 | * Download files and folders via a toolbar button. 40 | * Items can be displayed as a thumbnail image, including folders. Thumbnails are intelligently bulk loaded in the background using a custom lazy loader. 41 | * Items can have detailed tooltips, overlays, size information, etc. 42 | * Automatic item sorting (can be disabled per folder). 43 | * Provides useful feedback on the status bar - items in a folder, number selected, active upload information, etc. 44 | * Can easily be connected to a WebSocket backend (e.g. [Data Relay Center](https://github.com/cubiclesoft/php-drc)) to efficiently watch for folder updates. 45 | * Event-handler style callbacks. Way more callbacks than you'll probably need. 46 | * Plenty of automation possibilities too via the extensive [FileExplorer API](docs/file_explorer.md). 47 | * Multilingual support. 48 | * And much, much more. 49 | 50 | Getting Started 51 | --------------- 52 | 53 | To use this widget, you should be quite comfortable with writing both client-side Javascript and secure server-side code. Client-side Javascript is never a proper defense mechanism for proper server-side security and assume someone will try to break into your server by sending bad folder and file paths to the server to read/write data they shouldn't have access to. 54 | 55 | Also note that this widget only provides the client-side (web browser) portion of the equation. You will need to supply your own server-side handlers (e.g. PHP) but that's the comparatively easy part. 56 | 57 | With those caveats out of the way, download/clone this repo, put the `file-explorer` directory on a server, and add these lines to your page to load the widget core: 58 | 59 | ```html 60 | 61 | 62 | ``` 63 | 64 | Next, create an instance of the FileExplorer class inside a closure for security reasons: 65 | 66 | ```html 67 |
68 | 69 | 125 | ``` 126 | 127 | That code will produce a less-than-exciting 'Loading...' view and also doesn't show the toolbar since there are no event listeners for the tools (yet): 128 | 129 | ![A loading screen](https://user-images.githubusercontent.com/1432111/83955169-e4c9fe00-a804-11ea-9275-a19db61ec4a7.png) 130 | 131 | The next step is to connect the widget to the backend server. There are many ways to do that. The widget instance itself exports the [PrepareXHR class](docs/prepare_xhr.md) to make AJAX calls. Or you could use a framework specific mechanism of your choice (jQuery, Vue, whatever) or talk to a WebSocket server or whatever makes sense for your application. The entries returned from the server should ideally be compatible with [Folder.SetEntries](docs/folder.md#foldersetentriesnewentries). 132 | 133 | If using PHP on a server and this widget will reflect a physical file system on the same server, there is the useful [FileExplorerFSHelper PHP class](docs/file_explorer_fs_helper.md) that can simplify connecting the widget to the backend server: 134 | 135 | ```php 136 | "https://yoursite.com/yourapp/files/", 141 | "protect_depth" => 1, // Protects base_dir + additional directory depth. 142 | "recycle_to" => "Recycle Bin", 143 | "temp_dir" => "/tmp", 144 | "dot_folders" => false, // Set to true to allow things like: .git, .svn, .DS_Store 145 | "allowed_exts" => ".jpg, .jpeg, .png, .gif, .svg, .txt", 146 | "allow_empty_ext" => true, 147 | "thumbs_dir" => "/var/www/yourapp/thumbs", 148 | "thumbs_url" => "https://yoursite.com/yourapp/thumbs/", 149 | "thumb_create_url" => "https://yoursite.com/yourapp/?action=file_explorer_thumbnail&xsrftoken=qwerasdf", 150 | "refresh" => true, 151 | "rename" => true, 152 | "file_info" => false, 153 | "load_file" => false, 154 | "save_file" => false, 155 | "new_folder" => true, 156 | "new_file" => ".txt", 157 | "upload" => true, 158 | "upload_limit" => 20000000, // -1 for unlimited or an integer 159 | "download" => true, 160 | "copy" => true, 161 | "move" => true, 162 | "delete" => true 163 | ); 164 | 165 | FileExplorerFSHelper::HandleActions("action", "file_explorer_", "/var/www/yourapp/files", $options); 166 | ``` 167 | 168 | Once entries are populating in the widget, various bits of navigation functionality should start working. The widget is starting to come to life but is mostly read only. Let's add an `onrename` handler so users can press F2 or click on the text of a selected item to rename the item: 169 | 170 | ```js 171 | // Note: 'entry' is a copy of the original, so it is okay to modify any aspect of it, including 'id'. 172 | onrename: function(renamed, folder, entry, newname) { 173 | var xhr = new this.PrepareXHR({ 174 | url: '/yourapp/', 175 | params: { 176 | action: 'file_explorer_rename', 177 | path: JSON.stringify(folder.GetPathIDs()), 178 | id: entry.id, 179 | newname: newname, 180 | xsrftoken: 'asdfasdf' 181 | }, 182 | onsuccess: function(e) { 183 | var data = JSON.parse(e.target.response); 184 | console.log(data); 185 | 186 | // Updating the existing entry or passing in a completely new entry to the renamed() callback are okay. 187 | if (data.success) renamed(data.entry); 188 | else renamed(data.error); 189 | }, 190 | onerror: function(e) { 191 | console.log(e); 192 | renamed('Server/network error.'); 193 | } 194 | }); 195 | 196 | xhr.Send(); 197 | }, 198 | ``` 199 | 200 | A lot is going on here. When the user finishes renaming an item, `onrename` is called, which hands the request off to an AJAX request to the server to handle. During this operation, the textarea is marked read only and the busy state on the folder is enabled. When the AJAX operation completes, it must call `renamed()` to let the widget know that the operation has been completed and indicate success by passing in a compatible entry object - either a modified `entry` or a new entry from the server. On failure, a boolean of false or a string that is passed to renamed() to be used as part of the error message displayed to the user. 201 | 202 | The above examples and documentation should be enough to get the ball rolling. Most event handler callbacks utilize a similar approach: Receive an event callback, make a server call or two, and finally call the completion callback function with the result of the operation. Callbacks always have the 'this' context as the FileExplorer instance. 203 | 204 | See a complete, functional implementation of all of the important callbacks in the [FileExplorerFSHelper PHP class](docs/file_explorer_fs_helper.md) documentation. It's an excellent starting point when utilizing the FileExplorerFSHelper class. 205 | 206 | FileExplorer Options 207 | -------------------- 208 | 209 | The `options` object passed to the FileExplorer class accepts the following options: 210 | 211 | * group - An optional string containing a group name. When specified, this must be a unique string that indicates a compatible widget backend to allow cross-widget drag-and-drop and cut/copy/paste to function properly. When not specified, the instance receives a group name unique to the instance that disables the aforementioned cross-widget features. 212 | * alwaysfocused - A boolean that indicates whether or not the widget's appearance never loses focus (Default is false). This only affects visual appearance and does not stop onfocus/onblur event callbacks from firing. 213 | * capturebrowser - A boolean that indicates whether or not to capture the hardware back and forward mouse buttons when the mouse is hovering over the widget (Default is false). Read the 'Known Limitations' section before enabling this feature. 214 | * messagetimeout - An integer containing the number of milliseconds to show short-lived messages in the status bar (Default is 2000). 215 | * displayunits - A string containing one of 'iec_windows', 'iec_formal', or 'si' to specify what units to use when displaying file sizes to the user (Default is 'iec_windows'). 216 | * adjustprecision - A boolean indicating whether or not to adjust the final precision when displaying file sizes to the user (Default is true). 217 | * initpath - An optional array of arrays containing the initial path segments to set. Each path segment is an array consisting of `[id, value, attrs]`. This path is passed to [FileExplorer.SetPath](docs/file_explorer.md#fileexplorer-setpath). 218 | * onfocus(e) - An optional callback function that is called when the widget or one of its components receives focus. 219 | * e - The browser event object that triggered the event. 220 | * onblur(e) - An optional callback function that is called when the widget loses focus. This callback can be used to hide or `Destroy()` the widget instance if it is used in a popup overlay. Note that `onblur` will not fire if the window itself loses focus - only if the widget loses focus to another element on the page. 221 | * e - The browser event object that triggered the event. 222 | * onrefresh(folder, required) - An optional callback function that is called when a folder refresh should happen. 223 | * folder - A Folder instance to refresh. 224 | * refresh - A boolean indicating that the refresh is required for the widget to function properly. 225 | * onselchanged(folder, selecteditemsmap, numselecteditems) - An optional callback function that is called whenever the user changes the item selections. Rarely used. 226 | * folder - The current Folder instance. 227 | * selecteditemsmap - The internal selecteditemsmap object. Do not modify. 228 | * numselecteditems - An integer containing the number of selected items in the selecteditemsmap. 229 | * onrename(renamed, folder, entry, newname) - An optional callback function that is called when the user renames an item. 230 | * renamed(entry) - A callback function to call upon completion of renaming or on failure. 231 | * folder - The Folder in which the entry to rename is in. 232 | * entry - The entry to rename. 233 | * newname - A string containing the name that was entered by the user. 234 | * onopenfile(folder, entry) - An optional callback function that is called when the user double-clicks/taps on an item. 235 | * folder - The Folder that the entry to open is in. 236 | * entry - The entry to open. 237 | * tools - An optional object containing key-value pairs where the value is a boolean that indicates whether or not to show the tool and the keys are: new_folder, new_file, upload, download, copy, paste, cut, delete, item_checkboxes. Most toolbar tools show up automatically when an onhandler is defined and override any "don't show" setting. The only tool that doesn't show as a result of a handler being defined is 'item_checkboxes'. 238 | * onnewfolder(created, folder) - An optional callback function that is called when the user clicks the New Folder icon or presses Ctrl + Ins. 239 | * created(success) - A callback function to call upon completion of creating a new folder or on failure. 240 | * folder - The Folder in which to create a new folder. 241 | * onnewfile(created, folder) - An optional callback function that is called when the user clicks the New File icon or presses Ins. 242 | * created(success) - A callback function to call upon completion of creating a new file or on failure. 243 | * folder - The Folder in which to create a new file. 244 | * oninitupload(startupload, fileinfo, queuestarted) - An optional callback function that is called when the user clicks the Upload icon or presses Ctrl + U. 245 | * startupload(fileinfo, process) - A callback function to call upon completion of initializing the upload or on failure. The 'process' option can be used to tell the callback to process the upload itself or skip it if it was handled in the callback (e.g. creating an empty directory). When 'process' is a string, it is treated as an error message to display to the user. 246 | * fileinfo - The file information object of the file to initialize for uploading. 247 | * queuestarted - An integer containing a UNIX timestamp of when the current upload queue was started. Can be useful to pass to a server that can use the value to copy files that are going to be overwritten to a recycling bin folder before the overwrite happens. 248 | * onfinishedupload(finalize, fileinfo) - An optional callback function that is called when the upload finishes successfully. Can be used to finalize an uploaded file on a server (e.g. move from a temporary directory to its final location). 249 | * finalize(success, entry) - A callback function to call upon completion of finalizing the upload or on failure. The 'entry' parameter is an optional Folder entry to set in the current folder. 250 | * fileinfo - The file information object of the file upload to finalize. 251 | * onuploaderror(fileinfo, e) - An optional callback function that is called when the upload fails. Can be used to remove an associated temporary file that was created during initialization. 252 | * fileinfo - The file information object of the file upload that had an error. 253 | * e - An optional error event object (not all failure conditions include this parameter). 254 | * concurrentuploads - An integer containing the maximum number of concurrent uploads to perform simultaneously (Default is 4). 255 | * oninitdownload(startdownload, folder, ids, entries) - An optional callback function that is called when the user clicks the Download icon. Since browsers don't do well with downloading a lot of individual files, it is recommended that folders and files be sent from the server in a single, compressed file format (e.g. ZIP). 256 | * startdownload(xhroptions) - A callback function to call upon completion of preparing the download or on failure. When an object is passed for xhroptions, it must be a set of options compatible with [PrepareXHR](docs/prepare_xhr.md). 257 | * folder - The Folder in which the ids are located. 258 | * ids - An array containing the selected entry IDs to download. 259 | * entries - An array containing the selected entries to download. 260 | * ondownloadstarted(options) - An optional callback function that is called when the download has started. 261 | * options - The xhroptions object passed to startdownload(). 262 | * ondownloaderror(options) - An optional callback function to that is called if the download failed to start. 263 | * options - The xhroptions object passed to startdownload(). 264 | * ondownloadurl(result, folder, ids, name) - An optional synchronous callback function that is called when a user starts a drag operation or cuts/copies one or more selected items. This applies a DownloadURL MIME type to the content. This allows for dragging/pasting folders and files out of the browser and onto the desktop. Currently only supported in Chromium browsers and may not use asynchronous methods like AJAX to calculate the URL. 265 | * result - An object that should have 'name' and 'url' strings assigned to it. 266 | * folder - The Folder in which the ids are located. 267 | * ids - An array containing the selected entry IDs to download. 268 | * entry - The first folder entry in the associated IDs list. Can be used to set the 'name' of the file. 269 | * oncopy(copied, srcpath, srcids, destfolder) - An optional callback function that is called when the user copies folders/files from one folder to another. 270 | * copied(success, entries) - A callback function to call upon completion of copying the folders and files or on failure. The 'entries' should contain the successfully copied entries to add regardless of success/failure. 271 | * srcpath - An array of arrays representing the source path of the IDs. 272 | * srcids - An array of entry IDs in the source path to copy. 273 | * destfolder - A Folder to which the entries are to be copied. Note that the destination folder may be the same as the source, in which case the server may choose to copy the files to new files with different names or reject the request. 274 | * onmove(moved, srcpath, srcids, destfolder) - An optional callback function that is called when the user moves folders/files from one folder to another. 275 | * moved(success, entries) - A callback function to call upon completion of moving the folders and files or on failure. The 'entries' should contain the successfully moved entries to add regardless of success/failure. 276 | * srcpath - An array of arrays representing the source path of the IDs. 277 | * srcids - An array of entry IDs in the source path to move. 278 | * destfolder - A Folder to which the entries are to be moved. Note that the destination folder may be the same as the source, in which case the server should reject the request. 279 | * ondelete(deleted, folder, ids, entries, recycle) - An optional callback function that is called when the user deletes folders/files. 280 | * deleted(success) - A callback function to call upon completion of the deletion operation. 281 | * folder - The Folder in which the ids/entries are located. 282 | * ids - An array containing the selected entry IDs to delete. 283 | * entries - An array containing the selected entries to delete. 284 | * recycle - A boolean hinting at whether to send items to a recycling bin (Delete) or permanently delete them (Shift + Delete). The server is free to ignore this parameter and do whatever makes the most sense. 285 | * langmap - An object containing translation strings. Support exists for most of the user interface (Default is an empty object). 286 | 287 | The [Live Demo](https://cubiclesoft.com/demos/js-fileexplorer/demo.html) utilizes nearly all of the available callbacks. The [Live Demo source code](demo.html) was designed so as keep this documentation to a minimum and to provide decent example usage without incurring AJAX calls. 288 | 289 | Making Custom Tools 290 | ------------------- 291 | 292 | While most of the widget is not really intended to be modified externally, the toolbar is designed to be extensible. Building a new tool involves: 293 | 294 | * An icon to display and an associated CSS class. 295 | * Some Javascript that handles clicks and possibly a keyboard shortcut. 296 | * Being efficient. The toolbar buttons are updated regularly via toolbar events that fire from FileExplorer. 297 | * Cleaning up when the 'destroy' event fires. 298 | * Registering the new tool with the registered tools. 299 | 300 | The simplest approach to developing a new tool is to look at the existing tools. However, the Delete tool is fairly simple and short: 301 | 302 | ```js 303 | (function() { 304 | // Tools receive the FileExplorer instance as the only option passed to the tool. 305 | var FileExplorerTool_Delete = function(fe) { 306 | if (!(this instanceof FileExplorerTool_Delete)) return new FileExplorerTool_Delete(fe); 307 | 308 | // Do not create the tool if deleting is disabled. 309 | if (!fe.hasEventListener('delete') && !fe.settings.tools.delete) return; 310 | 311 | var enabled = false; 312 | 313 | // Register a toolbar button with File Explorer. 314 | var node = fe.AddToolbarButton('fe_fileexplorer_folder_tool_delete', fe.Translate('Delete (Del)')); 315 | 316 | // Handle clicks. 317 | var ClickHandler = function(e) { 318 | if (e.isTrusted && enabled) fe.DeleteSelectedItems(!e.shiftKey); 319 | }; 320 | 321 | node.addEventListener('click', ClickHandler); 322 | 323 | // Efficiently handle toolbar updates - only adding/removing the disabled class if it is different from its previous state. 324 | var UpdateToolHandler = function(currfolder, attrs) { 325 | var prevenabled = enabled; 326 | 327 | enabled = (!currfolder.waiting && (!('canmodify' in attrs) || attrs.canmodify) && fe.GetNumSelectedItems()); 328 | 329 | if (prevenabled !== enabled) 330 | { 331 | if (enabled) node.classList.remove('fe_fileexplorer_disabled'); 332 | else node.classList.add('fe_fileexplorer_disabled'); 333 | 334 | // Notify File Explorer that the state was updated. 335 | // When the event callback finishes, it will know that there is some work to do. 336 | fe.ToolStateUpdated(); 337 | } 338 | }; 339 | 340 | fe.addEventListener('update_tool', UpdateToolHandler); 341 | 342 | // Cleanly handle the destroy event. 343 | var DestroyToolHandler = function() { 344 | node.removeEventListener('click', ClickHandler); 345 | }; 346 | 347 | fe.addEventListener('destroy', DestroyToolHandler); 348 | }; 349 | 350 | // Register the tool in the second group of tools (0-based). 351 | window.FileExplorer.RegisterTool(1, FileExplorerTool_Delete); 352 | })(); 353 | ``` 354 | 355 | Some additional comments were added to the code above to aid in understanding what is going on. There are more complex tools to look at in the FileExplorer source code (e.g. FileExplorerTool_Download). The Class Documentation section below will be quite useful when developing a custom tool. 356 | 357 | For custom tools, you might want to prefix custom settings object keys with something like a company abbreviation so the likelihood of a naming conflict is reduced. 358 | 359 | One good idea for a custom tool might be a HTML embed tool. If a user selects a single item and clicks the embed tool, the clipboard receives some HTML code that can be pasted into another website to embed the item into a post. 360 | 361 | Class Documentation 362 | ------------------- 363 | 364 | * [FileExplorer class](docs/file_explorer.md) - The core FileExplorer class + tools. Does most of the heavy-lifting. Exported as `window.FileExplorer`. 365 | * [DebounceAttributes class](docs/debounce_attributes.md) - Debounces/throttles attribute changes. More efficient than most debounce functions that rely on events. 366 | * [PrepareXHR class](docs/prepare_xhr.md) - A basic and convenient wrapper around a XMLHttpRequest (XHR) object. 367 | * [ImageLoader class](docs/image_loader.md) - A multi-queue delayed image loader that only loads images when it is told to. Also exported as `window.FileExplorer.ImageLoader` for reusability purposes. 368 | * [PopupMenu class](docs/popup_menu.md) - Displays a popup menu of items. Used for Recent Locations and path segment expansion. Full keyboard, mouse, and touch support. Also exported as `window.FileExplorer.PopupMenu` for reusability purposes. 369 | * [TextareaOverlay class](docs/textarea_overlay.md) - Displays a positionable textarea with optional text with text selection. Full keyboard, mouse, and touch support. Also exported as `window.FileExplorer.TextareaOverlay` for reusability purposes. 370 | * [Folder class](docs/folder.md) - Tracks the contents of a single folder in the mapped folders of the FileExplorer class. The Folder class cannot be instantiated except from within the FileExplorer but instances of this class can be accessed primarily via callbacks from FileExplorer. 371 | * [FileExplorerFSHelper class](docs/file_explorer_fs_helper.md) - PHP server-side helper class to simplify interacting with server-local, physical file systems. 372 | 373 | Known Limitations 374 | ----------------- 375 | 376 | CubicleSoft File Explorer is a complex piece of software written in Javascript. As with every complex piece of software written in Javascript, there are going to be problems with certain combinations of OS + device + web browser for a garden variety of reasons. Web browsers have lots of bugs and the specifications that browsers follow don't cover all edge cases, which leaves things open to interpretation for the browser vendor. What follows are known limitations of the widget due to conditions beyond nearly everyone's direct control and most of the listed problems have reasonable workarounds. Please do not open issues on the issue tracker for these items unless you actually solve them. 377 | 378 | * Some devices and web browsers lack HTML 5 drag-and-drop support, notably any browser on iOS as the iOS webview implementation lacks support. It is NOT recommended to use a [polyfill](https://github.com/Bernardo-Castilho/dragdroptouch) with this widget to support HTML 5 drag-and-drop. There are several situations where a drag-and-drop polyfill will probably break certain touch-based features of this widget and/or break native drag-and-drop elsewhere. Instead, use the cut/copy/paste feature on devices/browsers where HTML 5 drag-and-drop is not natively supported. 379 | 380 | * The right-click context menu for cut/copy/paste can cause the main UI area to get stuck on some platforms until a click or keyboard event is registered, notably Mac OSX. There is a near-invisible textarea overlay that captures right-click events for cut/copy/paste operations but it doesn't always go away until a second mousedown/keyup event is registered. This happens because there is no such thing as an 'exitcontextmenu' event to detect that the context menu has closed and all known methods for detection are hacks. The solution is to either put up with the extra click or just not use right-click and use keyboard shortcuts or the toolbar buttons instead. 381 | 382 | * There is extremely limited "file paste" support from OS file systems into the widget. Raw image data that is stored on the clipboard (e.g. right-click on an image in a website then click Copy) can be pasted into the widget and it will be uploaded but files from the OS itself do not drop. Here's a [Chromium bug that's been open since 2013](https://bugs.chromium.org/p/chromium/issues/detail?id=316472) about the issue and has received almost no attention other than duplicates being merged into it. Dragging and dropping files from the OS into the browser is the most feature-complete file transfer mechanism available to date. 383 | 384 | * The iframe-based downloading method requires initiating a second request to the server for the same content. This kind of hack has to be done because there is no web browser event available to know that page navigation was cancelled when the download starts. The XHR request terminates as soon as it receives its first 'progress' event, usually in the first few KB and it assumes the iframe form submission equivalent, which started before the XHR request, completed in a similar amount of time and has started downloading the file. It is recommended that download requests that take more than a few seconds to process on the server (e.g. generating a compressed file) be run separately and the generated file stored on the server somewhere prior to calling `startdownload(fileinfo)` in the client so that both the form and XHR requests return quickly, the download begins, and the iframe is removed all within a few seconds. 385 | 386 | * The hardware back/forward mouse button capture logic modifies browser history. There is no way to capture the hardware mouse buttons except to modify browser history so that there are three distinct history push states (back, current, forward) while hovering over the widget and using mouseenter/mouseleave to enable/disable the back/forward button capture. There are a couple of extremely difficult to track down bugs as well. The first bug is that the `window.history.scrollRestoration` of the real page sometimes gets stuck on `manual` instead of being restored to `auto`, which causes page reload jumping issues and also causes Edge to jump during scrolling. That bug only seems to show up if lots of reloads happen. The second bug is the page the widget is on occasionally completely messes up the parent pushState and the widget decides it needs to back up too far in the history stack and ends up leaving the page altogether. I have no idea what causes either bug to occur. Also, during development of this specific feature, Firefox literally crashed a half-dozen times. Since browser history is modified, which may conflict with other software, the hardware back/forward mouse button capture feature is disabled by default. It is a pretty cool feature when it works. 387 | -------------------------------------------------------------------------------- /docs/file_explorer.md: -------------------------------------------------------------------------------- 1 | FileExplorer Class 2 | ================== 3 | 4 | The FileExplorer class is exported to the global `window` object and is core widget for File Explorer. `window.FileExplorer` also exports several internal classes and functions that can be useful for building custom features. 5 | 6 | See the main documentation in thie repository for example, common usage and use-cases for the class. This documentation focuses on the public functions and information available for each instance of the FileExplorer class. 7 | 8 | FileExplorer(parentelem, options) 9 | --------------------------------- 10 | 11 | Category: Constructor 12 | 13 | Parameters: 14 | 15 | * parentelem - A DOM node to append the root of the File Explorer widget to. 16 | * options - An object containing options to use to construct the widget. 17 | 18 | Returns: A Javascript function hierarchy. 19 | 20 | This function sets up a new File Explorer widget instance. The 'new' keyword is required in order to use it correctly. See the repository README to see a list of all options that can be passed in. 21 | 22 | FileExplorer.settings 23 | --------------------- 24 | 25 | Category: Settings 26 | 27 | The `settings` object contains the settings for the instance. Changing the settings after creating the instance will have little to no effect and changing them is not recommended. The settings are made public mostly so that tools can set up and trigger appropriate callbacks. 28 | 29 | FileExplorer.Translate(str) 30 | --------------------------- 31 | 32 | Category: Internationalization 33 | 34 | Parameters: 35 | 36 | * str - A string to translate using `FileExplorer.settings.langmap`. 37 | 38 | Returns: A replacement string, if available. 39 | 40 | Thie function is called whenever an internal string will be displayed to a user to find a replacement string in the language map object. 41 | 42 | FileExplorer.FormatStr(format, ...) 43 | ----------------------------------- 44 | 45 | Category: Internationalization 46 | 47 | Parameters: 48 | 49 | * format - A string containing matching placeholders for `{0}`, `{1}`, etc. for the rest of the parameters 50 | 51 | Returns: A formatted string with placeholders replaced with values from the other input parameters. 52 | 53 | This function is usually used in conjunction with Translate() to perform more complex multilingual string transformations that require multiple parameters to create. 54 | 55 | FileExplorer.EscapeHTML(text) 56 | ----------------------------- 57 | 58 | Cateogry: Strings 59 | 60 | Parameters: 61 | 62 | * text - A string to sanitize for safe insertion into HTML. 63 | 64 | Returns: A HTML-safe string. 65 | 66 | This function escapes input content for insertion into HTML. 67 | 68 | FileExplorer.GetDisplayFilesize(numbytes, adjustprecision, units) 69 | ----------------------------------------------------------------- 70 | 71 | Category: Files 72 | 73 | Parameters: 74 | 75 | * numbytes - An integer containing the number of bytes to convert for display. 76 | * adjustprecision - A boolean indicating whether or not to adjust the final precision when displaying file sizes to the user. 77 | * units - A string containing one of 'iec_windows', 'iec_formal', or 'si' to specify what units to use when displaying file sizes to the user. 78 | 79 | Returns: A string containing a displayable file size. 80 | 81 | This function converts an integer into a file size string (e.g. 1024 becomes 1 KB). 82 | 83 | FileExplorer.SetNamedStatusBarText(name, text, timeout) 84 | ------------------------------------------------------- 85 | 86 | Category: Status bar 87 | 88 | Parameters: 89 | 90 | * name - A string containing the status bar segment name to target for the message. 91 | * text - A string containing the text to display. Should be escaped with EscapeHTML() to avoid issues. 92 | * timeout - An integer containing the number of milliseconds to show the message (Default is infinite). 93 | 94 | Returns: Nothing. 95 | 96 | This function updates a named segment in the status bar with the specified text. 97 | 98 | When a timeout is specified, the message shows until the timeout or another message replaces it. A message with a timeout may also momentarily hide other messages such that it fits on the screen. 99 | 100 | There are three predefined segments: folder, selected, message. The first two should only be used by the widget. The third (message) should be used primarily for messages that timeout. Other segments can be added as needed. 101 | 102 | FileExplorer.CreateProgressTracker(cancelcallback) 103 | -------------------------------------------------- 104 | 105 | Category: Status bar 106 | 107 | Parameters: 108 | 109 | * cancelcallback - A function to call if the user clicks the cancel button. 110 | 111 | Returns: An object containing a progress tracker. 112 | 113 | This function registers a new progress tracker and returns it. This allows for long-running operations to take place while providing regular visual feedback (e.g. copying files). If a cancel callback is supplied, the user can cancel running operations by clicking the cancel button. 114 | 115 | Each tracker contains the following options: 116 | 117 | * started - A UNIX timestamp of when the object was created (Default is Date.now()). 118 | * totalbytes - An integer containing the number of bytes transferred/moved (Default is 0). 119 | * showbyterate - A boolean indicating whether or not to show the byte rate after 3 seconds (Default is false). 120 | * uploading - A boolean of false (if not uploading) or an integer that contains how many items are actively being uploaded (Default is false). 121 | * queueditems - An integer containing the number of known items in the queue (Default is 0). 122 | * queuesizeunknown - A boolean indicating whether or not the actual size of the queue is unknown (Default is false). This is useful when the actual queue size is unknown but some number of items (queueditems) is known. 123 | * itemsdone - An integer containing the number of items that have been processed successfully (Default is 0). 124 | * faileditems - An integer containing the number of items that did not process successfully (Default is 0). 125 | * cancelcallback - A function to call when the user clicks the cancel button (Default is null). 126 | * finishmessage - A string containing the message to display in the status bar when the trackers is done (Default is ''). Useful for showing 'Copying done' or 'Deletion stopped'. 127 | 128 | These options are intended to be updated on a regular basis. UpdateProgressText() is automatically called every second until no trackers are left. 129 | 130 | FileExplorer.UpdateProgressText() 131 | --------------------------------- 132 | 133 | Category: Status bar 134 | 135 | Parameters: None. 136 | 137 | Returns: Nothing. 138 | 139 | This function updates the progress area of the status bar with the combined information of all trackers. When a tracker exists, this function is automatically called every second until no trackers are left. 140 | 141 | FileExplorer.RemoveProgressTracker(tracker, finishmessage) 142 | ---------------------------------------------------------- 143 | 144 | Category: Status bar 145 | 146 | Parameters: 147 | 148 | * tracker - An object containing a progress tracker. 149 | * finishmessage - An optional string that contains the message to display if this is the last progress tracker (Default is false). 150 | 151 | Returns: Nothing. 152 | 153 | This function removes a progress tracker. If it is the last progress tracker, the status bar is left alone until an action takes place (mouse move, keyboard event, or touch) and is removed about one second after an action takes place. This allows a user to see the final result if they stepped away for a moment. 154 | 155 | FileExplorer.addEventListener(eventname, callback) 156 | -------------------------------------------------- 157 | 158 | Category: Events 159 | 160 | Parameters: 161 | 162 | * eventname - A string containing a name of a FileExplorer event to listen to. 163 | * callback - A function to call when the event fires. 164 | 165 | Returns: Nothing. 166 | 167 | This function presents a familiar function for registering for custom events emitted by FileExplorer. 168 | 169 | Known events: 170 | 171 | * tool_[event] - Reserved for tool-specific events. 172 | * blur - Dispatched when the widget is blurred. 173 | * focus - Dispatched when the widget is focused. 174 | * update_tool - Dispatched when a tool needs to update in response to changes in the current folder. 175 | * open_file - Dispatched when a user double-clicks/taps on one or more selected items. 176 | * selections_changed - Dispatched when the selections in the current folder change. 177 | * refresh_folder - Dispatched when it is time to refresh a specific folder (not necessarily the current folder). 178 | * navigated - Dispatched when navigation takes place. 179 | * history_changed - Dispatched whenever the history stack changes. 180 | * move - Dispatched when moving items. 181 | * copy - Dispatched when copying items. 182 | * upload_error - Dispatched when an upload fails (after all retry attempts fail) or one of the files or directories on the system is invalid/unreadable. 183 | * upload_done - Dispatched when an upload completes successfully. 184 | * update_upload_fileinfo - Dispatched when preparing the XHR request for an upload chunk. 185 | * init_upload - Dispatched when initializing an upload. 186 | * get_download_url - Dispatched when a drag-and-drop or copy/cut operation occurs to get the information needed to build a DownloadURL (Chromium only). 187 | * keydown - Dispatched when the user presses a key. Primarily used by tools. 188 | * rename - Dispatched when the user renames an item. 189 | * delete - Dispatched when the user deletes/recycles an item. 190 | * destroy - Dispatched when the Destroy() function is called. 191 | 192 | Most of these events have equivalents in the settings object and associated callbacks will automatically be registered as event listeners during initialization. 193 | 194 | FileExplorer.removeEventListener(eventname, callback) 195 | ----------------------------------------------------- 196 | 197 | Category: Events 198 | 199 | Parameters: 200 | 201 | * eventname - A string containing a name of a FileExplorer event to stop listening to. 202 | * callback - A function containing a registered callback to remove. 203 | 204 | Returns: Nothing. 205 | 206 | This function presents a familiar function for unregistering from custom events emitted by FileExplorer. 207 | 208 | FileExplorer.hasEventListener(eventname) 209 | ---------------------------------------- 210 | 211 | Category: Events 212 | 213 | Parameters: 214 | 215 | * eventname - A string containing a name of a FileExplorer event to check. 216 | 217 | Returns: A boolean of true if there are event listeners for the specified event, false otherwise. 218 | 219 | This function checks for the existence of an event and whether or not there are any listeners registered for the event. 220 | 221 | FileExplorer.ClearSelectedItems(ignorebusy, skipuiupdate) 222 | --------------------------------------------------------- 223 | 224 | Category: Item selection 225 | 226 | Parameters: 227 | 228 | * ignorebusy - An internal boolean that bypasses the busy folder check. Do not use. 229 | * skipuiupdate - An internal boolean that bypasses updating the toolbar and status bar. Do not use. 230 | 231 | Returns: Nothing. 232 | 233 | This function clears all existing selections. The various boolean options should not be used by external callers (i.e. just call the function like `fe.ClearSelectedItems()`). 234 | 235 | FileExplorer.SelectAllItems(skipuiupdate) 236 | ----------------------------------------- 237 | 238 | Category: Item selection 239 | 240 | Parameters: 241 | 242 | * skipuiupdate - An internal boolean that bypasses updating the toolbar and status bar. Do not use. 243 | 244 | Returns: Nothing. 245 | 246 | This function selects all items. The skipuiupdate option should not be used by external callers (i.e. just call the function like `fe.SelectAllItems()`). 247 | 248 | FileExplorer.SelectItemsFromLastAnchor(ignorebusy, skipuiupdate) 249 | ---------------------------------------------------------------- 250 | 251 | Category: Item selection 252 | 253 | Parameters: 254 | 255 | * ignorebusy - An internal boolean that bypasses the busy folder check. Do not use. 256 | * skipuiupdate - An internal boolean that bypasses updating the toolbar and status bar. Do not use. 257 | 258 | Returns: Nothing. 259 | 260 | This function selects all items from the internal anchor position to the currently focused element. The various boolean options should not be used by external callers (i.e. just call the function like `fe.SelectItemsFromLastAnchor()`). 261 | 262 | FileExplorer.SetSelectedItems(ids, keepprev, skipuiupdate) 263 | ---------------------------------------------------------- 264 | 265 | Category: Item selection 266 | 267 | Parameters: 268 | 269 | * ids - An array containing item IDs to select. 270 | * keepprev - A boolean that controls whether or not to clear previously selected items (Default is false). 271 | * skipuiupdate - An internal boolean that bypasses updating the toolbar and status bar. Do not use. 272 | 273 | Returns: Nothing. 274 | 275 | This function sets the selected items in the current folder with the specified item IDs. It clears previous selections by default. The skipuiupdate option should not be used by external callers. 276 | 277 | FileExplorer.ToggleItemSelection(elem, ignorebusy, skipuiupdate) 278 | ---------------------------------------------------------------- 279 | 280 | Category: Item selection 281 | 282 | Parameters: 283 | 284 | * elem - A string containing an item ID or a DOM node of an item to toggle selection. External callers should use the item ID string method. 285 | * ignorebusy - An internal boolean that bypasses the busy folder check. Do not use. 286 | * skipuiupdate - An internal boolean that bypasses updating the toolbar and status bar. Do not use. 287 | 288 | Returns: Nothing. 289 | 290 | This function toggles selection of a single item. The various boolean options should not be used by external callers (i.e. just call the function like `fe.ToggleItemSelection(elem)`). 291 | 292 | FileExplorer.GetNumSelectedItems() 293 | ---------------------------------- 294 | 295 | Category: Selected items 296 | 297 | Parameters: None. 298 | 299 | Returns: An integer containing the number of selected items. 300 | 301 | This function returns the number of currently selected items in the current folder. 302 | 303 | FileExplorer.GetSelectedFolderEntries() 304 | --------------------------------------- 305 | 306 | Category: Selected items 307 | 308 | Parameters: None. 309 | 310 | Returns: An array containing the selected folder entries. 311 | 312 | This function returns the currently selected entries in the current folder. 313 | 314 | FileExplorer.GetSelectedItemIDs() 315 | --------------------------------- 316 | 317 | Category: Selected items 318 | 319 | Parameters: None. 320 | 321 | Returns: An array containing the IDs of the currently selected items. 322 | 323 | This function returns just the IDs of the currently selected items in the current folder. 324 | 325 | FileExplorer.IsSelectedItem(id) 326 | ------------------------------- 327 | 328 | Category: Selected items 329 | 330 | Parameters: 331 | 332 | * id - A string containing an ID to check for currently selected status. 333 | 334 | Returns: A boolean of true if the item associated with the ID is selected, false otherwise. 335 | 336 | This function returns whether or not the item associated with the ID is selected. 337 | 338 | FileExplorer.OpenSelectedItems() 339 | -------------------------------- 340 | 341 | Category: Selected item actions 342 | 343 | Parameters: None. 344 | 345 | Returns: Nothing. 346 | 347 | This function triggers an open event for each selected non-folder item. If a single folder is selected among all selected items, this function will also trigger navigation to that folder. 348 | 349 | FileExplorer.RenameSelectedItem() 350 | --------------------------------- 351 | 352 | Category: Selected item actions 353 | 354 | Parameters: None. 355 | 356 | Returns: Nothing. 357 | 358 | This function starts a rename operation if there is exactly one selected item and at least one 'rename' event listener. The UI shows a textarea over the existing text with the item name contained within it. If the name is modified, event listeners are called to handle the rename operation. 359 | 360 | FileExplorer.DeleteSelectedItems(recycle) 361 | ----------------------------------------- 362 | 363 | Category: Selected item actions 364 | 365 | Parameters: 366 | 367 | * recycle - A boolean indicating whether or not the selected items should move to a recycling bin. 368 | 369 | Returns: Nothing. 370 | 371 | This function starts a delete operation of selected items if there is at least one 'delete' event listener. The 'recycle' option can be passed to and utilized by event handlers to optionally move items to a recycling bin instead of permanently deleting items off the server. A cron job could be used to automatically clean up items in a recycling bin folder after they have been in there for a week. 372 | 373 | FileExplorer.SetFocusItem(id, updateanchor) 374 | ------------------------------------------- 375 | 376 | Category: Focused item 377 | 378 | Parameters: 379 | 380 | * id - A string containing an item ID to focus or a boolean of false to clear focus. 381 | * updateanchor - A boolean that indicates whether or not to update the anchor position for later Shift key selections. 382 | 383 | Returns: Nothing. 384 | 385 | This function sets/clears the focused item. When there is no focused item, focus reverts to the scroll region. The anchor position, which is used when holding down the Shift key, can be updated at the same time. 386 | 387 | FileExplorer.ScrollToFocusedItem() 388 | ---------------------------------- 389 | 390 | Category: Focused item 391 | 392 | Parameters: None. 393 | 394 | Returns: Nothing. 395 | 396 | This function scrolls the scroll region so that the focused item is fully visible. 397 | 398 | FileExplorer.GetFocusedItem() 399 | ----------------------------- 400 | 401 | Category: Focused item 402 | 403 | Parameters: None. 404 | 405 | Returns: The DOM node containing the focused item or a boolean of false if not set. 406 | 407 | This function returns the internal DOM node of the focused item. When the focused item is not set, it returns false. 408 | 409 | FileExplorer.GetFocusedItemID() 410 | ------------------------------- 411 | 412 | Category: Focused item 413 | 414 | Parameters: None. 415 | 416 | Returns: A string containing the folder item ID of the focused item or a boolean of false if the focused item is not set. 417 | 418 | This function returns the folder item ID of the focused item. When the focused item is not set, it returns false. While it is possible to get the ID directly from a DOM node, it is not recommended. 419 | 420 | FileExplorer.HasItemFocus() 421 | --------------------------- 422 | 423 | Category: Focused item 424 | 425 | Parameters: None. 426 | 427 | Returns: A boolean of true if there is a set focused item and it is also the `document.activeElement`, false otherwise. 428 | 429 | This function returns whether or not the set focused item is also the currently focused item in the browser DOM. 430 | 431 | FileExplorer.HasFocus(itemsonly) 432 | -------------------------------- 433 | 434 | Category: Focus 435 | 436 | Parameters: 437 | 438 | * itemsonly - A boolean that can restrict the return value to the folder items area (Default is false). 439 | 440 | Returns: A boolean of true if the widget or items currently have focus. 441 | 442 | This function determines whether the currently focused `document.activeElement` is part of the folder items area when `itemsonly` is true or part of the widget otherwise (navigation, path segments, toolbar, etc). 443 | 444 | FileExplorer.Focus(itemsonly, alwaysfocus) 445 | ------------------------------------------ 446 | 447 | Category: Focus actions 448 | 449 | Parameters: 450 | 451 | * itemsonly - A boolean that indicates focus should be for the folder items area only (Default is false). 452 | * alwaysfocus - A boolean that indicates that focus should always take place (Default is false). Do not use. 453 | 454 | Returns: Nothing. 455 | 456 | This function focuses on the items area if `itemsonly` is true, the widget otherwise. If the widget/items region already has focus, nothing happens unless `alwaysfocus` is set to true. The second parameter is only useful for stealing keyboard focus away from, for example, the hidden clipboard capture overlay, which shares the same DOM root as the the main items region. 457 | 458 | Folder.GetPathIDs(path) 459 | ----------------------- 460 | 461 | Category: Path information 462 | 463 | Parameters: 464 | 465 | * path - An array of arrays that defines a path. 466 | 467 | Returns: An array of path IDs. 468 | 469 | This function iterates over the path and constructs an array of path IDs. The return value is intended to be useful for sending the path of a folder to a server. 470 | 471 | FileExplorer.IsValidPath(path) 472 | ------------------------------ 473 | 474 | Category: Path 475 | 476 | Parameters: 477 | 478 | * path - An array of arrays that defines a path. 479 | 480 | Returns: A boolean if the array structure looks correct, false otherwise. 481 | 482 | This function checks an input path array for validity. Used by SetPath() to prevent invalid structures from being used. 483 | 484 | FileExplorer.SetPath(newpath) 485 | ----------------------------- 486 | 487 | Category: Path actions 488 | 489 | Parameters: 490 | 491 | * newpath - An array of arrays that defines the path to set. 492 | 493 | Returns: Nothing. 494 | 495 | This function performs a path change operation, setting the path to the new path, adding to the history/navigation stack, triggering folder refreshes, and updating the DOM. For most use-cases, using the 'initpath' option gets things started without needing to call this function directly. 496 | 497 | If the calculated new path key is identical to the current path key, the current folder is refreshed in-place without modifying the history stack. 498 | 499 | FileExplorer.GetMappedFolderFromPath(path) 500 | ------------------------------------------ 501 | 502 | Category: Mapped folders 503 | 504 | Parameters: 505 | 506 | * path - An array of arrays that defines a path. 507 | 508 | Returns: An object containing a Folder instance if the path is mapped, a boolean of false otherwise. 509 | 510 | This function returns the Folder object associated with a path if it is in the folder map. A folder is placed into the internal widget folder map when it is referenced by a path segment somewhere in the history stack. During the lifetime of the widget, mapped folders can come and go. It is not safe to access a mapped folder reference beyond the lifetime of a function callback. 511 | 512 | FileExplorer.GetCurrentFolder() 513 | ------------------------------- 514 | 515 | Category: Mapped folders 516 | 517 | Parameters: None. 518 | 519 | Returns: The current Folder object that is associated with the DOM. 520 | 521 | This function returns the current Folder object that is associated with the DOM. Updating the entries in this object triggers event callbacks within the widget that reflect in DOM updates. 522 | 523 | FileExplorer.IsMappedFolder(folder) 524 | ----------------------------------- 525 | 526 | Category: Mapped folders 527 | 528 | Parameters: 529 | 530 | * folder - A valid Folder object instance. 531 | 532 | Returns: A boolean of true if the object is in the folder map, false otherwise. 533 | 534 | This function checks the folder map to see if the input object is a mapped folder. It actually first compares the input object with the current folder for efficiency and then falls back to walking through the folder map to find a match. When using asynchronous logic, it is possible for a folder to be removed from the folder map before the asynchronous action completes (e.g. the user navigates to another folder during an operation). 535 | 536 | FileExplorer.RefreshFolders(forcecurrfolder) 537 | -------------------------------------------- 538 | 539 | Category: Mapped folder actions 540 | 541 | Parameters: 542 | 543 | * forcecurrfolder - A boolean indicating whether or not to ignore the 5 minute refresh timer for the current folder (Default is false). 544 | 545 | Returns: Nothing. 546 | 547 | This function triggers refresh events for folders in the folder map that were last refreshed over 5 minutes ago. 548 | 549 | FileExplorer.HistoryBack(e) 550 | --------------------------- 551 | 552 | Category: Navigation actions 553 | 554 | Parameters: 555 | 556 | * e - An optional browser event object to call preventDefault() on. 557 | 558 | Returns: Nothing. 559 | 560 | This function navigates back through the history stack one level. 561 | 562 | FileExplorer.HistoryForward(e) 563 | ------------------------------ 564 | 565 | Category: Navigation actions 566 | 567 | Parameters: 568 | 569 | * e - An optional browser event object to call preventDefault() on. 570 | 571 | Returns: Nothing. 572 | 573 | This function navigates forward through the history stack one level. 574 | 575 | FileExplorer.NavigateUp(e) 576 | -------------------------- 577 | 578 | Category: Navigation actions 579 | 580 | Parameters: 581 | 582 | * e - An optional browser event object to call preventDefault() on. 583 | 584 | Returns: Nothing. 585 | 586 | This function navigates up one path segment level. 587 | 588 | FileExplorer.CreateNode(tag, classes, attrs, styles) 589 | ---------------------------------------------------- 590 | 591 | Category: Miscellaneous exports 592 | 593 | Parameters: 594 | 595 | * tag - A string containing the tag to use for the new DOM node. 596 | * classes - An optional string or array of strings containing classes to assign to the new DOM node. 597 | * attrs - An optional object of key-value pairs to assign to attributes of the new DOM node. 598 | * styles - An optional object of key-value pairs to assign to styles of the new DOM node. 599 | 600 | Returns: A newly created, detached DOM node. 601 | 602 | This function creates a new DOM node with classes, attributes, and styles. Can be useful for building some custom tools. 603 | 604 | FileExplorer.DebounceAttributes 605 | ------------------------------- 606 | 607 | Category: Miscellaneous exports 608 | 609 | See: [DebounceAttributes Class](docs/debounce_attributes.md) 610 | 611 | FileExplorer.PrepareXHR(options) 612 | -------------------------------- 613 | 614 | Category: Miscellaneous exports 615 | 616 | See: [PrepareXHR Class](docs/prepare_xhr.md) 617 | 618 | FileExplorer.GetElements() 619 | -------------------------- 620 | 621 | Category: Miscellaneous exports 622 | 623 | Parameters: None. 624 | 625 | Returns: The internal elems object for the widget. 626 | 627 | This function returns the internal elements object for use with certain tools. While element keys are not likely to change, there is no guarantee as this is an internal structure. 628 | 629 | FileExplorer.GetScrollLineHeight() 630 | ---------------------------------- 631 | 632 | Category: Miscellaneous exports 633 | 634 | Parameters: None. 635 | 636 | Returns: An integer containing the pixel count line height of a 1em unstyled character to be used for scroll calculations. 637 | 638 | This function returns the precalculated value of the pixel count line height of a 1em unstyled character to be used for scroll calculations. This is used, for example, to convert a vertical mouse wheel event into a horizontal scroll of the correct amount in the path segment bar. 639 | 640 | FileExplorer.ShowClipboardPasteBox() 641 | ------------------------------------ 642 | 643 | Category: Miscellaneous exports 644 | 645 | Parameters: None. 646 | 647 | Returns: Nothing. 648 | 649 | This function shows the clipboard paste box. Used by the paste tool. 650 | 651 | FileExplorer.HideClipboardPasteBox(e) 652 | ------------------------------------- 653 | 654 | Category: Miscellaneous exports 655 | 656 | Parameters: 657 | 658 | * e - An optional browser event object to compare the target of for focus handling. 659 | 660 | Returns: Nothing. 661 | 662 | This function hides the clipboard paste box and removes event handlers. 663 | 664 | FileExplorer.ProcessFilesAndUpload(targettype, targetnode, dt) 665 | -------------------------------------------------------------- 666 | 667 | Category: Miscellaneous exports 668 | 669 | Parameters: 670 | 671 | * lasttype - A string containing one of 'currfolder', 'path', or 'item'. External callers should use 'currfolder'. 672 | * lastnode - A DOM node for 'path' or 'item' types or null. 673 | * dt - A DataTransfer object instance containing 'items' and/or 'files' arrays. 674 | 675 | Returns: Nothing. 676 | 677 | This function processes the incoming data transfer files/folders and starts uploading them to the specified target. With some minor effort, it is possible to upload a Blob instance from outside the widget to the current folder using this function (e.g. save an image from a canvas element). 678 | 679 | The 'path' type requires pointing at a valid DOM node in the path segment region. The 'item' type requires pointing at a valid folder item DOM node. These types are mostly internal for handling drag-and-drop operations. 680 | 681 | FileExplorer.StartOperationIndicator() 682 | -------------------------------------- 683 | 684 | Category: Miscellaneous exports 685 | 686 | Parameters: None. 687 | 688 | Returns: Nothing. 689 | 690 | This function starts a wait indicator when hovering over the widget for up to 15 seconds or until `StopOperationIndicator()` is called, whichever comes first. This function is refcounted, so equal numbers of Start/Stop calls need to be made to stop the indicator. 691 | 692 | FileExplorer.StopOperationIndicator() 693 | ------------------------------------- 694 | 695 | Category: Miscellaneous exports 696 | 697 | Parameters: None. 698 | 699 | Returns: Nothing. 700 | 701 | This function reduces the refcount of StartOperationIndicator() by 1. When it reaches 0, the wait indicator class is removed. 702 | 703 | FileExplorer.DispatchToolEvent(eventname, params) 704 | ------------------------------------------------- 705 | 706 | Category: Tool events 707 | 708 | Parameters: 709 | 710 | * eventname - A string containing a name of a tool event to dispatch. 711 | * params - A single option or an array of options to pass to callbacks. 712 | 713 | Returns: Nothing. 714 | 715 | This function dispatches a tool event. It should only be called by registered toolbar tools. 716 | 717 | FileExplorer.addToolEventListener(eventname, callback) 718 | ------------------------------------------------------ 719 | 720 | Category: Tool events 721 | 722 | Parameters: 723 | 724 | * eventname - A string containing a name of a tool event to listen to. 725 | * callback - A function to call when the event fires. 726 | 727 | Returns: Nothing. 728 | 729 | This function presents a familiar function for registering for custom events emitted by toolbar tools. 730 | 731 | Most events have equivalents in the settings object and associated callbacks will automatically be registered as event listeners during initialization. 732 | 733 | FileExplorer.removeToolEventListener(eventname, callback) 734 | --------------------------------------------------------- 735 | 736 | Category: Tool events 737 | 738 | Parameters: 739 | 740 | * eventname - A string containing a name of a tool event to stop listening to. 741 | * callback - A function containing a registered callback to remove. 742 | 743 | Returns: Nothing. 744 | 745 | This function presents a familiar function for unregistering from custom events emitted by FileExplorer. 746 | 747 | FileExplorer.hasToolEventListener(eventname, callback) 748 | ------------------------------------------------------ 749 | 750 | Category: Tool events 751 | 752 | Parameters: 753 | 754 | * eventname - A string containing a name of a tool event to check. 755 | 756 | Returns: A boolean of true if there are event listeners for the specified tool event, false otherwise. 757 | 758 | This function checks for the existence of a tool event and whether or not there are any listeners registered for the event. 759 | 760 | FileExplorer.ToolStateUpdated() 761 | ------------------------------- 762 | 763 | Category: Tool notifications 764 | 765 | Parameters: None. 766 | 767 | Returns: Nothing. 768 | 769 | This function is used by tools to let the FileExplorer class instance know that at least one tool has toggled between enabled/disabled states and it should adjust tabIndex attributes and element focus as needed. 770 | 771 | FileExplorer.AddToolbarButton(classname, title) 772 | ----------------------------------------------- 773 | 774 | Category: Toolbar 775 | 776 | Parameters: 777 | 778 | * classname - A string containing a class name to use for the toolbar button. 779 | * title - A string containing a title to use for the button (tooltip). 780 | 781 | Returns: The created DOM node. 782 | 783 | This function is used by tools to add a toolbar button during setup of the tool. 784 | 785 | FileExplorer.Destroy() 786 | ---------------------- 787 | 788 | Category: Destructor 789 | 790 | Parameters: None. 791 | 792 | Returns: Nothing. 793 | 794 | This is a hefty function that tears down the entire widget. Calling other functions except IsDestroyed() after this function will result in an error or undefined behavior. Given the nature of the widget, it might make more sense to hide it and show it again later if it is needed rather than destroying it so users aren't forced to constantly navigate to specific paths. 795 | 796 | FileExplorer.IsDestroyed() 797 | -------------------------- 798 | 799 | Category: Destructor 800 | 801 | Parameters: None. 802 | 803 | Returns: A boolean that indicates whether or not Destroy() was called. 804 | 805 | This function tracks whether or not an instance has been destroyed. 806 | --------------------------------------------------------------------------------