// ==UserScript== // @name Supercharged Local Directory File Browser // @version 4.0.2b // @description Makes file:/// directory ("Index of...") pages (and many server-generated index pages) actually useful. Adds sidebar and preview pane; keyboard navigation for directory items; audio playback with shuffle and loop; video player; edit, preview, and save markdown/plain text files; preview images and fonts; image and font grids; sorting; user-defined shortcuts; more. // @author Gaspar Schott (Michael Schrauzer) mshroud@gmail.com // @license GPL-3.0-or-later // @homepageURL https://openuserjs.org/scripts/gaspar_schot/Supercharged_Local_Directory_File_Browser // @contributionURL https://paypal.me/mschrauzer // @include file://* // @include about:blank // @require https://code.jquery.com/jquery-latest.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it/8.4.2/markdown-it.js // @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it-footnote/3.0.1/markdown-it-footnote.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-toc-done-right@2.1.0/dist/markdown-it-toc-made-right.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-sub@1.0.0/dist/markdown-it-sub.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-sup@1.0.0/dist/markdown-it-sup.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-deflist@2.0.3/dist/markdown-it-deflist.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-multimd-table@3.1.3/dist/markdown-it-multimd-table.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-center-text@1.0.4/dist/markdown-it-center-text.min.js // NOTE: This script was developed in Vivaldi, running on Mac OS High Sierra. It has been tested in various Chrome and Gecko-based browsers. // It has been minimally tested on Windows and not at all on other OSes. It should work, but please report any issues. // The script does not work on local directories in Safari because Safari does not allow local directories to be browsed, but it will work on remote directories (or on local directories through a local server). // NOTE: By default, Greasemonkey and Tampermonkey will not run scripts on file:/// urls, so for this script to work, you will have to enable it first. // For Tampermonkey, go to Chrome extension page, and tick the 'Allow access to file URLs' checkbox at the Tampermonkey extension section. // For Greasemonkey, open about:config and change greasemonkey.fileIsGreaseable to true. // @namespace https://greasyfork.org/users/16170 // @downloadURL none // ==/UserScript== (function() { 'use strict'; const $ = window.jQuery; // ***** USER SETTINGS ***** // const $settings = { // Paste your exported settings between the two lines below: //--------------------------------------------------------// shortcuts: // N.B.: Directory links must end with "/", file links must end with another character. // You may add as many menus and links as you like; just copy the example below and edit as needed. // Local directory shortcuts must begin with "file:///"; external shortcuts must begin with the correct protocol ("http://" or "ftp://", etc.). // Note that because of same-origin security concerns, the browser will not allow you to navigate directly from an external webpage to a local directory. [ { "menu_title":"My Sample Menu", "links": [ { "link_name":"My Directory Link 1", "link":"file:///Path/To/My/Directory/" }, { "link_name":"My Directory Link 2", "link":"file:///Path/To/My/Directory_2/" }, { "link_name":"My External Link", "link":"https://www.mywebpage.com/" }, { "link_name":"My File Link", "link":"file:///Path/To/My/File.ext" }, ] }, { "menu_title":"My Second Sample Menu", "links": [ { "link_name":"My Directory Link 1", "link":"file:///Path/To/My/Directory/" }, { "link_name":"My Directory Link 2", "link":"file:///Path/To/My/Directory_2/" }, { "link_name":"My External Link", "link":"https://www.mywebpage.com/" }, { "link_name":"My File Link", "link":"file:///Path/To/My/File.ext" }, ] }, ], // GENERAL USER SETTINGS alternate_background: true, // If true (default true), alternate sidebar row background color. apps_as_dirs: false, // Un*x/Mac OS only: if true, treat apps as directories; allows app contents to be browsed. This is the default behavior for Chrome. // If false (default), treat apps as ignored files. autoload_media: true, // If true (default: true), the first audio or video file found in a directory will be automatically selected and loaded for playback; also, cover art (if any, will be loaded in the preview pane). autoload_index_files: false, // If true (default: false), automatically select first "index.xxx" (.xxx !== .htm) file found in directory. // Note: the browser will automatically load any index.html files it finds in the directory, so the script will not work properly in such cases. theme: 'light', // Options: 'light' or 'dark' sort_by: 'default', // Choose from: 'name', 'size', 'date', 'kind', 'ext', 'default'. // default = Chrome sorting: dirs on top, files alphabetical. dirs_on_top: false, // If true, directories will always be listed firs except when sorting by "name" (since otherwise sorting by "name" would equal "default"). // If false (default), directories and files will be sorted together. (In practice, dirs will typically still be separated when sorting by size, kind, and extension.) grid_font_size: 1, // Default = 1 grid_image_size: 184, // Default = 184 (200px - 16px) show_details: true, // If true (default), hide file and directory details; if false, show them. show_ignored_files: false, // If true, ignored files will appear greyed-out. // If false (default), ignored files will be completely hidden from the file list; ignore_ignored_files: true, // If true (default), ignored files (see "$row_settings" below, after Keybindings and Changelog) will be greyed-out (default) in the file list and will not be loaded in the content pane when selected; // If false, ignored files will be treated like normal files, so if they are selected, the browser will attempt to download any file types it can't handle (which makes keyboard navigation inconvenient but may be useful in some circumstances). show_invisibles: true, // Un*x/Mac OS only: If true (default), files or directories beginning with a "." will be hidden. show_numbers: true, // If true (default true), number index items UI_font: 'system-ui, sans-serif', // Choose an installed font for the UI; if undefined, use browser defaults instead. UI_font_size: '13px', // Choose a default UI font size; use any standard CSS units. use_custom_icons: true, // if true (default), use custom icons for dirs and files // if false, use browser/server default icons // TEXT EDITING SETTINGS enable_text_editing: true, // If true (default), allow plain text files to be edited. default_text_view: 'preview_text', // Options: 'source_text' or 'preview_text' for text editor. // Note that split_view = true overrides this setting. split_view: true, // If true, show split view on plain text file load. // if true (default), use default preview_text setting. sync_scroll: true // If true (default: true), show split view on plain text file load // if false, use default preview_text setting. //--------------------------------------------------------// // Paste your exported settings between the above two lines. }; // $ROW_TYPES: // DO NOT DELETE ANY EXISTING CATEGORIES! // Add file extensions for sorting and custom icon display to the existing categories. // You can also define your own new categories, but do not add an extension to more than one row_type category. // Do not add leading "." to the extensions. const $row_types = { // myRowType: ['ext1','ext2'], dir: ['/'], app: ['app/','app','exe','msi'], archive: ['7z','archive','bz2','cbr','dmg','gz','pkg','rar','tar','zip'], audio: ['aac','aif','aiff','ape','flac','m4a','mp3','ogg','opus','wav','m3u'], bin: ['dll','dylib','icc','msi'], code: ['bak','bash','bash_profile','bashrc','c','cfg','cnf','codes','coffee','conf','csh','cshrc','cson','css','custom_aliases','default','dist','editorconfig','emacs','example','gemspec','gitconfig','gitignore','gitignore_global','h','hd','ini','js','json','jsx','less','list','local','login','logout','lua','mkshrc','old','php','pl','plist','pre-oh-my-zsh','profile','pth','py','rb','rc','rdoc','sass','settings','sh','strings','taskrc','tcl','viminfo','vimrc','vue','xml','yaml','yml','zlogin','zlogout','zpreztorc','zprofile','zsh','zshenv','zshrc'], database: ['db','sql', 'sqlite'], font: ['otf','ttf','woff','woff2','afm','pfb','pfm','tfm'], graphics: ['ai','book','dtp','eps','fm','icml','idml','indd','indt','inx','mif','pmd','pub','qxb','qxd','qxp','sla','swf'], htm: ['htm','html','xhtm','xhtml'], image: ['apng','bmp','gif','jpeg','jpg','png','svg','webp'], ignored_image: ['ai','arw','cr2','dng','eps','nef','psd','psd','raw','tif','tiff'], markdown: ['md','markdown','mdown','mkdn','mkd','mdwn','mdtxt','mdtext'], office: ['csv','doc','docx','epub','key','numbers','odf','ods','odt','pages','rtf','scriv','xls','xlsx','xlm'], pdf: ['pdf'], system: ['DS_Store','ds_store','icon','ics'], text: ['log','nfo','txt','m3u'], video: ['m4v','mov','mp4','mpeg','webm'] }; // $ROW_SETTINGS: Ignore or Exclude files by extension const $row_settings = { // Ignore: $row_types or files with extensions added here will not be loaded if selected in the sidebar (prevents the browser from attempting to download the file). ignore: $row_types.archive.concat( 'alias', $row_types.bin, $row_types.database, $row_types.graphics, $row_types.ignored_image, $row_types.office, $row_types.system), // Exclude: Files with these exensions will not be inverted in dark mode exclude: ['htm','html','xhtm','xhtml'] }; // ***** END USER SETTINGS ***** // // ## FEATURES INCLUDE: // - Resizable sidebar and directory/file preview pane. // - Arrow navigation in sidebar: // - Up and Down Arrows select next/prev item. // - Left and Right Arrows select next/prev item of same type. // - Navigate sidebar by typed string. // - Show/Hide file details (size (if avail), date modified (if avail), kind, extension). // - Sort sidebar items by name or file details. // - Default sort = sort by name with folders on top. // - Preview all file types supported by browser (html, text, images, pdf, audio, video, etc.) and preview fonts. // - Preview and edit markdown and plain text files, with option to save files locally. // - Markdown rendered with markdownit.js ( https://github.com/markdown-it/markdown-it ). // - Uses Github Markdown styles for preview ( https://github.com/sindresorhus/github-markdown-css ), with a few customizations. // - Support for: // - TOC creation ( `${toc}` ) ( https://github.com/nagaozen/markdown-it-toc-done-right ) // - Multimarkdown table syntax ( https://github.com/RedBug312/markdown-it-multimd-table ) // - Live checkboxes ( `\[ ], [x]` ), allowed in lists and deflists. // - Superscript ( `^sup^` ) ( https://github.com/markdown-it/markdown-it-sup ) // - Subscript ( `~sub~` ) ( https://github.com/markdown-it/markdown-it-sub ) // - Definition lists ( https://github.com/markdown-it/markdown-it-deflist; for syntax, see http://pandoc.org/MANUAL.html#definition-lists ) // - Centered text ( `->centered<-` ) ( https://github.com/jay-hodgson/markdown-it-center-text ) // - Footnotes ( https://github.com/markdown-it/markdown-it-footnote ) // - View source text, preview, or split pane with proportional sync scroll. // - Save edited source text or previewed HTML. // - Create and edit text in separate text editor. // - Audio and video playback, with shuffle, loop, skip audio +/- 10 or 30 sec via keyboard. // - Preview other files (e.g., lyrics or cover art) in same directory while playing audio. // - User setting to autoload cover art (if any images in directory, load "cover.ext" or first image found) // - Grid view for images and fonts. // - User settings (see $settings in code; some settings can be changed via the main menu in the UI and will be remembered in URL query): // - Light or Dark theme. // - Bookmarks for local or remote directories. // - Default image grid size. // - Default UI font size and font-family. // - Default UI font and font-size. // - Default file sorting. // - Sort with directories on top. // - Treat apps as directories (MacOS and *nix only) // - Show or hide invisible files. // - Show or hide ignored files in the ignored files list (see $row_settings in code below $settings). // - Show or hide file details. // - Use custom file icons or browser defaults. // - Autoload index.ext files. // - Autoload cover art in directories with audio files. // - Text editing default view: split, source, or preview. // - Text editing sync scroll: on or off. // ## KEYBINDINGS (These don't work in all browsers): // - Arrow Up/Down: Select prev/next item. // - If audio is playing, and prev/next file is also audio, it will be highlighted but not loaded in the audio player; press return to load it. // - Arrow Left/Right: Select prev/next row of the same kind as the current selection. // - If current selection is a media file, select and begin playback of the next media item. // - Opt/Alt + Arrow Left/Right: Skip audio ±10s // - Opt/Alt + Shift + Arrow Left/Right: Skip audio ±30s // - Cmd/Ctrl + Arrow Up: Go to parent directory // - Cmd/Ctrl + Arrow Down: Open selected directory // - Return: Open selected directory, select file, or pause/play media. // - Space: Pause/Play media files // - Cmd/Ctrl + D: Toggle file details (size, date modified) in some index page types. // - Cmd/Ctrl + E: Show text editor. // - Cmd/Ctrl + G: Show or Reset Grid. // - Cmd/Ctrl + I: Toggle Invisibles. // - Cmd/Ctrl + Shift + O: Open selected item in new window/tab. // - Cmd/Ctrl + R: Reload grids and previewed content, reset scaled images/fonts, reset media files to beginning. // - Cmd/Ctrl + W: Close previewed content (doesn't work in all browsers; use close button instead), or close window if no content is being previewed. // - Cmd/Ctrl + Shift + < or >: Scale preview items and grids. // CHANGELOG: // **VERSION 4.0.1b** // **FIXED:** Audio files weren't being loaded. // **FIXED:** Script would fail if a file name included a special regex character `[\^$.|?*+()`. // **FIXED:** Various issue with parsing "pre"-type index pages. // **IMPROVED:** Sorting and display of items with names beginning with white spaces. // **IMPROVED:** More efficient and robust index type detection. // **ADDED:** Sorting for previewed directory contents. Initial sorting is the same as the parent's current sort pref. // **ADDED:** Custom icons and numbering for previewed directory contents; numbering reflects the parent's current numbering pref. // **ADDED:** Append some server info and other provided information to the stats footer. // **NOTE:** There is an issue with Chrome browsers and pdf file display, so pdfs don't display reliably. // **NOTE:** Some further fixes and styles tweaks coming. // **VERSION 4.0.0b** // Numerous additions, improvements, and massive internal changes. Virtually no line of code has been left untouched. // **"b" === "bugs" likely. Updates will be coming. // **IMPORTANT:** This version uses a new format for user settings in the code; you will have to re-enter your defaults manually after updating. // - Do NOT use exported settings from any earlier version of the script. // **NEW:** Added independent text editor pane. // - Invoke with Cmd/Ctrl + E, or in main menu > Text Editing > Toggle Text Editor", or under "Show Details". // - To prevent loss of work (and for convenience, e.g., to refer to a file while writing), previously entered text will not be cleared when the "New" button is clicked again, when the "Close" button is clicked, or when a sidebar item is selected. // - Use the Save button to save the text as a text or html file, which can be previewed and edited as usual by navigating to its saved location. // **ADDED:** Option to number index items, with new user setting. // **ADDED:** Stats footer in sidebar showing dir and file count. // **ADDED:** Icons for shortcuts menu to indicate local vs. remote links. // **ADDED:** Text editing: Clear button to empty text editing pane. // **CHANGED:** Text editing: Github styling customizations: Make table cells top-aligned, darker blockquote text color. // **IMPROVED:** Text editing: When saving rendered HTML, header uplinks will be removed. // **IMPROVED:** Text editing: Don't close other previewed content when making new text editing pane. // **IMPROVED:** Text editing: Much improved warning system for edited text: now uses `postMessage` to communicate between iframe and parent. // **IMPROVED:** Content display: use the same code to prep and style directory contents in the preview pane. // **IMPROVED:** Live sorting of grid items (but images and fonts are still sorted separately). // **IMPROVED:** Image zoom positioned accurately under click. // **IMPROVED:** Better handling of 404 Errors (Page not found): server error message will appear in sidebar, warning icon in content pane. // **IMPROVED:** File URLs: If a file URL (instead of a directory) is entered directly in the browser URL bar, the parent directory will be loaded instead and the file automatically selected. // **IMPROVED:** Navigation: modifed highlighting styles to show when a non-audio item is selected for navigation vs. when it is loaded in preview pane but not selected (e.g. click a directory and then click an audio file; the directory item will be dimmed). // **IMPROVED:** Audio: Greatly simplified shuffle play code and fixed several bugs; shuffle list now correctly updates when individual audio tracks are checked or unchecked. // **CHANGED:** Moved scale buttons and prev/next image buttons to preview title bar. // **CHANGED:** Sort by "Name" always sorts files and directories together; "Default" sort always keeps files and directories separate. // **FIXED:** Text editing: Some issues with split-pane resizing. // **FIXED:** Cmd/Ctr+W (close) should work now: previewed content will be closed first, then audio, then the browser tab itself. // **FIXED:** Don't autoload audio cover art when next audio track begins; i.e., leave open whatever file is being previewed, including cover art or lyrics. // **FIXED:** An issue with sorting by size. // **FIXED:** An issue with the user UI font setting. // **FIXED:** Navigation by typed string now correctly scrolls directory list. // **OTHER:** Many small style fixes and tweaks. Among others, make the previewed image and image grid background color light in default theme. // **INTERNAL:** Complete code overhaul. // - Completely rewrote the code that preps the served directory index for processing by the script. // - Completely rewrote and simplied the sorting code. // - Alphabetized User Settings for easier editing. // - Fixes for additional server index configurations. // – Performance improvments (e.g., removed multiple calls to various functions, reduced initial DOM manipulation, etc.). // - General code cleanup (e.g., removed unused variables and unnecessary globals, named many formerly anonymous functions, fixed numerous syntax errors, etc.). // // **STILL TO COME:** // - Dark mode for text editing. // - Additional code cleanup, and more. // ***** GENERAL SETUP ***** // // ************************************ // // DON'T EDIT ANYTHING BELOW THIS LINE. // // ************************************ // // PATHS // Fix "%" error in file name; see https://stackoverflow.com/questions/7449588/why-does-decodeuricomponent-lock-up-my-browser function decodeURIComponentSafe(s) { if (!s) { return s; } return decodeURIComponent(s.replace(/%(?:^[0-9]{2,})/g, '%25')); } const $protocol = window.location.protocol; const $origin = $protocol +'//'+ window.location.host; const $location = decodeURIComponentSafe( [location.protocol, '//', location.host, location.pathname].join('') ); const $current_dir_path = $location.replace(/[\/|_|—]/g,'/').replace(/\\/g,'/'); // URL w/o query string for display function escapeStr(str) { str = str.replace(/([\^\$\|\?\*\+\(\)\[])/g,'\$1'); } // if URL is a file, change window location to parent dir, add querystring of file name; then autoload file. function loadFile() { if ( $location.slice($location.lastIndexOf('/')).indexOf('.') !== -1 && !$location.endsWith('/') && window.top === window.self ) { let $query_prefs = getQueryPrefs(); $query_prefs.set( 'file', $location.slice($location.lastIndexOf('/') + 1) ); window.location = $location.slice(0,$location.lastIndexOf('/') + 1) +'?'+ $query_prefs; return; } } loadFile(); // QUERY PREFS function getQueryPrefs() { return new URL(window.location).searchParams; } // set query key/value function setQuery(key, value) { let $query_prefs = getQueryPrefs(); $query_prefs.set( key, value ); updateQuery($query_prefs); } // get query value function getQuery(key) { let $query_prefs = getQueryPrefs(); let value = ''; if ( key === 'width' ) { value = ( !$query_prefs.has(key) ? 30 : Math.round(100 * $query_prefs.get('width')/window.innerWidth) ); // number string } else { value = ( $query_prefs.has(key) ? $query_prefs.get(key) : $settings[key] !== undefined ? $settings[key].toString() : '' ); } return value; } // toggle query key function toggleQuery(key) { let $query_prefs = getQueryPrefs(); let nonBoolPrefs = { 'theme_light':{'theme':'dark'}, 'theme_dark':{'theme':'light'}, 'source_text':{'default_text_view':'preview_text'}, 'preview_text':{'default_text_view':'source_text'}, 'sort_by_default':{'sort_by':'default'}, 'sort_by_name':{'sort_by':'name'}, 'sort_by_size':{'sort_by':'size'}, 'sort_by_date':{'sort_by':'date'}, 'sort_by_kind':{'sort_by':'kind'}, 'sort_by_ext':{'sort_by':'ext'}, }; var value, queryValue, settingsValue; if ( nonBoolPrefs[key] !== undefined ) { value = Object.values(nonBoolPrefs[key]).toString(); key = Object.keys(nonBoolPrefs[key]).toString(); // must come after value: i.e., don't redefine key before getting value if ( $settings[key] === value ) { $query_prefs.delete( key ); } else { $query_prefs.set( key, value ); } } else { queryValue = $query_prefs.get(key); settingsValue = $settings[key]; value = ( queryValue === null ? settingsValue.toString() : queryValue.toString() ); value = ( value === 'true' ? 'false' : 'true' ); if ( ( queryValue !== null && queryValue !== settingsValue ) ) { $query_prefs.delete( key ); } else { $query_prefs.set( key, value ); } } updateQuery($query_prefs); } // remove query key function removeQuery(key) { let $query_prefs = getQueryPrefs(); $query_prefs.delete(key); updateQuery($query_prefs); } // update query string function updateQuery(querystr) { window.history.replaceState({}, document.title, window.location.pathname +'?'+ querystr); updateParentLinks(); } // ***** SET UP UI ELEMENTS ***** // // ***** SIDEBAR ELEMENTS ***** // const $parent_dir_menu = $(''); const $parents_dir_menu = $(''); const $shortcuts_menu = $(''); const $show_details = $(''); const $inv_checkbox = $(''); const $grid_btn = $('
'); const $sidebar_header = $(''); const $text_editor_item = $('Text Editor'); const $dir_list_head = $('NameDefaultSizeDateKindExt'); const $dir_list_body = $(''); var $dir_list = $('
'); const $sidebar = $(''); const $handle = $('
'); const $sidebar_wrapper = $(''); const $toggle_sidebar = $('
'); const $index_stats = $(''); const $warnings = $('

Warning:

You have unsaved changes.

Are you sure you want to clear all your text?

Can\'t load local directories or files from non-local web pages. Use your browser\'s bookmarks or enter the URL manually.

'); const $overlay = $('
'); // ***** CONTENT PANE ELEMENTS ***** // const $content_audio_title = $(''); const $content_audio = $(''); const $prev_track = $('
 
'); const $next_track = $('
 
'); const $audio_player = $(''); const $loop = $(''); const $shuffle = $(''); const $close_audio = $('
'); const $content_grid = $('
'); const $content_text = $('
'); const $sample_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789 [(!@#$%^&*;:)]'; const $hamburger_string = '

Typography

The art of using types to produce impressions on paper, vellum, &c.

S P E C I M E N

Typography is the work of typesetters (also known as compositors), typographers, graphic designers, art directors, manga artists, comic book artists, graffiti artists, and, now, anyone who arranges words, letters, numbers, and symbols for publication, display, or distribution.

'; const $lorem_string = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'; const $specimen = $('
'+ $sample_string +'
'+ $hamburger_string +'
'+ $lorem_string +'
'+ $lorem_string +'
'+ $lorem_string +'
'); const $content_font = $('
'); const $content_image = $(''); const $content_video = $(''); const $content_pdf = $(''); // if ( navigator.userAgent.indexOf('Chrome') > -1 ) { $content_pdf.attr('type','application/x-google-chrome-pdf'); } const $content_iframe = $(''); const $checkbox_cont = $('
'); const $title_buttons_left = $(''); // const $content_stop_btn = $(''); const $title = $(''); const $content_title = $(''); const $title_buttons_right = $(''); const $content_header = $('
'); // const $prev_btn = $(''); // const $next_btn = $(''); const $content_container = $('
'); const $content_pane = $(''); const $main_content = $('
'); // SVG UI ICONS const $svg_prefix = 'url("data:image/svg+xml;utf8,")'; const $up_arrow_inv = $svg_prefix + 'width=\'12.728px\' height=\'7.779px\' viewBox=\'0 0 12.728 7.779\' enable-background=\'new 0 0 12.728 7.779\' xml:space=\'preserve\'>")'; // const $svg_arrow = $svg_prefix + 'width=\'11px\' height=\'16px\' viewBox=\'234.5 248 11 16\' enable-background=\'new 234.5 248 11 16\' xml:space=\'preserve\'>")'; const $svg_arrow = $svg_prefix + 'width=\'88.4px\' height=\'141.4px\' viewBox=\'0 0 88.4 141.4\' enable-background=\'new 0 0 88.4 141.4\' xml:space=\'preserve\'>")'; const $toggle = $svg_prefix + 'width=\'13.779px\' height=\'12.729px\' viewBox=\'2.474 -2.475 13.779 12.729\' enable-background=\'new 2.474 -2.475 13.779 12.729\' xml:space=\'preserve\'> ")'; const $check_mark = $svg_prefix + 'width=\'17px\' height=\'14px\' viewBox=\'250.182 490.01 17 14\' enable-background=\'new 250.182 490.01 16.971 14.143\' xml:space=\'preserve\'>")'; const $check_mark_inv = $svg_prefix + 'width=\'17px\' height=\'14px\' viewBox=\'250.182 490.01 17 14\' enable-background=\'new 250.182 490.01 16.971 14.143\' xml:space=\'preserve\'>")'; const $menu_arrow = $svg_prefix + 'width=\'24px\' height=\'16px\' viewBox=\'0 0 24 16\' enable-background=\'new 0 0 24 16\' xml:space=\'preserve\'> ")'; const $menu_arrow_inv = $svg_prefix + 'width=\'24px\' height=\'16px\' viewBox=\'0 0 24 16\' enable-background=\'new 0 0 24 16\' xml:space=\'preserve\'> ")'; const $menu_icon = $svg_prefix + 'width=\'13px\' height=\'10px\' viewBox=\'0 0 13 10\' enable-background=\'new 0 0 13 10\' xml:space=\'preserve\'>")'; const $grid_icon = $svg_prefix + 'width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' enable-background=\'new 0 0 16 16\' xml:space=\'preserve\'>")'; const $grid_icon_inv = $svg_prefix + 'width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' enable-background=\'new 0 0 16 16\' xml:space=\'preserve\'>")'; const $plus_sign = $svg_prefix + 'width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' xml:space=\'preserve\'>")'; const $minus_sign = $svg_prefix + 'width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' xml:space=\'preserve\'> ")'; const $next_track_arrow = $svg_prefix + 'width=\'12.8px\' height=\'14px\' viewBox=\'-2 0 12.8 14\' enable-background=\'new -2 0 12.8 14\' xml:space=\'preserve\'>")'; const $next_track_arrow_gecko = $svg_prefix + 'width=\'12.8px\' height=\'14px\' viewBox=\'-2 0 12.8 14\' enable-background=\'new -2 0 12.8 14\' xml:space=\'preserve\'>")'; const $next_track_arrow_gecko_hover = $svg_prefix + 'width=\'12.8px\' height=\'14px\' viewBox=\'-2 0 12.8 14\' enable-background=\'new -2 0 12.8 14\' xml:space=\'preserve\'>")'; const $music = $svg_prefix + 'width=\'143.717px\' height=\'199.404px\' viewBox=\'0 0 143.717 199.404\' enable-background=\'new 0 0 143.717 199.404\' xml:space=\'preserve\'> ")'; const $error_icon = $svg_prefix + 'viewBox=\'0 0 512 512\' enable-background=\'new 0 0 512 512\' xml:space=\'preserve\'> ")'; // const $spinner = $svg_prefix + ' width=\'40px\' height=\'40px\' viewBox=\'-1 -1 40 40\' style=\'enable-background:new -1 -1 40 40;\' xml:space=\'preserve\'> ")'; //SVG FILE ICONS // Chrome default icons const $file_icon_dir_default = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ")'; const $file_icon_file_default = 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ")'; // Custom file icons const $svg_icon_prefix = 'url("data:image/svg+xml;utf8, '; const $file_icon_dir = $svg_icon_prefix + ' ")'; const $file_icon_dir_invisible = $svg_icon_prefix + ' ")'; const $file_icon_app = $svg_icon_prefix + ' ")'; const $file_icon_file = $svg_icon_prefix + ' ")'; const $file_icon_text = $svg_icon_prefix + ' ")'; const $file_icon_image = $svg_icon_prefix + ' ")'; const $file_icon_pdf = $svg_icon_prefix + ' ")'; const $file_icon_font = $svg_icon_prefix + '")'; const $file_icon_code = $svg_icon_prefix + ' ")'; const $file_icon_html = $svg_icon_prefix + ' ")'; const $file_icon_ignored = $svg_icon_prefix + '")'; const $file_icon_ignored_inv = $svg_icon_prefix + '")'; const $file_icon_invisible = $svg_icon_prefix + ' ")'; const $file_icon_video = $svg_icon_prefix + '")'; const $file_icon_audio = $svg_prefix + 'width=\'143.717px\' height=\'199.404px\' viewBox=\'0 0 143.717 199.404\' enable-background=\'new 0 0 143.717 199.404\' xml:space=\'preserve\'> ")'; // const $file_icon_archive = 'url("data:image/svg+xml;utf8,")'; // Assemble UI Elements function assembleUIElements() { $parents_dir_menu.find('div').append( $current_dir_path ); $sidebar_header.find('thead th'); $sidebar_header.find('tbody tr').first().find('td').first().append( $parent_dir_menu ).next().append( $parents_dir_menu ).next().append( $shortcuts_menu ); $sidebar_header.find('tbody tr:last-child td').append( $show_details, $inv_checkbox, $grid_btn ); $dir_list_head.append($text_editor_item); $dir_list.append($dir_list_head, $dir_list_body, $index_stats); $sidebar.append($sidebar_header, $dir_list); $sidebar_wrapper.append( $sidebar, $handle, $toggle_sidebar ); // content pane items $checkbox_cont.append( $loop, $shuffle ); $content_audio.find('td').append( $prev_track, $next_track, $audio_player, $close_audio, $checkbox_cont ); $content_title.append($title_buttons_left, $title, $title_buttons_right); $content_header.find('tbody').append( $content_title, $content_audio_title, $content_audio ); $content_font.append( $specimen ); $content_container.append( $content_grid, $content_text, $content_font, $content_image, $content_pdf, $content_video, $content_iframe ); $content_pane.append( $content_header, $content_container ); $main_content.find('thead').append($warnings, $overlay); } //***** STYLES *****// // DEFINE STYLES var $main_style_rules = // Align-content '#content_pane.has_image #content_container' + //body.theme_light #dir_list .selected.audio, '{ align-items: center; justify-content: center; }' + // BACKGROUND: COLOR '#sidebar_wrapper, body.theme_light #sidebar, body.theme_light #sidebar ul, body.theme_light #preview_text, body.theme_light #source_text, body.theme_light #content_header' + '{ background-color: lightgray }' + 'body.theme_light #dir_list tr.selected:not(.playing)' + //body.theme_light #dir_list .selected.audio, '{ background-color: lightsteelblue !important; }' + 'body.theme_light #dir_list tr.loaded:not(.selected)' + //body.theme_light #dir_list .selected.audio, '{ background-color: rgba(69%,77%,87%,0.75); }' + 'body.theme_light #dir_list tr.loaded:hover' + //body.theme_light #dir_list .selected.audio, '{ background-color: rgba(69%,77%,87%,1) !important; }' + '#content_pane.has_grid .image_grid_item::after' + //body.theme_light #dir_list .selected.audio, '{ background-color: gray; }' + 'body.theme_dark #dir_list tr.selected:not(.playing)' + '{ background-color: slategray !important; }' + 'body.theme_dark #dir_list tr.loaded:not(.selected)' + '{ background-color: rgba(44%,50%,56%,0.5); }' + 'body.theme_dark #dir_list tr.loaded:hover' + '{ background-color: rgba(44%,50%,56%,1) !important; }' + 'body.theme_dark #content_pane.has_grid #content_container, body.theme_dark #content_grid > div:hover, body.theme_dark #content_grid > div.hovered, body.theme_dark #content_grid > div.selected' + '{ background-color: #262626; }' + 'body.theme_dark #content_grid > div, body.theme_dark #content_pane.has_image, body.theme_dark #content_font, body.theme_dark #content_pane, body.theme_dark #content_pane.has_grid #content_grid::after, .split_btn::after' + '{ background-color: #333; }' + 'body.theme_dark #sidebar ul, body.theme_dark #preview_text_menu_item span, body.theme_dark #sidebar_header thead, body.theme_dark #sidebar_menus, body.theme_dark #preview_text, body.theme_dark #source_text, body.theme_dark.alternate_background #dir_list tbody tr:nth-of-type(odd):not(.selected):not(.loaded), body.theme_dark.alternate_background #dir_list tbody tr:nth-of-type(odd):not(.loaded), body.theme_dark #index_stats, body.theme_dark .playlist_item:nth-of-type(odd)' + '{ background-color: #444; }' + 'body.theme_dark #sidebar, body.theme_dark #dir_list #tbody, body.theme_dark #grid_btn .menu li, body.theme_dark #content_header, body.theme_dark .font_grid_item:hover, body.theme_dark .font_grid_item.hovered, body.theme_dark .image_grid_item:hover, body.theme_dark .image_grid_item.hovered' + '{ background-color: #555; }' + 'body.theme_dark #sidebar ul li:not(#preview_text_menu_item):hover, body.theme_dark #preview_text_menu_item span:hover, body.theme_dark #preview_text:hover, body.theme_dark #source_text:hover' + '{ background-color: #666; }' + 'body.theme_dark #sidebar .hovered, body.theme_dark #grid_btn .menu li:hover, body.theme_dark #dir_list tbody tr:hover, body.theme_dark #dir_list tbody li:hover, body.theme_dark.alternate_background #dir_list #tbody tr:hover, body.theme_dark.alternate_background #dir_list #tbody tr:nth-of-type(odd).hovered, body.theme_dark #content_iframe[href^="/"]' + '{ background-color: #777; }' + 'body.theme_light #sidebar_header thead tr, body.theme_light #sidebar_menus, #parents_dir_menu + ul li:hover, #shortcuts_menu + ul li:not(.has_submenu):not(#preview_text_menu_item):hover, body.theme_light #preview_text_menu_item span:hover, body.theme_light #preview_text:hover, body.theme_light #source_text:hover, #grid_btn.has_images.has_fonts:hover .menu li:hover, body.theme_light #dir_list tbody tr:hover, body.theme_light.alternate_background #dir_list #tbody tr:hover, body.theme_light #dir_list .hovered, body.theme_light.alternate_background #dir_list #tbody tr.hovered' + '{ background-color: #BBB; }' + 'body.theme_light #grid_btn .menu li, body.theme_light.alternate_background #dir_list tbody tr:nth-of-type(odd):not(.selected):not(.playing):not(.loaded), body.theme_light #index_stats, body.theme_light .playlist_item:nth-of-type(odd)' + '{ background-color: #CCC; }' + 'body.theme_light #dir_list tbody' + '{ background-color: #DFDFDF; }' + 'body.theme_light #content_pane.has_image, body.theme_light #content_grid > div, #warnings, body.theme_light #content_pane.has_grid #content_grid::after, body.theme_light #content_pane.has_grid .image_grid_item::after' + '{ background-color: #EEE; }' + 'body.theme_light #content_pane, body.theme_light #content_grid, body.theme_light #content_grid div.selected, #content_font, #content_iframe, #scale, body.is_chrome #audio:focus, body.theme_light #content_grid div:hover, body.theme_light #content_grid div.hovered' + '{ background-color: #FFF; }' + // EXCLUDED: Prevent previewed files with these extensions from being inverted in dark mode //for ( i = 0; i < $row_settings.exclude.length; i += 1) { // 'body.theme_dark #content_iframe[src*="'+ $row_settings.exclude[i] +'" i] { background:#FFF; filter: unset; }' + //} 'body.is_chrome #audio' + '{ background-color: rgb(241, 243, 244); }' + 'body.theme_light #dir_list .playing, body.theme_light.has_text #text_editor_row, body.theme_light.edited #text_editor_row' + '{ background-color: #99bebf; }' + 'body.theme_dark #dir_list .playing, body.theme_dark.alternate_background #dir_list tbody tr.playing:nth-of-type(odd), body.theme_dark.has_text #text_editor_row, body.theme_dark.edited #text_editor_row' + //body.theme_dark #dir_list .selected.audio, '{ background-color: #4C7E80; }' + '#dir_list tbody tr, #dir_list .audio a, #dir_list .video a, body.has_audio #content_pane.has_ignored, body #dir_list tr.file.audio a.icon, body #dir_list tr.file.video a.icon, body.use_custom_icons #dir_list tr.file.ignore a.icon' + '{ background-color: transparent; }' + '#warnings button:focus,#warnings button.focus' + '{ background: #0E4399; }' + // BACKGROUND: SVG IMAGES & ICONS '#parent_dir_menu a { background:' + $up_arrow + 'center no-repeat; }' + '#shortcuts_menu div { background:'+ $menu_icon + 'center no-repeat; }' + 'body.theme_light #shortcuts > li.has_submenu { background:'+ $menu_arrow +' right no-repeat; background-size: 12px; }' + 'body.theme_light #shortcuts > li.has_submenu:hover { background:#BBB '+ $menu_arrow +' right no-repeat; background-size: 12px; }' + 'body.theme_dark #shortcuts > li.has_submenu { background:'+ $menu_arrow_inv +' right no-repeat; background-size: 12px; }' + 'body.theme_dark #shortcuts > li.has_submenu:hover { background:#666 '+ $menu_arrow_inv +' right no-repeat; background-size: 12px; }' + 'body.theme_light.sort_by_default #sort_by_default span::before, body.theme_light.sort_by_name #sort_by_name span::before, body.theme_light.sort_by_size #sort_by_size span::before, body.theme_light.sort_by_date #sort_by_date span::before, body.theme_light.sort_by_kind #sort_by_kind span::before, body.theme_light.sort_by_ext #sort_by_ext span::before, body.theme_light.sort_by_default #default, body.theme_light.sort_by_name #name, body.theme_light.sort_by_size #size, body.theme_light.sort_by_date #date, body.theme_light.sort_by_kind #kind, body.theme_light.sort_by_ext #ext, body.theme_light #theme span, body.theme_light.alternate_background #alternate_background span, body.theme_light.show_numbers #show_numbers span, body.theme_light.autoload_media #autoload_media span, body.theme_light.split_view #split_view_menu_item, body.theme_light.split_view #split_view, body.theme_light:not(.enable_text_editing) #enable_text_editing, body.theme_light.source_text #source_text, body.theme_light.preview_text #preview_text { background:'+ $check_mark +' 4px center no-repeat; background-size:10px; }' + 'body.theme_dark.sort_by_default #sort_by_default span::before, body.theme_dark.sort_by_name #sort_by_name span::before, body.theme_dark.sort_by_size #sort_by_size span::before, body.theme_dark.sort_by_date #sort_by_date span::before, body.theme_dark.sort_by_kind #sort_by_kind span::before, body.theme_dark.sort_by_ext #sort_by_ext span::before, body.theme_dark.sort_by_default #default, body.theme_dark.sort_by_name #name, body.theme_dark.sort_by_size #size, body.theme_dark.sort_by_date #date, body.theme_dark.sort_by_kind #kind, body.theme_dark.sort_by_ext #ext, body.theme_dark #theme span, body.theme_dark.alternate_background #alternate_background span, body.theme_dark.show_numbers #show_numbers span, body.theme_dark.autoload_media #autoload_media span, body.theme_dark.split_view #split_view_menu_item, body.theme_dark.split_view #split_view, body.theme_dark:not(.enable_text_editing) #enable_text_editing, body.theme_dark.source_text #source_text, body.theme_dark.preview_text #preview_text { background:'+ $check_mark_inv +' 4px center no-repeat; background-size:10px; }' + 'body #grid_btn { background:'+ $grid_icon +' right 6px top 0 no-repeat; }' + 'body.theme_light.has_images.has_fonts #grid_btn:hover .menu { background: #DDD '+ $grid_icon +' right 6px top 6px no-repeat; }' + 'body.theme_dark.has_images.has_fonts #grid_btn:hover .menu { background: #555 '+ $grid_icon_inv +' right 6px top 6px no-repeat; }' + '#toggle_sidebar { background:'+ $toggle +' center no-repeat; background-size:12px; }' + // 'body.theme_light #dir_list thead th.checked span::before { background-image:'+ $check_mark +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + // 'body.theme_dark #dir_list thead th.checked span::before { background-image:'+ $check_mark_inv +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + 'body.theme_light.sort_by_default #sort_by_default span::after, body.theme_light.sort_by_name #sort_by_name span::after, body.theme_light.sort_by_size #sort_by_size span::after, body.theme_light.sort_by_date #sort_by_date span::after, body.theme_light.sort_by_kind #sort_by_kind span::after, body.theme_light.sort_by_ext #sort_by_ext span::after { background-image:'+ $up_arrow +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + 'body.theme_dark.sort_by_default #sort_by_default span::after, body.theme_dark.sort_by_name #sort_by_name span::after, body.theme_dark.sort_by_size #sort_by_size span::after, body.theme_dark.sort_by_date #sort_by_date span::after, body.theme_dark.sort_by_kind #sort_by_kind span::after, body.theme_dark.sort_by_ext #sort_by_ext span::after { background-image:'+ $up_arrow_inv +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + '#dir_list tbody a { background-size:auto 13px; background-position:6px 4px; }' + 'body.has_audio #content_pane:not(.has_image):not(.has_video):not(.has_ignored) { background-image: ' + $music +'; background-position: center; background-repeat: no-repeat; background-size:33.33%; }' + '#prev_track, #next_track { background: rgb(241, 243, 244) '+ $next_track_arrow +' center no-repeat; background-blend-mode:difference; }' + '#prev_track:hover, #next_track:hover, #close_audio:hover { background-blend-mode:normal; }' + '#close_audio { background:rgb(241, 243, 244); }' + '#close_audio::after { background:'+ $plus_sign +' center no-repeat; background-blend-mode:difference; background-size:14px; }' + '#decrease { background:'+ $minus_sign +' center no-repeat; background-size: 10px; }' + '#increase { background:'+ $plus_sign +' center no-repeat; background-size: 10px; }' + '#prev_btn, #next_btn { background: ' + $svg_arrow + ' 45% center no-repeat; background-size: contain; }' + 'body #content_pane.has_ignored:not(.has_grid) { background-image:'+ $file_icon_ignored +'; background-position: center; background-repeat: no-repeat; background-size:50%; }' + 'body.theme_dark #content_pane.has_ignored:not(.has_grid) { background-color:#333; background-image:'+ $file_icon_ignored_inv +'; background-position: center; background-repeat: no-repeat; background-size:50%; }' + 'body.theme_light.is_error #content_pane { background:#FFF '+ $error_icon +' center no-repeat; background-size:50%;}' + 'body.theme_dark.is_error #content_pane { background:#333 '+ $error_icon +' center no-repeat; background-size:50%;}' + // '#content_pane.has_image #content_container, #content_pane.has_pdf #content_container { background: '+ $spinner +' center no-repeat; background-size:20px; }' + // Default File Icons 'body.use_default_icons #dir_list .dir a.icon span { background:'+ $file_icon_dir_default + ' 6px 0 no-repeat; background-size:auto 13px; }' + 'body.use_default_icons #dir_list .file a.icon span { background:'+ $file_icon_file_default + ' 6px 0 no-repeat; background-size:auto 13px; }' + // Custom File Icons 'body.use_custom_icons #dir_list tr.file:not(.dir) a.icon span { background: '+ $file_icon_file +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file.audio a.icon span, body.use_custom_icons #dir_list tr.file.video a.icon span { background: transparent; }' + 'body.use_custom_icons #dir_list tr.file.font a.icon span { background: '+ $file_icon_font +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file.image a.icon span { background: '+ $file_icon_image +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file.pdf a.icon span { background: '+ $file_icon_pdf +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file[class*="htm"] a.icon span { background: '+ $file_icon_html +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file.ignore a.icon span { background: '+ $file_icon_ignored +' 6px 0 no-repeat; }' + 'body.use_custom_icons #dir_list tr.file.invisible a.icon span { background: '+ $file_icon_invisible +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.dir.invisible a.icon span { background: '+ $file_icon_dir_invisible +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.dir:not(.app) a.icon span { background: '+ $file_icon_dir +' 6px 0 no-repeat; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.app a span { background: '+ $file_icon_app +' 6px 0 no-repeat !important; background-size:14px 14px; }' + 'body.use_custom_icons #dir_list tr.file.code a.icon span { background: '+ $file_icon_code +' 6px 0 no-repeat; background-size:14px 14px }' + 'body.use_custom_icons #dir_list tr.file.text a.icon span, body.use_custom_icons #dir_list tr.file.markdown a.icon span { background: '+ $file_icon_text +' 6px 0 no-repeat; background-size:14px 14px }' + // shortcuts icons '#shortcuts ul a { background: '+ $file_icon_file +' 8px center no-repeat; background-size:14px 14px }' + '#shortcuts ul a[href^="file"] { background: '+ $file_icon_dir +' 8px center no-repeat; background-size:14px 14px }' + '#shortcuts ul a[href^="http"] { background: '+ $file_icon_html +' 8px center no-repeat; background-size:14px 14px }' + // BORDERS ':root, html, body, #sidebar_wrapper, #sidebar_header, #dir_list, #main_content, #content_pane, #content_pdf, #content_iframe' + '{ border: 0 !important; }' + 'body.theme_dark ul' + '{ border: solid 1px #222; }' + 'button' + '{ border: solid 1px #333; }' + 'body.theme_light #sidebar ul' + '{ border: solid 1px gray; }' + // border-top 'body.theme_dark #sidebar_header .menu, body.theme_dark #grid_btn ul.menu, body.theme_dark #text_editor_row, body.theme_dark #dir_list #tbody, body.theme_dark #index_stats' + '{ border-top:solid 1px #111; }' + 'body.theme_light #dir_list tbody, #grid_btn .menu, body.theme_light #shortcuts, body.theme_light #text_editor_row, #index_stats, .font_grid_item:not(:first-of-type), .image_grid_item + .font_grid_item' + '{ border-top:solid 1px grey; }' + '#sort_by, tr.sorted, tr:not(.invisible) ~ tr.invisible + tr:not(.invisible)' + // , tr.dir ~ tr:not(.dir,.invisible,.ignore) '{ border-top:solid 1px #999; }' + // border-right '#parents_dir_menu + ul, #shortcuts_menu + ul, #grid_btn ul.menu' + '{ border-right:0 !important; }' + 'body.theme_dark #parents_dir_menu, body.theme_dark #sidebar, body.theme_dark #grid_btn .menu li, body.theme_dark #warnings' + '{ border-right:solid 1px #111; }' + '#sidebar, body.theme_light #parents_dir_menu, #grid_btn .menu li, .image_grid_item' + '{ border-right:solid 1px grey; }' + // border-bottom 'body.theme_dark #sidebar_title, body.theme_dark #sidebar_menus, body.theme_dark #sidebar_header .menu, body.theme_dark #content_header, body.theme_dark #content_pane.has_audio #content_title, body.theme_dark #grid_btn .menu li:first-of-type, body.theme_dark #grid_btn ul.menu, body.theme_dark #warnings' + '{ border-bottom:solid 1px #111; }' + 'body.theme_light #sidebar_header thead tr, body.theme_light #shortcuts, body.theme_light #sidebar_menus, #grid_btn .menu li:first-of-type, #grid_btn .menu, .specimen, .font_grid_item:last-of-type, .image_grid_item' + '{ border-bottom:solid 1px grey; }' + 'body.theme_light #content_title, body.theme_light #content_pane.has_audio #content_header' + '{ border-bottom:solid 1px #888; }' + '#shortcuts_menu + ul > li.has_submenu.ruled, .rule' + '{ border-bottom:solid 1px #999; }' + 'body.theme_dark #content_pane.has_font #content_font hr, .hamburger h4' + '{ border-bottom:solid 1px #CCC; }' + // border-left '#parents_dir_menu + ul, #shortcuts_menu + ul' + '{ border-left:0; }' + 'body.theme_dark #parents_dir_menu, body.theme_dark #grid_btn ul.menu, body.theme_dark #warnings' + '{ border-left:solid 1px #111; }' + 'body.theme_light #parents_dir_menu, #grid_btn .menu' + '{ border-left:solid 1px grey; }' + // border-collapse 'table' + '{ border-collapse: collapse; }' + // border-radius 'html, body, :root' + '{ border-radius: 0; }' + 'button' + '{ border-radius: 3px; }' + '#warnings' + '{ border-radius: 0 0 3px 3px; }' + // bottom '#handle, #parent_dir_menu, #dir_list, #index_stats, #close_audio::after, #dir_list tbody, #content_container, #overlay, #content_pane.has_grid #content_grid::after, #content_pane.has_grid .image_grid_item::after, .split_btn::after' + '{ bottom: 0; }' + // box-shadow 'body.theme_light #sidebar ul' + '{ box-shadow: 0px 2px 3px -2px #888; }' + 'body.theme_dark #sidebar ul' + '{ box-shadow:0px 2px 3px -2px #111; }' + '#warnings' + '{ box-shadow:0px 2px 12px 0 #111; }' + 'body.theme_dark #grid_btn ul.menu' + '{ box-shadow:none; }' + // box-sizing 'html, body, :root, #sidebar, #grid_btn .menu li, #content_container, #content_source, #content_preview' + '{ box-sizing: border-box; }' + // clear '#dir_list tbody .name' + '{ clear:right; }' + '#checkbox_div label, #grid_btn .menu li, #content_grid .font_grid_item' + '{ clear: both; }' + // columns '.lorem + .lorem' + '{ columns:2; column-gap:2em; }' + '.lorem + .lorem + .lorem' + '{ columns:3; }' + // COLOR 'body.theme_light #sidebar, body.theme_light #sidebar a, #content_header, body.theme_light #content_font, body.theme_light .font_grid_item a, body.theme_light .image_grid_item p, body.theme_light #content_font, body.theme_light .font_grid_item p, body.theme_light .font_grid_item a, body.theme_light .image_grid_item p, .split_btn span, body #warnings' + '{ color: #111 }' + 'body.theme_light #index_stats' + '{ color: #444 }' + 'body.theme_light #dir_list tr.ignore a, body.theme_light #dir_list tr.ignore.app a' + '{ color: #777 }' + '#sort_menu .disabled span, #dir_list th.disabled' + '{ color: #999 }' + 'body.theme_dark #dir_list tr.ignore td, body.theme_dark #dir_list tr.file.ignore a, body.theme_dark #index_stats' + '{ color: #BBB }' + 'body.theme_dark #sidebar th:not(.disabled), body.theme_dark #sidebar td, body.theme_dark #sidebar a, body.theme_dark #error_message *, body.theme_dark #content_header tr, body.theme_dark #content_header tr a, body.theme_dark #content_font, body.theme_dark .font_grid_item p, body.theme_dark .font_grid_item a, body.theme_dark .image_grid_item p, #warnings button:focus, #warnings button.focus' + '{ color: #EEE }' + // CONTENT 'body#top.edited #warnings.unloading h3::before, #dir_list th span::before, #dir_list th span::after, body.has_hidden_sidebar #handle, #dir_list tr:empty, #dir_list .audio td.icon, #dir_list .video td.icon, tr.invisible, body.hide_ignored .ignore, .split_btn::after, #close_audio::after, #content_pane.has_grid #content_grid::after, #content_pane.has_grid .image_grid_item::after' + '{ content:"" }' + '#content_pane.has_audio #content_audio_title td::before, body #content_pane.has_video #title::before' + '{ content:"Playing: " }' + // .audio, .video '#content_pane.has_dir:not(.has_grid) #title::before' + '{ content:"Index of: " }' + // .dir '#content_pane.has_grid:not(.has_ignored) #title::before' + '{ content:"Fonts and Images from: " }' + // font and image grid 'body:not(.has_images) #content_pane.has_grid:not(.has_ignored) #title::before, #content_pane.has_grid #title.font_grid::before' + '{ content:"Fonts from: " }' + // font grid 'body:not(.has_fonts) #content_pane.has_grid:not(.has_ignored) #title::before, #content_pane.has_grid #title.image_grid::before' + '{ content:"Images from: " }' + // image grid '#content_pane.has_ignored:not(.has_grid) #title::before' + '{ content:"Ignored content: " }' + // .ignored 'body.edited.has_text #title::after, body.iframe_edited:not(.has_text) #content_pane.has_iframe #title::after' + '{ content:" (edited)" }' + // .ignored 'body#top.edited #text_editor_row a:after' + '{ content: " (edited)" }' + // .dir 'body#top.edited #warnings.unloading h3::before' + '{ content: "Text Editor: " }' + // .dir '#title::after' + '{ content: attr(data-after) }' + // .dir // counter 'body.show_numbers #tbody' + '{ counter-reset: row; }' + 'body.show_numbers #tbody tr td.name a::before' + '{ counter-increment: row; content:counter(row);}' + // cursor '#sidebar_title th, #sort_menu .disabled span, #dir_list .disabled' + '{ cursor: default; }' + '#sidebar_menus td:hover, #parents_dir_menu div, #shortcuts_menu div, #grid_btn, #dir_list thead th, .split_btn span' + '{ cursor: pointer; }' + '#handle' + '{ cursor: col-resize; }' + '#content_pane:not(.has_zoom_image) #content_image' + '{ cursor: zoom-in; }' + '#content_pane.has_zoom_image content_image' + '{ cursor: zoom-out; }' + // DISPLAY '#sidebar_menus ul, #show_details span, #grid_btn, #grid_btn .menu, #dir_list thead .name input, #dir_list thead th.up::before, #dir_list .details, #dir_list thead td.icon, #dir_list tr::before, #tbody tr td:not(.name), #text_editor_row, body.has_hidden_sidebar #handle, body.has_hidden_sidebar #sidebar, #dir_list tr:empty, #dir_list tr.audio td.icon, #dir_list tr.video td.icon, tr.invisible, body.hide_ignored #tbody tr.ignore, #content_title::before, #content_pane #content_audio_title, .split_btn, #content_pane #content_audio, #content_pane #content_grid, #content_pane #content_text, #content_pane .content, #content_pane.has_grid .content, body.has_text .content:not(#content_text), #content_pane.has_hidden_grid #content_grid, body.theme_light #theme_dark, body.theme_dark #theme_light, body.use_custom_icons #dir_list img, #dir_list tr.file.audio a img, #dir_list tr.file.video a img, #warnings, #warnings p, #warnings button, #clear_warning, #overlay' + '{ display: none; }' + '#sidebar li, #parent_dir_menu, #parent_dir_menu a, #parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul > li:hover > ul, #shortcuts_menu + ul > li > ul:hover, body.show_details #show_details span:last-of-type, body:not(.show_details) #show_details span:first-of-type, body.has_hidden_text #text_editor_row, #sort_by_default, #dir_list tbody a, #content_header, #content_pane.has_font:not(.has_grid) #content_font, #content_pane.has_image:not(.has_grid) #content_image, #content_pane.has_zoom_image #content_image, #content_pane.has_pdf:not(.has_grid) #content_pdf, body.has_text #content_pane:not(.has_grid) #content_text, #content_pane.has_video:not(.has_grid) #content_video, body:not(.has_text) #content_pane.has_iframe:not(.has_grid) #content_iframe, #content_pane.has_dir:not(.has_grid) #content_iframe, #content_pane.has_grid #content_grid.has_grid, #content_pane.has_grid #content_grid.has_font_grid, #content_pane.has_grid .nav_btn, #content_pane.has_font .nav_btn, .font_grid_item a, .image_grid_item a, #checkbox_div label, body.theme_dark #theme_dark, body.theme_light #theme_light, body:not(.has_hidden_sidebar) #dir_list .name, body.has_warning #warnings, body.has_warning #warnings.unloading p#warning_unsaved, body.has_warning #warnings.clear #warning_clear, body.has_warning #warnings.local p#warning_local, body.has_warning #overlay' + '{ display: block; }' + 'body.has_text #dir_list tr#text_editor_row td, body #dir_list tr#text_editor_row td a, body.show_details #text_editor_row td, body.show_details #text_editor_row td a, body.has_images.has_fonts #grid_btn:hover ul.menu' + '{ display:block !important; }' + '#parents_dir_menu div, body.has_fonts #grid_btn, body.has_images #grid_btn, #dir_list thead th span::before, #enable_text_editing::before, #dir_list thead th span::after, body.show_details #dir_list th.details:not(#name):not(#sort_by_default), body.show_details #dir_list td.details:not(.name):not(.ext), body.show_numbers #tbody tr td.name a::before, body.has_audio #dir_list thead input, #title, #checkbox_div, #prev_track, #next_track, #close_audio, #content_pane.has_grid .split_btn, #content_pane.has_image .split_btn, #content_pane.has_zoom_image .split_btn, #content_pane.has_font .split_btn, .split_btn span, body.has_warning #warnings.unloading #warning_ignore_btn, body.has_warning #warnings.unloading #warning_cancel_btn, body.has_warning #warnings.unloading #warning_save_btn, body.has_warning #warnings.clear #warning_clear_btn, body.has_warning #warnings.clear #warning_cancel_btn, body.has_warning #warnings.local #warning_ok_btn' + '{ display: inline-block; }' + '#dir_list tr td.name span, #content_pane.has_image:not(.has_grid) #content_container, #content_pane.has_video:not(.has_grid) #content_container' + '{ display: flex; }' + '#content_pane.has_audio #content_audio_title, #content_pane.has_audio #content_audio' + '{ display: table-row !important; }' + '#shortcuts_menu div, #content_pane, #content_pane.has_audio #content_audio td' + '{ display: table-cell; }' + // display grid: dir_list editor row 'body.has_text #dir_list #text_editor_row, body.show_details #text_editor_row' + '{ display: grid; grid-gap:0; grid-template-columns: 1fr; }' + // display grid: table header '#theader' + '{ display: grid; grid-gap:0; grid-template-columns: 1fr 1fr 1fr 1fr; }' + 'th#sort_by_name' + '{ grid-column: 1 / span 2; }' + 'th#sort_by_default' + '{ grid-column: 3 / span 2; }' + // display grid: dir_list rows and cells '#dir_list #tbody tr:not(.invisible), body.show_invisibles #tbody tr.invisible, body.show_details #dir_list tr td.details' + '{ display: grid; grid-gap:0; grid-template-columns: minmax(auto,6rem) 1fr minmax(auto,6rem); }' + 'td.name' + '{ grid-column: 1 / span 3; }' + 'td.size' + '{ grid-column: 1; grid-row: 2; }' + 'td.date' + '{ grid-column: 2; grid-row: 2; }' + 'td.kind' + '{ grid-column: 3; grid-row: 2; }' + // display grid: content pane grids '#content_pane.has_grid #content_grid' + '{ display: grid !important; grid-gap:0; grid-template-columns: repeat(auto-fill, minmax('+ ($settings.grid_image_size +16) +'px, auto)); grid-auto-rows: minmax(min-content, max-content); }' + '#content_pane.has_grid #content_grid .image_grid_item' + '{ grid-column: auto; display:flex; align-items: center; }' + '#content_pane.has_grid #content_grid .font_grid_item' + '{ grid-column: 1 / -1; }' + // FILTER 'body.theme_dark #grid_btn, body.theme_dark #grid_btn .menu, body.theme_dark #parent_dir_menu, body.theme_dark #shortcuts_menu, body.theme_dark #toggle_sidebar' + '{ filter:invert(100%); }' + // FLOAT '#dir_list tr td.name a::before, #checkbox_div label' + '{ float: left; }' + '#grid_btn' + '{ float: right; }' + // font-family 'html, body, :root' + '{ font-family:'+ $settings.UI_font +'; }' + // font-size 'html' + '{ font-size: 100.001%; }' + 'body, :root, #content_text' + '{ font-size:'+ $settings.UI_font_size +'; }' + '#sidebar, #sidebar_header, #dir_list, #index_stats, #content_header, #content_header table, #warnings' + '{ font-size: 0.875rem; }' + '#content_grid, .font_grid_item p, #error_message h1, #error_message h2' + '{ font-size: 1rem; }' + '#content_grid .font_grid_item h2' + '{ font-size:'+ $settings.grid_font_size * 4 +'em; }' + '#content_font' + '{ font-size:'+ $settings.grid_font_size +'em; }' + '#content_font .specimen' + '{ font-size:4em; }' + '#content_font .hamburger h1' + '{ font-size: 8em }' + '#content_font .hamburger h2' + '{ font-size:6em; text-align:justify; }' + '#content_font .hamburger h3' + '{ font-size:2em; }' + '#content_font .hamburger h4' + '{ font-size:1.618em; }' + '.lorem.first:first-line' + '{ font-size:'+ $settings.grid_font_size * 1.33 +'em; }' + // font-variant '.lorem.first:first-line' + '{ font-variant: small-caps }' + // font-weight '#sidebar_title th, h1, h2, h3, h4, h5, h6' + '{ font-weight: normal }' + '#dir_list .selected a' + '{ font-weight: bold }' + // HEIGHT 'html, body, :root, #parent_dir_menu a, #dir_list, #main_content, #content_pane, #content_pdf, #content_text, #content_iframe' + '{ height: 100%; }' + '#sidebar_header, #parents_dir_menu, #parents_dir_menu div, #content_pane:not(.has_zoom_image) #content_image, #content_grid div img' + '{ height: auto; }' + '#dir_list thead th span::before, #dir_list thead th span::after' + '{ height: 8px; }' + '#toggle_sidebar' + '{ height: 14px; }' + '#dir_list td.icon' + '{ height: 16px; }' + '#grid_btn, #scale, #prev_next_btns, #close_btn, #reload_btn' + '{ height: 18px; }' + '#audio' + '{ height: 32px; }' + '.image_grid_item a' + '{ align-self: center; justify-self: center; }' + //'#content_grid.has_grid .image_grid_item' + // '{ height: '+ $grid_image_size +'px; }' + '#main_content' + '{ height:'+ window.innerHeight +'px; }' + // max-height '#content_pane:not(.has_zoom_image) #content_image' + '{ max-height: calc(100% - 4em); }' + '#content_pane.has_zoom_image #content_image' + '{ max-height: none; }' + '#content_grid div img' + '{ max-height:'+ ($settings.grid_image_size) +'px; }' + // min-height '#title' + '{ min-height: 18px; }' + '#sidebar' + '{ min-height: 100%; }' + // hyphens '#parents_dir_menu div, #content_header td button, #content_font' + '{ hyphens: none; }' + 'html, body, :root, .hamburger h3, .lorem' + '{ hyphens: auto; }' + // LEFT '#sidebar ul, #parent_dir_menu, #dir_list thead, #dir_list tbody, #index_stats, #close_audio::after, body.has_hidden_sidebar #toggle_sidebar, #overlay' + '{ left: 0; }' + ' #grid_btn ul.menu' + '{ left: unset; }' + 'body.has_hidden_sidebar #sidebar_wrapper' + '{ left: 3px; }' + 'body.show_numbers #tbody tr td.name a::before' + '{ left: 6px; }' + '#warnings, .split_btn::after' + '{ left: 50%; }' + '#shortcuts_menu + ul > li > ul' + '{ left: 100%; }' + '#dir_list thead th span::before' + '{ left: -16px; }' + // letter-spacing '.lorem.first:first-line, .font_grid_item p' + '{ letter-spacing: 0.1em }' + '#sidebar_title th' + '{ letter-spacing: 0.5em }' + // line-height '.image_grid_item a' + '{ line-height: 0; }' + '.split_btn span, .font_grid_item p' + '{ line-height: 1; }' + '#content_font .specimen' + '{ line-height: 1.2; }' + '#dir_list tr a, #title, .lorem' + '{ line-height: 1.4; }' + // list-style '#sidebar ul, #grid_btn .menu li' + '{ list-style-type: none; }' + // MARGIN 'html, body, :root, #sidebar ul, #parent_dir_menu, #parent_dir_menu, #parents_dir_menu, #parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu, #grid_btn, #dir_list tbody a, #content_font .hamburger *, #content_grid p, #content_grid h2, #content_text, #warnings h3' + '{ margin: 0; }' + // margin-top '.image_grid_item + .font_grid_item' + '{ margin-top:-1px; }' + '#checkbox_div label input, #show_details, body.is_error #tbody h1' + '{ margin-top: 0; }' + 'body.has_audio #dir_list input' + '{ margin-top: 1px; }' + // margin-right '#content_image, #content_video, .image_grid_item a' + '{ margin-right: auto; }' + '#increase' + '{ margin-right: -4px; }' + '#tbody th input, tr.media input, #reload_btn, #scale' + '{ margin-right: 8px; }' + '#show_details' + '{ margin-right: 0.5em; }' + '#dir_list th#sort_by_default span, #warning_ignore_btn' + '{ margin-right: 2em; }' + '#checkbox_div' + '{ margin-right: calc(-6em - 4px); }' + // margin-bottom '#show_details' + '{ margin-bottom: 0; }' + 'body.has_audio #dir_list input' + '{ margin-bottom: 1px; }' + '#content_grid.has_image_grid' + '{ margin-bottom: 1rem; }' + // margin-left '#content_image, #content_video, .image_grid_item a' + '{ margin-left: auto; }' + '#decrease' + '{ margin-left: -4px; }' + 'th input, tr.media input' + '{ margin-left: 7px; }' + 'body.has_hidden_sidebar #title_buttons_left' + '{ margin-left: 16pt; }' + '#show_details, #warnings button' + '{ margin-left: 0.5em; }' + '#warnings' + '{ margin-left: -12em; }' + '#dir_list tbody tr' + '{ margin-inline-start:0; }' + // -webkit-margin '#sidebar ul' + '{ -webkit-margin-before:0em !important; -webkit-margin-after:0em !important; -webkit-padding-start:0em; }' + // Object-fit '#content_image' + '{ object-fit:contain; }' + // OPACITY '#content_pane.has_ignored::before, #close_audio::after' + '{ opacity:0.3; }' + '#close_audio:hover::after' + '{ opacity:0.6; }' + '#sidebar_menus td:last-of-type:hover > div, #shortcuts_menu div, #shortcuts_menu div, #parent_dir_menu, #content_pane:hover #prev_btn, #content_pane:hover #next_btn, #toggle_sidebar, body.use_custom_icons #dir_list tr.file.ignore a.icon::before, .split_btn span' + '{ opacity: 0.7; }' + '#content_grid div img' + '{ opacity:0.8; }' + '#grid_btn:hover, #parent_dir_menu:hover, #content_pane #prev_btn:hover, #content_pane #next_btn:hover, #toggle_sidebar:hover, .split_btn span:hover' + '{ opacity:1; }' + // outline '#grid_btn, #dir_list tbody, #dir_list tbody a, #audio:focus, #content_grid .font_grid_item, #content_font, #warnings button:focus, #content_video' + '{ outline: none; }' + // OVERFLOW 'html, body, :root, #parents_dir_menu div, #shortcuts_menu, #dir_list, #dir_list tbody a, #main_content, #close_audio, .hamburger h1, .hamburger h2, .hamburger h4' + '{ overflow: hidden; }' + '#dir_list tbody, #next_track, #prev_track, #content_container, #content_font, #content_grid' + '{ overflow: auto; }' + '#sidebar, #content_font' + '{ overflow-wrap: break-word; }' + '.lorem' + '{ overflow-wrap: normal; }' + // PADDING 'html, body, :root, #sidebar_wrapper, #sidebar ul, #parent_dir_menu, #sidebar_header tbody tr td, #parent_dir_menu, #parent_dir_menu a, #parents_dir_menu, #shortcuts_menu, #dir_list .details a, #content_pane, #content_pdf, #content_iframe, #content_text, audio::-webkit-media-controls-panel' + '{ padding: 0; }' + '#sidebar_title th' + '{ padding: 4px; }' + '.image_grid_item' + '{ padding:6px; }' + '#error_message, #warnings' + '{ padding:1rem; }' + // padding-top '#dir_list thead th, #dir_list .details, #prev_track, #next_track, #close_audio' + '{ padding-top: 0; }' + '#show_details, #text_editor_row a' + '{ padding-top: 2px; }' + '#parents_dir_menu div, #grid_btn .menu li, #dir_list tbody a, #index_stats, #title_buttons_left, #title_buttons_right, #title, body #content_audio_title td, #content_audio td' + '{ padding-top: 4px; }' + '#sidebar_header tbody tr:last-of-type td, #parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul li div span, .hamburger h4' + '{ padding-top: 6px; }' + '#content_header table' + '{ padding-top: 7px; }' + '#content_grid .font_grid_item, .font_grid_item p, #content_font div.lorem' + '{ padding-top: 0.5rem; }' + 'body:not(.has_text) #content_pane.has_image:not(.has_grid) #content_container, #content_font div.specimen' + '{ padding-top: 2rem; }' + // padding-right '#sidebar_header tbody tr:last-of-type td, #prev_track, #next_track, #prev_next_btns, #close_audio' + '{ padding-right: 0; }' + '#scale' + '{ padding-right: 4px; }' + '#parents_dir_menu div, #show_details, #grid_btn .menu li, #index_stats, #title_buttons_left, #title_buttons_right, #content_audio td, #close_audio' + '{ padding-right: 6px; }' + '#parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul li div span, body.show_numbers #tbody tr td.name a::before, #dir_list tbody a' + '{ padding-right: 8px; }' + '#dir_list td.details, #content_header table, #title' + '{ padding-right: 12px; }' + '#grid_btn .menu, #content_audio_title td' + '{ padding-right: 29px; }' + '.font_grid_item p, .font_grid_item a' + '{ padding-right: 2rem; }' + 'body:not(.has_text) #content_pane.has_image:not(.has_grid) #content_container, #content_font div' + '{ padding-right: 2.5rem; }' + // padding-bottom '#prev_track, #next_track, #close_audio' + '{ padding-bottom: 0px }' + '#show_details, body.is_dirs_on_top #dir_list tbody tr.sorted:not(:last-of-type)' + '{ padding-bottom: 2px; }' + '#title, body #content_audio_title td, #text_editor_row a' + '{ padding-bottom: 3px;}' + '#parents_dir_menu div, #grid_btn .menu li, #dir_list tbody a, #dir_list .details, #index_stats' + '{ padding-bottom: 4px; }' + '#title_buttons_left, #title_buttons_right' + '{ padding-bottom: 3px; }' + '#content_header table' + '{ padding-bottom: 5px; }' + '#sidebar_header tbody tr:last-of-type td, #parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul li div span, #dir_list thead th, #content_audio td' + '{ padding-bottom: 6px; }' + '#dir_list thead th.details, .hamburger h4' + '{ padding-bottom: 9px; }' + '.specimen, .font_grid_item p, .font_grid_item a' + '{ padding-bottom: 0.5rem; }' + 'body:not(.has_text) #content_pane.has_image:not(.has_grid) #content_container, #content_font div:first-of-type, #content_font .lorem:last-of-type' + '{ padding-bottom: 2rem; }' + // padding-left '#dir_list #tbody td.name a.icon, #dir_list td.details, #grid_btn .menu, #sidebar_header tbody tr:last-of-type td, #prev_next_btns' + '{ padding-left: 0px; }' + '#dir_list .audio a, #dir_list .video a, #checkbox_div, #scale' + '{ padding-left: 4px; }' + '#parents_dir_menu div, #dir_list th#name, #dir_list td.icon, #dir_list .icon + td.name a, #checkbox_div #parents_dir_menu div, #show_details, #grid_btn .menu li, #index_stats, #title_buttons_left, #title_buttons_right, #content_audio td, #prev_track' + '{ padding-left: 6px; }' + '#parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul li div span' + '{ padding-left: 8px; }' + '#content_header table, #title' + '{ padding-left: 12px; }' + '#shortcuts ul li a' + '{ padding-left: 16px; }' + 'body:not(.has_media) #sort_by_name' + '{ padding-left: 20px; }' + '#dir_list #tbody tr:not(.media) a span, #text_editor_row a' + '{ padding-left: 27px; -webkit-padding-start: 27px; }' + '#dir_list thead th#size, #dir_list #tbody td.details.size, #content_audio_title td' + '{ padding-left: 29px; }' + 'tr.media a.icon' + '{ padding-left: 31px; }' + '#sort_menu li span, body.show_numbers.has_media #dir_list thead .name, .font_grid_item p, .font_grid_item a' + '{ padding-left: 2rem; }' + 'body:not(.has_text) #content_pane.has_image:not(.has_grid) #content_container, #content_font div' + '{ padding-left: 2.5rem; }' + //-webkit-padding '#dir_list td.name a' + '{ -webkit-padding-start:0; }' + '#dir_list .icon + td.name a' + '{ -webkit-padding-start:1em; }' + // POSITION '#sidebar_wrapper, #sidebar_header, #sidebar_buttons, #sidebar_menus td:first-of-type, #sidebar_header tbody tr:last-of-type td, #dir_list, #dir_list thead th span, body.show_numbers #tbody tr td.name a::before, #dir_list tr.ignore a, #dir_list tr.ignore.app a, #dir_list tr.ignore td.details, #shortcuts_menu + ul > li.has_submenu, #content_pane, #content_header, #content_grid, #content_text, #content_font, #content_pdf, #content_iframe, #close_audio, #content_grid div img, #content_text, .split_btn' + '{ position: relative; }' + '#sidebar ul, #handle, #parent_dir_menu, #toggle_sidebar, body.has_hidden_sidebar #sidebar_wrapper, #dir_list tbody, #close_audio::after, .split_btn::after, #content_container, #content_image, #warnings, #overlay, #content_pane.has_grid #content_grid::after, #content_pane.has_grid .image_grid_item::after' + '{ position: absolute; }' + '#dir_list thead, #index_stats' + '{ position: fixed; }' + // RIGHT '#sidebar ul, #parent_dir_menu, #grid_btn .menu, #dir_list thead, #dir_list tbody, #index_stats, #close_audio::after, #title_buttons_right, #next_btn, #overlay, #content_pane.has_grid #content_grid::after, #content_pane.has_grid .image_grid_item::after' + '{ right: 0; }' + '#dir_list thead th span::after' + '{ right: -16px; }' + '#toggle_sidebar' + '{ right: 4px; }' + '#handle' + '{ right: -4px; }' + // table-layout '#dir_list' + '{ table-layout: fixed; }' + // text-align '#sidebar ul, #dir_list tbody, #dir_list tbody .name, #dir_list thead th:not(.details), #dir_list tr.details, #title_buttons_left' + '{ text-align: left; }' + '#parent_dir_menu a, #parents_dir_menu, th.details, #parents_dir_menu div, #shortcuts_menu div, #content_header, #content_title, #content_audio_title, #content_audio td' + '{ text-align: center; }' + '#grid_btn .menu li, body.show_numbers #tbody tr td.name a::before, #dir_list th#sort_by_default, #dir_list .size, #dir_list .date, #dir_list .kind, #title_buttons_right, #warnings div, .playlist_time' + '{ text-align: right; }' + '.hamburger, .lorem' + '{ text-align: justify; }' + // text-decoration 'a, a:hover' + '{ text-decoration: none !important; }' + // text-indent '#shortcuts li' + '{ text-indent: 1em; }' + // text-transform '.font_grid_item p' + '{ text-transform: uppercase; }' + // TOP '#handle, #parent_dir_menu, #dir_list, #title_buttons_left, #title_buttons_right, #close_audio::after, #prev_btn, #next_btn, #warnings, #overlay, #content_pane.has_grid #content_grid::after, .split_btn::after' + '{ top: 0; }' + '#shortcuts_menu + ul > li > ul, body.theme_light #grid_btn .menu' + '{ top: -1px !important; }' + 'body.has_hidden_sidebar #sidebar_wrapper, #dir_list thead th span::before, #dir_list thead th span::after' + '{ top: 2px; }' + '#toggle_sidebar' + '{ top: 4px; }' + 'body.theme_dark #grid_btn .menu' + '{ top: -7px; }' + // TRANSFORM '#dir_list' + '{ transform: scale(1); }' + // needed to establish #dir_list as containing block for thead and tfoot position fixed. 'body.has_hidden_sidebar #toggle_sidebar, #dir_list thead th:not(.up) span::after, #next_track, #next_btn' + '{ transform:rotate(180deg); }' + '#close_audio::after' + '{ transform:rotate(45deg); }' + // user-select '#sidebar_header, #content_pane:not(.has_zoom_image) #content_image' + '{ user-select:none; -webkit-user-select:none; }' + // vertical-align '#content_pane' + '{ vertical-align:top; }' + '#title_buttons_left, #title_buttons_right, #title' + '{ vertical-align:middle; }' + // white-space '#sidebar_header tbody tr:last-of-type td, #parents_dir_menu div, #parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #dir_list tbody a, .specimen, .lorem' + '{ white-space: normal; }' + '#tbody td:not(.name), #grid_btn .menu li, .hamburger h1, .hamburger h2, .hamburger h4' + '{ white-space: pre; }' + // WIDTH 'html, body, :root, table, #parent_dir_menu a, #dir_list thead, #tbody, #text_editor_row td, #tbody tr, #shortcuts_menu + ul > li > ul, #grid_btn .menu li, #content_container, #content_header, #content_grid, #content_text, #content_font svg, #content_pdf, #content_iframe' + '{ width: 100%; }' + '#sidebar_menus td:nth-of-type(2), #dir_list .date, #title, #title_buttons_left, #title_buttons_right, #content_pane:not(.has_zoom_image) #content_image, #content_grid div img' + '{ width: auto; }' + '.split_btn span' + '{ width: 2em; }' + '#content_pane.has_grid #content_grid::after, #content_pane.has_grid .image_grid_item::after, .split_btn::after' + '{ width: 1px; }' + '#handle' + '{ width: 8px; }' + '#dir_list thead th span::before, #dir_list thead th span::after, #toggle_sidebar' + '{ width: 16px; }' + '#sidebar_menus td:nth-of-type(odd)' + '{ width: 24px; }' + '#grid_btn' + '{ width: 28px; }' + '#prev_track, #next_track, #close_audio' + '{ width: 2rem; }' + '#shortcuts_menu div, #checkbox_div' + '{ width: 6em; }' + '#content_pane.has_image #title_buttons_left, #content_pane.has_image #title_buttons_right' + '{ width: 11em; }' + '#warnings' + '{ width: 26em; }' + 'body.has_hidden_sidebar #sidebar_wrapper' + '{ width: 0 !important; }' + //'#content_grid.has_grid .image_grid_item' + // '{ width: '+ $settings.grid_image_size +'px; }' + 'body.has_hidden_sidebar #content_pane' + '{ width: 100% !important; }' + 'body:not(.has_hidden_sidebar) #sidebar_wrapper' + '{ width:'+ getQuery('width').toString() +'%; }' + 'body:not(.has_hidden_sidebar) #content_pane' + '{ width:'+ (100 - getQuery('width')).toString() +'%; }' + // max-width 'html, body, :root' + '{ max-width: 100%; }' + '#content_pane:not(.has_zoom_image) #content_image' + '{ max-width: calc(100% - 5em); }' + '#content_pane.has_zoom_image #content_image' + '{ max-width: none; }' + '#sidebar_menus td:nth-of-type(odd)' + '{ max-width: 24px; }' + '#content_grid div img' + '{ max-width:'+ ($settings.grid_image_size).toString() +'px; }' + // min-width 'body.show_numbers #tbody tr td.name a::before' + '{ min-width: 17px; }' + 'body:not(.has_hidden_sidebar) #sidebar_menus td:nth-of-type(odd)' + '{ min-width: 24px; }' + 'body:not(.has_hidden_sidebar) #dir_list' + '{ min-width: 100px; }' + 'body:not(.has_hidden_sidebar) #sidebar_wrapper' + '{ min-width: 220px; }' + // will-change '#sidebar_wrapper, #content_pane' + '{ will-change: width }' + // word-break '#content_header td button' + '{ word-break: none; }' + '#title' + '{ word-break: break-word; }' + '#content_font .specimen' + '{ word-break: break-all; }' + '.lorem' + '{ word-break: normal; }' + // Z-INDEX '#content_pane' + '{ z-index: 0; }' + '#handle, #sidebar_wrapper' + '{ z-index: 1 !important; }' + '#parents_dir_menu + ul, #content_header' + '{ z-index: 20; }' + '#sidebar_header, #content_pane.has_grid .image_grid_item::after' + '{ z-index: 2000; }' + '#shortcuts_menu + ul, #toggle_sidebar' + '{ z-index: 9997; }' + '#overlay' + '{ z-index: 9997; }' + '#warnings' + '{ z-index: 9999; }' + 'body.has_hidden_sidebar #sidebar_header' + '{ z-index:unset; }' ; // Gecko Styles: const $gecko_style_rules = 'html, body.is_gecko { border: solid 1px gray !important; }' + 'body.is_gecko button { padding:revert; }' + 'body.is_gecko #grid_btn .menu { top:-7px; left:-120px; }' + 'body.is_gecko thead {font-size:100%;}' + 'body.is_gecko #dir_list th, body.is_gecko #dir_list td {width:auto;}' + 'body.is_gecko #dir_list .dir::before {position:absolute;}' + 'body.is_gecko.use_default_icons:not(.is_converted_list) #dir_list .file .name .icon { padding-left:4px; background:none; }' + 'body.is_gecko.use_default_icons #dir_list .file .name .icon img { margin-right:6px; height:14px; }' + 'body.is_gecko #tbody > tr > td:not(:first-of-type) { float:left }' + 'body.is_gecko #content_audio_title td { padding-top: 6px; }' + 'body.is_gecko #content_audio_title td { padding-bottom: 0; }' + 'body.is_gecko #prev_track { padding-left: 16px; }' + 'body.is_gecko #close_audio { background-color: #252525; }' + 'body.is_gecko #close_audio::after { filter:invert(100%); opacity:0.5; }' + 'body.is_gecko #close_audio:hover::after { opacity:0.75; }' + 'body.is_gecko.dark #prev_track, body.is_gecko.dark #next_track { background: #252525 '+ $next_track_arrow_gecko +' center no-repeat; }' + 'body.is_gecko #prev_track:hover, body.is_gecko #next_track:hover { background: #252525 '+ $next_track_arrow_gecko_hover +' center no-repeat; }' ; var $text_editing_style_rules = 'html, body, #iframe_body { margin:0; padding:0; }' + // toolbar '#toolbar { margin:0; padding:0; height:32px; display:block; position:relative; left:0; right:0; z-index:100; background:#EEE; border:0; border-bottom: solid 1px #999; font-family:'+ $settings.UI_font +'; font-size:'+ parseFloat($settings.UI_font_size) * 0.875 + $settings.UI_font_size.replace(/\d*/,'') +'; -webkit-user-select: none; -moz-user-select: none; user-select:none; }' + '#toolbar li { margin:4px; padding:4px; width:3.5em; display:block; opacity:0.5; list-style-type:none; cursor:pointer; }' + '#toolbar li:hover, .preview_text:not(.split) #toolbar li#show_preview, .source_text:not(.split) #toolbar li#showSRC, .split #toolbar li#toggle_split, .edited #save_btn { opacity:1; }' + '#toolbar li#toggle_split { float:left; width:16px; height: 16px; margin: 4px 0 4px 4px; background:url("data:image/svg+xml;utf8,") center no-repeat; }' + '#toolbar li#sync_scroll { width:8em; float:left; opacity:1; }' + '#toolbar li#sync_scroll input { float:left; }' + '#toolbar li#sync_scroll label { width:8em; display:block; font-size:inherit; line-height:1.5; }' + '#toolbar li#clear_text { height:16px; float:right; text-align:center; }' + '#toolbar li#save_btn { float:right; width:20px; height:16px; background: url("data:image/svg+xml;utf8, ") 8px 4px no-repeat; position:relative; }' + '#toolbar li#show_source { float:left; width:16px; height: 16px; margin: 4px 0 4px 12px; background:url("data:image/svg+xml;utf8, ") left 5px no-repeat; }' + '#toolbar li#show_preview { float:left; width:16px; height: 16px; margin: 4px 0 4px 4px; background:url("data:image/svg+xml;utf8, ") -24px 5px no-repeat; }' + '.edited #toolbar li#save_btn { background: url("data:image/svg+xml;utf8, ") 8px 4px no-repeat; position:relative; }' + '#toolbar li#save_btn div { display:none; position:relative; top:-9px; left:-24px; color:#999; text-align:right; }' + '#toolbar li#save_btn:hover div { display:block; }' + '#toolbar li#save_btn span { width:6rem; padding:4px 6px; background: #EEE; float:right; display:block; border:solid 1px #999; position:relative; z-index:1; }' + '#toolbar li#save_btn span:first-of-type { border-bottom-width:0px; }' + '#toolbar li#save_btn span:hover { color:#444; }' + // resize handle '.split_view #text_editing_handle { width:9px; position:absolute; top:0; bottom:0; left:calc(50% - 4px); cursor:col-resize; z-index:11; }' + '#text_editing_handle { z-index:-1; }' + // source '#content_source { margin:0; padding: 14px; width:100%; display:block; line-height:1.2; box-sizing:border-box; z-index:1; border:0; overflow-y:scroll; background:#EEE; resize:none; font-family:monospace; font-size:'+ parseFloat($settings.UI_font_size) + $settings.UI_font_size.replace(/\d*/,'') +'; }' + '#content_source, #content_preview { position:absolute; top:32px; right:0; bottom:0; left:0; }' + '#content_source:focus { outline:none; background:#FFF; box-shadow: inset 0 0 4px #888; }' + // preview '#content_preview { margin:0; padding: 14px; box-sizing:border-box; z-index:1; border:0; overflow-y:scroll; background:#FFF; font-size:'+ parseFloat($settings.UI_font_size) + $settings.UI_font_size.replace(/\d*/,'') +'; }' + // split views '.preview_text:not(.split_view) #content_source, .source_text:not(.split_view) #content_preview, li#save_btn div, .comment { display:none; }' + '.split_view #content_preview { border-left:solid 1px #999; }' + '.split_view #content_source {width:50%; }' + '.split_view #content_preview {left:50%; }' + // preview styles '#content_preview pre { border:solid 1px #CCC; border-radius:3px; white-space:pre-wrap; word-break:break-word; font-size:'+ parseFloat($settings.UI_font_size) + $settings.UI_font_size.replace(/\d*/,'') +'; }' + '#content_preview .no_list { list-style:none; }' + '#content_preview > .no_list { padding:0; }' + '#content_preview .text-align-center { text-align:center; }' + '#content_preview th, #content_preview td { vertical-align:top; }' + '#content_preview blockquote { margin-top:1em; margin-bottom:1em; color: #555; }' + '#content_preview blockquote + blockquote { margin-top:0; }' + '.markdown-body input[type="checkbox"] { margin-top:0.375em; margin-right:6px; float:left; }' + 'h1 .uplink,h2 .uplink,h3 .uplink,h4 .uplink,h5 .uplink,h6 .uplink { margin:0; padding:0; display:inline-block; font-size:0.875em; cursor:pointer; transition: opacity 0.25s; opacity:0; }' + 'h1:hover .uplink,h2:hover .uplink,h3:hover .uplink,h4:hover .uplink,h5:hover .uplink,h6:hover .uplink { transition: opacity 0.25s; opacity:0.5; }' + '#content_preview table { font-size:inherit; }' + '#content_preview table th { background-color:#EEE; }' + '.markdown-body::before, .markdown-body::after { display:none !important; background:transparent; }' + // edited warning '#iframe_body #warnings p, #iframe_body #warnings button { display:none; }' + '#iframe_body #warnings { width:22em; margin-left:-12.5em; padding:1rem; font-size:0.75rem; border-radius:0 0 3px 3px; display:none; position:absolute; top:0; left:50%; z-index:9999; background:#EEE; box-shadow: 0px 2px 12px 0 #111; }' + '#iframe_body #warnings h3 { margin:0; font-weight:normal; }' + '#iframe_body #warnings div { text-align:right; }' + '#iframe_body #warnings button { margin-left:0.5em; }' + '#iframe_body #warnings #warning_ignore_btn { margin-right:2em; }' + '#iframe_body.has_warning #warnings, #iframe_body.has_warning #warnings.unsaved p#warning_unsaved, #iframe_body.has_warning #warnings.clear p#warning_clear { display:block; }' + '#iframe_body.has_warning #warnings.clear #warning_clear_btn, #iframe_body.has_warning #warnings.clear #warning_cancel_btn, #iframe_body.has_warning #warnings.unloading p#warning_unsaved, #iframe_body.has_warning #warnings.unloading #warning_ignore_btn, #iframe_body.has_warning #warnings.unloading #warning_cancel_btn, #iframe_body.has_warning #warnings.unloading #warning_save_btn { display:inline-block; }' + // disabled text editing '#iframe_body.enable_text_editing #toolbar, #iframe_body.enable_text_editing #preview_text, #iframe_body.enable_text_editing #text_editing_handle { display:none; }' + '#iframe_body.enable_text_editing #content_source.disabled { top:0; background:white; }' ; var $iframe_styles = // background '#iframe_body a.up { background:transparent; }' + '#iframe_body :root, html, body { background-color:#BBB; }' + '#iframe_body #thead, #tbody tr { background:rgba(221,221,221,0.5); }' + '#iframe_body #thead tr#parent { background:rgba(144,144,144,0.33); }' + '#iframe_body #tbody tr:nth-of-type(odd) { background:rgba(221,221,221,1); }' + '#iframe_body #tbody tr:hover { background:#BBB; }' + // background icons '#iframe_body #dir_list tr td.name a::before { content:""; width:14px; height:14px; margin-right:4px; bottom:-1px;}' + '#iframe_body #dir_list tr.dir td.name a::before { background: '+ $file_icon_dir +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.file td.name a::before { background: '+ $file_icon_file +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.app td.name a::before { background: '+ $file_icon_app +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.audio td.name a::before { background: '+ $file_icon_audio +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.video td.name a::before { background: '+ $file_icon_video +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.text td.name a::before { background: '+ $file_icon_text +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.image td.name a::before { background: '+ $file_icon_image +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.pdf td.name a::before { background: '+ $file_icon_pdf +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.font td.name a::before { background: '+ $file_icon_font +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.code td.name a::before { background: '+ $file_icon_code +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.htm td.name a::before { background: '+ $file_icon_html +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.invisible td.name a::before { background: '+ $file_icon_invisible +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list tr.ignored td.name a::before { background: '+ $file_icon_ignored +' center no-repeat; background-size:14px 14px; }' + '#iframe_body #dir_list.sort_by_default #sort_by_default span::before, #iframe_body #dir_list.sort_by_name #sort_by_name span::before, #iframe_body #dir_list.sort_by_size #sort_by_size span::before, #iframe_body #dir_list.sort_by_date #sort_by_date span::before, #iframe_body #dir_list.sort_by_kind #sort_by_kind span::before, #iframe_body #dir_list.sort_by_ext #sort_by_ext span::before { background-image:'+ $check_mark +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + '#iframe_body #dir_list.sort_by_default #sort_by_default span::after, #iframe_body #dir_list.sort_by_name #sort_by_name span::after, #iframe_body #dir_list.sort_by_size #sort_by_size span::after, #iframe_body #dir_list.sort_by_date #sort_by_date span::after, #iframe_body #dir_list.sort_by_kind #sort_by_kind span::after, #iframe_body #dir_list.sort_by_ext #sort_by_ext span::after { background-image:'+ $up_arrow +'; background-repeat: no-repeat; background-size:10px; background-position: center; }' + '#iframe_body .sorting.down span::after { transform:rotate(180deg) }' + // border ':root, html, #iframe_body { border:0 !important; }' + 'html, #iframe_body { border-radius:0; }' + '#iframe_body #dir_list { border-collapse:collapse; }' + '#iframe_body #dir_list thead th { border-bottom:solid 1px #999; }' + // box-sizing '#iframe_body, iframe_body td.name, iframe_body td.details { box-sizing:border-box; }' + // color '#iframe_body a { color:#111111; }' + '#iframe_body a:hover { color:#000000; }' + '#iframe_body tr.ignore, #iframe_body tr.ignore a { color:grey; }' + // content '.sorting span::before,.sorting span::after { content:""; width:16px; height:8px; display:inline-block; position:relative; }' + // counter '#iframe_body tbody { counter-reset: row; }' + '#iframe_body.show_numbers tr td.name::before { counter-increment: row; content:counter(row); margin-right:6px; min-width:1.25em; text-align:right;}' + // cursor '#iframe_body #dir_list th.sorting { cursor: pointer; }' + // display '#iframe_body #dir_list tr::before, #iframe_body #dir_list td.name input, #iframe_body td.ext { display:none; }' + '#iframe_body a { display:block; }' + '#iframe_body #dir_list #tbody tr { display: grid; grid-gap:0; grid-template-columns: minmax(200px,100%) minmax(auto,5em) minmax(auto,1fr) minmax(auto,5em); }' + '#iframe_body td.name { grid-column: 1; }' + '#iframe_body td.size { grid-column: 2; }' + '#iframe_body td.date { grid-column: 3; }' + '#iframe_body td.kind { grid-column: 4; }' + // float '#iframe_body #dir_list td.name::before, #iframe_body #dir_list a::before { float:left; }' + // fonts '#iframe_body { font-family:'+ $settings.UI_font +'; }' + '#iframe_body { font-size:'+ parseFloat($settings.UI_font_size) * 0.875 + $settings.UI_font_size.replace(/\d*/,'') +'; }' + '#iframe_body #dir_list, #iframe_body #thead { font-size: 1em; }' + // height '#iframe_body, #iframe_body #dir_list { height:100%; }' + '#iframe_body #content_source { height:inherit; }' + '#iframe_body #thead { height:2em; max-height:2em; }' + // line-height '#iframe_body #tbody tr { line-height:1.5; }' + // margin 'html, body, #iframe_body { margin:0; }' + '#iframe_body .dir::before, #iframe_body .file > img { margin-inline-end: 6px; }' + // outline '#iframe_body #dir_list tr, #iframe_body #tbody tr:hover { outline:0; }' + // overflow '#iframe_body, #iframe_body #dir_list { overflow:hidden; }' + '#iframe_body #dir_list #tbody { overflow:auto; }' + // padding 'html, :root, #iframe_body, body { padding:0; }' + '#iframe_body #tbody tr td, #iframe_body #thead tr th { padding-top:3px; }' + '#iframe_body #tbody tr td { padding-right: 6px; }' + '#iframe_body #tbody tr td, #iframe_body #thead tr th { padding-bottom:3px; }' + '#parent th, #iframe_body #tbody tr td.details.kind { padding-right: 1em; }' + '#iframe_body td.details { padding-left: 6px; }' + '#parent th, #tbody tr td.name { padding-left:1em; }' + '#iframe_body #dir_list, #iframe_body #dir_list tr td.name a::before { position:relative; }' + // position '#iframe_body, #iframe_body #dir_list #tbody { position:absolute; right:0; bottom:0; left:0; }' + '#iframe_body th { text-align:center; }' + // text-align '#iframe_body th:last-of-type, #iframe_body td.details { text-align:right; }' + '#iframe_body th:first-of-type { text-align:left; }' + '#iframe_body a, #iframe_body a:hover, #iframe_body td:hover { text-decoration:none !important; }' + // text-decoration '#iframe_body a.icon { text-indent:2px; }' + // text-indent '#iframe_body #thead { user-select:none; -webkit-user-select:none; }' + // vertical-align '#iframe_body td.details { vertical-align:top; }' + // width 'html, #iframe_body, #iframe_body #dir_list, #iframe_body #dir_list tr { width:100%; max-width:100%; min-width:100%; }' + '#iframe_body #dir_list td:not(:first-child) { width:unset; }' + '#iframe_body #dir_list th.sorting { width:25%; }' + // white-space '#iframe_body td:not(.name) { white-space:pre; }' ; // ADD STYLES const $font_styles = document.createElement('style'); const $font_grid_styles = document.createElement('style'); function addStyles(el) { el.find('style, link[rel="stylesheet"], link[href$="css"]').remove(); // remove any existing stylesheets el.append(''); el.append(''); el.append($font_styles); // empty until font is previewed el.append($font_grid_styles); // empty until font grid is made el.append(''); el.append(''); } // ***** END STYLES ***** // // ***** BUILD MENUS ***** // // Parent and Parents Menus function updateQueryStr(str) { str = str.replace(/([^\?]*)selected=[^&]*(.*)$/m,'$1$2') // delete current selected query, if any .replace(/([^\?]*)history=(\d+)\+*([^&]*)(&*)(.*)/m,'$1$4$5&selected=$2&history=$3').replace(/&{2,}/g,'&').replace(/\?&/m,'\?'); // format query with selected and history at end if ( str.endsWith('&history=') ) { str = str.replace(/(.+)&history=$/m,'$1'); } // if no history, delete query return str; } function createParentLinks() { let $links = []; let $protocol = window.location.protocol; let $href = decodeURIComponentSafe(window.location.href); let str = decodeURIComponentSafe(window.location.search); let $linkPieces = $href.split('/'); $linkPieces = $linkPieces.slice(2,-2); // remove beginning and ending empty elements and current directory while ( $linkPieces.length > 0 ) { // while there are link pieces... str = updateQueryStr(str); // update selected and history let link = $protocol +'//'+ $linkPieces.join('/') +'/'+ str; // assemble link $links.push(link); // add to link array $linkPieces.pop(); // remove last link piece and repeat... } return $links; } function createParentLinkItems() { let $parent_link_menu_items = []; let $links = createParentLinks(); let $content_parent_link = '
Parent Directory
'; // $content_iframe.attr( 'srcdoc', $content_parent_link ); // set parent link $parent_dir_menu.find('a').attr( 'href', $links[0] ); // set parent link for ( let i = 0; i < $links.length; i++ ) { let menu_item = '
  • ' + $links[i].slice(0,$links[i].lastIndexOf('?') - 1) + '/
  • '; $parent_link_menu_items.push(menu_item); } return $parent_link_menu_items; // return parents link items } function updateParentLinks() { $parents_dir_menu.siblings('ul').empty().append( createParentLinkItems() ); } // MENUS: User Shortcuts function shortcutMenuItems() { const $shortcuts = $settings.shortcuts; let menu_items = []; let $links_arr = []; let $links_arr_str = ''; let $links; if ( $shortcuts.length > 0 ) { for ( let i = 0; i < $shortcuts.length; i+=1 ) { $links = $shortcuts[i].links; // make array of links for ( let j = 0; j < $links.length; j+=1 ) { $links_arr[j] = '
  • ' + $links[j].link_name + '
  • '; if ( !$links[j].link.endsWith('/') ) { $links[j].link = $links[j].link.slice(0,$links[j].link.lastIndexOf('/') + 1) + '?file=' + $links[j].link.slice($links[j].link.lastIndexOf('/') + 1) ; } $links_arr[j] = '
  • ' + $links[j].link_name + '
  • '; } $links_arr_str = $links_arr.join(''); menu_items[i] = '
  • '+ $shortcuts[i].menu_title +'
      '+ $links_arr_str +'
  • '; } menu_items = menu_items.join(''); } return menu_items; } // MENUS: Other menu items const $sort_by = $('
  • Sort by…
    • Name
    • Size
    • Date
    • Kind
    • Extension
    • Default
    '); const $autoload_media = $('
  • Autoload Media
  • '); const $theme = $('
  • Dark ThemeLight Theme
  • '); const $alternate_background = $('
  • Alternate Backgrounds
  • '); const $show_numbers = $('
  • Show Numbers
  • '); const $text_editing = $('
  • Text Editing
    • Toggle Text Editor
    • Split View
    • Source TextPreview Text
    • Disable Text Editing
    '); const $default_settings = $('
  • Default User Settings
  • '); const $export_settings = $('
  • Export User Settings
  • '); const $contact_link = $('
  • Contact
  • '); const $donate_link = $('
  • '); function assembleMenus() { // called by buildUI(); $parents_dir_menu.siblings('ul').empty().append( createParentLinkItems() ); $shortcuts_menu.siblings('ul').append( shortcutMenuItems(), $sort_by, $theme, $alternate_background, $show_numbers, $autoload_media, $text_editing, $default_settings, $export_settings, $contact_link, $donate_link ); } // ***** END BUILD MENUS ***** // // ***** INDEX PREP ***** // // Return Index items, Index type, remove parent directory link, and add body class. function getIndexItems(el) { let parentDirEl = 'a[href="../"] ,a[href="/"], a:contains("Parent Directory"), a:contains("[parent directory]")'; let parentDirElParent = parentDirEl.length > 0 ? $(el).find(parentDirEl).last().parent() : null; let nodeName = parentDirElParent.length > 0 ? parentDirElParent[0].nodeName.toLowerCase() : 'error'; let els, type, info; switch(nodeName) { case 'li': $(el).addClass('is_converted_list'); els = parentDirElParent.parent('ul'); els.find('li').first().remove(); type = 'list'; break; case 'pre': if ( parentDirElParent.siblings('pre').length > 0 ) { info = parentDirElParent.siblings('pre').html(); } $(el).addClass('is_converted_pre'); els = parentDirElParent.html(); type = 'pre'; break; case 'td': $(el).addClass('is_converted_table'); els = parentDirElParent.closest('table > tbody'); els.find('tr').first().remove(); type = 'table'; break; case 'div': // local chrome default $(el).addClass('is_default'); els = parentDirElParent.next('table').find('tbody'); type = 'default'; break; case 'error': // error $(el).addClass('is_error'); els = $('body').html(); type = 'error'; break; } // console.log(els); return [els,type,info]; } // *** GET any non-directory info on the index page, since some index pages add readme and description text function getIndexInfo(el) { let address = el.find('address'); } // Index Prep: convert rows and return array of rows, with link, size, date-modified function convertIndexItems(type,items) { let converted = []; switch(type) { case 'list': converted = convertListType(items); break; case 'pre': converted = convertPreType(items); break; case 'table': case 'default': // local chrome indexes converted = convertTableType(type,items); break; case 'error': converted = convertErrorType(items); break; } return converted; } // Index Prep: convert list type function function convertListType(items) { let preppedIndex = []; const rows = Array.from(items.find('li')); for ( let i = 0; i < rows.length; i++ ) { let row = rows[i].innerHTML; row = prepRow(row).split(' '); if ( row.length > 0 ) { preppedIndex.push(row); } } return preppedIndex; } // Index Prep: convert pre type function function convertPreType(items) { items = items.replace(/\s* 0 ) { preppedRow.push(cells[i]); } } if ( preppedRow.length > 0 ) { preppedIndex.push(preppedRow); } } return preppedIndex; } // Index Prep: convert table type function function convertTableType(type,items) { // for local chrome indexes and server-generated table-type indexes let preppedIndex = []; const rows = Array.from(items.find('> tr')); for ( let i = 0; i < rows.length; i++ ) { let preppedRow = []; let cellContents = ''; let cells = Array.from( $(rows[i]).find('td') ); for ( let i = 0; i < cells.length; i++ ) { cellContents = cells[i].innerHTML.trim(); if ( cellContents.indexOf('table') > 0 ) { cellContents = ' '; } // for Gecko-style local indexes, which uses nested tables for the item name if ( type === 'default' && cellContents === '' ) { cellContents = '-'; } // chrome doesn't report local dir sizes cellContents = prepRow(cellContents); if ( cellContents.length > 0 && cellContents !== ' ' ) { preppedRow.push(cellContents); } // make prepped row } if ( preppedRow.length > 2 ) { preppedIndex.push(preppedRow); } // preppedRow.length > 2 in order to omit parent directory row } return preppedIndex; } // Index Prep: convert error pages (page not found, etc.) function convertErrorType(items) { items = items.replace(/ style="[^"]*?"/g,'').replace(/
    /g,''); items = '
    '+ items +'
    '; return items; } // Index Prep: Remove images, empty cells, hrs, and extract href from link function prepRow(str) { str = str.replace(/]+?>\s*/g,'') // remove images .replace(/]*?>[^<]*?<\/a>\s*]*?>[^<]*?<\/a>/,'') // some servers add an extra link for icons .replace(/]*?>\s*<\/a>/,'') // some servers add an extra link for icons .replace(//g,'$1') // extract link .replace(/
    /g,'') // remove hr // .replace(/^[\s\/-]+$/m,'') // remove empty headers .replace(/>[ |\s*]<'); // remove empty elements (typically "description" or dir size) return str; } // Index Prep: Build new Index from prepped rows function buildNewIndex(preppedIndex,sort) { let newIndexItems = []; for ( let i = 0; i < preppedIndex.length; i++ ) { // Get row attrs and text var rowLink = preppedIndex[i][0].replace(/&/g,'&');//.replace(//,''); // decode some reserved characters const rowName = getItemName(rowLink).replace(/^\s/m,'\ ').replace(/^\//m,'').replace(/([-_——])/g,'$1'); // display name, with word breaks added after unbreakable chars const rowSortName = getItemName(rowLink).replace(/^\//m,'').replace('/','').toLocaleLowerCase(); const sizesAndDates = getItemSizeAndDate(preppedIndex[i]); const rowSize = sizesAndDates[0]; const rowSortSize = sizesAndDates[1]; const rowDate = sizesAndDates[2]; const rowSortDate = sizesAndDates[3]; const rowExt = getItemExt(rowLink); const rowSortKind = getItemKind(rowExt); const rowKind = rowSortKind.slice(0,1).toUpperCase() + rowSortKind.slice(1); const rowClasses = getItemClasses(rowName,rowSortKind,rowExt); // Assemble row elements let newRow = $('').attr('id','rowid-'+i).addClass(rowClasses).attr('data-kind',rowSortKind).attr('data-ext',rowExt); const checkbox = ( rowClasses.indexOf('media') > 0 ? $('') : '' ); const nameSpan = $('').append(checkbox, rowName); const cellLink = $('
    ').addClass('icon').attr('href',rowLink).append(nameSpan); const cellName = $('').addClass('name').attr('data-name',rowSortName).append(cellLink); const cellSize = $('').addClass('size details').attr('data-size',rowSortSize).append(rowSize); const cellDate = $('').addClass('date details').attr('data-date',rowSortDate).append(rowDate); const cellKind = $('').addClass('kind details').attr('data-kind',rowSortKind).append(rowKind); const cellExt = $('').addClass('ext details').attr('data-ext',rowExt); // Assemble row newRow.append(cellName, cellSize, cellDate, cellKind, cellExt); newIndexItems.push(newRow[0]); } if ( sort === undefined ) { sort = getQuery('sort_by'); } let sortedIndexItems = sortDirList($(newIndexItems), 'sort_by_'+ sort, 1); // initial sort return sortedIndexItems; } // Index Prep: get row name function getItemName(link) { let name = decodeURIComponentSafe(link); if ( name.split('/').length > 2 ) { // get name only if x = full path let arr = name.split('/'); if ( name.startsWith('/') && name.endsWith('/') ) { // dirs name = arr[arr.length - 2] + '/'; } else { name = arr[arr.length - 1]; // files } } return name; } // Index Prep: get row classes function getItemClasses(name,kind,ext) { let itemClasses = []; itemClasses.push(kind); if ( ext !== 'dir' && ext !== 'app' ) { itemClasses.push('file'); } if ( name.indexOf('.') === 0 ) { itemClasses.push('invisible'); } if ( !JSON.stringify($row_types).match( escapeStr(ext) ) ) { // else classify as "other" if extension is not in $row_types. itemClasses.push('other'); //itemType = 'Other'; itemKind = 'other'; } else if ( kind === '' ) { // itemClasses.push('code'); //itemType = 'Code'; itemKind = 'code'; } else { itemClasses.push(ext); } if ( $row_settings.ignore.includes( ext ) ) { itemClasses.push('ignore'); } if ( $row_settings.exclude.includes( ext ) ) { itemClasses.push('exclude'); } if ( kind === 'audio' || kind === 'video' ) { itemClasses.push('media'); } itemClasses = Array.from(new Set(itemClasses)); // remove dupe classes return itemClasses.join(' '); } // Index Prep: get formatted row size and date function getItemSizeAndDate(row) { let sizesAndDates = []; let rowSize; let rowSortSize; let rowDate; let rowSortDate; if ( row.length > 1 && row[1] !== undefined && row[2] !== undefined ) { // in case server doesn't provide size or date rowSize = ( row[1].length < row[2].length ? row[1] : row[2] ); // determine which cell is date and which is size, assuming date length is always longer than size length rowSize = ( rowSize === '-' || rowSize === '' ? '—' : rowSize.toUpperCase() ); rowSortSize = getItemSortSize(rowSize); rowDate = ( row[1].length < row[2].length ? row[2] : row[1] ); rowSortDate = getItemDate(rowDate).replace(/-|:|\s*/g,''); } else { if ( row[1] === undefined ) { rowSize = '—'; rowSortSize = '0'; } if ( row[2] === undefined ) { rowDate = '—'; rowSortDate = '0'; } } sizesAndDates.push(rowSize,rowSortSize,rowDate,rowSortDate); return sizesAndDates; } // Index Prep: get row size for sorting function getItemSortSize(val) { const size = val.replace('—','0').replace(/[A-z\s]+/,'').trim(); // = any non-alpha chars, i.e. numbers const unit = val.replace('—','B').replace(/[\d\\.]+/g,'').trim(); // = any non-numeric chars const factor = { '':1, B:1, K:1000, KB:1000, M:1000000, MB:1000000, G:1000000000, GB:1000000000, T:1000000000000, TB:1000000000000 }; // unit to file size const sortSize = size * factor[unit]; // convert byte size to multiplication factor return sortSize; } function processDate(match,p1,p2,p3) { //date formats: 2017-10-09 13:12 || 2015-07-25T02:02:57.000Z || 12-Mon-2017 21:11 const mo = 'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(p2)/3 + 1; // e.g., convert month into number, or use number return p3 +'-'+ mo +'-'+ p1; } // Index Prep: get row date function getItemDate(val) { const sortDate = val.replace(/^(\d{2})-(\w{3})-(\d{4})/m, processDate); return sortDate; } // Index Prep: get row kind function getItemKind(ext) { let kind = ''; if ( ext === 'dir' || ext === 'app' ) { kind = ext; } else { for ( let types in $row_types ) { if ( $row_types[types].includes( ext ) ) { kind = types; return kind; } } } if ( kind === '' ) { kind = 'other'; } return kind; } // Index Prep: get row extension function getItemExt(link) { let ext = ''; if ( ext.endsWith('app/') || ext.endsWith('exe') ) { ext = 'app'; } else if ( link.endsWith('/') ) { ext = 'dir'; } else if ( link.indexOf('.') < 0 ) { // if no '.' in link, ... ext = link.slice(link.lastIndexOf('/') + 1).toLowerCase(); } else { // find the last . and get the remaining characters ext = link.slice(link.lastIndexOf('.') + 1).toLowerCase(); } return ext; } // END INDEX PREP // ***** MAKE NEW INDEX ***** // function makeNewIndex(el,sort) { const indexItems = getIndexItems(el); const items = indexItems[0]; const type = indexItems[1]; const convertedIndex = convertIndexItems( type, items ); // = array of rows ["link","date","size"] if ( type === 'error' ) { return convertedIndex; } else { let newIndex = buildNewIndex( convertedIndex, sort ); return newIndex; } } function appendNewIndex(body_top) { // setUpUI(); $dir_list_body.append( makeNewIndex(body_top) ); } // get and set index stats function getIndexStats(el) { const total = el.length; const dirs = el.filter('.dir').length; const files = el.filter('.file').length; const stats = total +' items: '+ dirs +' directories, '+ files +' files'; return stats; } // ***** END DIR_LIST SETUP ***** // // ***** UI SETUP ***** // // Build UI: Append all assembled elements to $body function setUpBody() { if ( window.self === window.top ) { // if it's an iframe... $('head').prepend(''); $('body').attr('id','top').attr('lang','en').find('script').remove(); } else { $('body').attr('id','iframe_body'); } } function buildUI() { setUpBody(); addStyles( $('body#top').prev('head') ); assembleUIElements(); assembleMenus(); getIndexInfo($('body#top')); appendNewIndex($('body#top')); $main_content.find('tr').append( $sidebar_wrapper, $content_pane ); $index_stats.text(getIndexStats($dir_list.find('#tbody tr'))); $('body#top').empty().append($main_content); } buildUI(); const $body = $('body#top'); const $iframe_body = $('body#iframe_body'); const $iFrame_head = $iframe_body.prev('head'); const $dir_list_row = $dir_list_body.find('> tr'); const $audio_files = $dir_list_body.find('.audio'); const $font_files = $dir_list_body.find('.font'); const $image_files = $dir_list_body.find('.image'); const $media_files = $dir_list_body.find('.media'); const $video_files = $dir_list_body.find('.video'); function $selected_file() { return $dir_list_body.find('.selected'); } function $playing_file() { return $dir_list_body.find('.playing'); } // UI Setup: build UI and add body classes and other initial settings function setupUIprefs() { for ( let key in $settings ) { if ( getQuery(key) === 'true' ) { $body.addClass(key); } else { // non-boolean settings and others if ( key === 'theme' ) { $body.addClass( 'theme_'+ getQuery('theme') ); } if ( key === 'sort_by' ) { $body.addClass( 'sort_by_'+ getQuery(key) ); $('#theader').find('th[id="sort_by_'+ getQuery(key) +'"]').addClass('up'); } if ( key === 'default_text_view' ) { if ( getQuery(key) === 'source_text' ) { $body.addClass('source_text'); } else { $body.addClass('preview_text'); } } if ( getQuery('toggle_sidebar') === 'true' ) { $body.addClass( 'has_hidden_sidebar' ); } } } if ( navigator.userAgent.indexOf('Chrome') > 0 ) { $body.addClass('is_chrome'); } if ( navigator.userAgent.indexOf('Firefox') > 0 ) { $body.addClass('is_gecko'); } if ( $audio_files.length > 0 ) { $body.add($dir_list).addClass('has_audio has_media'); } if ( $font_files.length > 0 ) { $body.addClass('has_fonts'); } if ( $image_files.length > 0 ) { $body.addClass('has_images'); } if ( $video_files.length > 0 ) { $body.add($dir_list).addClass('has_video has_media'); } // UI Setup: show invisibles if ( navigator.platform.indexOf('Win') > -1 || $location.indexOf('file:') < 0 ) { $inv_checkbox.hide(); } else if ( $body.hasClass('show_invisibles') ) { $inv_checkbox.find('input').attr('checked','checked'); } //document.title = 'Index of: '+ $current_dir_path.replace(//g,''); } function setUpUI() { setupUIprefs(); setUpIframeUI( getQuery('enable_text_editing') ); initMedia(); autoSelectFile(); autoLoadCoverArt(); setContentTitle(); setContentHeight(); } setUpUI(); // SET UI TO DEFAULT SETTINGS: remove queries; function defaultSettings() { let $location = window.location.href; $location = $location.slice(0,$location.lastIndexOf('?')); window.location.assign($location); } $default_settings.on('click', function() { if (window.confirm( 'Are you sure you want to reset all your temporary UI settings to the defaults in your user_settings?\nThis action cannot be undone.' ) ) { defaultSettings(); } }); // EXPORT SETTINGS function saveSettings(filename, data) { const blob = new Blob([data], {type: 'text/html'}); const elem = window.document.createElement('a'); elem.href = window.URL.createObjectURL(blob); elem.download = filename; document.body.appendChild(elem); elem.click(); document.body.removeChild(elem); URL.revokeObjectURL(blob); } $export_settings.on('click','a',function(e) { e.preventDefault(); const $settings_string = ( JSON.stringify($settings,null,'\t')); saveSettings('settings.txt',$settings_string); }); // Click Menu Link (with warning) function setLocation(link) { window.location = link; } $('#parent_dir_menu,#parents_dir_menu + .menu,#shortcuts').on('click','a',function(e) { e.preventDefault(); if ( $(this).attr('href').indexOf('file://') > -1 && $protocol !== 'file:' ) { $body.addClass('has_warning').find('#warnings').addClass('local'); } else { showWarning( 'setLocation', thisLink($(this)) ); } }); // Show Menus function showMenus(el) { let $position = $(el).position(); $(el).find('> ul').css({'top':$position.top + $(el).innerHeight() + 'px'}).toggle().parent('td').siblings('td').find('.menu').hide(); } $parents_dir_menu.add($shortcuts_menu).parent('td').on('click',function(e) { e.stopPropagation(); showMenus(this); }); // Hide Menus $(document).on('click', function() { $('.menu').hide(); }); // Toggle UI Preferences function toggleUIpref(prefID) { let prefClass = prefID; if ( prefID === 'split_view' ) { sendMessage('iframe','split_view'); } if ( prefID.startsWith('sort_by') ) { $body.removeClass('sort_by_default sort_by_name sort_by_size sort_by_date sort_by_kind sort_by_ext'); } if ( prefID.startsWith('theme') ) { prefClass = 'theme_dark theme_light'; } if ( prefID.endsWith('text') && !$body.hasClass(prefID) ) { sendMessage('iframe','default_text_view'); $body.toggleClass('preview_text source_text'); } toggleQuery(prefID); $body.toggleClass(prefClass); setContentHeight(); if ( prefID === 'enable_text_editing' ) { $('.selected.text, .selected.markdown').click(); } // $('#shortcuts').hide(); // don't hide menus after click? } // Click Toggle UI Pref elements $('.toggle_UI_pref').on('click',function(e) { if ( !$(this).is('input') ) { e.preventDefault(); // allow checkboxes to be checked } toggleUIpref( $(this).attr('id') ); }); // Toggle Sidebar function toggleSidebar() { $body.toggleClass('has_hidden_sidebar'); if ( $body.hasClass('has_hidden_sidebar') ) { setQuery('toggle_sidebar','true'); } else { removeQuery('toggle_sidebar'); } setContentHeight(); scrollThis('tbody','selected',true); // true = instant scroll } $toggle_sidebar.on('click', function() { toggleSidebar(); }); // RESIZE Sidebar/Content Pane function resizeSidebar(f) { f.stopPropagation(); const $startX = f.pageX; let $window_width = window.innerWidth; let $sidebar_width = $sidebar_wrapper.width(); $('#overlay').css({'display':'block','z-index':'1'}); $('#handle').css({'z-index':'9999'}); $body.css({'-moz-user-select':'none','user-select':'none'}); $(document).on('mousemove',function(e) { e.stopPropagation(); e.preventDefault(); const $deltaX = e.pageX - $startX; if ( e.pageX > 230 && e.pageX < $window_width - 200 ) { $sidebar_wrapper.css({'width':$sidebar_width + $deltaX + 'px'}); $content_pane.css({'width':($window_width - $sidebar_width) - $deltaX + 'px'}); } setContentHeight(); }); $(document).on('mouseup',function() { $('#overlay').css({'display':'none','z-index':'unset'}); $('#handle').css({'z-index':'unset'}); $body.css({'-moz-user-select':'unset','user-select':'unset'}); $(document).off('mousemove'); $sidebar_width = $sidebar_wrapper.width(); setQuery('width',$sidebar_width); }); } $handle.on('mousedown', function(f) { f.stopPropagation(); resizeSidebar(f); }); // ***** BASIC UI FUNCTIONS ***** // // Get dir_list item row function thisRow(x) { return $(x).closest('#dir_list > tbody > tr').length > 0 ? $(x).closest('#dir_list > tbody > tr') : $(x).closest('#dir_list > li'); } function thisID(x) { return thisRow(x).attr('id'); } // Get row link function thisLink(x) { return $(x).find('a').length > 0 ? $(x).find('a').attr('href') : $(x).attr('href'); } // Get row name function thisText(x) { return $(x).find('a span').length > 0 ? decodeURIComponentSafe( $(x).find('a span').text().toLocaleLowerCase() ) : decodeURIComponentSafe( $(x).text().toLocaleLowerCase() ); } // get row text function thisExt(x) { let $this_name = thisText(x); return $this_name.endsWith('app/') ? 'app' : $this_name.endsWith('/') ? '/' : $this_name.lastIndexOf('.') === -1 ? undefined : $this_name.toLocaleLowerCase().slice( $this_name.lastIndexOf('.') + 1 ); } function getElById(id) { return $(document.getElementById(id) ); } // SET CONTENT HEIGHT function setContentHeight() { // accommodate multi-line title names in preview pane if ( $title.outerWidth() > ( $('#content_title').innerWidth() - 2 * $('#title_buttons_left').outerWidth() ) ) { $title.css({'margin-top':'2em'}); } else { $title.css({'margin-top':'0'}); } let $window_height = window.innerHeight; let $content_header_height = $content_header.outerHeight(); $sidebar.add($main_content).add($content_pane).css({'height':$window_height }); $dir_list.css({'height':$window_height - $('#sidebar_header').outerHeight(), 'max-height':$window_height - $('#sidebar_header').outerHeight() }); $dir_list_body.css({'top': $dir_list_head.outerHeight(),'bottom': $dir_list.find('tfoot').outerHeight(),'height': $dir_list.innerHeight() - $dir_list_head.outerHeight() - $dir_list.find('tfoot').outerHeight(),'max-height': $dir_list.innerHeight() - $dir_list_head.outerHeight() - $dir_list.find('tfoot').outerHeight() }); $('#iframe_body').find('#tbody').css({'top':$('#iframe_body').find('#thead').height() + 1 +'px'}); $prev_track.add($next_track).add($close_audio).css({'height':$('#audio').height() }); // set height of audio controls $content_container.css({'top':$content_header_height +'px' }); } window.addEventListener('resize', setContentHeight ); // SET CONTENT TITLE function setContentTitle() { let $title_text = ''; if ( $playing_file().hasClass('audio') ) { // set audio player title $content_audio_title.find('td').empty().text( $playing_file().find('td.name a').text() ); } if ( $content_pane.hasClass('has_grid') ) { // set main title for other content $title_text = $('#parents_dir_menu').find('> div').html().split('').reverse()[1]; } else if ( $body.hasClass('has_text') ) { $title_text = 'Text Editor'; } else if ( $selected_file().hasClass('audio') ) { return; } else if ( !$selected_file().hasClass('audio') || $content_pane.hasClass('has_hidden_text') ) { $title_text = $selected_file().not('.audio').find('td.name a span').text(); // Assemble title } if ( $content_pane.hasClass('has_image') ) { setDimensions($('.selected.image')); } else { $title.attr('data-after',''); // remove image dimensions } $title.empty().text($title_text); if ( $title.outerWidth() > ( $('#content_title').innerWidth() - 2 * $('#title_buttons_left').outerWidth() ) ) { $title.css({'margin-top':'2em'}); } else { $title.css({'margin-top':'0'}); } } // Get Image Dimensions function getDimensions(link, callback) { let img = new Image(); img.src = link; img.onload = function() { callback( this.width, this.height ); }; } function setDimensions(row) { getDimensions( thisLink(row), function( width, height ) { $title.attr('data-after',' (' + width + 'px × ' + height + 'px)'); }); } // Scroll Selected Items function scrollThis(elID,className,bool) { let $behavior = 'smooth'; if ( bool !== undefined ) { $behavior = 'instant'; } let $block = ( navigator.userAgent.indexOf('Firefox') > -1 ? 'start' : 'nearest' ); if ( document.getElementsByClassName(className).length > 0 ) { document.getElementById(elID).getElementsByClassName(className)[0].scrollIntoView({ behavior:$behavior, block:$block, inline:'nearest' }); } setContentHeight(); } // ***** SORTING ***** // function sortIndex(els,id,sortDirection) { // id = sort type let sorted = []; const newSort = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); // needs to be above makeNewIndex() sorted = els.removeClass('sorted').sort((a, b) => { let aName = $(a).find('td.name').data('name'); let bName = $(b).find('td.name').data('name'); let aData = $(a).find('td[data-'+ id +']').data(id); let bData = $(b).find('td[data-'+ id +']').data(id); if ( sortDirection === 1 ) { // sort by detail data value, then by name (i.e., if data values are the same, sort by name) if ( newSort.compare(aData, bData) === 0 ) { return newSort.compare(aName, bName); } else { return newSort.compare(aData, bData); } } else { // reverse sort if ( newSort.compare(bData, aData) === 0 ) { return newSort.compare(bName, aName); } else { return newSort.compare(bData, aData); } } }); sorted = sorted.sort((a, b) => { // add sorted style (rules between different rows) if ( id === 'kind' || id === 'ext' && sortDirection === 1 ) { if ( $(a).find('td[data-'+ id +']').data(id) !== $(b).find('td[data-'+ id +']').data(id) ) { $(a).addClass('sorted'); } } if ( id === 'kind' || id === 'ext' && sortDirection === -1 ) { if ( $(b).find('td[data-'+ id +']').data(id) !== $(a).find('td[data-'+ id +']').data(id) ) { $(a).addClass('sorted'); } } }); return sorted; } // Sort the Dir List on click function sortDirList(rows, id, sortDirection) { const $sort_all = rows; const $sort_dirs = $sort_all.filter('.dir:not(.app)'); const $sort_files = $sort_all.filter('.file,.app'); const $sort_id = id.slice(8);// === 'default' ? 'name' : id; const $sorted_dirs = sortIndex($sort_dirs, $sort_id, sortDirection); const $sorted_files = sortIndex( $sort_files, $sort_id, sortDirection ); const $sorted_all = sortIndex( $sort_all, $sort_id, sortDirection ); let $sorted = []; if ( $sort_id === 'default' || ( $sort_id !== 'name' && $settings.dirs_on_top === true )) { if (sortDirection === 1) { $sorted = $.merge($sorted_dirs,$sorted_files); } else { $sorted = $.merge($sorted_files,$sorted_dirs); } } else { $sorted = $sorted_all; } return $sorted; } // Sort on click function clickSort(el) { const id = el.attr('id'); // id from th sort item = 'sort_by_xxx' var sortDirection = ( el.hasClass('up') ? -1 : 1 ); // Only reverse sort order after clicking a sort column once. // SORT EM! const $sorted_index = sortDirList( $dir_list_row, id, sortDirection ); $dir_list_body.append($sorted_index); $('th[id="'+ id +'"]').toggleClass('up').siblings().removeClass('up'); if ( $content_grid.hasClass('has_font_grid') ) { $('#show_font_grid').click(); } if ( $content_grid.hasClass('has_image_grid') ) { $('#show_image_grid').click(); } if ( $content_grid.hasClass('has_grid') ) { $('#grid_btn').click(); } setContentHeight(); } // Sort on clicking dir_list sort item $('#theader').on('click','th.sorting:not(.disabled)',function(e) { e.preventDefault(); e.stopPropagation(); clickSort( $(this) ); }); // Sort Menu: click the list header that contains the selected menu text. $('#sort_menu').on('click','li:not(.disabled)',function(e) { e.preventDefault(); e.stopPropagation(); $('#theader th[id="sort_by_'+ $(this).attr('id') +'"]').click(); // click corresponding dir_list sort item }); // ***** END SORTING ***** // // ***** END BASIC UI FUNCTIONS ***** // // ***** CONTENT PANE ***** // // SELECT ROW on click and set classes for $content_pane function selectThis(row) { const $grid_selected = $content_grid.find('div.font_grid_item a[href="'+ thisLink(row) +'"]').closest('div').add('div.image_grid_item a[href="'+ thisLink(row) +'"]').closest('div').addBack(); if ( $content_pane.hasClass('has_grid') ) { // Select corresponding grid item row.addClass('selected').siblings().removeClass('selected hovered'); $grid_selected.addClass('selected').siblings().removeClass('selected'); } else { // remove classes from rows, but leave .audio with playing row.addClass('selected').siblings().removeClass('selected hovered'); } } //***** SHOW CONTENT *****// function showAudio(rowID) { let row = getElById(rowID); closeMedia('video'); if ( row.hasClass('audio') ) { row.addClass('playing selected').siblings('.media').removeClass('playing selected'); } $audio_player.attr('src', thisLink( row ) ); $content_pane.addClass('has_audio'); setContentTitle(); setContentHeight(); } // Show Grid function showGrid() { $content_pane.removeClass('has_hidden_grid').addClass('has_grid'); closeMedia('video'); setContentTitle(); setContentHeight(); selectThis($selected_file()); } // Show Font (and create font items) function showFont(row,bool,sheet) { // bool = true if for show font grid, sheet defined at fontGridItems() let fontStyles = $font_styles.sheet; const $font_family = thisText(row); const $font_url = thisLink(row); const $font_grid_item_el = $('
    '); if ( bool === false ) { if ( fontStyles.cssRules.length > 0 ) { fontStyles.deleteRule(0); } // delete previous @font-face rule fontStyles.insertRule('@font-face { font-family: "'+ $font_family +'"; src: url("'+ $font_url +'"); }'); $content_font.css({ 'font-family':'"'+ $font_family +'"' }); // set content font style } else { let grid_item = $font_grid_item_el.clone(); const $display_name = $font_family; sheet.insertRule('@font-face { font-family: "'+ $font_family +'"; src: url("'+ $font_url +'"); }'); grid_item.append('

    '+ $display_name +'

    '+ $display_name.slice(0,$font_family.lastIndexOf('.')) +'

    ' ); return grid_item; } } // Show/Hide Editor or Grid function showEditorOrGrid() { if ( $body.hasClass('has_hidden_text') ) { $body.toggleClass('has_text has_hidden_text'); } if ( $content_pane.hasClass('has_hidden_grid') ) { $content_pane.toggleClass('has_grid has_hidden_grid'); } } function hideEditorOrGrid() { if ( $body.hasClass('has_text') ) { $body.toggleClass('has_text has_hidden_text'); } if ( $content_pane.hasClass('has_grid') ) { $content_pane.toggleClass('has_grid has_hidden_grid'); } } // Set Content Pane classes function setContentClasses(content_el) { if ( content_el === 'audio' ) { $content_pane.addClass('has_audio'); } else { hideEditorOrGrid(); let classes = ['has_font','has_image','has_zoom_image','has_pdf','has_video','has_iframe','has_dir','has_ignored']; $content_pane.removeClass(classes.join(' ')).addClass( 'has_'+ content_el ); // remove classes, excluding grid and text classes; add content class } } // Set Content Element Sources and row classes function setContentSources(row,link,kind,content_el) { if ( kind === 'audio' ) { $audio_player.attr('src',link); } if ( kind === 'font' ) { showFont(row,false); } if ( kind === 'pdf' ) { link = link + '?#view=fitB&scrollbar=1&toolbar=1&navpanes=1'; } // add pdf query str to link if ( kind === 'code' || kind === 'markdown' || kind === 'text' ) { link = thisLink(row) +'?split_view='+ getQuery('split_view') +'&default_text_view='+ getQuery('default_text_view'); if ( !$body.hasClass('enable_text_editing') ) { link += '&enable_text_editing=false'; } else { link += '&enable_text_editing=true'; } } if ( kind === 'dir' ) { link = link + '?sort_by=' + getQuery('sort_by') +'&show_numbers='+ getQuery('show_numbers'); } // add pdf query str to link if ( kind === 'video' ) { row.addClass('playing'); } else { row.addClass('loaded'); } $('#content_'+ content_el).addClass('has_content').hide().attr('src',link).removeAttr('srcdoc').show(); } // Show Content function showContent(row) { // show any content excluding grids on row click if ( row.length === -1 ) { return; } // needed for left/right arrow nav when there are no valid items (i.e. images or fonts) let link = thisLink(row); let kind = thisRow(row).attr('data-kind') ; let rowID = row.attr('id'); let content_el = ( row.hasClass('ignore') && $body.hasClass('ignore_ignored_files') ? 'ignored' : !['audio','font','image','pdf','video'].includes(kind) || kind === 'dir' ? 'iframe' : kind ); // load dirs and any other kind of content except audio, font, image, pdf, or video into iframe if ( row.hasClass('m3u') ) { } else if ( row.hasClass('audio') ) { showAudio( rowID ); } else { closeContentEls(row); setContentClasses(content_el); setContentSources(row,link,kind,content_el); setContentTitle(); setContentHeight(); row.siblings().removeClass('loaded'); } } //***** CLOSE CONTENT (Close button or Cmd/Ctrl + W) *****// // Close Audio/Video function closeMedia(type) { // type === audio || video let $mediaEl = ( type === 'audio' ? $audio_player : $content_video ); // let $mediaFile = $(document.getElementsByClassName(type)); $('.media.playing, .media.loaded').removeClass('playing loaded'); $content_pane.removeClass('has_'+ type); $mediaEl.trigger('pause').attr('src',''); if ( type === 'audio' ) { $('#content_audio_title td').empty(); } else { $title.empty(); } setContentHeight(); } // Close Audio button click $close_audio.on('click',function(e) { e.stopPropagation(); closeMedia('audio'); $('.audio.selected').removeClass('selected'); if ( $('.loaded').length === 1 ) { $('.loaded').addClass('selected'); } }); // Close Text Editor // Close Grid function closeGrid() { $content_pane.removeClass('has_grid'); $content_grid.empty().removeClass().attr('style','').find('.image_grid_item, img').attr('style',''); } // Close .content elements (not #content_audio, #content_text, or #content_grid) when opening new content function closeContentEls(row) { // close media if ( row !== undefined && row.hasClass('video') ) { closeMedia('audio'); } else if ( row !== undefined && row.hasClass('audio') ) { closeMedia('video'); } // close content if ( $('body').hasClass('has_text') && $(this).hasClass('selected') ) { // if text editor visible, just hide it and show selected item $('body').removeClass('has_text').addClass('has_hidden_text'); } else if ( $('.content.has_content').length ) { let $contentID = $('.content.has_content').attr('id'); switch($contentID) { case 'content_font': $content_font.css({'font-family':''}); break; case 'content_image': $content_pane.removeClass('has_zoom_image'); $content_image.attr('style',''); // reset image: comment out to retain image scale after loading other content // $content_grid.find('a[href="' + thisLink(row) + '"]').parent('div').addClass('selected').siblings().removeClass('selected'); // select grid image break; case 'content_video': closeMedia('video'); break; } $content_pane.removeClass('has_'+ $contentID.slice(8)); $('.content').removeClass('has_content').removeAttr('src'); // $content_iframe.attr('srcdoc',$content_parent_link); } } // Close button function closeContent() { if ( $content_pane.hasClass('has_grid') ) { // close grid closeGrid(); } else if ( $body.hasClass('iframe_edited') ) { // warn if iframe edited hideEditorOrGrid(); showWarning('closeContent'); } else if ( ['has_font','has_image','has_zoom_image','has_pdf','has_video','has_iframe','has_dir','has_ignored','has_text'].some( c => $content_pane.attr('class').split(' ').indexOf( c ) >= 0 ) ) { closeContentEls(); // close content if content pane has one of these classes, except audio and grids $('.selected:not(.audio)').removeClass('selected'); $('.loaded').removeClass('loaded'); $title.removeAttr('data-after').empty(); showEditorOrGrid(); } else if ( $body.hasClass('has_text') && !$body.hasClass('edited') ) { // simply hide unedited text editor... $body.removeClass('has_text'); } else if ( $body.hasClass('edited') ) { // ...else show edited warning showWarning('closeContent'); } else { // close audio last of all closeMedia('audio'); $('.selected.audio').removeClass('selected'); } setContentTitle(); setContentHeight(); } $('#close_btn').on('click', function(e) { e.preventDefault(); closeContent(); // close content unless body.edited or body.iframe_edited }); //***** RESET CONTENT (Reset button or Cmd/Ctrl + R) *****// function resetContent() { if ( $content_pane.attr('class') === '' ) { window.location = window.location.href; } // reload page if ( $content_pane.hasClass('has_audio') ) { $audio_player.prop('currentTime', 0).trigger('pause'); } if ( $content_pane.hasClass('has_grid') ) { $grid_btn.click(); } if ( $content_pane.hasClass('has_font') ) { $content_font.css({'font-size':'1em'});} if ( $content_pane.hasClass('has_image') ) { $content_pane.removeClass('has_zoom_image').find('#content_image').attr('style',''); } if ( $content_pane.hasClass('has_video') ) { $content_video.prop('currentTime',0).trigger('pause'); } if ( $content_pane.hasClass('has_iframe') || $content_pane.hasClass('has_dir') ) { $selected_file().find('a').click(); } setContentHeight(); } $('#reload_btn').on('click', function(e) { e.preventDefault(); showWarning('resetContent'); }); //**********************// //***** NAVIGATION *****// function firstRowID(className) { return ( $('#tbody').find(':visible:not(.unchecked)').filter(className).length ? $('#tbody').find('tr:visible:not(.unchecked)').filter(className).first().attr('id') : null ); } function prevRowID(className) { let row; if ( ['.audio','.video','.media'].includes(className) ) { row = $playing_file(); } else { row = $selected_file(); } return ( !row.length || !row.prevAll(':visible:not(.unchecked)').filter(className).length ) ? $('#tbody').find('tr').filter(className).last().attr('id') : row.prevAll(':visible:not(.unchecked)').filter(className).first().attr('id'); } function nextRowID(className) { // if nothing selected, or if no next row with classname, return first row with classname, else return next row with classname let row; if ( ['.audio','.video','.media'].includes(className) ) { row = $playing_file(); } else { row = $selected_file(); } return ( !row.length || !row.nextAll(':visible:not(.unchecked)').filter(className).length ) ? $('#tbody').find('tr').filter(className).first().attr('id') : row.nextAll(':visible:not(.unchecked)').filter(className).first().attr('id'); } // function lastRowID(className) { // return ( $('#tbody').find(':visible:not(.unchecked)').filter(className).length ? $('#tbody').find('tr:visible:not(.unchecked)').filter(className).last().attr('id') : null ); // } function selectRowID(className,key) { let id = ''; if ( key === 'ArrowUp' ) { id = prevRowID('.dir,.file'); } if ( key === 'ArrowLeft' ) { id = prevRowID(className); } if ( key === 'ArrowRight' ) { id = nextRowID(className); } if ( key === 'ArrowDown' ) { id = nextRowID('.dir,.file'); } return id; } // NAVIGATION: select GRID items by left/right arrow keys @ arrowNavigation(); function gridNavigation(key) { let className = ''; if ( $content_grid.hasClass('has_font_grid') ) { className = '.font:not(.ignore)'; } if ( $content_grid.hasClass('has_image_grid') ) { className = '.image:not(.ignore)'; } if ( $content_grid.hasClass('has_grid') ) { className = '.font:not(.ignore),.image:not(.ignore)'; } selectThis( getElById(selectRowID(className,key) ) ); } // NAVIGATION: FONTS and IMAGES by prev/next buttons $content_pane.on( 'click','#prev_btn, #next_btn', function(e) { e.stopPropagation(); e.preventDefault(); let key = $(this).attr('id') === 'prev_btn' ? 'ArrowLeft' : 'ArrowRight'; clickRow( selectRowID('.font,.image',key)); }); // NAVIGATION: MEDIA tracks by arrow left/right @ leftRightArrowNavigation() & button click; // handle shuffle or loop play, as well as normal continuous playback after end of track with ArrowRight function playPrevNextTrack(key) { if ( $('.playing').length === 0 ) { // Arrow L/R selects first/last audio file if nothing selected clickRow( selectRowID('.media',key) ); playMedia('play'); } else if ( $('.playing').length === 1 ) { let mediaClass = ( $('.playing').hasClass('audio') ? '.audio' : '.video' ); // If shuffle play... if ( $body.hasClass('shuffle_audio') ) { let trackRowID = $audio_player.data('shufflelist').pop(); if ( trackRowID !== undefined ) { // if shuffle list is not empty... showAudio( trackRowID ); // load audio... playMedia('play'); // and play } else if ( trackRowID === undefined ) { // if end of shufflelist... if ( $body.hasClass('loop_audio') ) { // and if loop audio, update the shufflelist and play updateShuffleList(); playMedia('play'); } else { // else load the first track showAudio( firstRowID( mediaClass )); } } // else if there is another media file selected, play it next } else if ( $(mediaClass).filter('.selected').length === 1 && !$('.media.selected').hasClass('playing') ) { showAudio( $('.media.selected').attr('id') ); playMedia('play'); } else { if ( $body.hasClass('loop_audio') || nextRowID( mediaClass ) !== firstRowID( mediaClass ) ) { showAudio( selectRowID( mediaClass,key ) ); playMedia('play'); } else { showAudio( selectRowID( mediaClass,key ) ); } } } } // NAVIGATION: Audio by prev/next audio buttons $('.prev_next_track_btn').on('click',function() { let key = ( $(this).attr('id') === 'prev_track' ? 'ArrowLeft' : 'ArrowRight' ); playPrevNextTrack(key); }); // NAVIGATION: Prev/Next Audio or Prev/Next File of same data-kind by arrow left/right function leftRightArrowNavigation(className,key) { if ( $('.selected').hasClass('media') && $('.playing').length === 1 ) { playPrevNextTrack(key); } else { if ( $('.selected').length === 0 ) { // else select first/last row clickRow( selectRowID('.dir,.file',key) ); } else { // else select prev/next row of same data-kind clickRow( selectRowID('.'+ $('.loaded').attr('data-kind'),key) ); } } } function upDownArrowNavigation(key) { let row = $(document.getElementById(selectRowID('.dir,.file',key))); if ( row.hasClass('audio') && $('.audio.playing').length === 1 ) { // just select audio file if another audio is playing selectThis( row ); } else { clickRow( selectRowID('.dir,.file',key) ); } } // NAVIGATE directory index items by arrow up/down or left/right keys, with/without grid @ indexNavigation() function arrowNavigation(className,key) { if ( key === 'ArrowUp' || key === 'ArrowDown' ) { upDownArrowNavigation(key); } else { // key === 'ArrowLeft" || key === 'ArrowRight' if ( $content_pane.hasClass('has_grid') ) { // Grid navigation: L/R arrow selects images and fonts only gridNavigation(key); } else { leftRightArrowNavigation(className,key); } } if ( $content_pane.hasClass('has_grid') ) { scrollThis('content_grid','selected'); } else { scrollThis('tbody','selected'); } } // NAVIGATION: Main navigation by arrow keys function indexNavigation(key) { let className = ( $('.selected[data-kind]') === undefined ? $dir_list.find('tbody tr:visible').first().attr('data-kind') : $('.selected[data-kind]').attr('data-kind') ); arrowNavigation(className,key); } // NAVIGATE items by typed string var str = ''; function timeoutID() { return window.setTimeout( function() { str = ''; }, 1500 ); } function alphaNav(e) { // Select Dir_List row by typed string; Todo: select next row by nearest letter let timer = timeoutID(); if ( typeof timer === 'number' ) { window.clearTimeout( timer ); timer = 0; // id } timeoutID(); str += e.key; str = str.toLowerCase(); if ( $('#dir_list').find('td.name[data-name^="'+ str +'"]').length ) { $('#dir_list').find('td.name[data-name^="'+ str +'"]').first().find('a').click(); scrollThis('tbody','selected'); // } else { // null; // replace this with some sort of fuzzy match function? TBD } } //***** END NAVIGATION *****// //***** CLICK TO SELECT/SHOW CONTENT *****// // CLICK element by id function clickThis(id) { let el = $(document.getElementById(id)); if ( el.find('a').length > 0 ) { el.find('a').click(); } else { el.click(); } } // CLICK Row function clickRow(id) { let row = getElById(id); selectThis(row); showContent(row); } $body.find('#tbody').on('click','tr', function(e) { e.preventDefault(); e.stopPropagation(); if ( $(this).hasClass('playing') ) { playPauseMedia(); } else { showWarning( 'clickRow', $(this).attr('id') ); } }); // DOUBLE-CLICK Row to open directory function doubleClickRow(row) { // row.dir only let $query_str = decodeURIComponentSafe(window.location.search); if ( $query_str === '' ) { $query_str = '?'; } const $current_index = row.prevAll('.dir:visible:not(.ignore)').length; if ( $query_str.indexOf('history') !== -1 ) { $query_str = $query_str.replace(/&selected=\d+/,'').replace(/&history=/,'&history='+ $current_index +'+'); } else { $query_str = $query_str.replace(/&selected=\d+/,'') + '&history='+ $current_index; } window.location = row.find('a').attr('href') + $query_str; } $('#tbody').find('tr.dir').on('dblclick', function(e) { e.preventDefault(); e.stopPropagation(); showWarning( 'doubleClickRow', $(this) ); }); // CLICK grid item function gridItemClick(e,el) { e.preventDefault(); clickThis( thisID($dir_list.find('a[href*="'+ thisLink(el) +'"]') ) ); } $content_grid.on('click','div', function(e) { gridItemClick(e,$(this)); }); // HOVER Grid Item $content_grid.on('mouseenter','> div:not(.selected)',function() { thisRow($dir_list.find('a[href*="'+ thisLink(this) +'"]')).addClass('hovered'); }).on('mouseleave','> div:not(.selected)',function() { thisRow($dir_list.find('a[href*="'+ thisLink(this) +'"]')).removeClass('hovered'); }); // HOVER Dir_list_row and highlight corresponding grid item $dir_list_row.hover(function() { if ( $content_grid.is(':visible') ) { $content_grid.find('[href*="'+ thisLink(this) +'"]').closest('div').addClass('hovered'); } }, function() { if ( $content_grid.is(':visible') ) { $content_grid.find('.hovered').removeClass('hovered'); } }); //***** AUTOLOAD CONTENT: index files or files from the file shortcut list *****// function autoSelectFile() { let $query_prefs = getQueryPrefs(); let $UI_pref_selected = ( $query_prefs.get('selected') === null ? '' : $query_prefs.get('selected') ); if ( getQuery('file') !== undefined && getQuery('file').length > 0 && window.top == window.self ) { // load individual files clickRow( $dir_list.find('a[href*="'+ getQuery('file') +'"]').closest('tr').attr('id') ); removeQuery('file'); } else if ( $UI_pref_selected !== '' && !$body.hasClass('has_media') ) { clickRow( $dir_list.find('tr.dir:not(.invisible)').eq($UI_pref_selected).attr('id') ); } else if ( $body.hasClass('autoload_index_files') && $dir_list.find( 'a[href*="/index."]').length > 0 ) { // else load index file clickRow( $dir_list.find('a[href*="/index."]').closest('tr').attr('id') ); } else { // else select first non-media item // clickRow( $dir_list.find('tbody tr:not(.media):not(.invisible)').first() ); } if ( $body.hasClass('autoload_media') && $body.hasClass('has_media') ) { // else if audio and images, load cover art // showAudio( firstRowID('.audio,.video') ); clickRow( firstRowID('.audio,.video') ); if ( $playing_file() ) { scrollThis('tbody','playing'); } } if ( $selected_file() ) { scrollThis('tbody','selected'); } } // Autoload Cover Art function getImageNames() { let image_names = []; $image_files.each(function() { let name = $(this).find('td.name').attr('data-name'); name = name.slice(0,name.lastIndexOf('.')); image_names.push( name ); }); return image_names; } function getCoverArtID() { const cover_names = ['cover','front']; const image_names = getImageNames(); for ( let cover_name of cover_names ) { if ( image_names.includes(cover_name) ) { // file name = a cover name return $image_files.eq( image_names.indexOf(cover_name) ).attr('id'); } else if ( image_names.some( name => name.startsWith(cover_name)) ) { // file name starts with a cover name return $image_files.find('td.name[data-name^="'+ cover_name +'"]').closest('tr').attr('id'); } else if ( image_names.some( name => name.indexOf(cover_name) > 0 ) ) { // file name includes a cover name return $image_files.find('td.name[data-name*="'+ cover_name +'"]').closest('tr').attr('id'); } else { // else use first image return $image_files.first().attr('id'); } } } function autoLoadCoverArt() { // autoload cover art for audio if dir contains audio and images, and audio is loaded and non-image content is not loaded if ( $body.hasClass('has_audio') && $body.hasClass('has_images') && $body.hasClass('autoload_media') ) { let $coverID = getCoverArtID(); if ( $coverID !== undefined ) { let row = getElById($coverID); showContent(row); row.addClass('loaded'); } } } //***** KEYBOARD EVENTS *****// $body.on('keydown',$dir_list,function(e) { const $selected = $selected_file(); if ( $('#content_source').is(':focus') || $('#content_font div').is(':focus') && e.key !== 'Escape' ) { return; } // Disable all keydown events except return and tab when warning is shown if ( $('body').hasClass('has_warning') ) { if (e.key !== 'Enter' && e.key !== 'Tab' && e.key !== 'Shift' ) { e.preventDefault(); return false; } if ( e.key === 'Enter' ) { e.preventDefault(); e.stopPropagation(); $('#warnings').find('button.focus').click(); } if ( e.key === 'Tab' ) { e.preventDefault(); e.stopPropagation(); if ( $('#warnings').find('button.focus').length === 0 || $('#warnings').find('button.focus').prev('button').length === 0 ) { $('#warnings').find('button').last('button').focus().addClass('focus').siblings().removeClass('focus').blur(); } else { $('#warnings').find('button.focus').prev('button').focus().addClass('focus').siblings().removeClass('focus').blur(); } } } $(':focus').blur(); // Need this to able to select grid items after clicking close button (or other buttons). switch ( e.key ) { case 'ArrowUp': if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { // Cmd/Ctrl + up arrow = go to parent directory if ( $('#parents_dir_menu + ul a').length < 1 ) { return; } else { showWarning( 'clickThis', $('#parent_dir_menu').attr('id') ); } break; } if ( $('*[contentEditable="true"]').is(':focus') ) { // Allow arrow navigation within content_editable elements return; } e.preventDefault(); showWarning( 'indexNavigation', 'ArrowUp' ); break; case 'ArrowDown': if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey && $selected.hasClass('app') && $settings.apps_as_dirs === false ) { // Ignore Cmd/Ctrl + arrow or if focused element is content editable or open dir return; } else if ( $('*[contentEditable="true"]' ).is(':focus') ) { return; } else if ( (e.ctrl || e.metaKey) && $selected.hasClass('dir') ) { $selected.find('a').trigger('dblclick'); break; } e.preventDefault(); showWarning( 'indexNavigation', 'ArrowDown' ); break; case 'ArrowLeft': if ( (e.ctrl || e.metaKey) || (e.ctrl && e.metaKey) ) { return; } else if ( $('*[contentEditable="true"]').is(':focus') ) { // Ignore Cmd/Ctrl + arrow or if focused element is content editable return; } if ( (e.altKey && e.shiftKey) || e.altKey && !e.metaKey && !e.ctrlKey ) { // Skip audio 30s/10s: Opt-Shift-Arrow/Opt-Arrow mediaSkip(e); return; } else { showWarning( 'indexNavigation','ArrowLeft' ); } break; case 'ArrowRight': if ( e.metaKey && !e.altKey && !e.shiftKey && $selected.hasClass('dir') ) { // Open dir with Cmd/Ctrl + Right Arrow $selected.find('a').trigger('dblclick'); return; } if ( (e.ctrl || e.metaKey) || (e.ctrl && e.metaKey) ) { // Ignore Cmd/Ctrl + arrow or if focused element is content editable return; } else if ( $('*[contentEditable="true"]').is(':focus') || $selected.hasClass('dir ignore') ) { return; } if ( (e.altKey && e.shiftKey) || e.altKey && !e.metaKey && !e.ctrlKey ) { // Skip audio 30s/10s: Opt-Shift-Arrow/Opt-Arrow mediaSkip(e); return; } else { showWarning( 'indexNavigation','ArrowRight' ); } break; case ' ': // space if ( $content_pane.hasClass('has_audio') || $content_pane.hasClass('has_video') ) { // Play/pause media (space bar) e.preventDefault(); playPauseMedia(); } else { alphaNav(e); } break; case 'Enter': // Open directories (or ignore) if ( $selected.hasClass('app') && $settings.apps_as_dirs === false ) { break; } else { if ( $selected.hasClass('dir') ) { $selected.find('a').trigger('dblclick'); } else if ( $selected.hasClass('playing') || $selected.hasClass('video') ) { // content_audio or content_video playPauseMedia(); } else { $selected.click(); } } break; // Alphabetical navigation case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'f': case 'h': case 'j': case 'k': case 'l': case 'm': case 'n': case 'p': case 'q': case 's': case 't': case 'u': case 'v': case 'x': case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '`': case '~': case '!': case '@': case '#': case '$': case '%': case '^': case '&': case '*': case '(': case ')': case '+': case '[': case ']': case '{': case '}': /*case '\\':*/ case '|': case '/': case '.': case ',': case '?': case '–': case '—': case '\'': case '"': case '“': case '”': case '‘': case '’': case '…': case 'π': case '∫': case '∂': case 'ƒ': case '©': case '˙': case '∆': case '˚': case 'µ': case '®': case 'ß': case '†': case '√': case '∑': case '≈': case '¥': case 'Ω': case '¡': case '™': case '£': case '¢': case '∞': case '§': case '¶': case '•': case 'ª': case 'º': case '≠': case '⁄': case '€': case '‹': case '›': case 'fl': case '‡': case '°': case '·': case '‚': case '±': case '¯': case '˘': case '¿': case 'ı': case '': case '´': case '˝': case 'ˆ': case '': case '˜': case '‰': case 'ˇ': case '¨': case '◊': case '„': case '˛': case '¸': // case 'α': case 'β': case 'γ': case 'δ': case 'ε': case 'ζ': case 'η': case 'θ': case 'ι': case 'κ': case 'λ': case 'μ': case 'ν': case 'ξ': case 'ο': case 'π': case 'ρ': case 'ς': case 'σ': case 'τ': case 'υ': case 'φ': case 'χ': case 'ψ': case 'ω': case 'ϑ': case 'ϒ': case 'ϖ': // case 'Α': case 'Β': case 'Γ': case 'Δ': case 'Ε': case 'Ζ': case 'Η': case 'Θ': case 'Ι': case 'Κ': case 'Λ': case 'Μ': case 'Ν': case 'Ξ': case 'Ο': case 'Π': case 'Ρ': case 'Σ': case 'Σ': case 'Τ': case 'Υ': case 'Φ': case 'Χ': case 'Ψ': case 'Ω': case 'Θ': case 'ϒ': if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case 'd': // Cmd/Ctrl + D: Toggle Details if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $show_details.click(); } else { alphaNav(e); } break; case 'e': // Cmd/Ctrl + E: Show Text Editor if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $('#text_editor_row').find('a').click(); } else { alphaNav(e); } break; case 'g': // Cmd/Ctrl + G: Show image Grid if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $grid_btn.click(); } else { alphaNav(e); } break; case 'i': // Cmd/Ctrl + I: Toggle Invisibles if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $inv_checkbox.find('input').click(); } else { alphaNav(e); } break; case 'o': // Cmd/Ctrl + Shift + O: Open selected item in new window if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && e.shiftKey && !e.altKey ) { window.open( thisLink($selected_file()) ); } else { alphaNav(e); } break; case 'r': // Cmd/Ctrl + Shift + R: Refresh if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $('#reload_btn').click(); } else { alphaNav(e); } break; case 'w': // Close content pane if Close button visible with Cmd/Crtl + W if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { if ( $content_pane.attr('class').indexOf('has_') > -1 ) { e.preventDefault(); $('#close_btn').click(); } } else { alphaNav(e); } break; case '\\': if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $('#toggle_split_view').click(); } else { alphaNav(e); } break; case '=': if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $('#increase').click(); } else { alphaNav(e); } break; case '-': if ( (navigator.platform.match('Mac') ? e.metaKey && !e.ctrlKey : e.ctrlKey) && !e.shiftKey && !e.altKey ) { e.preventDefault(); $('#decrease').click(); } else { alphaNav(e); } break; case 'tab': break; case 'Escape': $('*:focus').blur(); break; } // end switch }); // ***** END KEYBOARD EVENTS ***** // // ***** GRID SETUP ***** // // Create Font Grid Items function fontGridItems() { let $font_grid_items_arr = []; let $font_files = $dir_list_body.find('.font'); let fontGridStyles = $font_grid_styles.sheet; for ( let i = 1; i < $font_files.length; i++ ) { let newGridItem = showFont($font_files[i],true,fontGridStyles); $font_grid_items_arr.push( newGridItem ); } return $font_grid_items_arr; } // Create Image Grid Items function imageGridItems() { let $image_grid_items_arr = []; let $image_files = $dir_list_body.find('.image'); for ( let i = 0; i < $image_files.length; i++ ) { const $this_link = thisLink($image_files[i]); const exts = $row_types.image.filter( ext => $.inArray(ext, $row_settings.ignore) == -1 ); // decide which image files can be displayed const $title_name = $this_link.slice($this_link.lastIndexOf('/') + 1); if ( $.inArray( thisExt($image_files[i]), exts ) > -1 ) { // if this row file ext is in the image extension array let item = '
    '; $image_grid_items_arr.push( item ); } } return $image_grid_items_arr; } // Make Grids function makeGrids(el) { closeGrid(); $content_pane.removeClass('has_hidden_grid').addClass('has_grid'); if ( el.attr('id') === 'show_font_grid' || !$body.hasClass('has_images') ) { // only show font grid $title.removeClass().addClass('font_grid'); $content_grid.addClass('has_font_grid'); $content_grid.append( fontGridItems() ); } else if ( el.attr('id') === 'show_image_grid' || !$body.hasClass('has_fonts') ) { // only show image grid $title.removeClass().addClass('image_grid'); $content_grid.addClass('has_image_grid'); $content_grid.append( imageGridItems() ); } else { // show grid of both images and fonts $title.removeClass(); if ( $body.hasClass() ) { $content_grid.addClass('has_image_grid'); } else { $content_grid.addClass('has_grid'); } $content_grid.append( imageGridItems(), fontGridItems() ); } } // Click grid button $sidebar_header.on('click', '#grid_btn, #show_font_grid, #show_image_grid', function(e) { e.stopPropagation(); makeGrids($(this)); showGrid(); }); // ***** SCALE PREVIEWED IMAGES & FONTS ***** // // Scale Fonts function scaleFonts(incr, y) { const $em = parseInt(getComputedStyle(document.body).fontSize); // pts/em const getFontSize = function(el) { return parseFloat(el.css('font-size')); }; if ( y === 'decrease' ) { incr = 1/incr; } if ( $content_pane.hasClass('has_grid') && ( $content_grid.hasClass('has_font_grid') || $content_grid.hasClass('has_grid') ) ) { $content_grid.css({'font-size':( getFontSize($content_grid)/$em * incr ) +'em'}); return; } if ( $content_pane.hasClass('has_font') ) { $content_font.css({'font-size':( getFontSize($content_font)/$em * incr ) +'em'}); return; } } // Scale Images function scaleImages(incr, y) { if (y === 'decrease' ) { incr = 1/incr; } if ( $content_pane.hasClass('has_image') || $content_pane.hasClass('has_zoom_image') && !$content_pane.hasClass('has_grid') ) { var $image_width = Math.round( $content_image.width() ) * incr; // increment image size var $image_height = Math.round( $content_image.height() ) * incr; // increment image size $content_pane.removeClass('has_zoom_image').addClass('has_image'); $content_image.css({'width':$image_width +'px', 'height': $image_height +'px', 'max-width':'none', 'max-height':'none' }); $content_container.scrollLeft( ( $image_width - $(window).width() )/2 ) ; // if image is wider or taller than the window height, adjust position to enable scrolling: if ( ( ( $image_width - $(window).width() )/2 ) > 0 ) { $content_image.css({'left':0}); } else { $content_image.css({'left':'unset'}); } if ( ( ( $image_height - $(window).height() )/2 ) > 0 ) { $content_image.css({'top':0}); } else { $content_image.css({'top':'unset'}); } return; } if ( $content_pane.hasClass('has_grid') && ( $content_grid.hasClass('has_image_grid') || $content_grid.hasClass('has_grid') ) ) { let $image_grid_item_width = Number.parseFloat( $('.image_grid_item img').width(),10) * incr; let $image_grid_item_height = Number.parseFloat( $('.image_grid_item img').height(),10) * incr; let $image_grid_item_maxwidth = Number.parseFloat( $('.image_grid_item img').css('maxWidth'),10) * incr; let $image_grid_item_maxheight = Number.parseFloat( $('.image_grid_item img').css('maxHeight'),10) * incr; // prevent reducing grid image size on first scale click: if ( $image_grid_item_width < $image_grid_item_maxwidth ) { $image_grid_item_width = $image_grid_item_maxwidth; } if ( $image_grid_item_height < $image_grid_item_maxheight ) { $image_grid_item_height = $image_grid_item_maxheight; } // set grid properties $content_grid.css({'grid-template-columns':'repeat(auto-fill, minmax('+ ($image_grid_item_width +16) +'px, auto ) )'}); $content_grid.find('img').css({'max-width':( $image_grid_item_width ) +'px', 'max-height':( $image_grid_item_height ) +'px'}); return; } } // Scale Fonts and Images function scalePreviewItems(y) { // combine scaling into one function scaleImages( 1.125, y ); scaleFonts( 1.125, y ); } // Scale Content $('#scale').on('click','span',function(e) { e.preventDefault(); e.stopPropagation(); let val = ( $(this).attr('id') === 'increase' ? 'increase' : 'decrease' ); scalePreviewItems(val); }); // Zoom Images on click function zoomImage(e) { const $this_link = $content_image.attr('src'); const $offset = $content_image.offset(); const $this_width = $content_image.width(); const $this_height = $content_image.height(); const percentX = ( e.pageX - $offset.left ) / $this_width; const percentY = ( e.pageY - $offset.top ) / $this_height; if ( ( $content_image.attr('style') !== '' || $content_image.attr('style') !== undefined ) ) { $content_image.attr('style',''); } if ( $this_link !== undefined ) { getDimensions( $this_link, function( width, height ) { if ( width < $content_container.width() && height < $content_container.height() ) { // don't zoom small images $content_pane.removeClass('has_zoom_image').addClass('has_image'); // remove zoom classes in case window resized after zoom } else if ( width > $content_container.width() && height < $content_container.height() ) { // scroll-x to click position, center vertically $content_pane.toggleClass('has_image has_zoom_image'); if ( $content_pane.hasClass('has_image') ) { $content_image.css({'margin-top':0}); } else { $content_image.css({'margin-top': ($content_container.height() - $content_image.height() )/2 }); } $content_container.scrollLeft( width * percentX - ( $content_container.width() * percentX ) ) ; } else if ( width < $content_container.width() && height > $content_container.height() ) { // center horizonally $content_pane.toggleClass('has_image has_zoom_image'); if ( $content_pane.hasClass('has_image') ) { $content_image.css({'margin-left':0}); } else { $content_image.css({'margin-left': ($content_container.width() - $content_image.width() )/2 }); } $content_container.scrollTop( height * percentY - ( $content_container.height() * percentY ) ); } else { $content_pane.toggleClass('has_image has_zoom_image'); $content_container.scrollLeft( width * percentX - ( $content_container.width() * percentX ) ) ; $content_container.scrollTop( height * percentY - ( $content_container.height() * percentY ) ); } }); } } $content_image.on('click', function(e) { zoomImage(e); }); // ***** END SCALE PREVIEW ITEMS ***** // // ***** AUDIO CONTENT ***** // // Update Playlist function updatePlaylist() { let playlist = []; $audio_files.not('.unchecked').each(function() { playlist.push( thisID( $(this) ) ); }); return playlist; } // Randomize Shuffle List function shuffleArray(array) { for ( let i = array.length - 1; i > 0; i-- ) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; } // Attach Shuffle List data to $audio_player function updateShuffleList(id) { if ( !$body.hasClass('shuffle_audio') ) { return; } else if ( id !== undefined ) { // don't include .playing and .unchecked track in shufflelist let shuffleList = $audio_player.data('shufflelist'); if ( $(document.getElementById(id)).hasClass('unchecked') || $(document.getElementById(id)).hasClass('playing') ) { shuffleList.splice(shuffleList.indexOf(id), 1); $audio_player.data('shufflelist',shuffleList); } else { shuffleList.push(id); shuffleList = shuffleArray( shuffleList ); } } else { let shuffleList = shuffleArray( updatePlaylist() ); $audio_player.data('shufflelist',shuffleList); } } // Check/Uncheck Audio/Video Files function toggleChecked(e) { e.stopPropagation(); $(this).blur(); thisRow(this).toggleClass('unchecked'); updateShuffleList(thisRow(this).attr('id')); } $media_files.on('click','input', toggleChecked ); // Check/Uncheck all Audio/Video Files function toggleAllChecked(e) { e.stopPropagation(); $dir_list_row.find('input').trigger('click'); updateShuffleList(); } $dir_list.find('#play_toggle').on('click', toggleAllChecked ); // Is Playing function isPlaying(el) { return (el !== undefined && el.get(0).currentTime > 0 && !el.get(0).paused && !el.get(0).ended); // returns true if all conditions are true } // Play Media function playMedia(task) { if ( $playing_file().hasClass('audio') ) { $audio_player.trigger(task); } else { $content_video.trigger(task); } } // Skip media tracks +/-10/30 seconds function mediaSkip(e) { const factor = ( e.key === 'ArrowLeft' ? -1 : 1 ); // forward or backward? const skip = ( e.altKey && e.shiftKey ? 30 : e.altKey ? 10 : null ); // 30s or 10s? const $player = ( $playing_file().hasClass('audio') ? $audio_player : $content_video ); // audio or video? const time = $player.prop('currentTime'); // current time $player.prop('currentTime', time + factor*(skip)); // set time } // Play/Pause Audio/Video function playPauseMedia() { let $player = ( $content_pane.hasClass('has_audio') ? $('#audio') : $('#content_video') ); if ( isPlaying( $player ) ) { $player.trigger('pause'); } else { $player.trigger('play'); } } // Play Next Track function playPrevNextTrackBtn(el) { let key = ( el.attr('id') === 'prev_track' ? 'ArrowLeft' : 'ArrowRight' ); playPrevNextTrack(key); } // Prev/Next Track buttons $('.prev_next_track_btn').on( 'click', function() { playPrevNextTrackBtn( $(this) ); }); // Toggle Shuffle Play $('#checkbox_div').on('click','#shuffle', function() { $body.toggleClass('shuffle_audio'); updateShuffleList(); if ( $body.hasClass('shuffle_audio') && $('.playing').length === 0 ) { playPrevNextTrack('ArrowRight'); } else { // do nothing: i.e., allow current track to continue playing } }); // Toggle Loop Play $('#checkbox_div').on('click','#loop', function() { $body.toggleClass('loop_audio'); document.getElementById('audio').toggleAttribute('loop'); }); // Initialize Audio function initMedia() { $('#audio, #content_video').on('ended', function() { playPrevNextTrack('ArrowRight'); scrollThis('tbody','playing'); }); } // ***** END AUDIO PLAYBACK ***** // // ***** IFRAME SETUP ***** // // For directory display or editable text files // If row is a directory, set up iFrameDirUI(); if it's an editable text document, set up iFrameTextEditingUI(). function setUpIframeUI(bool) { if ( window.self !== window.top ) { const $textFiles = $row_types.markdown.concat($row_types.text, $row_types.code); // define which files are editable // if selected index item is a directory, set up the directory UI.... if ( window.location.pathname.endsWith('/') ) { iFrameDirUI( $('#iframe_body') ); } if ( JSON.parse(bool) === true && $textFiles.includes( window.location.pathname.slice( window.location.pathname.lastIndexOf('.') + 1 ) ) ) { $iFrame_head.append(''); $iFrame_head.append(''); let splitClass = ( getQuery('split_view') === 'true' ? 'split_view' : '' ); let viewClass = getQuery('default_text_view'); TextEditing( $('body:not(#top)') ); $iframe_body.removeClass().addClass(splitClass).addClass(viewClass).prepend($warnings); $('#content_source').removeClass().prop('disabled',false); } } } // IFRAME DIRECTORY Prep function iFrameDirUI(el) { // el = iframeBody let queryPrefs = window.location.search; queryPrefs = queryPrefs.slice(1).split('&'); let sortPref = queryPrefs[0].slice(queryPrefs[0].indexOf('=') + 1); // sort determined by parent's current sorting pref let numbersPref = queryPrefs[1]; numbersPref === 'show_numbers=true' ? $('#iframe_body').addClass('show_numbers') : null; $iFrame_head.find('style').remove(); $iFrame_head.append(''); let parentLink = decodeURIComponentSafe(window.location.pathname); parentLink = parentLink.split('/').slice(0,-2).join('/'); const parentLinkCell = 'Parent Directory'; const sortingRow = 'NameDefaultSizeDateKindExt'; const preppedIndex = makeNewIndex('#iframe_body',sortPref); const iFrameTable = $(''+ parentLinkCell + sortingRow +'
    '); // append prepped index el.empty().append(iFrameTable).find('tbody').append(preppedIndex); $('#iframe_body').find('#tbody').css({'top':$('#iframe_body').find('#thead').height() + 1 +'px'}); $('#iframe_body').data('sort_direction',1).find('#dir_list').addClass('sort_by_'+ sortPref); } // IFRAME Directory sorting $('#iframe_body').on('click','.sorting', function() { const $dir_list_row = $('#iframe_body').find('#tbody').find('tr'); const id = $(this).attr('id'); if ( $('#iframe_body').data('sorting') !== id ) { // if clicking sorting item for the first time $('#iframe_body').data('sorting',id); $('#iframe_body').data('sorting',id).data('sort_direction', 1 ); $(this).removeClass('down'); } else { // clicking the same sorting item again -- reverse sort order $('#iframe_body').data('sort_direction', $('#iframe_body').data('sort_direction') * -1 ); $(this).toggleClass('down'); } const sort_direction = $('#iframe_body').data('sort_direction'); const $sorted_index = sortDirList( $dir_list_row, id, sort_direction ); $('#iframe_body').find('#dir_list').removeClass().addClass(id).find('#tbody').empty().append($sorted_index); }); //***** TEXT EDITING PANE *****// function textEditorUI(el) { // if ( el.attr('id') === 'content_text' && $content_text.children().length === 0 ) { // only add UI once $body.addClass('has_text'); $content_pane.removeClass('has_dir'); TextEditing($content_text); el.find('#content_preview').html(el.find('#content_source').val()); // make sure any source text is also previewed. if ( getQuery('split_view') === 'true' || getQuery('default_text_view') === 'source_text' ) { el.find('#content_source').focus(); } } else { // show text editor $body.addClass('has_text').removeClass('has_hidden_text'); } setContentTitle(); setContentHeight(); } // show text editor pane $('#text_editor, #text_editor_row a').on('click', function(e) { e.preventDefault(); textEditorUI($content_text); }); // Main Text Editing Function function TextEditing(container_el) { // container_el = $content_text or $content_iframe body const $srctxt = ( container_el.find('> pre').length ? container_el.find('> pre').text() : container_el.html() ); // source text equals file content or nothing MDbuildUI(container_el); const $toolbar = container_el.find('#toolbar'); const $source = container_el.find('#content_source'); const $preview = container_el.find('#content_preview'); const $MDhandle = container_el.find('#text_editing_handle'); MDsetupTextEditingUI(container_el,$srctxt); // Toolbar button functions $toolbar.on('click','li,span',function(e) { e.stopPropagation(); MDtoolBarFunctions($(this)); }); $(window).on('resize',function() { $source.add($preview).add($MDhandle).attr('style',''); }); $('body#top').on('input', '#content_source', function() { $source.add($preview).css({'height':$('#main_content').height() - $('#content_header').height() - 32 }); }); // Resize $MDhandle.on('mousedown', function(e) { e.stopPropagation(); MDresizeSplit($MDhandle,$source,$preview); }); // Click labels to toggle checkboxes $preview.add($toolbar).on('click','label', function(e) { e.stopPropagation(); $(this).siblings('input').click(); }); // Sync scroll $source.on('scroll',function() { MDsyncScroll(this); }); $preview.on('scroll',function() { MDsyncScroll(this); }); // TEXT EDITING // Generate Preview const $source_text = ( $source.length === 0 ? '' : $source.val() ); MDmarkdown( $source_text, $preview ); // Live preview update, and set edited classes for unsaved warning $source.on('input', function() { if ( !$('body').hasClass('edited') && $(this).parents('#top').length === 1 ) { $('body#top').addClass('edited'); } if ( !$('body').hasClass('edited') && $(this).parents('#iframe_body').length === 1 ) { $('body#iframeBody').addClass('edited'); sendMessage('top','iframe_edited','',''); } MDlivePreview($source,$preview); }); // Checklists MDsetChecklistClass(); // Live checkboxes $preview.on('click','.checklist input',function(e) { e.stopPropagation(); MDliveCheckBoxes($(this),$source,$preview); }); // Preview TOC click navigation $preview.on('click','.table-of-contents a',function(e) { e.preventDefault(); MDtocClick($(this),$preview); }); $preview.on('click','.uplink',function(e) { e.stopPropagation(); MDheaderClick($preview); }); } ///// END MAIN MD FUNCTION // MARKDOWN Functions // MD Build UI function MDbuildUI(container_el) { const toggleSplitBtn = $('
  • '); const syncScrollEl = $('
  • '); const toggleSrcBtn = $('
  • '); const togglePreviewBtn = $('
  • '); const clearTextBtn = $('
  • Clear
  • '); const saveBtn = $('
  • Save SourceSave HTML
  • '); const buttonsCont = $('
      '); buttonsCont.append(toggleSrcBtn, togglePreviewBtn, toggleSplitBtn, syncScrollEl, saveBtn, clearTextBtn); const textEditingUI = '
      '; // append the UI to the container_el container_el.prepend(buttonsCont).append(textEditingUI); } // MD Set up UI function MDsetupTextEditingUI(container_el,sourceText) { container_el.find('pre').first().remove(); container_el.find('#content_source').val(sourceText); // set source text from pre if ( getQuery('split_view') === 'true' ) { $('body').addClass('split_view'); } else { $('body').removeClass('split_view'); } if ( getQuery('default_text_view') === 'preview' ) { $('body').addClass('preview_text').removeClass('source_text'); } else { $('body').addClass('source_text').removeClass('preview_text'); } if ( getQuery('sync_scroll') === 'true' ) { $('#sync_scroll input').prop({checked:true}); } } // MD UI Buttons functions function MDtoolBarFunctions(btn) { let $thisFileName; let container_el = btn.closest('body'); let sourceEl = container_el.find('#content_source'); let previewEl = container_el.find('#content_preview'); if ( $body.hasClass('has_text') ) { $thisFileName = 'untitled'; } else { $thisFileName = decodeURI(window.location.pathname.slice(window.location.pathname.lastIndexOf('/') + 1)); } const $thisId = btn.attr('id'); const $saveHTMLOpen = ''; const $saveHTMLClose = ''; switch ($thisId) { case 'toggle_split': $('body').toggleClass('split_view').find('#content_source,#content_preview,#text_editing_handle').attr('style',''); if ( container_el.hasClass('source_text') ) { sourceEl.focus(); document.getElementById('content_source').setSelectionRange(0,0); } break; case 'show_source': container_el.removeClass('split_view preview_text').addClass('source_text').find('#content_source,#content_preview,#text_editing_handle').attr('style',''); // remove styles in case split has been resized sourceEl.css({'width':'100%'}).focus(); document.getElementById('content_source').setSelectionRange(0,0); break; case 'show_preview': container_el.removeClass('split_view source_text').addClass('preview_text').find('#content_source,#content_preview,#text_editing_handle').attr('style',''); break; case 'clear_text': container_el.addClass('has_warning').find('#warnings').removeClass().addClass('clear'); break; case 'save_text': saveMD( $thisFileName, sourceEl.val() ); break; case 'save_HTML': saveMD( $thisFileName.slice(0,$thisFileName.lastIndexOf('.') + 1) + 'html', $saveHTMLOpen + MDprepHTML(previewEl.html()) + $saveHTMLClose ); break; } } // MD Custom pre- and post-processing for text. function MDaddHeaderIDs(match, p1, p2, p3, offset, string) { // create header ids for TOC return ''+ p3; } function MDcustomPreProcess(src) { return src; // we're not doing anything here just yet... } function MDcustomPostProcess(html) { html = html.replace(/<(p|li|dt|dd)>\-*\s*\[\s*x\s*\]\s*(.+?)<\/(p|li|dt|dd)>$/gm,'<$1 class="checklist">') // checkboxes in p,li,dt,dd .replace(/<(p|li|dt|dd)>-*\s*\[\s{1,}\]\s*(.+?)<\/(p|li|dt|dd)>$/gm,'<$1 class="checklist">') // checkboxes // .replace(/
    • "/g,'

    • ') .replace(/^]*)>([^<]+)/gm, MDaddHeaderIDs) // add header IDs; .replace(/<\/h(\d)>/g,''); return html; } //MD Render markdown from preprocessed source text function MDmarkdown(sourceText,previewEl) { const MDit = window.markdownit({linkify:false,typography:false,html:true}) .use(window.markdownitMultimdTable, {enableMultilineRows: true}) .use(window.markdownitSub) .use(window.markdownitSup) .use(window.markdownitFootnote) .use(window.markdownitCentertext) .use(window.markdownitDeflist) .use(window.markdownitTocDoneRight) ; let MDpreview = MDit.render( MDcustomPreProcess( sourceText ) ); previewEl.html( MDcustomPostProcess( MDpreview ) ); // set previewed html } // MD Live preview, add edited warning function MDlivePreview(sourceEl,previewEl) { MDmarkdown( sourceEl.val(),previewEl ); MDsetChecklistClass(); } // MD Live Checkboxes prep: find each instance of [ ] or [x] and replace text in index = to clicked checkbox in Preview. function MDreplaceAt(str, replacement, position) { str = str.substring(0, position) + replacement + str.substring(position + replacement.length); return str; } function MDreplaceNthSubStr(str,substr,replacement,index) { let count = 0; let found = substr.exec(str); while ( found !== null ) { if ( count === index ) { return MDreplaceAt(str, replacement, found.index ); } else { count++; found = substr.exec(str); } } } // MD Live Checkboxes function MDliveCheckBoxes(checkbox,sourceEl,previewEl) { $('.checklist').removeClass('clicked'); checkbox.closest('p,li,dt,dd').addClass('clicked'); const thisIndex = previewEl.find('.checklist').index( $('.clicked') ); const srctext = sourceEl.val(); const substr = new RegExp(/\[\s*.\s*\]/g); const replacement = ( checkbox.is(':checked') ? '[x]' : '[ ]' ); sourceEl.val( MDreplaceNthSubStr(srctext, substr, replacement, thisIndex) ); } // MD Checkbox list class: Prevent checkbox lists from having list bullets function MDsetChecklistClass() { $('input[type="checkbox"]').closest('ul').addClass('no_list'); } // MD Resize Split View function MDresizeSplit(handle,sourceEl,previewEl) { let $sidebarWidth = $('#sidebar').outerWidth(); let $pageWidth = window.innerWidth; $(document).on('mousemove',function(e) { e.stopPropagation(); e.preventDefault(); let pageX = e.pageX; if ( pageX > $sidebarWidth + 100 && pageX < $pageWidth - 100 ) { // min widths handle.css({'left': pageX - $sidebarWidth - 4 + 'px'}); sourceEl.css({'width': pageX - $sidebarWidth + 'px'}); previewEl.css({'left': sourceEl.outerWidth() + 'px'}); } }); handle.on('mouseup',function() { $(document).off('mousemove'); }); } // MD UI Sync Scroll function MDpercentage(el) { return (el.scrollTop / (el.scrollHeight - el.offsetHeight)); } function MDsyncScroll(el1) { let el2 = ( el1.getAttribute('id') === 'content_preview' ? document.getElementById('content_source') : document.getElementById('content_preview') ); if ( document.querySelector('input[name="sync_scroll"').checked ) { el2.scrollTo( 0, (MDpercentage(el1) * (el2.scrollHeight - el2.offsetHeight)).toFixed(0) ); // toFixed(0) prevents scrolling feedback loop } } // click TOC anchors function MDtocClick(el,previewEl) { let thisId = el.attr('href'); if ( thisId ) { previewEl.scrollTop( $(thisId).offset().top - 48 ); } } // click Headers to return to TOC or top function MDheaderClick(previewEl) { if ( previewEl.find('.table-of-contents').length > 0 ) { document.getElementsByClassName('table-of-contents')[0].scrollIntoView(true); } else { document.getElementById('preview').scroll(0,0); } } // MD Clear text source function clearText(container_el) { if ( window.top !== window.self ) { // if iframe, send message to top (to remove iframe_edited class) sendMessage('top','clear'); } container_el.find('#content_source').show().focus().val(''); container_el.find('#content_preview').empty(); container_el.removeClass('edited has_warning'); } // MD SAVE SOURCE or HTML function MDprepHTML(data) { data = data.replace(/.<\/span>/g,''); return data; } function saveMD(filename, data) { let blob = new Blob([data], {type: 'text/plain'}); let downloadEl = window.document.createElement('a'); downloadEl.href = window.URL.createObjectURL(blob); downloadEl.download = filename; document.body.appendChild(downloadEl); downloadEl.click(); document.body.removeChild(downloadEl); URL.revokeObjectURL(blob); if ( window.top !== window.self ) { // if iframe, send message to top sendMessage('top','clear'); } $('body,#content_source,#content_text').removeClass('edited'); } // list of functions to remember while sending messages and then execute after warning button click function doFunction(funcName,args) { var funcDictionary = { 'setLocation':setLocation, 'resetContent':resetContent, 'closeContent':closeContent, 'clickThis':clickThis, 'clickRow':clickRow, 'doubleClickRow':doubleClickRow, 'indexNavigation':indexNavigation, 'clearText':clearText, 'null':null }; return funcName === 'null' ? null : funcDictionary[funcName](args); } // Show warning after certain user actions if text editor or iframe has edited text; otherwise do the action. function showWarning(funcName,args) { // Don't show the warning if func = indexNavigation or clickRow; i.e., just hide text editor; // In other words, only show warning when changing directories or if iframe content has been edited if ( ( $('body').hasClass('edited') && funcName !== 'indexNavigation' && funcName !== 'clickRow' ) || $('body').hasClass('iframe_edited') ) { if ( $('body').hasClass('edited') ) { // show warning and text editor (if hidden) $body.addClass('has_warning').find('#warnings').removeClass().addClass('unloading'); $body.removeClass('has_hidden_text').addClass('has_text'); } if ( $('body').hasClass('iframe_edited') ) { // if iframe is edited, send unloading message sendMessage('iframe','unloading',funcName,args); // upon receipt of message, iframe will show its warning message, based on the funcName } } else { doFunction(funcName,args); } } // Send a message to iframe or parent function sendMessage(target,message,funcName,args) { var messageObj = { 'messageContent': message, 'functionName': funcName, 'arguments': args }; if ( target === 'iframe' ) { let contentIFrame = document.getElementById('content_iframe'); contentIFrame.contentWindow.postMessage( messageObj, '*' ); } if ( target === 'top' ) { window.parent.postMessage( messageObj, '*'); } } // Receive a message from iframe or parent, do appropriate action function receiveMessage(e) { if ( e.origin === 'null' || e.origin === $origin ) { let $message = e.data.messageContent; let funcName = e.data.functionName; let args = e.data.arguments; if ( $message === 'split_view' ) { $iframe_body.toggleClass('split_view'); } if ( $message === 'default_text_view' ) { $iframe_body.toggleClass('preview_text source_text').removeClass('split_view'); } // warn iframe that user wants to change iframes if ( $message === 'unloading' && !$iframe_body.hasClass('has_warning') ) { $iframe_body.addClass('has_warning').find('#warnings').removeClass().addClass('unloading').attr('data-function_name',funcName).attr('data-args',args); } // let top know iframe text has been edited if ( $message === 'iframe_edited' && !$('body#top').hasClass('iframe_edited') ) { $('body#top').addClass('iframe_edited'); } if ( $message === 'ignore' || $message === 'clear' ) { $('body#top').removeClass('iframe_edited'); if ( $message === 'ignore' ) { doFunction(funcName,args); } } } } window.addEventListener('message',receiveMessage,false); // Edited Warning buttons: what to do when the user clicks a warning button function editedWarningButtons(id) { let btn = $(document.getElementById(id)); let container_el = btn.closest('body'); let func = $('#warnings').attr('data-function_name'); let args = $('#warnings').attr('data-args'); switch(id) { case 'warning_ignore_btn': // do the user initiated func without saving the edited text if ( window.self !== window.top ) { // if iframe, send message to top sendMessage('top','ignore',func,args); } container_el.removeClass('edited has_text has_warning'); clearText(container_el); break; case 'warning_cancel_btn': // cancel the func container_el.removeClass('has_warning').find('#warnings').removeClass(); break; case 'warning_clear_btn': // clear the text editor clearText(container_el); break; case 'warning_save_btn': // save the text if ( window.top !== window.self ) { // if iframe, send message to top sendMessage('top','clear'); } container_el.removeClass('edited has_warning'); $('#save_text').click(); break; case 'warning_ok_btn': // clear the text editor $('body').removeClass('has_warning').find('#warnings').removeClass('local'); break; } } $('#warnings').on('click','button',function(e) { e.preventDefault(); editedWarningButtons( $(this).attr('id') ); }); // Edited Warning overlay: prevent user clicks on rest of UI $('#overlay').on('click mousedown mouseup',function(e) { e.preventDefault(); e.stopPropagation(); return; }); // END Text Editing })(); // THE END!