// ==UserScript== // @name Supercharged Local Directory File Browser // @version 3.2.5 // @description Makes file:/// directory ("Index of...") pages (and many server-generated index pages) actually useful. Adds sidebar and preview pane, keyboard navigation, audio and video player, markdown/plain text preview and editing, image and font previews and grid views, 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 file://*/?* // @include *!localhost*/ // @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: By default, userscripts will not run on file:/// urls, so for this script to work, you will have to enable it in your browser extension settings. // E.G.: For Tampermonkey in Chrome, go to Chrome the extension page, click the details button on the Tampermonkey pane and check 'Allow access to file URLs'. // NOTE: Safari does not allow local directories to be browsed, so the script will not work on local directories, but it will work on remote directories (or on local directories through a local server). // NOTE: This script was developed in Vivaldi, running on Mac OS Mojave. It has been tested in several other Chrome and Gecko-based browsers. // It has been very minimally tested on Windows and not at all on other OSes or browsers. It should work, but please report any issues. // @namespace https://greasyfork.org/users/16170 // @downloadURL none // ==/UserScript== (function() { 'use strict'; var $ = 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.). // Hint: you can add query strings to your urls to override user settings on a site by site basis. // Note that because of same-origin security concerns, the browser will not allow you to navigate from an external webpage to a local directory. // (But see this page for possible workarounds: https://stackoverflow.com/questions/39007243/cannot-open-local-file-chrome-not-allowed-to-load-local-resource) [ { "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" }, ] }, ], UI_font: // Choose an installed font for the UI. 'lucidagrande, sans-serif', UI_font_size: // Choose a default UI font size; use any standard CSS units. '13px', alternate_background: // If true (default true), alternate sidebar row background color. true, ignore_files: // 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, they will be treated as 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). true, hide_ignored_files: // If true, ignored files will be completely hidden from the file list; // If false (default), ignored files will appear greyed-out. false, hide_invisibles: // Un*x/Mac OS only: If true (default), files or directories beginning with a "." will be hidden. true, hide_details: // If true (default), hide file and directory details; if false, show them. true, default_sort: // Choose from: 'name', 'size', 'date', 'kind', 'ext', 'default'. // default = Chrome sorting: dirs on top, files alphabetical. 'default', dirs_on_top: // 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.) false, apps_as_dirs: // 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. false, dark_theme: // If true (default: false), gives the content pane a dark background, and inverts html and text content. false, grid_image_size: // Default = 200 200, grid_font_size: // Default = 1 1, autoload_media: // If true (defautl: 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). true, autoload_index_files: // If true (default: false), automatically select first "index.ext" file found in directory. false, use_custom_icons: // if true (default), use custom icons for dirs and files // if false, use browser/server default icons true, // TEXT EDITING SETTINGS preview_text: // If true (default), show rendered plain text and markdown file load; // if false, show editable source text on file load. // Note that split_view = true overrides this setting. true, split_view: // If true (default: false), show split view on plain text file load // if false, use default preview_text setting. false, sync_scroll: // Sync scrolling in split view. false //--------------------------------------------------------// // 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 = { // myCategory: ['ext1','ext2',], dir: ['/'], app: ['app/','app','exe','msi'], archive: ['zip','rar','cbr','7z','tar','gz','dmg','pkg','archive'], audio: ['mp3','m4a','aac','aif','aiff','ape','flac','ogg','wav','opus'], font: ['otf','ttf','woff','woff2','afm','pfb','pfm','tfm'], graphics: ['indd','idml','indt','icml','ai','eps','pages','qxp','qxb','qxd','mif','sla','dtp','pmd','pub','fm','book','inx'], htm: ['htm','html','xhtm','xhtml'], image: ['jpg','jpeg','png','apng','gif','bmp','webp','svg','tif','tiff','psd','raw','dng','cr2','nef','arw'], markdown: ['md','markdown','mdown','mkdn','mkd','mdwn','mdtxt','mdtext'], office: ['doc','docx','epub','xls','xlsx','xlm','odt','odf','rtf'], pdf: ['pdf'], text: ['txt','log','nfo'], code: ['bak','bash','c','cnf','codes','conf','csh','cshrc','cson','css','default','dist','example','gemspec','h','hd','ini','js','json','jsx','less','list','local','lock','login','logout','lua','old','php','pl','plist','pth','py','rb','rc','rdoc','sass','sh','strings','tcl','vue','xml','yaml','yml'], video: ['mpeg','mov','m4v','webm','mp4'], }; // $ROW_SETTINGS: Ignore or Exclude files by extension const $row_settings = { ignore: // Files with these extensions will not be loaded if selected in the sidebar (prevents the browser from attempting to download the file). ['exe','doc','docx','rtf','xls','xlsx','odt','odp','csv','msi','dll','indd','idml','pages','numbers','tif','tiff','raw','dng','cr2','nef','arw','eps','psd','ai','afm','pfb','pfm','tfm','zip','pkg','swf','pls','ics','DS_Store','ds_store','ds_store','alias','dmg','gz','qxp','icon.jpg','thumbs.db','ape','srf','epub'], exclude: // Files with these exensions will not be inverted in dark mode ['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) plus fonts. // - Preview and edit markdown and plain text files. // - 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. // - 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 + 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: // **3.2.4** More Markdown goodness // **ADDED:** Multimarkdown table syntax (https://github.com/RedBug312/markdown-it-multimd-table) // **ADDED:** Markdown `->`centered text`<-` (https://github.com/jay-hodgson/markdown-it-center-text) // **ADDED:** Markdown definition lists (https://github.com/markdown-it/markdown-it-deflist; for syntax, see http://pandoc.org/MANUAL.html#definition-lists) // **ADDED:** Github Markdown styles for preview (https://github.com/sindresorhus/github-markdown-css), with a few customizations. // **IMPROVED:** Allow checkboxes in definition lists (in both term and details). // **FIXED:** Various issues with checkboxes and live updating. // **FIXED:** Allow empty text files to be edited. // **FIXED:** Markdown preview: Clicking up arrow on hovered header will scroll to TOC inserted with `${toc}` (if present) or to top of previewed text (wasn't working before). // **FIXED:** Some long-standing bugs with image grid display. // **FIXED:** A long-standing bug with clicking left and right arrows in preview pane; only images and fonts should be selected. // **OTHER:** Improved documentation. // **3.2.3** Markdown extensions // **ADDED:** Markdown TOC (https://github.com/nagaozen/markdown-it-toc-done-right): Insert ${toc} in your text where you want the TOC to appear. // **ADDED:** Markdown footnotes (https://github.com/markdown-it/markdown-it-footnote). // **ADDED:** Markdown subscript (~sub~) (https://github.com/markdown-it/markdown-it-sub). // **ADDED:** Markdown superscript (^sup^) (https://github.com/markdown-it/markdown-it-sup). // **IMPROVED:** Added basic HTML head and body elements on save. // **IMPROVED:** Markdown: made sync-scrolling proportional. // **IMPROVED:** Markdown table styling. // **OTHER:** Added 'opus' to the default list of supported audio formats. // 3.2.2 More bug fixes. // FIXED: Markdown source text was being interpreted as HTML. // FIXED: Markdown checkboxes added to source weren't "live." // IMPROVED: Markdown live preview update on input. // IMPROVED: Markdown Nested blockquote styling. // 3.2.1 // FIXED: A bad bug with saving source text. // ADDED: Made text split-view resizable. // IMPROVED: Various UI tweaks for text editing. // 3.2.0 // **NEW!:** Preview, edit, and save Markdown and plain-text files. (Now how much would you pay? Or donate?) // - Basic Markdown syntax is rendered via markdownit.js (https://github.com/markdown-it/markdown-it). // - View editable source text or rendered HTML preview, or both in split pane. // - Live preview of source edits in split-pane view. // - Render Checkboxes/Checklists with [x] and [ ], with live updating of source text. // - Save edited source text or rendered HTML. // - More to come. // - *Caveat:* You must manually save your work if you want to keep it; autosave is not possible. // - Moreover, because of security concerns with local files, the editing iframe cannot communicate with the parent index page, or vice versa. // - * It is therefore entirely possible to navigate away from the page and LOSE YOUR WORK. * // To help prevent loss of work, the script will attempt to warn you when the editing pane loses focus (if you have made any edits), // e.g., when you click in the script sidebar or in the browser UI, or when the browser tab/window or the browser itself loses focus. // But note that if the editing pane is already unfocused, the warning will not be issued. // ADDED: New user settings: set default view for markdown/text files: source or preview, or split pane view. See user settings for details. // IMPROVED: Plain text and code file type detection. // CHANGED: Treat files without extensions as text (code) files. (Extension-less binary files will still initiate a download.) // FIXED: Malformed URI error if file name included "%". // FIXED: Some issues with image zoom. // FIXED: An issue with content pane sizing. // FIXED: An issue with parent directory navigation. // ***** GENERAL SETUP ***** // // ************************************ // // DON'T EDIT ANYTHING BELOW THIS LINE. // // ************************************ // const $userAgent = navigator.userAgent; // PATHS // Fix "%" error in file name; see https://stackoverflow.com/questions/7449588/why-does-decodeuricomponent-lock-up-my-browser function decodeURIComponentSafe(uri, mod) { var out = '', arr, i = 0, l, x; typeof mod === "undefined" ? mod = 0 : 0; arr = uri.split(/(%(?:d0|d1)%.{2})/); for (l = arr.length; i < l; i++) { try { x = decodeURIComponent(arr[i]); } catch (e) { x = mod ? arr[i].replace(/%(?!\d+)/g, '%25') : arr[i]; } out += x; } return out; } var $href = decodeURIComponentSafe(window.location.href); // complete URL including query string: http://www.host.com/path/to/my_dir/?query_string var $location = decodeURIComponentSafe( [location.protocol, '//', location.host, location.pathname].join('') ); var $location_arr = $location.split('/'); var $current_dir_path = $location.replace(/\//g,'/').replace(/_/g,'_').replace(/—/g,'—').replace(/\\/g,'/'); // URL w/o query string for display var $current_dir_name = $location.replace(/%20/g,' ').slice(0,-1); $current_dir_name = $current_dir_name.slice($current_dir_name.lastIndexOf('/') + 1); // Dir name without parents for display: "my_dir" // QUERY PREFS var getQueryPrefs = function() { return new URLSearchParams( window.location.search ); }; var $query_prefs = getQueryPrefs(); var $UI_pref_width = $query_prefs.get('width') === null ? '25' : (Math.round(100*($query_prefs.get('width'))/window.innerWidth)).toString(); // number string var $UI_pref_theme = $query_prefs.get('dark_theme') === null ? $settings.dark_theme : JSON.parse( $query_prefs.get('dark_theme') ); // bool var $UI_pref_background = $query_prefs.get('alternate_background') === null ? $settings.alternate_background : JSON.parse( $query_prefs.get('alternate_background') ); // bool var $UI_pref_details = $query_prefs.get('hide_details') === null ? $settings.hide_details : JSON.parse( $query_prefs.get('hide_details') ); var $UI_pref_sort = $query_prefs.get('sort') === null ? $settings.default_sort.toLowerCase() : $query_prefs.get('sort'); var $UI_pref_file = $query_prefs.get('file') === null ? '' : $query_prefs.get('file'); var $UI_pref_autoload_media = $query_prefs.get('autoload_media') === null ? $settings.autoload_media : JSON.parse( $query_prefs.get('autoload_media') ); var $UI_pref_split_view = $settings.split_view; var $UI_pref_preview_text = $settings.preview_text; // var $UI_pref_invisibles = $query_prefs.get('hide_invisibles') == null ? $settings.hide_invisibles.toLowerCase() : $query_prefs.get('hide_invisibles'); var $UI_pref_selected = $query_prefs.get('selected') === null ? '' : JSON.parse( $query_prefs.get('selected') ); var $UI_pref_history = $query_prefs.get('history') === null ? '' : $query_prefs.get('history'); var $UI_pref_history_arr; var $grid_image_size = $settings.grid_image_size ? $settings.grid_image_size : 150; var $grid_font_size = $settings.grid_font_size ? $settings.grid_font_size : 1; // set query key/value function setQuery(key, value) { $query_prefs = getQueryPrefs(); $query_prefs.set( key, value ); updateQuery(); } // toggle query key function toggleQuery(key) { var value; $query_prefs = getQueryPrefs(); value = $query_prefs.has(key) ? JSON.parse( $query_prefs.get(key) ) : $settings[key]; value === true ? $query_prefs.set( key, 'false' ) : $query_prefs.set( key, 'true' ); updateQuery(); } // update query string function updateQuery() { $query_prefs = decodeURIComponent($query_prefs); window.history.replaceState({}, document.title, window.location.pathname +'?'+ $query_prefs); } // Styles for iFrame Directory Index pages const $fileName = window.location.pathname.slice(window.location.pathname.lastIndexOf('/') + 1); const $textFiles = $row_types.markdown.concat($row_types.text, $row_types.code); if ( ( window.frameElement !== null || window.top !== window.self ) && window.location.href.endsWith('/') ) { const $custom_iframe_styles = document.createElement("style"); const $font_size_units = $settings.UI_font_size.replace(/\d*/,''); var $iframe_styles = 'a.up { background:transparent; }' // B + ':root, html, body { background-color:#BBB; }' + 'body > table > thead, body > table > tbody > tr, body ul li { background:rgba(221,221,221,0.5); }' + 'body > table > tbody > tr:nth-of-type(odd), body > ul > li:nth-of-type(odd) { background:rgba(221,221,221,1); }' + 'body > table > tbody > tr:hover, body > ul > li:hover:not(:first-of-type) { background:#ABABAB; }' + ':root, html, body { border:0 !important; }' + 'body > table { border-top:solid 1px #888888; }' + 'body > ul > li:first-of-type { border-bottom:solid 1px #888888; }' + 'html, body { border-radius:0; }' + 'body > table { border-collapse:collapse; }' + 'html, body { box-sizing:border-box; }' + '#parentDirLinkBox span { color:transparent; }' // C + 'a:hover { color:#000000; }' + 'a, #parentDirLinkBox span:before { color:#111111; }' + '#parentDirLinkBox span:before { content:"Parent Directory"; }' + '#UI_goUp a.up:before { display:none; }' // D + 'a, li { display:block; }' + '#UI_goUp, #UI_showHidden { display:inline-table; }' + 'body > table table a:before { float:left; }' // F + ':root, html, body, * { font-family:'+ $settings.UI_font +'; }' + 'html, body { font-size:'+ parseFloat($settings.UI_font_size) * 0.875 + $font_size_units +'; }' + 'body > div, body > table, thead, body p { font-size: 1em; }' + 'body > ul > li:first-of-type, #parentDirLinkBox span:before, #UI_goUp a { font-weight:bold; }' + 'html { height:100%; }' // H + 'body { height:auto; }' + '#UI_goUp, #UI_showHidden, #UI_showHidden label { height:1.5em !important; }' + 'body > table > tbody > tr, body > ul > li { line-height:1.5; }' // L + '#UI_goUp, #UI_showHidden { line-height:2; }' + 'body > ul { list-style:none; }' + 'html, body, body div, body > ul > li a, #UI_goUp, #UI_showHidden, #parentDirLink, #parentDirLinkBox { margin:0; }' // M + 'body > div { margin:1em; }' + 'body p { margin:1rem; }' + 'body > ul > li { margin-bottom:0; }' + '.up { margin-inline-start:0; }' + '.dir::before, .file > img { margin-inline-end: 6px; }' + 'body table tr, body ul li, body > table > tbody > tr:hover { outline:0; }' // O + ':root, html, body, body > div, body > ul > li, .up { padding:0; }' // P + 'body > table > tbody > tr > td, body > table > thead > tr > th, body > ul > li a, #parentDirLinkBox, #UI_goUp, #UI_showHidden { padding-top:3px; }' + 'body > table > tbody > tr > td:first-of-type, body > table > thead > tr > th:first-of-type, body > ul > li a { padding-right:0; }' + 'body > table th:last-of-type, body > table > tbody > tr > td:last-of-type, body > ul > li a, #parentDirLinkBox, #UI_showHidden { padding-right:1em; }' + '#parentDirLinkBox { padding-bottom:0; }' + 'body > table > tbody > tr > td, body > table > thead > tr > th, body > ul > li a, #parentDirLinkBox, #UI_goUp, #UI_showHidden { padding-bottom:3px; }' + 'body > ul { padding-left:0; }' + 'body > table > tbody > tr > td:first-of-type, body > table > thead > tr > th:first-of-type, body > ul > li a, #parentDirLinkBox, #UI_goUp { padding-left:1em; }' + 'th:not(:first-of-type) { text-align:right; }' // T + 'th:first-of-type { text-align:left; }' + 'a, a:hover, td:hover, li:hover { text-decoration:none !important; }' + 'a.icon { text-indent:2px; }' + '#UI_goUp, #UI_showHidden { vertical-align:middle; }' // V + 'html, body, body > table { width:100%; }' // W + 'thead th:first-of-type { width:50%; }' + 'html, body { max-width:100%; }' + 'html, body { min-width:100%; }'; $('body').css({'font-family':$settings.UI_font}); $('body > h1, address, body > hr').remove(); $('body > table > tbody').find('hr').closest('tr').remove(); $('body > table th:contains("Name")').css({'text-align':'left'}); $('body > table th:contains("Size")').css({'text-align':'right'}); // pre type if ( $('body > pre').length ) { let $list_items = $('body pre').html(); let $parent_dir = $('body pre').find('a:contains("Parent")').first().attr('href'); $list_items = '' + $list_items.replace(/Parent Directory<\/a>/,'').replace(/^\s*
/g,'').replace(/
').replace(/\s{2,}/g,'
') + '
'; $('body').empty().append($list_items).find('tr:first-of-type').remove(); $('body').prepend(''); } $custom_iframe_styles.appendChild(document.createTextNode("")); $custom_iframe_styles.append($iframe_styles); document.head.appendChild($custom_iframe_styles); return; // MARKDOWN FILES $row_types.markdown } else if ( ( window.frameElement !== null || window.top !== window.self ) && ( $textFiles.includes( window.location.href.slice( window.location.href.lastIndexOf('.') + 1 ) ) ) ) { // Styles const $custom_iframe_MDstyles = document.createElement("style"); var $iframe_MDstyles = 'body { margin:0; padding:32px 0 0; font-size:1rem; position:relative; }' + 'body #source, body #preview { margin:0; padding:1rem; height:100%; box-sizing:border-box; position:relative; z-index:1; border:0; overflow-y:scroll; }' + 'body.preview:not(.split) #source, body.source:not(.split) #preview, li#saveBtn div, .comment { display:none; }' + 'body.split #preview, body.split #source { width:50%; float:left; }' + 'body.split #preview { border-left:solid 1px #999; }' + 'body.split #MDhandle { width:8px; position:absolute; top:0; bottom:0; left:calc(50% - 4px); cursor:col-resize; z-index:11; }' + 'body:not(.split) #MDhandle { z-index:-1; }' + '#buttons { margin:-32px 0 0; padding:0; display:block; width:100%; position:fixed; z-index:100; background:#EEE; border-bottom: solid 1px #999; font-size:0.875em; -webkit-user-select: none; -moz-user-select: none; user-select:none; }' + '#buttons li { margin:4px; padding:4px; width:3.5em; height:100%; display:block; opacity:0.5; list-style-type:none; cursor:pointer; }' + '#buttons li:hover, body.preview:not(.split) #buttons li#showPreview, body.source:not(.split) #buttons li#showSRC, body.split #buttons li#toggleSplit, body.edited #saveBtn { opacity:1; }' + '#buttons li#toggleSplit { float:left; width:16px; height: 16px; margin: 4px 0 4px 4px; background:url("data:image/svg+xml;utf8,") center no-repeat; }' + '#buttons li#syncScroll { width:8em; float:left; opacity:1; }' + '#buttons li#syncScroll input { float:left; }' + '#buttons li#syncScroll label { width:8em; display:block; font-size:0.875em; line-height:1.5; }' + '#buttons li#showSRC { float:left; width:16px; height: 16px; margin: 4px 0 4px 8px; background:url("data:image/svg+xml;utf8, ") left 5px no-repeat; }' + '#buttons li#showPreview { float:left; width:16px; height: 16px; margin: 4px 0 4px 4px; background:url("data:image/svg+xml;utf8, ") -24px 5px no-repeat; }' + '#buttons li#saveBtn { float:right; width:20px; height: 16px; background: url("data:image/svg+xml;utf8, ") 8px 4px no-repeat; position:relative; }' + 'body.edited #buttons li#saveBtn { background: url("data:image/svg+xml;utf8, ") 8px 4px no-repeat; position:relative; }' + '#buttons li#saveBtn div { position:relative; top:-9px; left:-24px; color:#999; text-align:right; }' + '#buttons li#saveBtn:hover div { display:block; }' + '#buttons li#saveBtn span { width:6rem; padding:4px 6px; background: #EEE; float:right; display:block; border:solid 1px #999; }' + '#buttons li#saveBtn span:first-of-type { border-bottom-width:0px; }' + '#buttons li#saveBtn span:hover { color:#444; }' + '#source { width:100%; height:100%; min-height:100%; display:block; line-height:1.2; overflow-y:visible; font-family:monospace; font-size:1rem; position:relative; top:0;bottom:0; background:#EEE; resize:none; }' + '#source:focus { outline:none; background:#FFF; }' + '#preview { background:#FFF; font-size:0.875em; }' + '#preview pre { border:solid 1px #CCC; border-radius:3px; white-space:pre-wrap; word-break:break-word; font-size:1em; }' + '#preview .no_list { list-style:none; }' + '#preview > .no_list { padding:0; }' + '#preview .text-align-center { text-align:center; }' + '.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; }' + '#preview table { font-size:inherit; }' + '#preview table th { background-color:#EEE; }' ; $custom_iframe_MDstyles.appendChild(document.createTextNode("")); $custom_iframe_MDstyles.append($iframe_MDstyles); document.head.appendChild($custom_iframe_MDstyles); // append github styles $('head').append(''); // END styles // UI BUILD // Get source text first, then delete default pre, append new elements, set textarea value to source text. let $srctxt = $('body > pre').length ? $('body > pre').text() : ''; $('body').prepend('
').find('pre').first().remove(); // UI ELEMENTS: Buttons const toggleSplitBtn = $('
  • '); const syncScrollEl = $('
  • ') const toggleSrcBtn = $('
  • '); const togglePreviewBtn = $('
  • '); const saveBtn = $('
  • Save SourceSave HTML
  • '); const buttonsCont = $(''); buttonsCont.append(toggleSrcBtn, togglePreviewBtn, toggleSplitBtn, syncScrollEl, saveBtn); $('body').prepend(buttonsCont); // UI INIT const $buttons = $('#buttons'); const $source = $('#source'); const $preview = $('#preview'); const $MDhandle = $('#MDhandle'); $source.val($srctxt); $settings.split_view === true ? $('body').addClass("split") : null; $settings.preview_text === true ? $('body').addClass("preview") : $('body').addClass("source"); $settings.sync_scroll === true ? $('#syncScroll input').prop({checked:true}) : null; // UI FUNCTIONS // UI Resize Source/Preview Panes var resizeSplit = function (f) { f.stopPropagation(); var $startX = f.pageX; var $split_width = $source.width(); var $window_width = window.innerWidth; $(document).on('mousemove',function(e) { e.stopPropagation(); e.preventDefault(); var $deltaX = e.pageX - $startX; if ( e.pageX > 200 && e.pageX < $window_width - 200 ) { $MDhandle.css({'left':$split_width + $deltaX + -4 + 'px'}); $source.css({'width':$split_width + $deltaX + 'px'}); $preview.css({'width':($window_width - $split_width) - $deltaX + 'px'}); } }); $(document).on('mouseup',function() { $(document).off('mousemove'); $split_width = $source.width(); }); } $MDhandle.on('mousedown', resizeSplit ); // Click labels to toggle checkboxes $preview.add($buttons).on('click','label', function(e) { e.stopPropagation(); $(this).siblings('input').click(); }); // UI Buttons functions $buttons.on('mousedown','li,span',function(e) { e.stopPropagation(); $source.off('blur', unsavedWarning); let $name = decodeURI($fileName); let $thisId = $(this).attr('id'); let $saveHTMLOpen = ''; let $saveHTMLClose = ''; $thisId === 'toggleSplit' ? $('body').toggleClass('split').find('#source,#preview,#MDhandle').attr('style','') : $thisId === 'showSRC' ? $('body').removeClass('split preview').addClass('source').find('#source,#preview,#MDhandle').attr('style','') : $thisId === 'showPreview' ? $('body').removeClass('split source').addClass('preview').find('#source,#preview,#MDhandle').attr('style','') : $thisId === 'saveText' ? saveMD( $name, $source.val() ) : $thisId === 'saveHTML' ? saveMD( $name.slice(0,$name.lastIndexOf('.') + 1) + 'html', $saveHTMLOpen + $preview.html() + $saveHTMLClose ) : null; }); $buttons.on('mouseup','li,#saveText,#saveHTML',function(e) { e.stopPropagation(); $source.focus(); $source.on('blur', unsavedWarning); }); $('body').on('mouseover','#preview,#buttons',function(e) { e.stopPropagation(); $source.off('blur', unsavedWarning); }); $('body').on('mouseout','#preview,#buttons',function(e) { e.stopPropagation(); $source.one('blur', unsavedWarning); }); $(window).on('resize',function() { $($source,$preview,$MDhandle).attr('style',''); }); // UI Sync Scroll var el2; var percentage = function(el) { return (el.scrollTop / (el.scrollHeight - el.offsetHeight)) }; var syncScroll = function (el1) { el1.getAttribute('id') === 'preview' ? el2 = document.getElementById('source') : el2 = document.getElementById('preview'); if ( document.querySelector('input[name="syncScroll"').checked ) { el2.scrollTo( 0, (percentage(el1) * (el2.scrollHeight - el2.offsetHeight)).toFixed(0) ); // toFixed(0) prevents scrolling feedback loop } } $source.on('scroll',function() { syncScroll(this); }); $preview.on('scroll',function() { syncScroll(this); }); // END UI Functions // MARKDOWN PREVIEW var MDit = window.markdownit({linkify:false,typography:false,html:true}) // .use(window.markdownitSanitizer) .use(window.markdownitMultimdTable, {enableMultilineRows: true}) .use(window.markdownitSub) .use(window.markdownitSup) .use(window.markdownitFootnote) .use(window.markdownitCentertext) .use(window.markdownitDeflist) .use(window.markdownitTocDoneRight); // Custom pre- and post-processing for text. var addHeaderIDs = function(match, p1, p2, p3, offset, string) { // create header ids for TOC return ''+ p3; } var customPreProcess = function(src) { return src; } var customPostProcess = function(html) { html = html.replace(/<(p|li|dt|dd)>\-*\s*\[\s*x\s*\]\s*(.+?)<\/(p|li|dt|dd)>$/gm,'<$1 class="checklist">') .replace(/<(p|li|dt|dd)>\-*\s*\[\s{1,}\]\s*(.+?)<\/(p|li|dt|dd)>$/gm,'<$1 class="checklist">') .replace(/^]*)>([^<]+)/gm, addHeaderIDs) // add header IDs; .replace(/<\/h(\d)>/g,'\↑'); return html; } // Render markdown from preprocessed source text var markdown = function(src) { let MDpreview = MDit.render( customPreProcess( src ) ); $preview.html( customPostProcess( MDpreview ) ); // set previewed html } let $md = $source.length === 0 ? '' : $source.val(); markdown( $md ); // EDITING // "Live" Checkboxes $('input[type="checkbox"]').closest('ul').addClass('no_list'); var replaceAt = function(str, replacement, position) { return str = str.substring(0, position) + replacement + str.substring(position + replacement.length); } var replaceNthSubStr = function(str,substr,replacement,index) { let count = 0; let found; while ( (found = substr.exec(str)) !== null) { if ( count === index ) { return replaceAt(str, replacement, found.index ); } else { count++; } } } $preview.on('click','.checklist input',function(e) { e.stopPropagation(); $('.checklist').removeClass('clicked'); $(this).closest('p,dt,dd').addClass('clicked'); let checkboxLength = $preview.find('.checklist').length; let thisIndex = $preview.find('.checklist').index( $('.clicked') ); let srctext = $source.val(); let substr = new RegExp(/\[\s*.\s*\]/g); let replacement = $(this).is(':checked') ? '[x]' : '[ ]'; $source.val( replaceNthSubStr(srctext, substr, replacement, thisIndex) ); addEditedClass(); }); // click TOC anchors $preview.on('click','.table-of-contents a',function(e) { e.preventDefault(); let thisId = $(this).attr('href'); if ( thisId ) { $preview.scrollTop( $(thisId).offset().top - 48 ); } }); $preview.on('click','.uplink',function(e) { e.stopPropagation(); if ( $preview.find('.table-of-contents').length > 0 ) { let position = $preview.find('.table-of-contents').position(); document.getElementsByClassName('table-of-contents')[0].scrollIntoView(true); } else { document.getElementById('preview').scroll(0,0); } }); // Live preview, add edited warning $source.on('input', function(e) { addEditedClass(); markdown( $source.val() ); }); var addEditedClass = function() { if ( !$source.hasClass('edited') ) { $('#source, body').addClass('edited'); } } var unsavedWarning = function() { if ( $('#source, body').hasClass('edited') ) { let r = window.confirm('Warning! You have unsaved changes. Do you want to save the file before closing?'); if ( r == true ) { $('#saveText').trigger('mousedown'); } else { //$('#source').one('blur',unsavedWarning ); } } } $source.on('blur', unsavedWarning); // SAVE SOURCE or HTML var saveMD = function(filename, data) { var blob = new Blob([data], {type: 'text/plain'}); var temp = window.document.createElement('a'); temp.href = window.URL.createObjectURL(blob); temp.download = filename; document.body.appendChild(temp); $(temp).on('mousedown mouseup',function(e){ e.stopImmediatePropagation(); $source.off('blur', unsavedWarning); }) temp.click(); document.body.removeChild(temp); URL.revokeObjectURL(blob); $('body,#source').removeClass('edited'); } } // END IFRAME FUNCTIONS // Don't run script in previewed contentEditable text and html files. if ( window.location.pathname.slice(-1) != '/') { return; } // Globals var e, i, j, n; // ***** SET UP UI ELEMENTS ***** // const $body = $('body'); $body.attr('lang','en').find('> h1:contains("Index of"),> #parentDirLinkBox,> #UI_goUp,#UI_showHidden').remove(); $('head').prepend(''); // ***** SIDEBAR ELEMENTS ***** // const $parent_dir_menu = $(''); const $parents_dir_menu = $(''); const $shortcuts_menu = $(''); const $details_btn = $(''); const $inv_checkbox = $(''); const $grid_btn = $('
    '); const $sidebar_header = $(''); const $dir_list_head = $('NameSizeDateKindExtDefault'); const $dir_list_body = $(''); var $dir_list = $('
    '); const $dir_list_wrapper = $('
    '); const $sidebar = $(''); const $handle = $('
    '); const $sidebar_wrapper = $(''); const $toggle_sidebar = $('
    '); // ***** CONTENT PANE ELEMENTS ***** // const $content_grid = $('
    '); const $image_grid_item_el = $('
    '); const $font_grid_item_el = $('
    '); const $content_scale = $('
    '); const $sample_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ
    abcdefghijklmnopqrstuvwxyz
    0123456789 [(!@#$%^&*;:)]'; 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 +'
    '+ $lorem_string +'
    '+ $lorem_string +'
    '+ $lorem_string +'
    '); const $content_font = $('
    '); const $image = $(''); const $content_image = $('
    '); const $content_pdf = $(''); const $content_iframe = $(''); const $content_video = $(''); const $content_audio_title = $(''); const $content_audio = $(''); const $prev_track = $('
    '); const $next_track = $('
    '); const $audio = $(''); const $loop = $(''); const $shuffle = $(''); const $close_audio = $('
    '); const $checkbox_cont = $('
    '); const $content_reload_btn = $(''); const $content_stop_btn = $(''); const $content_title = $(''); const $content_close_btn = $(''); const $content_header = $('
    '); const $prev_btn = $(''); const $next_btn = $(''); const $content_container = $('
    '); const $content_pane = $(''); // 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 $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 $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\'> ")'; //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 = 'url("data:image/svg+xml;utf8,")'; // const $file_icon_audio = 'url("data:image/svg+xml;utf8,")'; // 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').append($toggle_sidebar); $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( $details_btn, $inv_checkbox, $grid_btn ); $dir_list.append($dir_list_head, $dir_list_body); $sidebar.append($sidebar_header, $dir_list); $sidebar_wrapper.append( $sidebar, $handle ); $content_image.append( $image ); $checkbox_cont.append( $loop, $shuffle ); $content_audio.find('td').append( $prev_track, $next_track, $audio, $close_audio, $checkbox_cont ); // $content_audio_title.find('td').after( $close_audio ); $content_title.prepend($content_reload_btn).append($content_close_btn); $content_header.find('tbody').append( $content_title, $content_audio_title, $content_audio ); $content_font.append( $specimen ); $content_container.append( $content_header, $content_image, $content_grid, $content_font, $content_pdf, $content_video, $content_iframe, $prev_btn, $next_btn, $content_scale ); $content_pane.append( $content_container ); } assembleUIElements(); //***** STYLES *****// // DEFINE STYLES var $styles = ''; // background-color $styles += '#sidebar_wrapper, body.light_theme #sidebar, body.light_theme #sidebar ul, body.light_theme #content_header' + '{ background-color: lightgray }'; $styles += 'body.light_theme #dir_list .selected, body.light_theme #dir_list .playing' + //body.light_theme #dir_list .selected.audio, '{ background-color: lightsteelblue; }'; $styles += 'body.dark_theme #dir_list .selected' + '{ background-color: slategray; }'; $styles += 'body.dark_theme #content_grid, #content_image, body.dark_theme #content_pane' + '{ background-color: #333; }'; $styles += 'body.dark_theme #sidebar ul, body.dark_theme #sidebar_header thead, body.dark_theme #sidebar_header tbody tr:first-of-type, body.dark_theme.alternate_background #dir_list tbody tr:nth-of-type(odd):not(.selected)' + '{ background-color: #444; }'; $styles += 'body.dark_theme #content_grid:not(.has_grid) .image_grid_item:hover, body.dark_theme #content_grid:not(.has_grid) div.image_grid_item.hovered, body.dark_theme #sidebar, body.dark_theme #content_header, body.dark_theme #dir_list #tbody, body.dark_theme #grid_btn .menu li, body.dark_theme .font_grid_item:hover, body.dark_theme .font_grid_item.hovered, body.dark_theme .image_grid_item:hover, body.dark_theme .image_grid_item.hovered' + '{ background-color: #555; }'; $styles += 'body.dark_theme #content_grid:not(.has_grid) .image_grid_item.selected, body.dark_theme #sidebar ul li:hover, body.dark_theme #content_grid .font_grid_item.selected, body.dark_theme #content_grid .image_grid_item.selected' + '{ background-color: #666; }'; $styles += 'body.dark_theme #grid_btn .menu li:hover, body.dark_theme #dir_list tbody tr:hover, body.dark_theme #dir_list tbody li:hover, body.dark_theme.alternate_background #dir_list #tbody tr:hover, body.dark_theme #sidebar .hovered, body.dark_theme #content_iframe[href^="/"], body.dark_theme.alternate_background #dir_list #tbody tr:nth-of-type(odd).hovered' + '{ background-color: #777; }'; $styles += 'body.light_theme #sidebar_header thead tr, body.light_theme #sidebar_header tbody tr:first-of-type, #parents_dir_menu + ul li:hover, #shortcuts_menu + ul li:not(.has_submenu):hover, #grid_btn.has_images.has_fonts:hover .menu li:hover, body.light_theme #dir_list tbody tr:hover, body.light_theme.alternate_background #dir_list #tbody tr:hover, body.light_theme #dir_list .hovered, body.light_theme.alternate_background #dir_list #tbody tr.hovered' + '{ background-color: #BBB; }'; $styles += 'body.light_theme #grid_btn .menu li, body.light_theme #content_grid div.selected, body.light_theme.alternate_background #dir_list tbody tr:nth-of-type(odd):not(.selected)' + '{ background-color: #CCC; }'; $styles += 'body.light_theme #content_grid div:hover, body.light_theme #content_grid div.hovered' + '{ background-color: #DDD; }'; $styles += 'body.light_theme #dir_list tbody' + '{ background-color: #DFDFDF; }'; $styles += 'body.light_theme #content_pane, #content_image .img, body.light_theme #content_grid, #content_font, #content_iframe' + '{ background-color: #FFF; }'; // EXCLUDED: Prevent previewed files with these extensions from being inverted in dark mode for ( let i = 0, n = $row_settings.exclude.length; i < n; i += 1) { $styles += 'body.dark_theme #content_iframe[src*="'+ $row_settings.exclude[i] +'" i] { background:#FFF; filter: unset; }'; } $styles += 'body.dark_theme #content_iframe[src$="/" i]' + '{ background:#AAA; filter:unset; }'; $styles += '#scale' + '{ background-color: rgba(128,128,128,0.3); }'; $styles += 'body.is_chrome #audio' + '{ background-color: rgb(241, 243, 244); }'; $styles += 'body.dark_theme #dir_list .playing, body.dark_theme.alternate_background #dir_list tbody tr.playing:nth-of-type(odd)' + //body.dark_theme #dir_list .selected.audio, '{ background-color: #4C7E80; }'; $styles += '#dir_list tbody tr, #dir_list .audio a, #dir_list .video a, body.has_audio #content_pane.has_ignored #content_image, body.light_theme #grid_btn .menu, body.dark_theme #grid_btn .menu, 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; }'; // BACKGROUND SVG IMAGES & ICONS $styles += '#parent_dir_menu a { background:' + $up_arrow + 'center no-repeat; }'; $styles += '#shortcuts_menu div { background:'+ $menu_icon + 'center no-repeat; }'; $styles += 'body.light_theme #shortcuts > li.has_submenu { background:'+ $menu_arrow +' right no-repeat; background-size: 12px; }'; $styles += 'body.light_theme #shortcuts > li.has_submenu:hover { background:#BBB '+ $menu_arrow +' right no-repeat; background-size: 12px; }'; $styles += 'body.light_theme #shortcuts li.checked span { background:'+ $check_mark +' 4px center no-repeat; background-size:12px; }'; $styles += '#grid_btn { background:'+ $grid_icon +' center no-repeat; }'; $styles += '#toggle_sidebar { background:'+ $toggle +' center no-repeat; background-size:12px; }'; $styles += '#dir_list thead th.checked { background:'+ $check_mark +' 10px 2px no-repeat; background-size:10px; }'; $styles += 'body.light_theme #dir_list thead th.checked:after { background:'+ $up_arrow +' center no-repeat; background-size:10px; }'; $styles += '#dir_list tbody a { background-size:auto 13px; background-position:6px 4px; }'; $styles += 'body.has_audio #content_pane { background-image: ' + $music +'; background-position: center; background-repeat: no-repeat; background-size:33.33%; }'; $styles += '#prev_track, #next_track { background: rgb(241, 243, 244) '+ $next_track_arrow +' center no-repeat; background-blend-mode:difference; }'; $styles += '#prev_track:hover, #next_track:hover, #close_audio:hover { background-blend-mode:normal; }'; $styles += '#close_audio { background:rgb(241, 243, 244); }'; $styles += '#close_audio:after { background:'+ $plus_sign +' center no-repeat; background-blend-mode:difference; background-size:14px; }'; $styles += '#scale span:first-of-type { background:'+ $plus_sign +' center no-repeat; }'; $styles += '#scale span:last-of-type { background:'+ $minus_sign +' center no-repeat; }'; $styles += '#prev_btn, #next_btn { background: ' + $svg_arrow + ' center no-repeat; }'; $styles += 'body #content_pane.has_ignored { background-image:'+ $file_icon_ignored +'; background-position: center; background-repeat: no-repeat; background-size:50%; }'; // Dark theme $styles += 'body.dark_theme #content_pane.has_ignored { background-image:'+ $file_icon_ignored_inv +'; background-position: center; background-repeat: no-repeat; background-size:50%; }'; $styles += 'body.dark_theme #shortcuts > li.has_submenu { background:'+ $menu_arrow_inv +' right no-repeat; background-size: 12px; }'; $styles += 'body.dark_theme #shortcuts > li.has_submenu:hover { background:#666 '+ $menu_arrow_inv +' right no-repeat; background-size: 12px; }'; $styles += 'body.dark_theme #shortcuts li.checked span { background:'+ $check_mark_inv +' 4px center no-repeat; background-size:12px; }'; $styles += 'body.dark_theme #dir_list thead th.checked { background:'+ $check_mark_inv +' 10px 2px no-repeat; background-size:10px; }'; $styles += 'body.dark_theme #dir_list thead th.checked:after { background:'+ $up_arrow_inv +' center no-repeat; background-size:10px; }'; // Default File Icons $styles += 'body.use_default_icons #dir_list .dir a.icon { background:'+ $file_icon_dir_default + ' 6px 4px no-repeat; background-size:auto 13px; }'; $styles += 'body.use_default_icons #dir_list .file a.icon { background:'+ $file_icon_file_default + ' 6px 4px no-repeat; background-size:auto 13px; }'; // Custom File Icons $styles += 'body.use_custom_icons #dir_list tr.file:not(.dir) a.icon { background: '+ $file_icon_file +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.audio a.icon, body.use_custom_icons #dir_list tr.file.video a.icon { background: transparent; }'; $styles += 'body.use_custom_icons #dir_list tr.file.font a.icon { background: '+ $file_icon_font +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.image a.icon { background: '+ $file_icon_image +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.pdf a.icon { background: '+ $file_icon_pdf +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file[class*="htm"] a.icon { background: '+ $file_icon_html +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.ignore a.icon { background: '+ $file_icon_ignored +' 6px 4px no-repeat; }'; $styles += 'body.use_custom_icons #dir_list tr.file.invisible a.icon { background: '+ $file_icon_invisible +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.dir.invisible a.icon { background: '+ $file_icon_dir_invisible +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.dir:not(.app) a.icon { background: '+ $file_icon_dir +' 6px 4px no-repeat; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.app a { background: '+ $file_icon_app +' 6px 4px no-repeat !important; background-size:14px 14px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.code a.icon { background: '+ $file_icon_code +' 6px 4px no-repeat; background-size:14px 14px }'; $styles += 'body.use_custom_icons #dir_list tr.file.text a.icon,body.use_custom_icons #dir_list tr.file.markdown a.icon { background: '+ $file_icon_text +' 6px 4px no-repeat; background-size:14px 14px }'; // Plain text file icons for ( let i = 0, n = $row_types.text.length; i < n; i += 1) { // $styles += 'body.use_custom_icons #dir_list tr.file.'+ $row_types.text[i] +' a.icon { background: '+ $file_icon_text +' 6px 4px no-repeat; background-size:14px 14px }'; } // border $styles += ':root, html, body, #sidebar_wrapper, #sidebar_header, #dir_list, #main_content, #content_pane, #content_pdf, #content_iframe' + '{ border: 0 !important; }'; $styles += 'body.dark_theme ul' + '{ border: solid 1px #222; }'; $styles += '#details_btn' + '{ border: solid 1px #333; }'; $styles += 'body.light_theme #sidebar ul, body.light_theme .image_grid_item img' + '{ border: solid 1px gray; }'; // border-top $styles += 'body.dark_theme #sidebar_header .menu, body.dark_theme #sidebar #grid_btn ul.menu' + '{ border-top:solid 1px #111; }'; $styles += 'body.dark_theme #dir_list #tbody' + '{ border-top:solid 1px #222; }'; $styles += 'body.light_theme #dir_list tbody, #grid_btn .menu, .font_grid_item:not(:first-of-type), .image_grid_item + .font_grid_item' + '{ border-top:solid 1px grey; }'; $styles += '#sort_by' + // , tr.dir ~ tr:not(.dir,.invisible,.ignore) '{ border-top:solid 1px #999; }'; $styles += 'body.dark_theme.is_dirs_on_top #dir_list tbody tr.dir + tr.file' + '{ border-top:solid 1px #CCC; }'; // border-right $styles += '#parents_dir_menu + ul, #shortcuts_menu + ul, body.dark_theme #sidebar #grid_btn ul.menu' + '{ border-right:0 !important; }'; $styles += 'body.dark_theme #parents_dir_menu, body.dark_theme #sidebar, body.dark_theme #sidebar #grid_btn .menu li' + '{ border-right:solid 1px #111; }'; $styles += '#sidebar, body.light_theme #parents_dir_menu, #grid_btn .menu li, .image_grid_item' + '{ border-right:solid 1px grey; }'; // border-bottom $styles += 'body.dark_theme #sidebar_header thead tr, body.dark_theme #sidebar_header tbody tr:first-of-type' + '{ border-bottom:solid 1px black; }'; $styles += 'body.dark_theme #sidebar_header .menu, body.dark_theme #content_header, body.dark_theme #sidebar #grid_btn .menu li:first-of-type, body.dark_theme #sidebar #grid_btn ul.menu' + '{ border-bottom:solid 1px #111; }'; $styles += 'body.dark_theme #content_header tr:first-of-type' + '{ border-bottom:solid 1px #333; }'; $styles += 'body.light_theme #sidebar_header thead tr, body.light_theme #sidebar_header tbody tr:first-of-type, #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; }'; $styles += '#content_header tr:first-of-type' + '{ border-bottom:solid 1px #888; }'; $styles += '#shortcuts_menu + ul > li.has_submenu.ruled, body.is_dirs_on_top #dir_list tbody tr.sorted:not(:last-of-type), .rule' + '{ border-bottom:solid 1px #999; }'; $styles += 'body.light_theme #content_header' + '{ border-bottom:solid 1px #AAA; }'; $styles += 'body.dark_theme.is_dirs_on_top #dir_list tbody tr.sorted:not(:last-of-type), body.dark_theme #content_pane.has_font #content_font hr' + '{ border-bottom:solid 1px #CCC; }'; // border-left $styles += '#parents_dir_menu + ul, #shortcuts_menu + ul' + '{ border-left:0; }'; $styles += 'body.dark_theme #parents_dir_menu, body.dark_theme #sidebar #grid_btn ul.menu' + '{ border-left:solid 1px #111; }'; $styles += 'body.light_theme #parents_dir_menu, #grid_btn .menu' + '{ border-left:solid 1px grey; }'; // border-collapse $styles += 'table' + '{ border-collapse: collapse; }'; // border-radius $styles += 'html, body, :root' + '{ border-radius: 0; }'; $styles += '#details_btn' + '{ border-radius: 3px; }'; // bottom $styles += '#handle, #parent_dir_menu, #close_audio:after, #content_image, #content_pdf, #content_iframe, #content_grid, #content_font, #prev_btn, #next_btn, #dir_list tbody' + '{ bottom: 0; }'; // box-shadow $styles += 'body.light_theme #sidebar ul' + '{ box-shadow: 0px 2px 3px -2px #888; }'; $styles += 'body.dark_theme #sidebar ul' + '{ box-shadow:0px 2px 3px -2px #111; }'; $styles += 'body.dark_theme #sidebar #grid_btn ul.menu' + '{ box-shadow:none; }'; // box-sizing $styles += 'html, body, :root, #sidebar, #grid_btn .menu li' + '{ box-sizing: border-box; }'; // clear $styles += '#dir_list tbody .name' + '{ clear:right; }'; $styles += '#checkbox_div label, #grid_btn .menu li, #dir_list tbody tr, #content_grid .font_grid_item' + '{ clear: both; }'; // columns $styles += '.lorem + .lorem' + '{ columns:2; column-gap:2em; }'; $styles += '.lorem + .lorem + .lorem' + '{ columns:3; }'; // color $styles += 'body.dark_theme #shortcuts_menu + ul > li > ul, body.dark_theme #shortcuts_menu + ul > li.has_submenu + li:not(.has_submenu), #content_font' + '{ color: #111 }'; $styles += '#sidebar, #parents_dir_menu + ul li a, body.light_theme #shortcuts_menu + ul li a, body.light_theme #shortcuts_menu + ul li:not(.disabled) > span, body.light_theme #dir_list th:not(.disabled), #dir_list tbody a, #dir_list .selected a, #dir_list .playing a, #content_header, body.dark_theme #details_btn span, .font_grid_item a, .image_grid_item p' + '{ color: #111 }'; $styles += 'body.dark_theme #sidebar_header thead tr, body.dark_theme #sidebar_header tbody tr:first-of-type' + '{ color: #444 }'; $styles += '#scale span:hover' + '{ color: #666 }'; $styles += '#dir_list tr.ignore a, #dir_list tr.ignore.app a, #dir_list tr.ignore td.details' + '{ color: #777 }'; $styles += '#sort_menu .disabled span, #dir_list th.disabled' + '{ color: #999 }'; $styles += 'body.dark_theme #dir_list tr.file.ignore a.icon, body.dark_theme #dir_list tr.ignore td.details' + '{ color: #BBB }'; $styles += 'body.dark_theme .font_grid_item p, body.dark_theme .font_grid_item a, body.dark_theme .image_grid_item p' + '{ color: #DDD }'; $styles += 'body.dark_theme #sidebar th:not(.disabled), body.dark_theme #sidebar td, body.dark_theme #sidebar a, body.dark_theme #content_header tr, body.dark_theme #sidebar tbody tr:first-of-type span' + '{ color: #EEE }'; // content $styles += '#dir_list thead th.checked:after, body.has_hidden_sidebar #handle, #dir_list thead th.checked:before, #dir_list thead td.icon, #dir_list tr:empty, #dir_list .audio td.icon, #dir_list .video td.icon, body.hide_invisibles .invisible, body.hide_ignored .ignore, body.use_custom_icons #dir_list tr.file.ignore a.icon::before, #close_audio:after' + '{ content:"" }'; $styles += 'body.dark_theme #dir_list thead th.checked:after' + '{ content:" " }'; $styles += '#content_pane.has_audio #content_audio_title td:before, body #content_pane.has_video #title:before' + '{ content:"Playing: " }'; // .audio, .video $styles += '#content_pane.has_dir:not(.has_grid) #title:before' + '{ content:"Index of: " }'; // .dir $styles += '#content_pane.has_grid:not(.has_ignored) #title:before' + '{ content:"Fonts and Images from: " }'; // font and image grid $styles += '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 $styles += '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 $styles += '#content_pane.has_ignored:not(.has_grid) #title:before' + '{ content:"Ignored content: " }'; // .ignored // cursor $styles += '#sidebar_header thead th, #sort_menu .disabled span, #dir_list .disabled' + '{ cursor: default; }'; $styles += '#sidebar_header tbody tr:first-of-type td:hover, #parents_dir_menu div, #shortcuts_menu div, #grid_btn, #dir_list thead th, #scale span' + '{ cursor: pointer; }'; $styles += '#handle' + '{ cursor: col-resize; }'; $styles += '#content_image img:not(.zoom_img)' + '{ cursor: zoom-in; }'; $styles += '#content_image img.zoom_img' + '{ cursor: zoom-out; }'; // display $styles += '#sidebar tbody tr:first-of-type ul, #light_theme, #details_btn span:last-of-type, #grid_btn, #grid_btn:not(:hover) .menu, #dir_list thead .name input, #dir_list .details, body.has_hidden_sidebar #handle, #dir_list thead th.checked:before, #dir_list thead td.icon, #dir_list tr td:not(.name), body.has_hidden_sidebar #dir_list tr td, #dir_list tr:empty, #dir_list tr.audio td.icon, #dir_list tr.video td.icon, body.hide_invisibles #tbody tr.invisible, body.hide_ignored #tbody tr.ignore, #content_title:before, #content_header, #content_audio_title, #content_audio td, #content_pane section header ~ *[id^="content"], .nav_btn, #content_grid, #content_pane.has_hidden_grid #content_grid, #scale, body.light_theme #dark_theme, body.dark_theme #light_theme, body.preview_text #edit_text, body:not(.preview_text) #preview_text, body.use_custom_icons #dir_list img, #dir_list tr.file.audio a img, #dir_list tr.file.video a img' + '{ display: none; }'; $styles += '#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, #default, #dir_list tbody a, #content_pane[class^="has_"] #content_header, #content_pane.has_image:hover #scale, #content_pane.has_font:hover #scale, #content_pane.has_font #content_font, #content_pane.has_image #content_image, #content_pane.has_pdf #content_pdf, #content_pane.has_video #content_video, #content_pane.has_iframe #content_iframe, #content_pane.has_dir #content_iframe, #content_pane.has_grid #content_grid.has_grid, #content_pane.has_grid #content_grid.has_font_grid, .font_grid_item, .image_grid_item a, #content_pane.has_grid .nav_btn, #content_pane.has_font .nav_btn, #content_pane.has_image .nav_btn, #scale span, #checkbox_div label, body.dark_theme #dark_theme, body.light_theme #light_theme, body.use_custom_icons #dir_list tr.file.ignore a.icon::before, body:not(.has_hidden_sidebar) #dir_list .name' + '{ display: block; }'; $styles += 'body.has_images.has_fonts #grid_btn:hover ul.menu' + '{ display:block !important; }'; $styles += '#parents_dir_menu div, body.has_fonts #grid_btn, body.has_images #grid_btn, #dir_list thead th.checked:after, #dir_list.show_details th:not(.name), #dir_list.show_details td:not(.name):not(.ext), body.has_audio #dir_list thead input, #content_grid .image_grid_item, #checkbox_div, #prev_track, #next_track, #close_audio, body.dark_theme #dir_list thead th.checked:after, #content_pane[class^="has_"] #content_container' + '{ display: inline-block; }'; $styles += '#content_pane.has_audio #content_audio_title, #content_pane.has_audio #content_audio' + '{ display: table-row !important; }'; $styles += '#shortcuts_menu div, #content_pane[class^="has"] #title, #content_pane[class^="has"] #content_header, #content_pane.has_audio #content_audio td' + '{ display: table-cell !important; }'; $styles += '#content_pane.has_grid #content_grid.has_image_grid' + '{ display: grid !important; }'; $styles += '#content_grid.has_image_grid' + '{ grid-gap:0; grid-template-columns:repeat(auto-fill, minmax('+ $grid_image_size +'px, 1fr)); grid-template-rows: repeat(auto-fill, '+ $grid_image_size +'px); }'; $styles += '#content_pane.has_grid #content_grid.has_image_grid .image_grid_item' + '{ display: flex; }'; $styles += '#thead, #theader, body[class^="is_default"] #tbody tr, body[class^="is_converted"] #tbody tr, body.show_invisibles #tbody tr, body.hide_invisibles #tbody tr:not(.invisible)' + '{ display: table; }'; // needed to make rows full width and dir_list scrollable // filter $styles += '#prev_btn, #next_btn' + '{ filter:invert(50%); }'; $styles += 'body.dark_theme #content_iframe, body.dark_theme #content_font' + '{ filter:invert(87.5%); }'; $styles += '#scale span:hover, body.dark_theme #sidebar #grid_btn, body.dark_theme #grid_btn .menu, body.dark_theme #parent_dir_menu, body.dark_theme #shortcuts_menu, body.dark_theme #toggle_sidebar' + '{ filter:invert(100%); }'; // float $styles += '#content_header tr:first-of-type td:first-of-type, #checkbox_div label' + '{ float: left; }'; $styles += '#grid_btn, #content_header tr:first-of-type td:last-of-type' + '{ float: right; }'; // font-family $styles += 'html, body, :root' + '{ font-family:'+ $settings.UI_font +', arial, "fira sans", helvetica, sans-serif; }'; // font-size $styles += 'html' + '{ font-size: 100.001%; }'; $styles += 'body, :root' + '{ font-size:'+ $settings.UI_font_size +'; }'; $styles += '#sidebar, #sidebar_header, #sidebar_header thead th, #dir_list, #dir_list .details, #content_header, #content_header table' + '{ font-size: 0.875rem; }'; $styles += '#content_grid, .font_grid_item p' + '{ font-size: 1rem; }'; $styles += '#scale span' + '{ font-size: 2rem; }'; $styles += '#content_grid .font_grid_item h2' + '{ font-size:'+ $grid_font_size * 4 +'em; }'; $styles += '#content_font' + '{ font-size:'+ $grid_font_size +'em; }'; $styles += '.lorem.first:first-line' + '{ font-size:'+ $grid_font_size*1.33 +'em; }'; // font-variant $styles += '.lorem.first:first-line' + '{ font-variant: small-caps }'; // font-weight $styles += '#sidebar_header thead th, h2' + '{ font-weight: normal }'; $styles += '#dir_list .selected a, #dir_list .playing a' + '{ font-weight: bold }'; // height $styles += 'html, body, :root, #parent_dir_menu a, #content_container, #main_content, #content_pdf, #content_iframe' + '{ height: 100%; }'; $styles += '#sidebar_header, #parents_dir_menu, #parents_dir_menu div, #content_grid div img, #content_image img:not(.zoom_img)' + '{ height: auto; }'; $styles += '#dir_list thead th.checked:after' + '{ height: 8px; }'; $styles += '#toggle_sidebar' + '{ height: 14px; }'; $styles += '#dir_list td.icon' + '{ height: 16px; }'; $styles += '#grid_btn, body.use_custom_icons #dir_list tr.file.ignore a.icon::before' + '{ height: 18px; }'; $styles += '#audio' + '{ height: 32px; }'; $styles += 'body.dark_theme #dir_list thead th.checked:after' + '{ height: 1em; }'; $styles += '#scale span' + '{ height: 2rem; }'; $styles += '.image_grid_item a' + '{ align-self: center; justify-self: center; }'; $styles += '#content_grid.has_grid .image_grid_item' + '{ height: '+ $grid_image_size +'px; }'; $styles += '#sidebar' + '{ height:'+ window.innerHeight +'px; }'; // max-height $styles += '#content_image img.zoom_img' + '{ max-height: none; }'; $styles += '#content_grid div img' + '{ max-height:'+ ($grid_image_size - $grid_image_size/8) +'px; }'; // min-height $styles += '#sidebar' + '{ min-height: 100%; }'; // hyphens $styles += '#parents_dir_menu div, #content_header td button, #content_font' + '{ hyphens: none; }'; $styles += 'html, body, :root, .lorem' + '{ hyphens: auto; }'; // justify-seld $styles += '.image_grid_item' + '{ justify-self: stretch; }'; // left $styles += '#sidebar ul, #parent_dir_menu, #dir_list thead, #dir_list tbody, #close_audio:after, #content_header, #content_image, #content_pdf, #content_iframe, #content_grid, #content_font, body.use_custom_icons #dir_list tr.file.ignore a.icon::before, body.has_hidden_sidebar #toggle_sidebar' + '{ left: 0; }'; $styles += '#sidebar #grid_btn ul.menu' + '{ left: unset; }'; $styles += 'body.has_hidden_sidebar #sidebar_wrapper' + '{ left: 3px; }'; $styles += '#shortcuts_menu + ul > li > ul' + '{ left: 100%; }'; // letter-spacing $styles += '.lorem.first:first-line, .font_grid_item p' + '{ letter-spacing: 0.1em }'; $styles += '#sidebar_header thead th' + '{ letter-spacing: 0.5em }'; // line-height $styles += '.font_grid_item p' + '{ line-height: 1 }'; $styles += '#dir_list tr a, .lorem' + '{ line-height: 1.4 }'; // list-style $styles += '#sidebar ul, #grid_btn .menu li' + '{ list-style-type: none; }'; // margin $styles += '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_grid p, #content_grid h2' + '{ margin: 0; }'; // margin-top $styles += '.image_grid_item + .font_grid_item' + '{ margin-top:-1px; }'; $styles += '#checkbox_div label input, #details_btn' + '{ margin-top: 0; }'; $styles += 'body.has_audio #dir_list input' + '{ margin-top: 1px; }'; // margin-right $styles += '#content_video, .image_grid_item a' + '{ margin-right: auto; }'; $styles += '#dir_list thead th.checked' + '{ margin-right: 0; }'; $styles += 'body.has_audio #dir_list input, #reload_btn' + '{ margin-right: 8px; }'; $styles += '#details_btn' + '{ margin-right: 0.5em; }'; $styles += '#dir_list thead th:last-of-type' + '{ margin-right: 1em; }'; $styles += '#checkbox_div' + '{ margin-right: calc(-6em - 4px); }'; // margin-bottom $styles += '#details_btn' + '{ margin-bottom: 0; }'; $styles += 'body.has_audio #dir_list input' + '{ margin-bottom: 1px; }'; // margin-left $styles += '#content_video, .image_grid_item a' + '{ margin-left: auto; }'; $styles += '#dir_list thead th.checked' + '{ margin-left: 0; }'; $styles += 'body.has_hidden_sidebar #reload_btn' + '{ margin-left: 16pt; }'; $styles += '#details_btn' + '{ margin-left: 0.5em; }'; $styles += '#dir_list tbody tr' + '{ margin-inline-start:0; }'; // -webkit-margin $styles += '#sidebar ul' + '{ -webkit-margin-before:0em !important; -webkit-margin-after:0em !important; -webkit-padding-start:0em; }'; // opacity $styles += '#content_pane #scale' + '{ opacity:0; }'; $styles += '#scale span:first-of-type, #scale span:last-of-type, #content_pane.has_ignored:before, #close_audio::after' + '{ opacity:0.3; }'; $styles += '#scale span:hover' + '{ opacity:0.5; }'; $styles += '#prev_btn, #next_btn, #close_audio:hover::after' + '{ opacity:0.6; }'; $styles += '#sidebar_header tbody tr:first-of-type td:last-of-type:hover > div, #shortcuts_menu div, #shortcuts_menu div, #parent_dir_menu, #prev_btn, #next_btn, #toggle_sidebar, body.use_custom_icons #dir_list tr.file.ignore a.icon::before' + '{ opacity: 0.7; }'; $styles += '#content_grid div img' + '{ opacity:0.8; }'; $styles += '#grid_btn:hover, #parent_dir_menu:hover, #prev_btn:hover, #next_btn:hover, #toggle_sidebar:hover, #content_pane.has_grid:hover #scale, #content_pane.has_font:hover #content_font ~ #scale, #content_pane.has_image:hover #content_image ~ #scale' + '{ opacity:1; }'; // outline $styles += '#grid_btn, #dir_list tbody, #dir_list tbody a, #content_grid .font_grid_item, #content_font' + '{ outline: none; }'; // overflow $styles += '#content_container' + '{ overflow: visible; }'; $styles += 'html, body, :root, #parents_dir_menu div, #shortcuts_menu, #dir_list, #dir_list tbody a, #main_content, #close_audio' + '{ overflow: hidden; }'; $styles += '#content_font, #content_grid, #content_image' + '{ overflow: auto; }'; $styles += '#dir_list tbody' + '{ overflow-y: auto; }'; $styles += '#sidebar, #content_font' + '{ overflow-wrap: break-word; }'; $styles += '.lorem' + '{ overflow-wrap: normal; }'; // padding $styles += '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, audio::-webkit-media-controls-panel' + '{ padding: 0; }'; $styles += '#sidebar_header thead th' + '{ padding: 4px; }'; $styles += '.image_grid_item' + '{ padding:6px; }'; // padding-top $styles += '#dir_list thead th, #dir_list .details, #prev_track, #next_track, #close_audio' + '{ padding-top: 0; }'; $styles += '#details_btn, #prev_btn, #next_btn' + '{ padding-top: 2px; }'; $styles += '#parents_dir_menu div, #grid_btn .menu li, #dir_list tbody a, #content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type, #title, body #content_audio_title td, #content_audio td' + '{ padding-top: 4px; }'; $styles += '#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' + '{ padding-top: 6px; }'; $styles += '#content_header table' + '{ padding-top: 7px; }'; $styles += '#content_grid .font_grid_item, .font_grid_item p' + '{ padding-top: 0.5rem; }'; $styles += '#content_image, #content_font div' + '{ padding-top: 2rem; }'; // padding-right $styles += '#sidebar_header tbody tr:last-of-type td, #dir_list .details, #prev_track, #next_track, #close_audio' + '{ padding-right: 0; }'; $styles += '#parents_dir_menu div, #details_btn, #grid_btn .menu li, #dir_list tbody a, #content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type, #content_audio td, #close_audio' + '{ padding-right: 6px; }'; $styles += '#parents_dir_menu + ul li a, #shortcuts_menu + ul li a, #shortcuts_menu + ul li > span, #shortcuts_menu + ul li div span' + '{ padding-right: 8px; }'; $styles += '#dir_list tbody tr, #content_header table, #title, #prev_btn, #next_btn' + '{ padding-right: 12px; }'; $styles += '#grid_btn .menu, #dir_list thead th, #content_audio_title td' + '{ padding-right: 29px; }'; $styles += '#content_grid .font_grid_item, #content_image, #content_font div' + '{ padding-right: 2.5rem; }'; // padding-bottom $styles += '#prev_track, #next_track, #close_audio, #prev_btn, #next_btn' + '{ padding-bottom: 0px }'; $styles += '#details_btn, body.is_dirs_on_top #dir_list tbody tr.sorted:not(:last-of-type)' + '{ padding-bottom: 2px; }'; $styles += '#title, body #content_audio_title td' + '{ padding-bottom: 3px;}'; $styles += '#parents_dir_menu div, #grid_btn .menu li, #dir_list tbody a, #dir_list .details' + '{ padding-bottom: 4px; }'; $styles += '.specimen, .font_grid_item p' + '{ padding-bottom: 0.25em; }'; $styles += '#content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type' + '{ padding-bottom: 3px; }'; $styles += '#content_header table' + '{ padding-bottom: 5px; }'; $styles += '#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; }'; $styles += '#dir_list thead th.details' + '{ padding-bottom: 9px; }'; $styles += '#content_grid .font_grid_item' + '{ padding-bottom: 0.5rem; }'; $styles += '#content_grid.has_image_grid' + '{ padding-bottom: 1rem; }'; $styles += '#content_image, #content_font div:first-of-type' + '{ padding-bottom: 2rem; }'; // padding-left $styles += '#grid_btn .menu, #sidebar_header tbody tr:last-of-type td' + '{ padding-left: 0; }'; $styles += '#dir_list .audio a, #dir_list .video a, #checkbox_div' + '{ padding-left: 4px; }'; $styles += '#parents_dir_menu div, #dir_list td.icon, #dir_list .icon + td.name a, #checkbox_div #parents_dir_menu div, #details_btn, #grid_btn .menu li, #content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type, #content_audio td, #prev_track' + '{ padding-left: 6px; }'; $styles += '#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; }'; $styles += '#content_header table, #dir_list td.size, #title, #prev_btn, #next_btn' + '{ padding-left: 12px; }'; $styles += '#dir_list thead th, #dir_list .details, #dir_list td.date' + '{ padding-left: 24px; }'; $styles += '#dir_list tbody a' + '{ padding-left: 27px; -webkit-padding-start: 27px; }'; $styles += '#content_audio_title td' + '{ padding-left: 29px; }'; $styles += '#sort_menu li span, #dir_list thead .name, #default' + '{ padding-left: 2em; }'; $styles += '#content_grid .font_grid_item, #content_image, #content_font div' + '{ padding-left: 2.5rem; }'; //-webkit-padding $styles += '#dir_list .icon + td.name a' + '{ -webkit-padding-start:1em; }'; // position $styles += '#sidebar_wrapper, #sidebar_header, #sidebar_header tbody tr, #sidebar_header tbody tr:first-of-type td:first-of-type, #sidebar_header tbody tr:last-of-type td, #dir_list, #dir_list thead, #dir_list thead th.checked ,#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, #close_audio, #content_grid div img, #content_image img:not(.zoom_img)' + '{ position: relative; }'; $styles += '#sidebar ul, #handle, #parent_dir_menu, #toggle_sidebar, body.has_hidden_sidebar #sidebar_wrapper, #dir_list tbody, #dir_list thead th.checked:after, #content_header, #close_audio:after, #content_grid, #content_image, #content_font, #content_pdf, #content_iframe, #scale, #prev_btn, #next_btn, body.use_custom_icons #dir_list tr.file.ignore a.icon::before' + '{ position: absolute; }'; // right $styles += '#sidebar ul, #parent_dir_menu, #grid_btn .menu, #dir_list thead, #dir_list tbody, #close_audio:after, #content_header, #content_image, #content_pdf, #content_iframe, #content_grid, #content_font, #next_btn' + '{ right: 0; }'; $styles += '#toggle_sidebar' + '{ right: 4px; }'; $styles += '#handle' + '{ right: -4px; }'; $styles += '#scale' + '{ right: 1rem; }'; // table-layout $styles += '#dir_list' + '{ table-layout: fixed; }'; // text-align $styles += '#sidebar ul, #dir_list thead, #dir_list tbody, #dir_list tbody .name, #dir_list .details, #content_header tr:first-of-type td:first-of-type, #content_grid, #content_grid .font_grid_item, .specimen' + '{ text-align: left; }'; $styles += '#parent_dir_menu a, #parents_dir_menu, #parents_dir_menu div, #shortcuts_menu div, #content_header, #title, #content_grid .image_grid_item, #content_image, #content_audio_title, #content_audio td, #scale span' + '{ text-align: center; }'; $styles += '#grid_btn .menu li, #dir_list .size, #dir_list .date, #content_header tr:first-of-type td:last-of-type' + '{ text-align: right; }'; $styles += '.lorem' + '{ text-align: justify; }'; // text-decoration $styles += 'a, a:hover' + '{ text-decoration: none !important; }'; // text-indent $styles += '#shortcuts li' + '{ text-indent: 1em; }'; // text-transform $styles += '.font_grid_item p' + '{ text-transform: uppercase; }'; // top $styles += '#handle, #parent_dir_menu, #content_container, #content_header, #close_audio:after, #content_image, #content_image img.zoom_img, #content_pdf, #content_iframe, #prev_btn, #next_btn, body.use_custom_icons #dir_list tr.file.ignore a.icon::before' + '{ top: 0; }'; $styles += '#shortcuts_menu + ul > li > ul, body.light_theme #grid_btn .menu' + '{ top: -1px !important; }'; $styles += 'body.has_hidden_sidebar #sidebar_wrapper, #dir_list thead th.checked:after' + '{ top: 2px; }'; $styles += '#toggle_sidebar' + '{ top: 4px; }'; $styles += 'body.dark_theme #grid_btn .menu' + '{ top: -7px; }'; $styles += '#content_image img:not(.zoom_img), .vert_center' + '{ top: 50%; }'; // transform $styles += 'body.has_hidden_sidebar #toggle_sidebar, #dir_list thead th.checked:not(.up):after, #next_track, #next_btn' + '{ transform:rotate(180deg); }'; $styles += '#close_audio:after' + '{ transform:rotate(45deg); }'; $styles += '.vert_center' + '{ transform:translateY(50%); }'; $styles += '#content_image img:not(.zoom_img)' + '{ transform:translateY(-50%); }'; $styles += '#content_image img.zoom_img' + '{ transform:translateY(0); }'; // transition $styles += '#scale' + '{ transition:opacity 1s ease-in-out; }'; // user-select $styles += '#sidebar_header, #content_image img:not(.zoom_img)' + '{ user-select:none; -webkit-user-select:none; }'; // vertical-align $styles += '#dir_list .details' + '{ vertical-align: top }'; $styles += '#sidebar_header tbody tr:last-of-type td, #parent_dir_menu a, #parents_dir_menu div, #shortcuts_menu div, #content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type, #title, #content_grid .image_grid_item' + '{ vertical-align:middle; }'; // white-space $styles += '#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; }'; $styles += '#grid_btn .menu li' + '{ white-space: pre; }'; $styles += '#dir_list thead' + '{ white-space: pre-wrap; }'; // width $styles += 'html, body, :root, table, #sidebar_header tbody tr:first-of-type td:nth-of-type(even), #parent_dir_menu a, #dir_list thead, #tbody, #tbody tr, #shortcuts_menu + ul > li > ul, #grid_btn .menu li, body.has_hidden_sidebar #content_pane, #content_container, #content_header, #content_pdf, #content_iframe' + '{ width: 100%; }'; $styles += '#content_grid, #content_grid div img, #content_image img:not(.zoom_img)' + '{ width: auto; }'; $styles += '#handle' + '{ width: 8px; }'; $styles += '#toggle_sidebar' + '{ width: 16px; }'; $styles += 'body.use_custom_icons #dir_list tr.file.ignore a.icon::before' + '{ width: 20px; }'; $styles += '#sidebar_header tbody tr:first-of-type td:nth-of-type(odd)' + '{ width: 24px; }'; $styles += '#grid_btn' + '{ width: 28px; }'; $styles += '#dir_list thead th.checked:after, #prev_track, #next_track, #close_audio, #scale span' + '{ width: 2rem; }'; $styles += '#shortcuts_menu div, #checkbox_div' + '{ width: 6em; }'; $styles += '#content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type' + '{ width: 4em; }'; $styles += 'body.has_hidden_sidebar #sidebar_wrapper' + '{ width: 0 !important; }'; $styles += '#dir_list .size, #dir_list .kind' + '{ width: 16%; }'; $styles += '#dir_list .date' + '{ width: 30%; }'; $styles += '#content_grid.has_grid .image_grid_item' + '{ width: '+ $grid_image_size +'px; }'; $styles += 'body.has_hidden_sidebar #content_pane, #content_header tr:first-of-type td:nth-of-type(2)' + '{ width: 100% !important; }'; $styles += 'body:not(.has_hidden_sidebar) #sidebar_wrapper' + '{ width:'+ $UI_pref_width +'%; }'; $styles += '#content_pane' + '{ width:'+ (100 - $UI_pref_width).toString() +'%; }'; $styles += '#content_grid .font_grid_item' + '{ width:calc(100% - 5rem); }'; // max-width $styles += 'html, body, :root, #content_image img:not(.zoom_img)' + '{ max-width: 100%; }'; $styles += '#content_image img.zoom_img' + '{ max-width: none; }'; $styles += '#sidebar_header tbody tr:first-of-type td:nth-of-type(odd)' + '{ max-width: 24px; }'; $styles += '#content_grid div img' + '{ max-width:'+ ($grid_image_size - $grid_image_size/8) +'px; }'; // min-width $styles += 'body:not(.has_hidden_sidebar) #sidebar_header tbody tr:first-of-type td:nth-of-type(odd)' + '{ min-width: 24px; }'; $styles += '#dir_list .size, #dir_list .kind' + '{ min-width: 5em; }'; $styles += '#dir_list td.date' + '{ min-width: 12em; }'; $styles += 'body:not(.has_hidden_sidebar) #dir_list' + '{ min-width: 100px; }'; $styles += 'body:not(.has_hidden_sidebar) #sidebar_wrapper' + '{ min-width: 220px; }'; // will-change $styles += '#sidebar_wrapper, #content_pane' + '{ will-change: width }'; // word-break $styles += '#content_header td button' + '{ word-break: none; }'; $styles += '#title' + '{ word-break: break-word; }'; $styles += '#content_font' + '{ word-break: break-all; }'; $styles += '.lorem' + '{ word-break: normal; }'; // z-index $styles += '#content_grid' + '{ z-index: -1; }'; $styles += '#content_pane.has_grid #content_grid' + '{ z-index: 1; }'; $styles += '#scale, #prev_btn, #next_btn' + '{ z-index: 10; }'; $styles += '#parents_dir_menu + ul, #content_header' + '{ z-index: 20; }'; $styles += '#handle' + '{ z-index: 1000; }'; $styles += '#sidebar_header' + '{ z-index: 2000; }'; $styles += '#shortcuts_menu + ul, #toggle_sidebar' + '{ z-index: 9999; }'; $styles += 'body.has_hidden_sidebar #sidebar_header' + '{ z-index:unset; }'; // Gecko Styles: var $gecko_styles = ''; $gecko_styles += 'html, body.is_gecko { border: solid 1px gray !important; }'; $gecko_styles += 'body.is_gecko button { padding:0; }'; $gecko_styles += 'body.is_gecko #grid_btn .menu { top:-7px; left:-120px; }'; $gecko_styles += 'body.is_gecko thead {font-size:100%;}'; $gecko_styles += 'body.is_gecko #dir_list th, body.is_gecko #dir_list td {width:auto;}'; $gecko_styles += 'body.is_gecko #dir_list .dir::before {position:absolute;}'; $gecko_styles += 'body.is_gecko.use_default_icons:not(.is_converted_list) #dir_list .file .name .icon { padding-left:4px; background:none; }'; $gecko_styles += 'body.is_gecko.use_default_icons #dir_list .file .name .icon img { margin-right:6px; height:14px; }'; $gecko_styles += 'body.is_gecko #tbody > tr > td:not(:first-of-type) { float:left }'; $gecko_styles += 'body.is_gecko #content_audio_title td { padding-top: 6px; }'; $gecko_styles += 'body.is_gecko #content_audio_title td { padding-bottom: 0; }'; $gecko_styles += 'body.is_gecko #prev_track { padding-left: 16px; }'; $gecko_styles += 'body.is_gecko #close_audio { background-color: #252525; }'; $gecko_styles += 'body.is_gecko #close_audio:after { filter:invert(100%); opacity:0.5; }'; $gecko_styles += 'body.is_gecko #close_audio:hover:after { opacity:0.75; }'; $gecko_styles += 'body.is_gecko.dark_theme #prev_track, body.is_gecko.dark_theme #next_track { background: #252525 '+ $next_track_arrow_gecko +' center no-repeat; }'; $gecko_styles += 'body.is_gecko #prev_track:hover, body.is_gecko #next_track:hover { background: #252525 '+ $next_track_arrow_gecko_hover +' center no-repeat; }'; $gecko_styles += 'body.is_gecko #content_title td:first-of-type, body.is_gecko #content_title td:last-of-type { padding-top:8px; }'; // ADD STYLES const $font_preview_styles = document.createElement('style'); const $custom_styles = document.createElement("style"); const $custom_gecko_styles = document.createElement("style"); const $highlightjs_link = document.createElement('link'); $highlightjs_link.setAttribute('rel','stylesheet') ; $highlightjs_link.setAttribute('href','http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.14.2/styles/default.min.css') ; document.head.appendChild($highlightjs_link); function addStyles() { // for font previews $font_preview_styles.appendChild(document.createTextNode("")); document.head.append($font_preview_styles); var $font_styles = ''; $font_preview_styles.append( $font_styles ); // basic UI styles $custom_styles.appendChild(document.createTextNode("")); $custom_styles.append($styles); document.head.appendChild($custom_styles); // Gecko styles if ( $userAgent.indexOf('Firefox') > -1 ) { $custom_gecko_styles.appendChild(document.createTextNode("")); $custom_gecko_styles.append($gecko_styles); document.head.appendChild($custom_gecko_styles); } } addStyles(); // ***** END STYLES ***** // // ***** BUILD MENUS ***** // var $paths_arr = []; const parentLinksArr = function() { // create array of parent links from $location w/o query string let $path = $location; // https://www.example.com/path/to/my/dir/ while ( $path.lastIndexOf('/') > 0 && !$path.endsWith(':/') ) { $path = $path.slice( 0,$path.lastIndexOf('/') ); $paths_arr.push($path); } $paths_arr.pop(); // remove last element return $paths_arr; }; parentLinksArr(); // MENUS: Create menu list items var $menu_item; const menuItems = function(x,y,i,b) { // (link, name, count, boolean) let $qstr = '/?'; if ( b === true ) { // don't include query string in link $qstr = ''; $query_prefs = ''; } $menu_item = '
  • ' + y[i] + '/
  • '; return $menu_item; }; // Parent directory link setup var $parent_dir_link; function setParentLink() { let $query_prefs = new URLSearchParams( window.location.search ); $query_prefs.delete('file'); $UI_pref_history_arr = $query_prefs.get('history') !== null ? $query_prefs.get('history').split(' ') : []; if ( $UI_pref_history_arr.length == 1 ) { $query_prefs.set('selected',$UI_pref_history_arr.shift(0)); $query_prefs.delete('history'); } else if ( $UI_pref_history_arr.length > 1 ) { $query_prefs.set('selected',$UI_pref_history_arr.shift(0)); $query_prefs.set('history',$UI_pref_history_arr.join('+')); } else { $query_prefs.delete('selected'); } let $qstr = $query_prefs.toString().length === 0 ? '' : '?'; $query_prefs.sort(); $parent_dir_link = $location_arr.slice(0,-2).join('/') + '/' + $qstr + decodeURIComponent($query_prefs); $parent_dir_menu.find('a').attr( 'href', $parent_dir_link ); } setParentLink(); // Click parent directory menu button $parent_dir_menu.on('click','a',function(e) { e.preventDefault(); setParentLink(); // update link in case query string has changed $('#parent_dir_menu').find('a').attr( 'href', $parent_dir_link ); window.location = $parent_dir_link; }); // MENUS: Directory Parents Links const parents_dir_menu_arr = function() { var $parents_dir_menu_items = []; // make array of directory parents menu items for ( let i = 1, n = $paths_arr.length + 1; i < n; i+=1 ) { $parents_dir_menu_items[i] = menuItems( $paths_arr, $paths_arr, i, false); } $parents_dir_menu_items.pop(); // remove current directory if ( $parents_dir_menu_items[1] !== undefined ) { let str = $parents_dir_menu_items[1].slice($parents_dir_menu_items[1].lastIndexOf('?'),$parents_dir_menu_items[1].lastIndexOf('">')); for ( let i = 1; i < $parents_dir_menu_items.length; i+=1 ) { // recursively update selected and history query str str = str.replace(/selected=\d+&*/,'').replace(/history=(\d+)$/,'selected=$1').replace(/history=(\d+)\+/,'selected=$1&history=').replace(/&$/,''); $parents_dir_menu_items[i] = $parents_dir_menu_items[i].replace(/\?.+?">/,str +'">'); } } // cleanup links $parents_dir_menu_items = $parents_dir_menu_items.join('') .replace(/%20/g,' ').replace(/file=.+?&/g,'&').replace(/file=.+?/g,'').replace(/>\/(?!\/)/g,'>').replace(/>\/\/\/\//<').replace(/>\/\/\//<'); return $parents_dir_menu_items; }; // MENUS: User Shortcuts var $menu_items = []; var $shortcuts_links_arr = []; const shortcutMenus = function() { const $shortcuts = $settings.shortcuts; if ( $shortcuts.length > 0 ) { for ( let i = 0; i < $shortcuts.length; i+=1 ) { var $links_arr = []; var $links = $shortcuts[i].links; // make array of links for ( let j = 0; j < $links.length; j+=1 ) { 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) ; } $shortcuts_links_arr.push($links[j].link); $links_arr[j] = '
  • ' + $links[j].link_name + '
  • '; } var $links_arr_str = $links_arr.join(''); $menu_items[i] = '
  • '+ $shortcuts[i].menu_title +'
      '+ $links_arr_str +'
  • '; } $menu_items = $menu_items.join(''); } return ($shortcuts_links_arr,$menu_items); }; shortcutMenus(); // MENUS: Other menu items var $sort_by = $('
  • Sort by…
    • Name
    • Size
    • Date
    • Kind
    • Extension
    • Default
    '); const $autoload_media = $('
  • Autoload Media
  • '); const $toggle_dark_theme = $('
  • Dark ThemeLight Theme
  • '); const $toggle_alt_bckgrd = $('
  • Alternate Backgrounds
  • '); // const $text_editing = $('
  • Text Editing
    • Split View
    • Preview Text FilesEdit Text Files
    '); 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').append( parents_dir_menu_arr() ); $shortcuts_menu.siblings('ul').append( $menu_items, $sort_by, $toggle_dark_theme, $toggle_alt_bckgrd, $autoload_media, $default_settings, $export_settings, $contact_link, $donate_link ); } assembleMenus(); // ***** END BUILD MENUS ***** // // ***** DIRECTORY LIST Setup ***** // // CONVERT INDEX PAGES TO DEFAULT (Chrome) STRUCTURE // Convert matched date and size strings to default size and date format, calculate data-values for sorting var yr, mo, dd, pref; var factor = {k:1, kb:1, m:1000, mb:1000, g:1000000, gb:1000000, t:1000000000,tb:1000000000}; // for file size conversion var sizeCalc = function(x,y) { // x = number, y = byte size y === '' ? y = 'k' : y = y; return x == '-' ? 0 : x * factor[ y.toString().toLowerCase() ]; // convert byte size to multiplication factor }; var sizeAndDate = function(match,p1,p2,p3,p4,p5,p6,offset,string) { p1.toString().length == 4 ? (yr = p1, dd = p3) : (yr = p3, dd = p1); p2.toString().length == 3 ? mo = "JanFebMarAprMayJunJulAugSepOctNovDec".indexOf(p2)/3 + 1 : mo = p2; // convert month into number, or use number p6 = undefined|'' ? p6 = 1 : p6 = p6; mo.toString().length == 1 ? pref = 0 : pref = null; // add a zero before single digit months (i.e., multiply year by 10) return '' + [p5,p6].join('') + ''+ [yr, mo, dd].join('-') +' '+ [p4].join(':') +'\n'; }; // Standardize directory lists function convertDirList() { var $list_items; // AMPPS index pages let $protocol = window.location.protocol; if ( $protocol.indexOf('localhost') > -1 && $body.find('> title:contains(AMPPS)').length ) { $dir_list = $body.find('> center > div > table'); $dir_list.remove(); $body.addClass('is_ampps').empty().append($dir_list); } // Pre-type if ( $protocol !== 'file:' && $body.find('> pre').length > 0 ) { $list_items = $body.find('> pre').html(); $body.addClass('is_converted_pre').find('> pre').remove(); $list_items = $list_items .replace(/^.+?\n/, '') // delete header row .replace(/^.+?Parent Directory.+?\n/gm, '\n') // delete parent directory link .replace(/^\s*\.\.\/<\/a>\s*$/gm, '') // delete parent directory link (list type) .replace(/^\s*\s*/gm, '') // delete all images (icons) .replace(/^\s*
    .+?<\/address>\s*/,'') // delete address element .replace(/^\s*(.+?)<\/a>\s*/gm, '$2') // create name cell .replace(/(\d{2}|\d{4})[\/-](\d{2}|\w{3})[\/-](\d{2}|\d{4})\s+?([\d:]+)\s*([\.\d]+)([A-z]{0,2})\s*$/gm, sizeAndDate); // dates (search dd-mmm-yyyy hh:mm) and sizes } // List-type if ( $protocol !== 'file:' && $body.find('> ul').length > 0 ) { $list_items = $body.find('> ul').html(); $body.addClass('is_converted_list').find('> ul').remove(); if ( $list_items.indexOf('') != -1 ) { $list_items = $list_items.replace(/
  • \s*/g,'').replace(/\s*<\/li>/g, '\n'); $list_items = $list_items.replace(/data-value="">\s+(.+?)<\/a>/g, 'data-value="">$2<\/a>'); $list_items = $list_items.replace(//,''); } } // Table-type if ( $protocol !== 'file:' && $body.find('> table').length > 0 ) { $list_items = $body.find('> table:last-of-type tbody').length > 0 ? $body.find('> table:last-of-type tbody').html() : $body.find('> table:last-of-type'); $body.addClass('is_converted_table').find('> table').remove(); $list_items = $list_items // .replace(//g, '') // delete all images (icons) .replace(/<\/tr>/g, '') // delete empty tr .replace(/<\/tr>/, '') // delete empty tr .replace(/(?:||)(?: |\s*)(?:<\/th>|<\/td>)/g, '') // delete empty th or td .replace(/\s*(.+?)<\/a>\s*<\/td>/g, '$2') .replace(/<\/td>(.+?)<\/a>/g, '$4') // move default image to .name td .replace(/(?:|)(\d{4}|\d{2})-(\d{2}|\w{3})-(\d{4}|\d{2})\s*([\d:-]*)\s*<\/td>(?:|)\s*([-\.\d]*)([A-z]*)\s*<\/td><\/tr>/g, sizeAndDate) .replace(/^\s*
    .+?<\/address>\s*$/,''); // delete address line } // Gecko-style local index pages if ( $protocol === 'file:' && $userAgent.indexOf('Firefox') > -1 ) { $body.find('> table').find('> thead').find('th[colspan="2"]').attr('colspan',1); $list_items = $body.find('> table').find('> tbody').html(); $body.find('> table').remove(); $list_items = $list_items .replace(/') .replace(/ table').length > 0 && $userAgent.indexOf('Firefox') < 0) { $list_items = $body.find('> table tbody').html(); $body.addClass('is_default_table').find('> table').remove(); } $dir_list_body.append($list_items); } convertDirList(); // ***** END CONVERT INDEX PAGES ***** // // Append directory list var $dir_list_row = $dir_list_body.find('> tr'); var $dir_list_item_name = $dir_list_row.find('a').parent('td'); var $dir_list_details = $dir_list_item_name.nextAll(); $dir_list_details.addClass('details'); // ***** END CONVERT INDEX PAGES ***** // // ***** PREPARE DIR LIST ***** // var $this_link; var $this_text; var $this_ext; // Get dir_list item row var thisRow = function(x) { return $(x).closest('#dir_list > tbody > tr').length > 0 ? $(x).closest('#dir_list > tbody > tr') : $(x).closest('#dir_list > li'); }; // Get row link var thisLink = function(x) { return $(x).find('a').length > 0 ? $(x).find('a').attr('href') : $(x).attr('href'); }; // Get row name var thisText = function(x) { return $(x).find('a').length > 0 ? decodeURIComponentSafe( $(x).find('a').text().toLocaleLowerCase() ) : decodeURIComponentSafe( $(x).text().toLocaleLowerCase() ); }; // get row text var thisExt = function(x) { let $this_name = thisText(x); // return $this_link.endsWith('app/') ? 'app' : $this_link.endsWith('/') ? '/' : $this_link.lastIndexOf('.') === -1 ? undefined : $this_link.toLowerCase().slice( $this_link.lastIndexOf('.') + 1 ); return $this_name.endsWith('app/') ? 'app' : $this_name.endsWith('/') ? '/' : $this_name.lastIndexOf('.') === -1 ? undefined : $this_name.toLowerCase().slice( $this_name.lastIndexOf('.') + 1 ); }; // Normalize row name data-value function stringNormalize(str) { return str.normalize('NFD').replace(/[\u0300-\u036f]/g, "").replace(/ª/g,'a').replace(/[æÆ]/g,'ae').replace(/©/g,'c').replace(/[ÐÐ]/g,'d').replace(/fi/g,'fi').replace(/fl/g,'fl').replace(/[œŒ]/g,'oe').replace(/[ºøØ]/g,'o').replace(/π∏/g,'p').replace(/®/g,'r').replace(/ß/g,'ss').replace(/™/g,'tm').replace(/[‘’]/g,'\'').replace(/[“”«»]/g,'"').replace(/[†‡§]/g,'*'); } // Dir_List: Classify items function classifyDirListItems() { $dir_list_row.each(function() { let row = {}; $this_link = thisLink(this); $this_text = thisText(this).endsWith('/') ? thisText(this).slice(0,-1) : thisText(this); // don't include '/' $this_ext = thisExt(this); // add classes and data to row cells $(this).attr('id',$(this).index()).find('td').first().addClass('name').attr( 'data-value',stringNormalize( $this_text )).next('td:not(.kind)').attr('class','size').next('td:not(.kind)').attr('class','date'); // add tr ID and td.name data-value // add dir or file classes if ( $this_ext === '/' ) { // add tr data-ext $(this).addClass('dir').attr('data-ext','dir'); } else { $(this).addClass('file').attr('data-ext',$this_ext); } // add tr invisible class if ( $this_text.startsWith('.') ) { $(this).addClass('invisible'); } // add kind and ext detail columns $(this).append('') .append(''); if ( $this_ext === undefined ) { $(this).addClass('code').attr('data-type','Code').attr('data-kind','code').find('td.kind').attr('data-value','Code').text('Code'); return; } else if ( !JSON.stringify($row_types).includes($this_ext) ) { // else classify as "other" if extension is not in $row_types. $(this).addClass('other').attr('data-type','Other').attr('data-kind','other').find('td.kind').attr('data-value','other').text('Other'); } for ( let key in $row_types ) { // Categorize rows by listed supported file types if ( $row_types[key].includes($this_ext) ) { let $display_key = key.charAt(0).toUpperCase() + key.slice(1); // make display name for file type let kind = $display_key === undefined ? 'File' : $display_key; $(this).addClass(key).addClass($this_ext).attr('data-type',$display_key).attr('data-kind',kind.toLowerCase() ).find('td.kind').attr('data-value',kind).text(kind); // add kind and ext classes, data-type, data-kind if ( key === 'audio' || key === 'video' ) { // media classes and prepend checkbox $(this).addClass('media').find('a').prepend(''); } } } // For ignored and excluded items for ( let key in $row_settings ) { if ( $row_settings[key].includes($this_ext) ) { $(this).addClass(key); } if ( $row_settings[key].includes($this_ext) && key == 'ignore' ) { } } }); // end classify dir_list items } classifyDirListItems(); // ***** END DIR_LIST SETUP ***** // // ***** UI SETUP ***** // // Add body classes function setupUI() { if ( $dir_list.find('.audio').length > 0 ) { $body.add($dir_list).addClass('has_audio has_media'); } if ( $dir_list.find('.font').length > 0 ) { $body.addClass('has_fonts'); } if ( $dir_list.find('.image').length > 0 ) { $body.addClass('has_images'); } if ( $dir_list.find('.video').length > 0 ) { $body.add($dir_list).addClass('has_video has_media'); } setQuery('autoload_media',$UI_pref_autoload_media); if ( $UI_pref_autoload_media === true ) { $body.addClass('autoload_media'); $autoload_media.addClass('checked'); } else { $body.removeClass('autoload_media'); $autoload_media.removeClass('checked'); } if ( $settings.autoload_index_files === true ) { $body.addClass('autoload_index_files'); } if ( $settings.use_custom_icons === true ) { $body.addClass('use_custom_icons') } else { $body.addClass('use_default_icons'); } if ( $settings.hide_ignored_files === true ) { $body.addClass('hide_ignored'); } if ( navigator.platform.indexOf('Win') > -1 || $location.indexOf('file:') < 0 ) { $inv_checkbox.hide(); } else if ( $settings.hide_invisibles === true ) { $inv_checkbox.find('input').prop('checked',true); $body.addClass('hide_invisibles').removeClass('show_invisibles') } else { $inv_checkbox.find('input').prop('checked',false); $body.addClass('show_invisibles').removeClass('hide_invisibles') } setQuery('alternate_background',$UI_pref_background); if ( $UI_pref_background === true ) { $body.addClass('alternate_background'); $toggle_alt_bckgrd.addClass('checked'); } else { $body.removeClass('alternate_background'); $toggle_alt_bckgrd.removeClass('checked'); } if ( $UI_pref_details === false ) { $dir_list.addClass('show_details'); $dir_list_body.css({'top':$dir_list_head.height() + 1 +'px'}); $details_btn.find('span').first().hide().next().show(); } if ( $UI_pref_theme === true ) { $body.addClass('dark_theme'); } else { $body.addClass('light_theme'); } if ( $userAgent.indexOf('Chrome') > 0 ) { $body.addClass('is_chrome'); } if ( $userAgent.indexOf('Firefox') > 0 ) { $body.addClass('is_gecko'); } } setupUI(); // Build UI function buildUI() { $dir_list.appendTo($sidebar); var $main_content = $('
    /g,'') .replace(/<\/a><\/td><\/tr><\/tbody><\/table>/g,'') .replace(/sortable-data="\d+?/g,'data-value="') .replace(/([\d-]+)<\/td>\s*(.+?)<\/td>/g,'$2, $3File 
    '); $main_content.find('tr').append( $sidebar_wrapper, $content_pane ); $body.empty().prepend($main_content); if ( $body.hasClass('is_converted_list') ) { $('#sort_by_size, #sort_by_date, #size, #date').addClass('disabled'); } if ( $body.hasClass('is_converted_table') || $body.hasClass('is_converted_pre') ) { if ( $dir_list.find('td.size').length < 1 ) { $('#sort_by_size,th#size').addClass('disabled'); } if ( $dir_list.find('td.date').length < 1 ) { $('#sort_by_date,th#date').addClass('disabled'); } } } buildUI(); // ***** BASIC UI FUNCTIONS ***** // // Show Menus function showMenus(el) { var $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 function hideMenus() { $('.menu').hide(); } $(document).on('click', hideMenus ); // Toggle Invisibles function toggleInvisibles() { $body.toggleClass('hide_invisibles').toggleClass('show_invisibles'); } $inv_checkbox.on('click','input', toggleInvisibles ); // Toggle Autoload Media function toggleAutoloadMedia(e) { e.preventDefault(); $body.toggleClass('autoload_media'); toggleQuery('autoload_media'); $autoload_media.toggleClass('checked'); } $autoload_media.on('click', toggleAutoloadMedia ); // Toggle Dark Theme function toggleDarkMode(e) { e.preventDefault(); $body.toggleClass('dark_theme').toggleClass('light_theme'); toggleQuery('dark_theme'); } $toggle_dark_theme.on('click', toggleDarkMode ); // Toggle Alternating Row Background function toggleAlternateBackground(e) { e.preventDefault(); $body.toggleClass('alternate_background'); toggleQuery('alternate_background'); $toggle_alt_bckgrd.toggleClass('checked'); } $toggle_alt_bckgrd.on('click', toggleAlternateBackground ); // Toggle Details function toggleDetails() { $dir_list.toggleClass('show_details'); $dir_list_body.css({'top':$dir_list_head.height() + 1 +'px'}); $details_btn.find('span').toggle(); toggleQuery('hide_details'); } $details_btn.on('click', toggleDetails ); // Show/Hide Sidebar function toggleSidebar() { $body.toggleClass('has_hidden_sidebar'); setContentHeight(); } $toggle_sidebar.on('click', function() { toggleSidebar(); scrollThis('dir_list','selected',true); // true = instant scroll }); // Default settings: remove queries; function defaultSettings() { $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?" ) ) { defaultSettings(); } }); //***** UI SETUP *****// // Set Content Height function setContentHeight() { let $window_height = window.innerHeight; let $dir_list_head_height = $dir_list_head.length ? $dir_list_head.height() : 0; let $content_header_height = $content_header.outerHeight(); $dir_list.add($dir_list_wrapper).css({'height':$window_height - $sidebar_header.outerHeight() }); $dir_list.find($dir_list_body).css({'top': $dir_list_head_height }); $content_image.add($prev_btn).add($next_btn).css({'top':$content_header_height }); $content_pane.hasClass('has_image') ? $content_image.find('img').css({'max-height':$content_image.innerHeight() - 52 + 'px'}) : null; $content_grid.add($content_pdf).add($content_iframe).add($content_font).css({'height':$window_height - $content_header_height,'top':$content_header_height }); $content_scale.css({'top':$content_header_height + 13 }); $('#prev_track, #next_track, #close_audio').css({'height':$audio.height() }); } window.addEventListener('resize', function(e) { setContentHeight(); }); // Set Content Title const $title = $content_pane.find('#title'); function setContentTitle() { let $title_text = ''; if ( $('.playing').hasClass('audio') ) { // set audio player title $content_audio_title.find('td').empty().append( $('.playing').find('td.name a').text() ); } if ( $content_pane.hasClass('has_grid') ) { // set main title for other content $title_text = $current_dir_name; } else { $title_text = $title_text + $('.selected:not(.audio)').find('td.name a').text(); // Assemble title } $title.empty().text( $title_text ); // Add file name if ( $('.selected').hasClass('image') && !$content_pane.hasClass('has_grid') ) { setDimensions($('.selected.image')); } } // Get Image Dimensions function getDimensions(link, callback) { var img = new Image(); img.src = link; img.onload = function() { callback( this.width, this.height ); }; } function setDimensions(row) { getDimensions( thisLink(row), function( width, height ) { $title.append(' (' + width + 'px × ' + height + 'px)' ); }); } // Scroll Selected Items function scrollThis(elID,className,bool) { let $behavior = 'smooth'; bool === undefined ? null : $behavior = 'instant'; var $block = $userAgent.indexOf('Firefox') > -1 ? $block = 'start' : $block = 'nearest'; if ( document.getElementsByClassName(className).length > 0 ) { document.getElementById(elID).getElementsByClassName(className)[0].scrollIntoView({ behavior:$behavior, block:$block, inline:'nearest' }); } } // ***** SORTING ***** // var $sort_all = $dir_list_body.find('tr'); var $sort_dirs = $dir_list_body.find('tr.dir').not('.app'); var $sort_files = $dir_list_body.find('tr').not('.dir').add('.app'); var currentIndex, prevIndex; var $default_index = $('#thead').find('#default').index(); var $sort_order = 1; var dataName = function(x) { return $(x).find('td').eq(0).data('value').toString(); }; var dataData = function(x,index) { return $(x).find('td').eq(index).attr('data-value') === undefined ? '' : $(x).find('td').eq(index).attr('data-value').toString(); }; // Sort comparison functions var sortByName = function(x,y,sortDirection) { return sortDirection === 1 ? dataName(x).localeCompare(dataName(y)) : dataName(y).localeCompare(dataName(x)); }; var sortByData = function(x,y,index,sortDirection) { // sort by data then by name if ( sortDirection === 1 ) { return dataData(x,index).localeCompare(dataData(y,index), undefined, { numeric:true }) === 0 ? dataName(x).localeCompare(dataName(y)) : dataData(x,index).localeCompare(dataData(y,index), undefined, { numeric:true }); } else { return dataData(y,index).localeCompare(dataData(x,index), undefined, { numeric:true }) === 0 ? dataName(y).localeCompare(dataName(x)) : dataData(y,index).localeCompare(dataData(x,index), undefined, { numeric:true }); } }; // Sort elements: sort by name if index = 0, else sort by data-value. var sortEls = function(els,index,sortDirection) { els.detach().sort(function(a,b) { return index === 0 ? sortByName(a,b,sortDirection) : sortByData(a,b,index,sortDirection); }); }; // Sort Dir List function sortDirList(index, sortDirection) { $dir_list_row.removeClass('sorted'); if ( index == $default_index ) { if ( index == $default_index ) { index = 0; } // sort dirs and files separately sortEls( $sort_dirs, index, sortDirection ); sortEls( $sort_files, index, sortDirection ); if (sortDirection === 1 ) { // append dirs and files according to sort direction $.each($sort_dirs, function() { $dir_list_body.append(this); }); $.each($sort_files, function() { $dir_list_body.append(this); }); } else { $.each($sort_files, function() { $dir_list_body.append(this); }); $.each($sort_dirs, function() { $dir_list_body.append(this); }); } } else if ( $settings.dirs_on_top === false || index == 0 && index !== $default_index ) { // sort all dirs and files, append, remove body class sortEls( $sort_all, index, sortDirection ); $.each($sort_all, function() { $dir_list_body.append(this); }); $body.removeClass('is_dirs_on_top'); } else if ( $settings.dirs_on_top === true || index !== 0 ) { // sort dirs and files separately sortEls( $sort_dirs, index, sortDirection ); sortEls( $sort_files, index, sortDirection ); if (sortDirection === 1 ) { // append dirs and files according to sort direction $.each($sort_dirs, function() { $dir_list_body.append(this); }); $.each($sort_files, function() { $dir_list_body.append(this); }); } else { $.each($sort_files, function() { $dir_list_body.append(this); }); $.each($sort_dirs, function() { $dir_list_body.append(this); }); } } if ( index === $('#thead').find('#kind').index() || index === $('#thead').find('#ext').index() ) { $body.addClass('is_dirs_on_top'); addSortStyle( index, sortDirection ); } } // Add Sort Styles (for rules) function addSortStyle(index, sortDirection) { var $this_value, $next_value; $dir_list_row.removeClass('sorted'); $dir_list_row.filter(':visible').not('.dir').add('.app').each(function() { $this_value = $(this).find('td').eq(index).attr('data-value'); $next_value = $(this).next('tr:visible').find('td').eq(index).attr('data-value'); if ( $this_value !== $next_value ) { $(this).addClass('sorted'); } if ( $(this).attr('data-type') !== $(this).next('tr:visible').attr('data-type') ) { $(this).addClass('sorted'); } }); // for last dir if ( sortDirection == 1 ) { $dir_list_row.filter('.dir').last().addClass('sorted'); } } // Sort on click function clickSort(x,y) { // x = clicked sort link, y = bool (false ? don't set query_prefs) currentIndex = x.index(); // Only reverse sort order after clicking a sort column once. if ( currentIndex != prevIndex ) { prevIndex = currentIndex; $sort_order = 1; } sortDirList(currentIndex, $sort_order); $sort_order = -1 * $sort_order; x.toggleClass('up').addClass('checked').siblings().removeClass('checked up'); $('#sort_menu').find('li').eq(currentIndex).addClass('checked').siblings().removeClass('checked'); setContentHeight(); // set sorting query pref if ( y === true ) { $query_prefs = getQueryPrefs(); $query_prefs.set('sort',$('#sort_menu').find('li').eq(currentIndex).text().toLowerCase() ); updateQuery(); } } // Sort on clicking dir_list sort header $('#thead').on('click','th:not(.disabled)',function(e) { e.preventDefault(); e.stopPropagation(); var i = $(this).index(); clickSort( $(this),true) }); // 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(); $(this).addClass('checked').siblings().removeClass('checked'); $('#theader th[id*="'+ thisText($(this)).slice(0,2) +'" i]').click(); }); // Initialize sort function initialSort() { switch ( $UI_pref_sort ) { case 'name': i = 0; break; case 'size': i = 1; break; case 'date': i = 2; break; case 'kind': i = 3; break; case 'extension': i = 4; break; default: i = 5; } $('#theader').find('th').eq(i).click(); } initialSort(); // ***** END SORTING ***** // // ***** END BASIC UI FUNCTIONS ***** // // ***** CONTENT PANE ***** // var $selected = $dir_list.find('.selected'); var $playing = $dir_list.find('.playing'); var $media = $dir_list.find('td').filter('.media:not(.unchecked):not(.ignored)'); // SELECT ROW on click and set classes for $content_pane function selectThis(row) { let $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 if ( row.hasClass('audio') ) { // if row is audio, remove playing and selected classes row.addClass('selected playing').siblings('.media').removeClass('selected playing hovered'); } else { // remove classes from rows, but leave .audio with playing row.addClass('selected').siblings().removeClass('selected hovered'); } } //***** SHOW CONTENT *****// // Show Font var $font_family_arr = []; function showFont(row) { var $font_family = thisText(row); if ( $font_family_arr.indexOf($font_family) == -1 ) { // if font family is not in array, add it $font_family_arr.push($font_family); $font_preview_styles.append('@font-face { font-family: "'+ $font_family +'"; src: url("'+ thisLink(row) +'"); }'); // only add style if it doesn't exist } $content_font.css({ 'font-family':'"'+ $font_family +'"' }); } // Show Grid function showGrid() { $content_pane.removeClass('has_hidden_grid').addClass('has_grid'); setContentSource($content_grid); setContentTitle(); setContentHeight(); selectThis($('.selected')); } // Hide Grid function hideGrid() { if ( $content_pane.hasClass('has_grid') ) { $content_pane.removeClass('has_grid').addClass('has_hidden_grid'); } } // Set Content Source function setContentSource(el,link) { // add source attribute to content containers, excluding $content_font let $el_ID = $(el).attr('id'); switch ($el_ID) { case 'content_audio': $(el).find('audio').attr('src',link); break; case 'content_image': $(el).find('img').attr('src',link); break; case 'content_font': break; default: // content_pdf, content_video, or content_iframe $(el).removeAttr('srcdoc').attr('src',link); } } // SHOW CONTENT function showContent(row) { // show any content excluding grids if ( row.length > 0 ) { // needed for left/right arrow nav when there are no valid items (i.e. images or fonts) let kind = thisRow(row).hasClass('ignore') ? 'ignored' : thisRow(row).attr('data-kind'); // get file kind !['audio','font','image','pdf','video','ignored'].includes(kind) || kind === 'dir' ? kind = 'iframe' : null; // load dirs and any other kind of content except audio, font, image, pdf, or video into iframe let link = kind === 'pdf' ? thisLink(row) + '?#view=fitB&scrollbar=1&toolbar=1&navpanes=1' : thisLink(row); // add pdf query str to link $content_pane.hasClass('has_grid') ? hideGrid() : null; closeAllContent(row); // except audio and grids if ( kind === 'ignored' ) { $content_pane.addClass('has_ignored'); } else { setContentSource( '#content_'+ kind, link ); // set content container source kind === 'font' ? showFont(row) : null; // set $content_font css kind === 'image' ? $content_grid.find('a[href="' + thisLink(row) + '"]').parent('div').addClass('selected').siblings().removeClass('selected') : null; // set image source kind === 'video' ? closeAudio() : null; // if video, close audio } thisRow(row).attr('data-kind') === 'dir' ? $content_pane.addClass( 'has_dir' ) : $content_pane.addClass( 'has_'+ kind ); // add content pane class setContentHeight(); setContentTitle(); kind === 'audio' ? autoLoadCoverArt() : null; // autoload cover art on selecting audio } } //***** CLOSE CONTENT (Close button or Cmd/Ctrl + W) *****// // Close Audio function closeAudio() { $('.audio.playing').removeClass('playing'); $content_pane.removeClass('has_audio').find('#content_audio_title td').empty(); $audio.trigger('pause').attr('src',''); setContentHeight(); } // Close audio button click $close_audio.on('click',function(e) { e.stopPropagation(); closeAudio(); }); // Close Grid function closeGrid() { $content_pane.removeClass('has_grid'); $content_grid.empty().removeClass().attr('style','').find('.image_grid_item, img').attr('style',''); } // Close content excluding audio and grids function closeAllContent(row) { if ( row !== undefined && row.hasClass('audio') ) { return; } else { let $content_classes = $content_pane.attr('class') !== undefined ? $content_pane.attr('class').split(' ') : []; // get array of content pane classes for ( let $content_class of $content_classes ) { // for each content_pane class, define the associated content container, remove class and source let $container_name = '#content_'+ $content_class.substring(4); let $content_el = $( $container_name ); // define content container from content pane class name if ( ['has_font','has_image','has_pdf','has_video','has_iframe','has_dir','has_ignored'].includes($content_class) ) { // if not grid or audio, remove class $content_pane.removeClass($content_class); if ( $content_class === 'has_font' ) { // remove font style $content_font.css({'font-family':''}) $content_font.css({'font-size':'1em'}); // reset font: comment out to retain font scale after loading other content } else if ( $content_class === 'has_image' ) { // remove image src $content_image.find('img').attr('src',''); $content_image.attr('data-image-scale-factor',1).find('img').removeClass('zoom_img').attr('style',''); // reset image: comment out to retain image scale after loading other content } else if ( $content_class === 'has_video' ) { // remove video src $content_video.trigger('pause').attr('src',''); } else { $content_el.attr('src',''); // remove src for anything else $content_iframe.attr('src',''); // remove src for anything else } } } $content_title.removeClass().find('#title').empty(); setContentHeight(); } } // CLOSE CONTENT function closeContent() { if ( $content_pane.hasClass('has_grid') ) { closeGrid(); // if has_grid, close grid } else if ( $content_pane.hasClass('has_hidden_grid') ) { showGrid(); // if has_hidden_grid, close content, show grid } else if ( ['has_font','has_image','has_pdf','has_video','has_iframe','has_dir','has_ignored'].some( c => $content_pane.attr('class').split(' ').indexOf( c ) >= 0 ) ) { closeAllContent(); // close content if content pane has one of these classes, except audio and grids } else { // close audio last of all closeAudio(); } setContentHeight(); } $('#close_btn').on('click', function(e) { e.preventDefault(); e.stopPropagation(); closeContent(); }); //***** 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.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_image.attr('data-image-scale-factor',1).find('img').removeClass('zoom_img').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').find('a').click(); } setContentHeight(); } $('#reload_btn').on('click', function(e) { e.preventDefault(); e.stopPropagation(); resetContent(); // $content_pane.addClass('has_iframe'); // $content_iframe.attr('src','data:text/plain,'); }); //***** SELECT ROWS *****// var prevRow = function(className) { return ( !$('.selected').length || !$('.selected').prevAll(':visible:not(.unchecked)').filter(className).length ) ? $('#tbody').find('tr').filter(className).last() : $('.selected').prevAll(':visible:not(.unchecked)').filter(className).first(); }; var nextRow = function(className) { // if nothing selected, or if no next row with classname, return first row with classname, else return next row with classname return ( !$('.selected').length || !$('.selected').nextAll(':visible:not(.unchecked)').filter(className).length ) ? $('#tbody').find('tr').filter(className).first() : $('.selected').nextAll(':visible:not(.unchecked)').filter(className).first(); }; //***** SELECT ROWS by typed string *****// var str = '', timer, $next_ltr; function timeoutID() { timer = window.setTimeout( function() { str = ''; }, 1500 ); } function alphaNav(e) { // Select Dir_List row by typed string; Todo: select next row by nearest letter if (typeof timer == 'number' ) { window.clearTimeout( timer ); timer = 0; // id } timeoutID(); str += e.key str = str.toLowerCase(); if ( $('#dir_list').find('td.name[data-value^="'+ str +'"]').length ) { $('#dir_list').find('td.name[data-value^="'+ str +'"]').first().find('a').click(); } else { // $('#dir_list').find('td.name[data-value^="'+ str +'"]').first().find('a').click(); null; // replace this with next closest match function } } // Click Prev/Next Arrows function prevNextBtn(el) { if ( el.attr('id') === 'prev_btn' ) { clickRow( prevRow('.image:visible,.font:visible') ); } if ( el.attr('id') === 'next_btn' ) { clickRow( nextRow('.image:visible,.font:visible') ); } } $content_pane.on( 'click','#prev_btn, #next_btn', function(e) { e.stopPropagation(); e.preventDefault(); prevNextBtn( $(this) ); }); // Click grid button $sidebar_header.on('click', '#grid_btn, #show_font_grid, #show_image_grid', function(e) { makeGrids(e,$(this)); showGrid(); }); // Click prev/next track buttons $('.prev_next_track_btn').on('click',function() { $(this).attr('id') === 'prev_track' ? playPrevNextTrack('ArrowLeft') : playPrevNextTrack('ArrowRight') ; }); // SELECT ROWS prev/next media track with arrow keys function playPrevNextTrack(key) { let $key = key.key; $shuffle.find('input').prop('checked') === true ? shuffle() : null; $playing = $('.playing'); let kind = $playing.attr('data-kind'); if ( $body.hasClass('has_media') ) { if ( $playing.length === 0 ) { // if no media selected, select first shuffle or first media file if ( $shuffle.find('input').prop('checked') === true ) { clickRow( $('.audio').eq($count) ); } else { switch ( $key ) { case 'ArrowLeft': clickRow( $media.last() ); break; case 'ArrowRight': clickRow( $media.first() ); break; } } } if ( $playing.length == 1 ) { if ( $shuffle.find('input').prop('checked') === true ) { selectThis( $('.audio').eq($count) ); showContent( $('.audio').eq($count) ); $shuffleList.length !== 0 ? playMedia('play') : null; } else { switch ( key ) { case 'ArrowLeft': if ( $playing.prevAll('.media[data-kind="'+ kind +'"]:not(.unchecked)').length === 0 ) { clickRow( $dir_list_row.filter('.media[data-kind="'+ kind +'"]:not(.unchecked)').last() ); } else { clickRow( $playing.prevAll('.media[data-kind="'+ kind +'"]:not(.unchecked)').first() ); } break; case 'ArrowRight': if ( $playing.nextAll('.media[data-kind="'+ kind +'"]:not(.unchecked)').length === 0 && $loop.find('input').is(':checked') === false ) { // loop playback selectThis( $dir_list_row.filter('.media[data-kind="'+ kind +'"]:not(.unchecked)').first() ); autoLoadCoverArt(); return true; } else if ( $playing.nextAll('.media[data-kind="'+ kind +'"]:not(.unchecked)').length === 0 ) { // else click first media file clickRow( $dir_list_row.filter('.media[data-kind="'+ kind +'"]:not(.unchecked)').first() ); } else { clickRow( $playing.nextAll('.media[data-kind="'+ kind +'"]:not(.unchecked)').first() ); // else click next media file } break; } } playMedia('play'); } } } // SELECT ROWS by arrow keys function leftRightArrowNavigation(key,kind) { if ( $body.hasClass('has_media') && $('.selected').hasClass('audio') && !$('.selected').hasClass('playing') ) { // play selected track (e.g., after up/down arrow) clickRow( $('.audio.selected') ); playMedia('play'); } else if ( $body.hasClass('has_media') && $('.selected').hasClass('audio')) { // play next audio track playPrevNextTrack(key); playMedia('play'); } else { // select prev/next row of same sort kind if ( key === 'ArrowLeft' ) { clickRow( prevRow('[data-kind="'+ kind +'"]:visible') ); } if ( key === 'ArrowRight' ) { clickRow( nextRow('[data-kind="'+ kind +'"]:visible') ); } if ( $('.selected').hasClass('video') ) { playMedia('play') } } } function arrowNavigation(e) { let $key = e.key; let $selected = $('.selected'); let kind = $('.selected').attr('data-kind') === undefined ? $dir_list.find('tbody tr:visible').first().attr('data-kind') : $('.selected').attr('data-kind'); if ( $content_pane.hasClass('has_grid') ) { // Grid navigation: L/R arrow selects images and fonts only; U/D arrow clicks row. switch ( $key ) { case 'ArrowUp': clickRow( prevRow('.dir:visible,.file:visible') ); break; case 'ArrowDown': clickRow( nextRow('.dir:visible,.file:visible') ); break; case 'ArrowLeft': if ( $content_grid.hasClass('has_font_grid') ) { selectThis( prevRow('.font:visible') ); } else if ( $content_grid.hasClass('has_image_grid') ) { selectThis( prevRow('.image:not(.ignore):visible') ); } else { selectThis( prevRow('.image:not(.ignore):visible,.font:visible') ); } break; case 'ArrowRight': if ( $content_grid.hasClass('has_font_grid') ) { selectThis( nextRow('.font:visible') ); } else if ( $content_grid.hasClass('has_image_grid') ) { selectThis( nextRow('.image:not(.ignore):visible') ); } else { selectThis( nextRow('.image:not(.ignore):visible,.font:visible') ); } break; } } else { switch ( $key ) { case 'ArrowUp': // if audio player not visible, show and load audio when selected; else if audio player visible, select but don't load prev/next audio file. if ( prevRow('.dir:visible,.file:visible').hasClass('audio') ) { closeAllContent(); // except audio and grids if ( !$content_pane.hasClass('has_audio') ) { clickRow( prevRow('.audio:visible') ); $('.selected:not(.audio)').removeClass('selected'); } else { prevRow('.audio:visible').addClass('selected').siblings().removeClass('selected hovered'); autoLoadCoverArt(); } } else { clickRow( prevRow('.dir:visible,.file:visible') ); } break; case 'ArrowDown': if ( nextRow('.dir:visible,.file:visible').hasClass('audio') ) { // if next row is audio... closeAllContent(); // except audio and grids if ( !$content_pane.hasClass('has_audio') ) { // if audio player is closed, click next row to load and show file clickRow( nextRow('.audio:visible') ); $('.selected:not(.audio)').removeClass('selected'); } else { // else simply select the next audio file without closing currently playing audio nextRow('.audio:visible').addClass('selected').siblings().removeClass('selected hovered'); autoLoadCoverArt(); } } else { clickRow( nextRow('.dir:visible,.file:visible') ); } break; case 'ArrowLeft': leftRightArrowNavigation('ArrowLeft',kind); break; case 'ArrowRight': leftRightArrowNavigation('ArrowRight',kind); break; } } scrollThis('dir_list','selected'); $content_pane.hasClass('has_grid') && $content_grid.find('.selected').length > 0 ? scrollThis('content_grid','selected') : null; } //***** CLICK & HOVER EVENTS for Content *****// // 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'); } }); // CLICK grid item function gridItemClick(e,el) { e.preventDefault(); clickThis($dir_list.find('a[href*="'+ thisLink(el) +'"]') ); } $content_grid.on('click','div', function(e) { gridItemClick(e,$(this)); }); // CLICK Row function clickRow(row) { // Pause/Play audio if .selected = audio, else click row normally if ( thisRow(row).hasClass('playing') && !thisRow(row).hasClass('video') ) { playPauseMedia(); } else { selectThis( thisRow(row) ); showContent( thisRow(row) ); } hideMenus(); } // CLICK Row $dir_list_row.on('click','a', function(e) { e.preventDefault(); e.stopPropagation(); clickRow( $(this) ); }); // Click element anchor function clickThis(el) { el.find('a').length > 0 ? el.find('a').click() : el.click(); } // DOUBLE-CLICK Row to open directory function doubleClickRow(row) { if ( row.hasClass('dir') ) { $query_prefs = getQueryPrefs(); var $history = $query_prefs.get('history') === null ? '' : '+'+ $query_prefs.get('history'); var $current_index = row.prevAll('.dir:visible:not(.ignore)').length; $history = $current_index + $history; // update history $query_prefs.delete('selected'); $query_prefs.set('history',$history); updateQuery(); window.location = row.find('a').attr('href') +'?'+ $query_prefs; } } $dir_list_row.filter('.dir').on('dblclick', function(e) { e.preventDefault(); e.stopPropagation(); doubleClickRow( $(this) ); }); //***** AUTOLOAD CONTENT: index files or files from the file shortcut list *****// function autoSelectFile() { if ( $UI_pref_selected !== '' ) { selectThis( $dir_list.find('tbody tr.dir:not(.invisible)').eq($UI_pref_selected) ); showContent( $dir_list.find('tbody tr.dir:not(.invisible)').eq($UI_pref_selected) ); } else if ( $UI_pref_file !== '' ) { clickThis( $dir_list_row.find('a:contains('+ $UI_pref_file +')') ); } else if ( $body.hasClass('autoload_index_files') && $dir_list.find( 'a[href*="/index."]').length > 0 ) { // else load index file clickThis( $dir_list.find('a[href*="/index."]') ); } else if ( $body.hasClass('autoload_media') && $body.hasClass('has_media') ) { // else if audio and images, load cover art clickThis( $dir_list.find('.audio,.video').first() ); } else { // else select first non-media item // clickThis( $dir_list.find('tbody tr:not(.media):not(.invisible)').first() ); } scrollThis('dir_list','selected'); scrollThis('dir_list','playing'); } autoSelectFile(); // Autoload Cover Art 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('autoload_media') ) { return; } else if ( $body.hasClass('has_audio') && $body.hasClass('has_images') && $content_pane.hasClass('has_audio') && $content_image.siblings().attr('src') === undefined ) { var $cover; var $this_ext; const $image_titles = ['cover','front']; for ( let i = 0; i < $image_titles.length; i++ ) { // select first image whose title begins with $image_titles[i] or which contains $image_titles[i]. $cover = $dir_list.find('.image').find('td.name[data-value^="'+ $image_titles[i] +'"]:not([data-value*="back"])').parent('tr').first() || $dir_list.find('.image').find('td.name[data-value*="'+ $image_titles[i] +'"]:not([data-value*="back"])').parent('tr').first(); if ( $cover.length === 1 ) { showContent($cover); $title.empty().text( $cover.find('a').text() ); setDimensions($cover); break; } else { showContent( $dir_list.find('.image').first() ); // otherwise show the first image $title.empty().append($dir_list.find('.image').first().find('a').text() ); setDimensions($dir_list.find('.image').first()); break; } } } } // File shortcuts menu: autoload directory, then auto-select file function showFileShortcut(item) { $this_link = thisLink(item); window.location = $this_link.slice( 0, $this_link.lastIndexOf('/') ); } //***** KEYBOARD EVENTS *****// $body.on('keydown',$dir_list,function(e) { setContentHeight(); $(':focus').blur(); // Need this to able to select grid items after clicking close button (or other buttons). let $dir_list_row = $dir_list.find('tbody tr:not(.unchecked)').filter(':visible'); let $selected = $dir_list.find('tbody tr.selected'); let $selected_href = thisLink($selected); let $playing = $dir_list_row.filter('.playing'); var $time; switch ( e.key ) { case 'ArrowUp': if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { // Cmd/Ctrl + up arrow = go to parent directory if ( $('#parents_dir_menu + ul a').length < 1 ) { return; } else { $('#parent_dir_menu a').trigger('click'); } break; } if ( $('*[contentEditable="true"]').is(':focus') ) { // Allow arrow navigation within content_editable elements return; } e.preventDefault(); arrowNavigation(e); break; case 'ArrowDown': if ( (e.ctrl || e.metaKey) && $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(); arrowNavigation(e); 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.metaKey && (e.altKey && e.shiftKey) || e.altKey ) { // Skip media -30s/-10s mediaSkip(e); return; } else { arrowNavigation(e); } 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.metaKey && (e.altKey && e.shiftKey) || e.altKey ) { // Skip audio 30s/10s: Opt-Shift-Arrow/Opt-Arrow mediaSkip(e); return; } else { arrowNavigation(e); } break; case ' ': // space if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } if ( $content_pane.hasClass('has_audio') || $content_pane.hasClass('has_video') ) { // Play/pause media (space bar) e.preventDefault(); playPauseMedia(); } 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 ( $content_pane.hasClass('has_grid') ) { $body.find('#dir_list').find('.selected a').click(); } else { clickThis(thisRow($selected)); if ( $selected.hasClass('media') && !$content_pane.hasClass('has_grid') ) { // Use return to play/pause media let e = new Event('keydown'); e.key = ' '; } } } 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 '': case 'e': case 'f': case '': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case '': case 'p': case 'q': case '': case 's': case 't': case 'u': case 'v': case '': 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 'Δ': 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 '¸': 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.preventDefault(); e.stopPropagation(); $details_btn.click(); } if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case 'g': // Cmd/Ctrl + G: Show image Grid if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { e.preventDefault(); e.stopPropagation(); $grid_btn.click(); } if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case 'i': // Cmd/Ctrl + I: Toggle Invisibles if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { e.preventDefault(); e.stopPropagation(); $inv_checkbox.find('input').click(); } if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case 'o': // Cmd/Ctrl + Shift + O: Open selected item in new window if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.shiftKey ) { window.open($selected_href); } break; case 'r': // Cmd/Ctrl + Shift + R: Refresh if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { e.preventDefault(); e.stopPropagation(); $content_reload_btn.find('button').click(); } if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case 'w': // Close content pane if Close button visible with Cmd/Crtl + W // Doesn't work in some browsers: can't override default keybinding if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && ( $content_pane.hasClass('[class^="has_"]') || $content_pane.hasClass('has_grid') ) ) { e.preventDefault(); e.stopPropagation(); $content_close_btn.find('button').click(); } if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } break; case '.': // Increase previewed content size if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.shiftKey ) { $('#increase').click(); } break; case ',': // Decrease previewed content size if ( !e.metaKey && !e.ctrlKey && !e.altKey ) { alphaNav(e); } if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.shiftKey ) { $('#decrease').click(); } break; case 'tab': break; } // end switch }); // ***** END KEYBOARD EVENTS ***** // // ***** GRID SETUP ***** // // Create Font Grid Items const fontGridItems = function() { var $font_grid_items_arr = []; $dir_list_row.filter('.font').each(function() { let $this_link = $(this).find('a').attr('href'); let $font_family = thisText($(this)); let $display_name = $(this).find('a').text().slice( 0,$font_family.lastIndexOf('.') ).replace(/[_|-]/g,' '); if ( $font_family_arr.indexOf($font_family) == -1 ) { $font_family_arr.push($font_family); $font_preview_styles.append('@font-face { font-family: "'+ $font_family +'"; src: url("'+ $this_link +'"); }'); // only add style if it doesn't exist } $font_grid_item_el.empty().append('

    '+ $display_name +'

    '+ $display_name +'

    ' ); $font_grid_items_arr.push($font_grid_item_el.clone()); }); return $font_grid_items_arr; }; // Create Image Grid Items const imageGridItems = function() { var $image_grid_items_arr = []; $dir_list_row.filter('.image').each(function() { let $this_link = thisLink(this); let $this_ext = thisExt(this); let exts = $row_types.image.filter( ext => $.inArray(ext, $row_settings.ignore) == -1 ); let $display_name = $this_link.slice($this_link.lastIndexOf('/') + 1).replace(/[_|-]/g,' '); if ( $.inArray( $this_ext, exts ) > -1 ) { // if this row file ext is in the image extension array $image_grid_item_el.empty().append(''); $image_grid_items_arr.push( $image_grid_item_el.clone() ); } }); return $image_grid_items_arr; }; // Make Grids function makeGrids(e,el) { e.stopPropagation(); closeGrid(); $content_pane.removeClass('has_hidden_grid').addClass('has_grid'); if ( el.attr('id') === 'grid_btn' ) { $title.removeClass(); fontGridItems().length === 0 ? $content_grid.addClass('has_image_grid') : $content_grid.addClass('has_grid'); $content_grid.append( imageGridItems(), fontGridItems() ); } else if ( el.attr('id') === 'show_font_grid' ) { $title.removeClass().addClass('font_grid'); $content_grid.addClass('has_font_grid'); $content_grid.append( fontGridItems() ); } else { $title.removeClass().addClass('image_grid'); $content_grid.addClass('has_image_grid'); $content_grid.append( imageGridItems() ); } } // ***** SCALE PREVIEWED IMAGES & FONTS ***** // var $em = parseInt(getComputedStyle(document.body).fontSize); // pts/em var $font_incr = 1.125; // scale factor for font size increase/decrease var $image_incr = 1.125; var $image_width; var $image_height; var $image_scale_factor; var $image_grid_item_size; var $grid_scale_factor; var fontSize = function(el) { return parseFloat(el.css('font-size')); }; // Scale Fonts function scaleFonts(incr, y) { if ( y === -1 ) { 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':( fontSize($content_grid)/$em * incr ) +'em'}); return; } if ( $content_pane.hasClass('has_font') ) { $content_font.css({'font-size':( fontSize($content_font)/$em * incr ) +'em'}); return; } } // Scale Images function scaleImages(incr, y) { if (y === -1 ) { incr = 1/incr; } if ( $content_pane.hasClass('has_image') && !$content_pane.hasClass('has_grid') ) { $image_width = parseFloat( $content_image.find('img').width() ) * incr; // increment image size $image_height = parseFloat( $content_image.find('img').height() ) * incr; // increment image size $image_scale_factor = parseFloat( $content_image.attr('data-image-scale-factor') ); // get scale factor $content_image.attr('data-image-scale-factor', parseFloat( $image_scale_factor ) * incr ).find('img').removeClass('zoom_img').css({'width':$image_width +'px', 'max-width':'none', 'max-height':'none','top':'0','transform':'translateY(0)'}); $content_image.scrollLeft( ( $image_width - $(window).width() )/2 ) ; if ( ( ( $image_height - $(window).height() )/2 ) > 0 ) { $content_image.scrollTop( ( $image_height - $(window).height() )/2 ); } return; } if ( $content_pane.hasClass('has_grid') && ( $content_grid.hasClass('has_image_grid') || $content_grid.hasClass('has_grid') ) ) { $image_grid_item_size = parseFloat( $('.image_grid_item').width() * incr); $grid_scale_factor = parseFloat( $content_grid.attr('data-grid-scale-factor') ); $content_grid.attr('data-grid-scale-factor', parseFloat( $grid_scale_factor ) * incr ).css({'grid-template-columns':'repeat(auto-fit, minmax('+ ($image_grid_item_size) +'px, 1fr))', 'grid-template-rows':'repeat(auto, minmax('+ ($image_grid_item_size) +'px))' }); $content_grid.find('.image_grid_item').css({'width':$image_grid_item_size +'px', 'height':$image_grid_item_size +'px'}); // grid items are square, so width = height $content_grid.find('img').css({'max-width':( $image_grid_item_size - $image_grid_item_size/8 ) +'px', 'max-height':( $image_grid_item_size - $image_grid_item_size/8) +'px'}); return; } } // Scale Fonts and Images function scalePreviewItems(y) { // combine scaling into one function scaleImages( $image_incr, y ); scaleFonts( $font_incr, y ); } // Scale Content $content_scale.on('click','span',function() { if ( $(this).attr('id') === 'increase' ) { scalePreviewItems(1); } if ( $(this).attr('id') === 'decrease' ) { scalePreviewItems(-1); } }); // Zoom Images on click function zoomImage(x,e) { $this_link = $(x).attr('src'); var $offset = $(x).offset(); var $this_width = $(x).width(); var $this_height = $(x).height(); $(x).toggleClass('zoom_img'); ( $(x).attr('style') !== '' || $(x).attr('style') !== undefined ) ? $(x).attr('style','') : null; $content_image.find('img:not(.zoom_img)').css({'max-height':$content_image.innerHeight() - 52 + 'px'}) if ( $this_link !== undefined ) { getDimensions( $this_link, function( width, height ) { $content_image.scrollLeft( (e.pageX - $offset.left) * width/($this_width + 13) - ( e.pageX - $offset.left ) - 52 ) ; $content_image.scrollTop( (e.pageY - $offset.top) * height/($this_height + 13) - ( e.pageY - $offset.top ) - 52 ); }); } } $content_image.on('click', 'img', function(e) { zoomImage( this,e ) }); // ***** END SCALE PREVIEW ITEMS ***** // // ***** AUDIO CONTENT ***** // var $count = 0; var $playlist; var $shuffleList = []; var $next; var $task; // Update Playlist function updatePlaylist() { $playlist = []; $dir_list_row.filter('.audio:not(.unchecked)').each(function() { $this_link = thisLink(this); $playlist.push($this_link); }); return $playlist; } // Initialize Shuffle List function initShuffleList() { updatePlaylist(); $shuffleList = []; for ( let i = 0; i < $playlist.length; i += 1 ) { $shuffleList.push(i); } return $shuffleList; } // Update Play Count function updateCount() { $count = $playing.index('.audio:not(.unchecked)'); } // Check/Uncheck Audio/Video Files function toggleChecked(e) { e.stopPropagation(); $(this).blur(); thisRow(this).toggleClass('unchecked'); updateCount(); updatePlaylist(); initShuffleList(); } $dir_list_row.filter('.media').on('click','input', toggleChecked ); // Check/Uncheck all Audio/Video Files function toggleAllChecked(e) { e.stopPropagation(); $dir_list_row.find('input').trigger('click'); updatePlaylist(); initShuffleList(); } $dir_list.find('#play_toggle').on('click', toggleAllChecked ); // Is Playing function isPlaying(el) { return (el.get(0).currentTime > 0 && !el.get(0).paused && !el.get(0).ended); } // Play Media function playMedia(task) { $('.playing').hasClass('audio') ? $audio.trigger(task) : $content_video.trigger(task); } // Skip media tracks +/-10/30 seconds function mediaSkip(e) { let factor = e.key === 'ArrowLeft' ? -1 : 1; if ( e.altKey && e.shiftKey ) { n = 30; } else if ( e.altKey ) { n = 10; } let $media = $('.playing').hasClass('audio') ? $audio : $content_video; let $time = $media.prop('currentTime'); $media.prop('currentTime', $time + factor*(n)); } // Play/Pause Audio/Video function playPauseMedia() { if ( $content_pane.hasClass('has_audio') ) { isPlaying($audio) ? $audio.trigger('pause') : $audio.trigger('play'); } if ( $content_pane.hasClass('has_video') ) { isPlaying($content_video) ? $content_video.trigger('pause') : $content_video.trigger('play'); } } // Play Next Track function playPrevNextTrackBtn(el) { e = $.Event("keydown"); e.key = el.attr('id') === "prev_track" ? 'ArrowLeft' : 'ArrowRight'; playPrevNextTrack(e); } // Prev/Next Track buttons $('.prev_next_track_btn').on( 'click', function() { playPrevNextTrackBtn( $(this) ); }); // Toggle Shuffle Play function toggleShuffle() { let $rand = Math.floor( Math.random() * ($media.length) ); if ( $shuffle.find('input').prop('checked') ) { ( !isPlaying($audio) && !isPlaying($content_video) ) ? clickThis( $media.eq($rand) ) : null; // if no media playing, select random track; if media playing, do nothing, then shuffle. updatePlaylist(); initShuffleList(); $count = Math.floor( Math.random() * $shuffleList.length ); } } $shuffle.on('click', toggleShuffle ); // Shuffle Play function shuffle() { if ( $shuffleList.length <= 1 && $loop.find('input').prop('checked') ) { // If loop is checked, and all songs have been shuffled... initShuffleList(); $next = Math.floor( Math.random() * $shuffleList.length ); // choose a random index number from the remaining unplayed songs, $count = $shuffleList[ $next ]; // set the playing $count to the index } else if ( $shuffleList.length === 0 ) { // else if all songs have been shuffled, select the first song and stop; $count = 0; } else { $next = Math.floor( Math.random() * $shuffleList.length ); // else choose a random index number from the remaining unplayed songs, $count = $shuffleList[ $next ]; // set the playing $count to the index $shuffleList.splice( $next, 1 ); // remove the indexed value from the unplayed list, } } // Initialize Audio function initMedia() { $('#audio, #content_video').on('ended', function() { playPrevNextTrack('ArrowRight'); scrollThis('dir_list','playing'); }); } initMedia(); // ***** END AUDIO CONTENT ***** // // ***** OTHER FUNCTIONS ***** // // Resize Sidebar/Content Pane function resizeSidebar(f) { f.stopPropagation(); var $startX = f.pageX; var $sidebar_width = $sidebar_wrapper.width(); var $window_width = window.innerWidth; $(document).on('mousemove',function(e) { e.stopPropagation(); e.preventDefault(); var $deltaX = e.pageX - $startX; if ( e.pageX > 200 && 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() { $(document).off('mousemove'); $sidebar_width = $sidebar_wrapper.width(); $query_prefs = getQueryPrefs(); $query_prefs.set('width',$sidebar_width); updateQuery(); }); } $handle.on('mousedown', resizeSidebar ); // EXPORT SETTINGS let $settings_string = unescape( $settings.toSource() ); $settings_string = $settings_string.replace('JSON.parse\(unescape\("\{','').replace('\}"))','').replace(/\/",/g,'",').replace(/\/"],/g,'"],').replace(/"(\w+?)":/g,'\n\n$1:\t'); var save = function(filename, data) { var blob = new Blob([data], {type: 'text/html'}); var 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(); save("settings.txt",$settings_string); }); })();