/* eslint-disable no-case-declarations, no-fallthrough, indent, no-mixed-spaces-and-tabs, no-multi-spaces, no-return-assign, no-useless-escape, quotes */ /* jshint esversion: 6 */ // ==UserScript== // @name Supercharged Local Directory File Browser // @version 8.0.2 // @description Makes directory index pages (either local or remote open directories) actually useful. Adds sidebar and content preview pane; keyboard navigation; sorting; light/dark UI; preview images/fonts in navigable grids; browse subdirectories w/o page reload; media playback, shuffle/loop options; basic playlist (m3u, extm3u) & cuesheet (.cue) support; create, edit, preview, save markdown/plain text files; open font files, view complete glyph repertoire, save glyphs as .svg; more. // @author gaspar_schot // @license GPL-3.0-or-later // @homepageURL https://openuserjs.org/scripts/gaspar_schot/Supercharged_Local_Directory_File_Browser // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACAAgMAAAC+UIlYAAAACVBMVEUmRcmZzP8zmf8pVcWPAAAAAXRSTlMAQObYZgAAAFBJREFUeF7tyqERwDAMBEE3mX5UiqDmqwwziTPHjG7xrmzrLFtRaApDIRiKQlMYCsFQFJrCUAiGotAU5hTA1WB4fhkMBsOJwWAwgHvB8CHpBcTbpxy4RZNvAAAAAElFTkSuQmCC // @match file://*/* // @match https://www.example.com/path/to/directory/* // @require https://cdn.jsdelivr.net/npm/markdown-it@13.0.1/dist/markdown-it.min.js // @require https://cdn.jsdelivr.net/npm/markdown-it-footnote@3.0.2/dist/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@4.0.2/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 // @require https://cdn.jsdelivr.net/npm/opentype.js@1.3.4/dist/opentype.min.js // @require https://cdn.jsdelivr.net/npm/@gerhobbelt/markdown-it-checkbox@1.2.0-3/dist/markdownItCheckbox.umd.js // @namespace https://greasyfork.org/users/16170 // @downloadURL none // ==/UserScript== (function() { // ************ J + M + J ************* // 'use strict'; // ***** UI SETTINGS ***** // const UI_Prefs_Bool = { alternate_background: true, apps_as_dirs: true, autoload_index_files: true, ignore_ignored_items: true, media_autoload: true, media_autoplay: true, media_play_all: true, show_details: true, show_ignored_items: true, show_image_thumbnails: true, show_image_thumbnails_always: true, show_large_image_thumbnails: true, show_invisibles: true, show_numbers: true, show_sidebar: true, text_editing_enable: true, texteditor_split_view: true, texteditor_sync_scroll: true, use_custom_icons: true, } const UI_Prefs_Non_Bool = { grid_font_size: 1, // Default = 1 grid_image_size: 184, // Default = 184 (200px - 16px) sort_by: 'default', // Choose from: 'name', 'size', 'date', 'kind', 'ext', 'default ( = Chrome sorting: dirs on top, files alphabetical). sort_direction: 'ascending', // Choose from: 'ascending' (A-Z) [default] or 'descending' (Z-A). texteditor_view: 'preview', // Options: 'texteditor_preview','texteditor_view_html' theme: 'light', // Options: 'light' or 'dark' ui_font: 'system-ui, sans-serif', // Choose an installed font for the UI; if undefined, use browser defaults instead. [system-ui, sans-serif] ui_font_size: '13px', // Choose a default UI font size; use any standard CSS units. ui_scale: '100', } let UI_Settings = {...UI_Prefs_Bool, ...UI_Prefs_Non_Bool}; const Item_Kinds = { dir: ['/'], // loaded in iframe#content_iframe app: ['app/','app','appimage','apk','exe','ipa','ipk','jar','msi','wsf'], // generally ignored; some apps may be opened as directories alias: ['alias','desktop','directory','lnk','symlink','symlink/'], archive: ['7z','archive','b6z','bin','bzip','bz2','cbr','dmg','gz','iso','mpkg','pkg','rar','sit','sitx','tar','tar.gz','zip','zipx','zxp'], // ignored audio: ['aac','aif','aiff','ape','flac','m4a','mka','mp3','ogg','opus','wav'], // loaded in audio#audio bin: ['a','ase','bundle','dll','dyld','dylib','gem','icc','msi','profraw','pyc','pyo','o','rakefile','ri','so','torrent','xml','2','opml','qm','scpt','uo','vsix','zwc'], // ignored code: ['bak','bash','bash_profile','bashrc','bat','cgi','com','c','cfg','cnf','codes','coffee','conf','csh','cshrc','cson','css','cuetxt','custom_aliases','d','default','description','dist','editorconfig','emacs','example','gemspec','gitconfig','gitignore','gitignore_global','h','hd','ini','js','json','jsx','less','list','local','login','logout','lua','mkshrc','old','pc','php','pl','plist','pre-oh-my-zsh','profile','pth','py','rb','rc','rdoc','sass','settings','sh','strings','taskrc','tcl','viminfo','vimrc','vue','vtt','yaml','yml','zlogin','zlogout','zpreztorc','zprofile','zsh','zshenv','zshrc'], // treated as text, opened in iframe#content_iframe text editor database: ['accdb','db','dbf','mdb','pdb','sql', 'sqlite','sqlitedb','sqlite3'], // ignored ebook: ['azw','azw1','azw3','azw4','epub','ibook','kfx','mobi','tpz'], // ignored font: ['otf','ttf','woff','woff2','afm','pfb','pfm','tfm'], // opened in div#content_font graphics: ['afdesign','afpub','ai','book','dtp','eps','fm','icml','icns','idml','indd','indt','inx','mif','pmd','pub','qxb','qxd','qxp','sla','swf','ai','arw','cr2','dng','eps','jpf','nef','psd','psd','raw','tif','tiff'], // ignored htm: ['htm','html','xhtm','xhtml'], // opened in iframe#content_iframe image: ['apng','bmp','gif','ico','jpeg','jpg','png','svg','webp'], link: ['url','webloc','inetloc'], markdown: ['md','markdown','mdown','mkdn','mkd','mdwn','mdtxt','mdtext'], // treated as text, opened in iframe#content_iframe text editor other_ignored: ['alias','cue','dat','dic','idx','xmp'], office: ['csv','doc','docx','epub','key','numbers','odf','ods','odt','pages','rtf','scriv','wpd','wps','xlr','xls','xlsx','xlm'], // ignored playlist: ['m3u','m3u8','pls','asx','wpl','xspf'], pdf: ['pdf'], // open in #content_pdf system: ['DS_Store','ds_store','icon','ics','spotlight-v100/','temporaryitems/','documentrevisions-v100/','trashes/','fseventsd/','dbfseventsd','file','programdata','localized'], // ignored system items text: ['log','nfo','txt','text','readme'], // opened in iframe#content_iframe text editor video: ['m4v','mkv','mov','mp4','mpeg','webm'] // loaded in video#content_video }; const Item_Settings = { // ITEM_SETTINGS: Ignore or Exclude files by extension (prevents browser from attempting to download the file). ignored: [...Item_Kinds.archive,...Item_Kinds.bin,...Item_Kinds.database,...Item_Kinds.graphics,...Item_Kinds.other_ignored,...Item_Kinds.office,...Item_Kinds.playlist,...Item_Kinds.system] }; // ***** UTILITIES ***** // function loadFileURL() { // ===> LOAD FILE URL // if window.location points to a file, change the location to the file's container dir, add search_param of file name; then load the file's container dir and load file in content pane. let search_params = getSearchParams(); search_params.set( 'file', window.location.pathname.split('/').reverse()[0]); window.location = window.location.pathname.slice( 0,window.location.pathname.lastIndexOf('/') ) +'/?'+ search_params ; return; } if ( !window.location.pathname.endsWith('/') && window.top === window.self ) { loadFileURL(); } // load file urls //==============================// function isTopWindow() { return ( window.top === window.self || false ) } // ===> TOP WINDOW OR IFRAME function getBrowser() { //*** needs testing for new userAgentData object --> what are possible brand names?; combine with getOS() // ===> GET BROWSER let brand = ( navigator.userAgentData !== undefined ? navigator.userAgentData.brands[1].brand.toLowerCase() : navigator.userAgent ); switch(true) { case brand === 'chromium' || ( /chrome?chromium/.test(brand) ): return 'is_chrome'; case brand === 'msie' || ( /msie/.test(brand) ): return 'is_explorer'; // case brand === 'edge' || ( /edge/.test(brand) ): return 'is_edge'; // need case for ms edge case brand === 'opera' || ( /opera/.test(brand) ): return 'is_opera'; case brand === 'safari' || ( /safari/.test(brand) ): return 'is_safari'; case brand === 'firefox' || ( !/chrome|chromium/.test(brand) ): return 'is_gecko'; } } function getOS() { // modded from https://***stackoverflow.com/questions/38241480/detect-macos-ios-windows-android-and-linux-os-with-js // ===> GET OS let platform = ( navigator.userAgentData !== undefined ? navigator.userAgentData.platform : window.navigator.platform ).toLowerCase(); let macos_platforms = ['macos','macintosh','macintel','macppc','mac68k'], windows_platforms = ['win32','win64','windows','wince'], os = null; switch(true) { case macos_platforms.indexOf(platform) !== -1: os = 'macos'; break; case windows_platforms.indexOf(platform) !== -1: os = 'windows'; break; case !os && /Linux/.test(platform): os = 'linux'; break; } return os; } function newURL(link) { try { return new URL(link,document.baseURI); } catch( error ) { return new URL(encodeURI(link) ); } } // ===> NEW URL function decodeURIComponentSafe(str) { if ( !str ) { return str; } // ===> DECODE URI COMPONENT SAFE; // Fix "%" error in file name; see stackoverflow.com/questions/7449588/why-does-decodeuricomponent-lock-up-my-browser try { return decodeURIComponent(str.replace(/%(?![0-9a-fA-F]{2})/g,'%25') ).replace(/\"/g,'\"'); } catch(e) { return str; } // replace % with %25 if not followed by two a-f/number; replace " with html entity } function convertHex2Decimal(d) { return parseInt(d, 16); } function convertDecimal2Hex(d, padding) { let hex = Number(d).toString(16); hex = ( isNaN(hex) ? null : "000000".substr(0, padding - hex.length) + hex ); return hex; } //==============================// const window_protocol = window.location.protocol; // GLOBAL: protocol let window_location = decodeURIComponentSafe( [location.protocol, '//', location.host, location.pathname].join('') ); // GLOBAL: current location const current_dir_path = window_location.replace(/([/|_|—])/g,'$1').replace(/\\/g,'/'); // GLOBAL: current dir path w/o query string for display //==============================// function setLocation(link) { window.location = link; } function changeLocation(args) { // args[0] === href, args[1] === 'external || ok' switch(true) { case args[1] === 'external': window.open(args[0]); break; // open external menu links: about, coffee, contact case args[1] === 'ok': window.location = args[0]; break; case ( /has_\w+list/.test(getClassNames('body'))): args = window.location.href; // nobreak; show playlist warning default: showWarning( 'setLocation',args.toString() ); } } function getSearchParams() { let search_params = new URL(window.location).searchParams; search_params.sort(); return search_params; } // ===> GET SEARCH PARAMS function searchParamSet(key,value,bool) { let search_params = getSearchParams(); search_params.set( key, value ); if ( bool !== false ) { updateSearchParams(search_params);} } // ===> SET SEARCH PARAM (bool false = don't update) function searchParamDelete(key) { let search_params = getSearchParams(); search_params.delete(key); updateSearchParams(search_params); } // ===> REMOVE SEARCH PARAM function updateSearchParams(search_params) { // ===> UPDATE SEARCH PARAMS search_params = sanitizeSearchParams(search_params); search_params.sort(); // sort and sanitize params let search_params_str = search_params.toString().replace(/%2F/g,'').replace('/','').replace(/%2Cfalse/g,''); // further sanitization let new_location = ( search_params_str.length === 0 ? window.location.pathname : window.location.pathname +'?'+ search_params_str ); // don't add ? if no search params window.history.replaceState({}, document.title, new_location); // set new location if ( isTopWindow() ) { updateParentLinks(); } } function sanitizeSearchParams(search_params_str) { // remove search_params that are not in UI_Settings for ( let entry of search_params_str.entries() ) { if ( !UI_Settings[entry[0]] && !/selected|history|width/.test(entry[0]) ) { search_params_str.delete(entry[0]); } } return search_params_str; } function getCurrentUIPref(pref_id) { // ===> GET SEARCH PARAM value by key let search_params = getSearchParams(), value = ''; switch(true) { case pref_id === 'width': if ( !isTopWindow() ) { return; } // width: set the stored sidebar width or use default 30% value = ( !search_params.has(pref_id) || window.innerWidth === 0 ? 30 : Math.round(100 * Number.parseInt(search_params.get('width'))/window.innerWidth) ); break; // percentage case pref_id === 'parent_id': value = ( search_params.has(pref_id) ? search_params.get(pref_id) : UI_Settings?.[pref_id] ? UI_Settings[pref_id].toString() : '' ); break; // default: // if query_string has key/value pair, use it, else use key/value pair from UI_Settings value = ( search_params.has(pref_id) ? search_params.get(pref_id) : UI_Settings?.[pref_id] ? UI_Settings[pref_id].toString() : pref_id ); value = value?.replace('%2F','').replace('/',''); // some servers add a '/' to end of query string } return value; } function getNewUIPref(key) { let value, bool_prefs = Object.keys(UI_Prefs_Bool); let non_bool_prefs = { 'sort_direction_ascending': {'sort_direction':'descending'}, 'sort_direction_descending': {'sort_direction':'ascending'}, 'sort_by_name': {'sort_by':'name'}, 'sort_by_default': {'sort_by':'default'}, 'sort_by_duration': {'sort_by':'duration'}, 'sort_by_size': {'sort_by':'size'}, 'sort_by_date': {'sort_by':'date'}, 'sort_by_kind': {'sort_by':'kind'}, 'sort_by_ext': {'sort_by':'ext'}, 'texteditor_view': {'texteditor_view':getCurrentUIPref('texteditor_view')}, 'texteditor_view_raw': {'texteditor_view':'txt'}, 'texteditor_view_preview': {'texteditor_view':'preview'}, 'texteditor_view_html': {'texteditor_view':'html'}, 'theme': {'theme':(getCurrentUIPref('theme') === 'light' ? 'dark' : 'light') }, 'theme_dark': {'theme':'dark'}, 'theme_light': {'theme':'light'}, 'ui_font': {'ui_font':getCurrentUIPref('ui_font')},'ui_scale': {'ui_scale':getCurrentUIPref('ui_scale')} } switch(true) { case bool_prefs.includes(key): return ( getCurrentUIPref(key) === 'true' ? [key,'false'] : [key,'true']); // toggle bool prefs default: value = Object.values( non_bool_prefs[key] ).toString(); key = Object.keys(non_bool_prefs[key]).toString(); return [key,value]; // get value for key; then key (i.e., don't redefine key before getting value) } } let str = ''; // global str var; function timeoutID() { return window.setTimeout( () => { str = ''; }, 1000 ); } // ===> TIMEOUT ID: reset typed string to '' after 1.5 sec. //==============================// function getEl(sel) { try { return document.querySelector(sel); } catch (error) { return null; } } function getEls(sel) { try { return document.querySelectorAll(sel); } catch (error) { return null; } } function elExists(sel) { return ( document.querySelector(sel) !== null ? true : false ); } function fileNotFound(e,id) { if ( e.type === 'error') { if (id === 'audio') { addClass('#content_pane','has_audio_error'); setContentTitle('has_audio_error'); } else { addClass('#content_pane','content_error'); closeContent(); setContentTitle('error'); } } } function getVisibleElsBySelector(sel) { // ===> GET VISIBLE ELS BY SELECTOR // remove els with display:none or 0 width/height let els = Array.from( getEls(sel) ).filter( (el) => { let el_styles = window.getComputedStyle(el); return ( el_styles.getPropertyValue('display') !== 'none' || ( el.offsetWidth > 0 || el.offsetHeight > 0 ) ); }); return els; } function getContentPaneData() { return getAttribute('#content_pane','data-content'); } // ===> GET CONTENT_PANE DATA content function hasContent(args) { // ===> HAS CONTENT? switch(true) { case args === undefined: return ( hasClass('#content_pane','has_audio') || getContentPaneData() !== 'has_null' ? true : false ); // has any content case args.includes('audio'): return ( hasClass('#content_pane','has_audio') && (args.includes('ignore') || getContentPaneData() === 'has_null') ? true : false ); // has audio only or ignore other content case args.includes('_'): return hasClass('#content_pane','has_'+args); default: return ( args.split(',').includes( getContentPaneData()?.split('_')[1] ) ? true : false ); // has named content (e.g., pdf, iframe) } } function initContentError(id,content_el_id) { if ( id !== 'close' ) { getEl(content_el_id).addEventListener('error',(e) => { fileNotFound(e,content_el_id); }); } } // ===> INIT CONTENT ERROR //==============================// function getClassNames(sel) { return getEl(sel)?.className; } function hasClass(sel,classname) { let el = getEl(sel); return el?.classList.contains(classname); } // ===> HAS CLASS function addClass(sel,classname) { let els = Array.from(getEls(sel)), classes = classname.split(' ').filter(item => item); els?.forEach( el => el.classList.add(...classes) ); } // ===> ADD CLASS function removeClass(sel,classname) { // ===> REMOVE CLASS let els = Array.from(getEls(sel)), classes = ( classname?.split(' ')?.filter(item => item) || null ); if ( classname === undefined || classes === null ) { els?.forEach( el => el.removeAttribute('class') ); } else { els?.forEach( el => el.classList.remove(...classes) ); } // if no className provided, remove all classes } function addRemoveClassSiblings(sel,classname) { // ===> ADD/REMOVE CLASS SIBLINGS let el = document.querySelector(sel), siblings = el?.parentElement.children; if ( el !== null ) { Array.from(siblings).forEach( sibling => sibling.classList.remove(...classname.replace(/\s{2,}/g,' ').split(' ') ) ); addClass(sel,classname); } // remove class from els & add class to selected el } //==============================// function getAttribute(sel,attributeName) { let el = getEl(sel); return el?.getAttribute(attributeName); } // ===> GET ATTRIBUTE function hasAttribute(sel,attributeName) { let el = getEl(sel); return el?.hasAttribute(attributeName); } // ===> HAS ATTRIBUTE function setAttribute(sel,attributeName,value) { let el = getEl(sel); el?.setAttribute(attributeName,value); } // ===> SET ATTRIBUTE function removeAttribute(sel,attributeNamesArr) { // ===> REMOVE ATTRIBUTE if ( typeof attributeNamesArr === 'string' ) { attributeNamesArr = [attributeNamesArr]; } let els = getEls(sel); Array.from(els)?.forEach( el => attributeNamesArr.forEach( attributeName => el.removeAttribute(attributeName) ) ); } function getData(sel,keyname) { let el = getEl(sel); return el.getAttribute('data-'+keyname); } function setData(sel,keyname,value) { let el = getEl(sel); el.setAttribute('data-'+keyname,value); } function setStyle(sel,property,value) { getEl(sel).style.setProperty(property,value); } function setValue(sel,value) { getEl(sel).value = value; } //==============================// function clickThis(sel) { let el = getEl(sel); ( el?.querySelector('a')?.click() || el?.click() ) } // ===> CLICK THIS by CSS selector function altKey(e) { return ( !e.metaKey && !e.ctrlKey && e.altKey && !e.shiftKey ); } // ===> ALT KEY test function altShiftKey(e) { return ( !e.metaKey && !e.ctrlKey && e.altKey && e.shiftKey ); } // ===> ALT SHIFT KEY test function cmdKey(e) { return ( (e.metaKey || e.ctrlKey) && !e.altKey && !e.shiftKey ); } // ===> CMD/CTRL KEY test function cmdAltKey(e) { return ( (e.metaKey || e.ctrlKey) && e.altKey && !e.shiftKey ); } // ===> CMD/CTRL ALT KEY test function cmdShiftKey(e) { return ( (e.metaKey || e.ctrlKey) && !e.altKey && e.shiftKey ); } // ===> CMD/CTRL SHIFT KEY test function eStopPrevent(e) { e?.preventDefault(); e?.stopPropagation(); } //============================// // ***** BASIC UI FUNCTIONS ***** // function isInViewport(sel) { const rect = ( getEl(sel) !== null ? getEl(sel).getBoundingClientRect() : null ); if ( rect === null ) { return false; } return ( rect.top >= getEl('#dir_header').offsetHeight && rect.bottom <= (window.innerHeight - getEl('#dir_footer').offsetHeight || document.documentElement.clientHeight - getEl('#dir_footer').offsetHeight) ); } function scrollThis(container_ID, sel, bool) { // ===> SCROLL to Selected Item let container = getEl(container_ID); if ( container?.height === 0 || isInViewport(sel) ) { return; } // don't scroll hidden elements let scroll_el = container?.querySelector(sel), scroll_behavior = ( ( bool !== undefined || bool === true ) ? 'instant' : 'smooth' ), scroll_block = ( hasClass('body','is_gecko') ? 'start' : 'nearest' ); scroll_el?.scrollIntoView({ behavior:scroll_behavior, block:scroll_block, inline:'nearest' }); } function mouseMove(e,sel,startX,startY,elOffsetLeft,elOffsetTop) { // ===> Init events to allow glyphs to be dragged into view let scale_factor = ( sel === '#font_specimen_glyph' ? 2 : 1 ); // scale_factor needed for svg glyphs setStyle(sel,'left',elOffsetLeft + (e.pageX - startX)*scale_factor + 'px'); setStyle(sel,'top',elOffsetTop + (e.pageY - startY)*scale_factor +'px'); } //==============================// OPEN/SAVE FILES function openFile(args) { menuClose(); // ===> OPEN FILE; type: font or playlist. if ( window.File && window.FileReader && window.FileList && window.Blob ) { // if browser supports file API... let files = args[0].target.files[0], id = args[1], reader = new FileReader(); switch(id) { case 'open_font': reader.readAsArrayBuffer(files); break; case 'open_playlist': reader.readAsText(files); break; } // get the file reader reader.onload = () => { // on file reader load switch(true) { case id === 'open_font': openFontFile(files,reader); break; case id === 'open_playlist': openPlaylist(files.name,'',reader.result); break; } // open the file return true; } getEl('#'+id).value = ''; // reset input to allow same item to be reopened immediately after closing } else { alert('Can\'t open file: file APIs are not fully supported in this browser.'); } // else error } function saveFile(content,mimetype,file_name) { // ===> SAVE FILE let blob = new Blob([content], {type: mimetype}); let download_el = window.document.createElement('a'); download_el.style = "display:none"; download_el.href = window.URL.createObjectURL(blob); download_el.download = file_name; // define & style download_el document.body.appendChild(download_el); download_el.click(); document.body.removeChild(download_el); URL.revokeObjectURL(blob); // add download_el, click, & remove } // END UTILITIES //==============================// // ***** SET UP UI ELEMENTS ***** // function updateParentLinkSearchParams(str) { //*** decrement selected and history values ***// // ===> UPDATE PARENT LINK SEARCH PARAMS let query_str = new URLSearchParams(str); query_str.sort(); // make new search params from window.location.search let history = ( query_str.has('history') ? query_str.get('history') : undefined ); switch(true) { case history !== undefined: history = history.split(' '); switch(true) { case history.length > 1: query_str.set('selected',history[0]); history.shift(); query_str.set('history',history.join('+')); break; case history.length === 1: query_str.set('selected',history[0]); history.shift(); query_str.delete('history'); break; } break; default: query_str.delete('selected'); } return decodeURIComponentSafe(query_str.toString()); } function createParentLinks() { // ===> CREATE PARENT LINKS let link, links = [], search_params = getSearchParams(); search_params.sort(); let query_str = search_params.toString(); let link_pieces = window_location.split('/'); link_pieces = link_pieces.slice(2,-2); // make array of parent directories; remove beginning and ending empty elements and current directory while ( link_pieces.length > 0 ) { // while there are link pieces... query_str = updateParentLinkSearchParams(query_str); // update selected and history link = window_protocol +'//'+ link_pieces.join('/') + '/?' + query_str; links.push(link); link_pieces.pop(); // assemble link; add to link array; remove last link piece and repeat... } return links; } function createParentLinkItems() { // ===> CREATE PARENT LINK ITEMS let parent_link_menu_items = [], links = createParentLinks(); for ( let i = 0; i < links.length; i++ ) { let display_name = links[i].split('/?')[0]; display_name = display_name.replace(/\//g,'\/'); let menu_item = `
  • ${ display_name }/
  • `; parent_link_menu_items.push(menu_item); } let parent_link = ( links[0] === undefined ? window.location.href : links[0]); parent_link = parent_link.replace(/parents_link_/,'parent_link_'); return [parent_link_menu_items.join(''),parent_link]; // return parents link items } function updateParentLinks() { // ===> UPDATE PARENT LINKS and init new item events let links = createParentLinkItems(); getEl('#parents_links').innerHTML = links[0]; getEl('#parent_dir_nav a').href = links[1]; // add the links getEls('#dir_menu_parent a,#parents_links a').forEach( el => el.onclick = function(e) { eStopPrevent(e); showWarning('changeLocation',[this.href,'false']); }); // reinit onclick } //==============================// // SVG UI ICONS const SVG_UI_Icons = { 'arrow': '', 'bookmark': '', 'check_mark': '', 'chevron': '', 'document': '', 'error': '', 'external_link': '', 'folder': '', 'grid': '', 'menu': '', 'minus': '', 'multiply': '', 'music': '', 'plus': '', 'prev_next_track': '', 'spinner': '', 'toggle': '', 'ui_layout': '' }; function get_SVG_UI_Icon(icon_name) { return `url("data:image/svg+xml;utf8,${ SVG_UI_Icons[icon_name] }")`; } const SVG_UI_File_Icons = { // n.b.: order is important 'file_icon_dir': '', 'file_icon_dir_open': '', 'file_icon_file': '', 'file_icon_invisible': '', 'file_icon_ignored': '', 'file_icon_dirinvisible': '', 'file_icon_alias': '', 'file_icon_archive': '', 'file_icon_app': '', 'file_icon_audio': '', 'file_icon_code': '', 'file_icon_database': '', 'file_icon_ebook': '', 'file_icon_font': '', 'file_icon_graphics': '', 'file_icon_htm': '', 'file_icon_ignoredimage': '', 'file_icon_image': '', 'file_icon_markdown': '', 'file_icon_office': '', 'file_icon_pdf': '', 'file_icon_playlist': '', 'file_icon_text': '', 'file_icon_video': '', 'file_icon_bin': '', 'file_icon_other': '', // <-- these two use file_icon_system: 'file_icon_system': '' }; const SVG_Text_Editing_UI_Icons = { 'toggle_theme': '', 'show_markdown': '', 'show_source': '', 'show_preview': '', 'show_html': '', 'toggle_split': '', 'save_btn': '', 'save_btn_edited': '' }; // ===> GET SVG UI ICON by name function get_SVG_UI_File_Icon(icon_name) { // ===> GET SVG UI FILE Icon by name switch(icon_name) { case 'favicon': return ''; case 'file_icon_dir_default': return '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= ")'; case 'file_icon_file_default': return 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ")'; default: return 'url("data:image/svg+xml;utf8,'+ SVG_UI_File_Icons[icon_name] +'")'; } } function CSS_UI_Icon_Rules() { // programatically add File icon CSS rules // ===> CSS UI ICON RULES let rules = '', kind, class_name; for ( let icon in SVG_UI_File_Icons ) { kind = icon.slice(icon.lastIndexOf('_') + 1); class_name = kind; if ( class_name !== ('file') ) { // exceptions: if ( kind === 'dirinvisible' ) { class_name = 'dir.invisible'; } if ( kind === 'ignoredimage' ) { class_name = 'ignored_image'; } if ( kind === 'open' ) { class_name = 'has_subdirectory'; kind = 'dir_open'; } if ( /alias|symlink/.test(kind) ) { class_name = 'link'; } if ( /bin|other/.test(kind) ) { kind = 'system'; } // add rules for dir_list items, content_header, stats details: rules += `body:not(.use_custom_icons_false) .${ class_name } .has_icon_before_before, #content_pane[data-content^="has_${ class_name }"] #content_title span::before,body:not(.use_custom_icons_false) .${ class_name }.has_icon_before::before, .${ class_name } .has_icon_before::before { background-image: url("data:image/svg+xml;utf8,${ SVG_UI_File_Icons['file_icon_'+kind] }"); }`; // add custom file icons } } return rules; } // END SVG UI ICONS //==============================// UI HTML // SIDEBAR ELEMENTS const Directory_Header_Menu_Elements = `
  • Go to item… (⌘⇧J)
  • UI Preferences${SVG_UI_Icons.arrow}
  • File Handling Preferences${SVG_UI_Icons.arrow}
  • Media Preferences${SVG_UI_Icons.arrow}
  • Text Editing Preferences${SVG_UI_Icons.arrow}
  • Default Preferences
  • Playlists${SVG_UI_Icons.arrow}
  • Script Home ↗
  • Help
  • Contact
  • `; const Directory_Header_Elements = function(body_id,parent_link) { let checked = '', parent_links = createParentLinkItems(), dir_header_title_element = '', dir_header_menus = '', texteditor_element = ''; if ( getCurrentUIPref('show_invisibles') === 'true' ) { checked = 'checked="true"'; } switch(body_id) { case 'top_body': dir_header_title_element = `
    `; dir_header_menus = `
    `; texteditor_element = ``; break; case 'iframe': dir_header_menus = ``; break; } return `
    ${ dir_header_title_element }
    ${ dir_header_menus }
    • Name
    • Default
    • Duration
    • Ext
    • Duration
    • Size
    • Date
    • Kind
    ${ texteditor_element }
    `; }; const Directory_Elements = function(body_id,parent_link) { // Assemble directory elements for both top and iframe directories let dir_footer_utilities = '', directory_utilities = ''; if ( body_id === 'top_body' ) { // various elements not needed in iframe directories dir_footer_utilities = ``; directory_utilities = `
    ${ SVG_UI_Icons.toggle }
    `; } const dir_nav = ``; const dir_footer = ``; return `
    ${ Directory_Header_Elements(body_id,parent_link) } ${ dir_nav } ${ dir_footer } ${ directory_utilities }
    `; }; //==============================// // CONTENT PANE ELEMENTS const Text_Editing_UI_Elements = `
    `; const Content_Text_Elements = `
    ${ Text_Editing_UI_Elements }
    `; const Content_Audio_Elements = `
    ${ SVG_UI_Icons.prev_next_track }
    ${ SVG_UI_Icons.prev_next_track }
    ${ SVG_UI_Icons.multiply }
    `; const Content_Font_Viewer = '
      '; const font_toolbar = `
      1. Text Color
      2. Text Stroke Color
      `; const Content_Font_Elements = function() { 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.`; return `
        ${ sample_string }

        Typography

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

        S P E C I M E N

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

        ${ lorem_string }
        ${ lorem_string }
        ${ lorem_string }
        ${ Content_Font_Viewer }`; }; const Content_Header_Elements = `
        ${ Content_Audio_Elements }
        ${ font_toolbar }
        `; // CONTENT containers const Content_Pane_Elements = `
        ${ Content_Header_Elements }
        ${ SVG_UI_Icons.spinner }
          ${ Content_Text_Elements }
          ${ Content_Font_Elements() }
          `; //==============================// // UTILITIES HTML (warnings and help) const Utilities_Warnings = `

          Warning:

          Make Playlist/Filelist (.m3u)

          Are you sure you want to close the font file?
          Are you sure you want to close the font file?
          You have unsaved changes.
          Are you sure you want to clear all your text?
          Can’t load local file from non-local page.
          Are you sure you want to close the playlist?
          This playlist contains local files.
           Please reload this playlist from a local page in order to play them.
          This is a non-local file/dir/link. Would you like to open it in a new window?
          `; const Utilities_Help = `
          HELP
            CONTENTS
          1. I. About this Script
          2. II. Keyboard Shortcuts
          3. III. Usage: The Main Menu
          4. IV. Other Script Functions
          5. V. Troubleshooting

          I. ABOUT THIS SCRIPT

          This script works “out-of-the-box” on local directories. To enable it to work on a remote directory, add its url to the list of included/allowed sites in your userscript manager’s settings for this script.

          Script home: openuserjs.org

          ${ SVG_UI_Icons.ui_layout }The UI consists of two main parts: the navigation Sidebar on the left and the preview Content Pane on the right. The Sidebar shows all the files in the current directory, while the Content Pane shows a preview of the items selected in the Sidebar.

          The Sidebar contains a Header area, the Directory List itself, and a Footer.

          The Sidebar is resizeable, or it can be hidden entirely via the double-chevron button at the Sidebar top right.

          The Sidebar Header includes a Parent Directory button, a Parent Directories menu, and the Main Menu. and below these, Show Details and Show Invisibles items, a Show Grid button (when appropriate), and sort by Name or Default items; if Show Details is selected, additional sorting options are shown, along with the Text Editor item. All of these items are also available in the Main Menu, and some can be toggled via a keyboard shortcut (see below).

          The Content Pane displays the selected sidebar item.

          `; let Utilities_Elements = function(body_id) { let help_elements = ''; if ( body_id === 'top_body' ) { help_elements = ``; } return `
          ${ help_elements }
          `; } // ===> END UI HTML //==============================// // ===> STYLES const background_images = ` /* BACKGROUND IMAGES & FILE ICONS */ .menu_item::before { content:""; width:12px; max-width:12px; min-width:12px; height:9px; margin:2px 0 -2px; background-position:center; background-repeat:no-repeat; display:flex; } .submenu .menu_item::before { width:24px; max-width:24px; min-width:24px; } .has_background, .has_background_before::before, .has_background_after::after { background-repeat:no-repeat; background-position:center; background-color:transparent !important; } .bookmark > a::before { background-image:${ get_SVG_UI_Icon("bookmark") }; } :is(.sort_by_default #menu_sort_by_default, .sort_by_name #menu_sort_by_name, .sort_by_duration #menu_sort_by_duration, .sort_by_size #menu_sort_by_size, .sort_by_date #menu_sort_by_date, .sort_by_kind #menu_sort_by_kind, .sort_by_ext #menu_sort_by_ext, #menu_theme_container, #toggle_text_editing) .menu_item::before, :is(.sort_by_default #sort_by_default, .sort_by_name #sort_by_name, .sort_by_duration #sort_by_duration, .sort_by_size #sort_by_size, .sort_by_date #sort_by_date, .sort_by_kind #sort_by_kind, .sort_by_ext #sort_by_ext) span::before, .loop_media #loop_media_menu::before, .shuffle_media #shuffle_media_menu::before, .background_color_check_mark::before, .texteditor_view_raw #toggle_texteditor_raw::before, .texteditor_view_preview #toggle_texteditor_preview::before, .texteditor_view_html #toggle_texteditor_html::before, body:not(.text_editing_enable_false) #text_editing_enable::before, .texteditor_view_html #texteditor_view_html::before, .cuesheet_track.selected .cue_track_id::before, .menu_item.checkmark::before { background-image:${ get_SVG_UI_Icon("check_mark") }; } :is( .show_invisibles_false #show_invisible_items, .alternate_background_false #alternate_background, .show_numbers_false #show_numbers, .use_custom_icons_false #use_custom_icons, .show_image_thumbnails_false #show_image_thumbnails, .show_image_thumbnails_always_false #show_image_thumbnails_always, .show_large_image_thumbnails_false #show_large_image_thumbnails, .show_ignored_items_false #show_ignored_items, .ignore_ignored_items_false #ignore_ignored_items, .autoload_index_files_false #autoload_index_files, .media_autoload_false #media_autoload, .media_autoplay_false #media_autoplay, .media_play_all_false #media_play_all, .texteditor_split_view_false #texteditor_split_view ) .menu_item.checkmark::before { background-image:none; } .sort_by_default #sort_by_default span::after, .sort_by_name #sort_by_name span::after, .sort_by_duration #sort_by_duration span::after, .sort_by_size #sort_by_size span::after, .sort_by_date #sort_by_date span::after, .sort_by_kind #sort_by_kind span::after, .sort_by_ext #sort_by_ext span::after { background-image:${ get_SVG_UI_Icon("chevron") }; background-size:75%; transform:rotate(180deg); } .is_error #dir_nav, .is_error #current_dir_path span::before { background-image:${ get_SVG_UI_Icon("error") }; } .is_error #dir_nav { background-repeat:no-repeat; background-position:center top 6rem; background-size:6rem;} .is_error #current_dir_path span::before { float:none; display:inline-flex; margin:0 0 -2px 0; width:24px; } #content_pane[data-content="has_ignored"] #content_container { background-image:${ get_SVG_UI_File_Icon('file_icon_ignored') }; background-size:28px; } #content_pane.has_audio[data-content="has_null"]:not([data-loaded="unloaded"]) #content_container, #content_pane.has_audio:not([data-content]) #content_container, .has_audio #content_pane[data-content="has_null"]:not([data-loaded="unloaded"]) #content_container, .has_audio #content_pane:not([data-content])[data-loaded="loaded"] #content_container { background-image:${ get_SVG_UI_Icon("music") }; } ${ CSS_UI_Icon_Rules() } #dir_menu_main ul a::before { background-image:${ get_SVG_UI_File_Icon('file_icon_file') }; } #dir_menu_main ul a[href^="file"]::before, #current_dir_path span::before { background-image:${ get_SVG_UI_File_Icon('file_icon_dir') }; margin-bottom:-3px; } #dir_menu_main ul a[href^="http"]::before { background-image:${ get_SVG_UI_File_Icon('file_icon_htm') }; } body.use_custom_icons_false .dir .has_icon_before_before { background-image:${ get_SVG_UI_File_Icon('file_icon_dir_default') }; background-size:auto 13px; } body.use_custom_icons_false.show_image_thumbnails_false .file:not(.app) .has_icon_before_before, body.use_custom_icons_false:not(.show_image_thumbnails_false) .file:not(.app) .has_icon_before_before { background-image:${ get_SVG_UI_File_Icon('file_icon_file_default') }; background-size:auto 13px; } body:not(.use_custom_icons_false).show_image_thumbnails_false .image .has_icon_before_before { background-image:${ get_SVG_UI_File_Icon('file_icon_image') } } .has_playlist #current_dir_path span::before { background-image:${get_SVG_UI_File_Icon('file_icon_playlist')}; display:inline-flex; margin:-2px 0 0; width:24px; vertical-align:middle;} .dirlist_item.dir:not(.has_subdirectory) .has_icon_before_before:hover { background-image:${ get_SVG_UI_Icon('chevron') }; transform:rotate(90deg); filter:invert(1); } .dirlist_item.dir.has_subdirectory .has_icon_before_before:hover { background-image:${ get_SVG_UI_Icon('chevron') }; transform:rotate(180deg); filter:invert(1); } .dirlist_item.non_local .name_span span::before { background-image:${ get_SVG_UI_Icon('external_link') }; content:""; width:20px; min-width:20px; height:14px; margin-top:-3px; margin-bottom:-3px; background-position:left center; background-repeat:no-repeat; background-blend-mode:screen; display:inline-block; } .dirlist_item.dir:is(.selected,:hover) a .has_icon_before_before, .dirlist_item.other:is(.selected,:hover) a .has_icon_before_before, .dirlist_item.system:is(.selected,:hover) a .has_icon_before_before, .dirlist_item.bin:is(.selected,:hover) a .has_icon_before_before, .dirlist_item.invisible:is(.selected,:hover) a .has_icon_before_before, .dirlist_item.markdown:is(.selected,:hover) a .has_icon_before_before { filter:brightness(var(--brightness_low)); } .theme_light .dirlist_item.audio:is(.selected,:hover) a .has_icon_before_before { filter:brightness(.66) contrast(1.66) saturate(2.66); mix-blend-mode:hard-light; } .theme_dark .dirlist_item.audio:is(.selected,:hover) a .has_icon_before_before { filter:brightness(1.33); } .dirlist_item.selected:is(.archive,.app) a .has_icon_before_before, .dirlist_item:is(.archive,.app):hover a .has_icon_before_before { filter:brightness(var(--brightness_high)) saturate(6); } .dirlist_item.non_local:is(.selected,.audio_loaded) .name_span span::before, .dirlist_item.non_local:hover .name_span span::before { filter:brightness(2); } .dirlist_subdir_loading .has_icon_before_before { background-image:${ get_SVG_UI_Icon('spinner') } !important; filter:invert(1); background-size:20px; } `; const global_styles = ` :root { --font_size_small:0.875rem; color-scheme:none; --text_color_default:hsl(0,0%,var(--percent_10)); --text_color_selected:white; } .theme_light { --percent_100:100%; --percent_95:95%; --percent_90:90%; --percent_85:85%; --percent_80:80%; --percent_75:75%; --percent_70:70%; --percent_65:65%; --percent_60:60%; --percent_55:55%; --percent_50:50%; --percent_45:45%; --percent_40:40%; --percent_35:35%; --percent_30:30%; --percent_25:25%; --percent_20:20%; --percent_15:15%; --percent_10:10%; --percent_05:05%; --percent_00:00%; --border_lum:40%; --border_lum_inverted:40%; --brightness_low:1.15; --brightness_med:1.33; --brightness_high:1.875; } .theme_dark { --percent_100:00%; --percent_95:05%; --percent_90:10%; --percent_85:15%; --percent_80:20%; --percent_75:25%; --percent_70:30%; --percent_65:35%; --percent_60:40%; --percent_55:45%; --percent_50:50%; --percent_45:55%; --percent_40:60%; --percent_35:65%; --percent_30:70%; --percent_25:75%; --percent_20:80%; --percent_15:85%; --percent_10:90%; --percent_05:95%; --percent_00:100%; --border_lum:05%; --border_lum_inverted:40%; --brightness_low:1.15; --brightness_med:1.5; --brightness_high:1.66; } :root, html, body { margin:0; padding:0; border:0; border-radius:0; overflow:hidden; display:flex; flex-direction:row; width:100%; height:100vh; font-family:${UI_Prefs_Non_Bool.ui_font}; font-size:${ UI_Prefs_Non_Bool.ui_font_size}; hyphens:auto; transform-origin:0 0; } a, a:hover { color:inherit; font-weight:inherit; text-decoration:none !important; } ul, li { list-style:none; } svg { margin:auto; } .selected, .audio_loaded { --background_opacity:1; } :hover, .hovered { --background_opacity:0.75; } .focus_content #dir_wrapper .selected, .focus_content #dir_wrapper .audio_loaded { --background_opacity:0.50; } .focus_content #dir_wrapper :hover, .focus_content #dir_wrapper .hovered { --background_opacity:0.25; } .align_left { text-align:left; } .center { text-align:center; } .align_right { text-align:right; } .align_justify { text-align:justify; text-justify:inter-character; hyphens:auto; } .background_grey_60 { background-color:hsl(0,0%,var(--percent_60)); } .background_grey_65 { background-color:hsl(0,0%,var(--percent_65)); } .background_grey_70 { background-color:hsl(0,0%,var(--percent_70)); } .background_grey_75, body { background-color:hsl(0,0%,var(--percent_75)); } .background_grey_80 { background-color:hsl(0,0%,var(--percent_80)); } .background_grey_85, .dirlist_item:nth-of-type(odd), .cuesheet_track:not(.header):nth-of-type(odd), #utilities_help li:nth-of-type(even), body.alternate_background_false .dirlist_item:nth-of-type(even) { background-color:hsl(0,0%,var(--percent_85)); } .background_grey_90, .dirlist_item:nth-of-type(even), .cuesheet_track:not(.header):nth-of-type(even), #stats li:nth-of-type(even) { background-color:hsl(0,0%,var(--percent_90)); } .background_grey_95, .background_grey_90:hover, .background_grey_90.hovered, .background_grey_90.selected, .background_grey_90:focus { background-color:hsl(0,0%,var(--percent_95)); } .background_grey_100, .background_grey_95:hover, .background_grey_95.hovered, .background_grey_95.selected { background-color:hsl(0,0%,var(--percent_100)); } ${ background_images } .border_0 { border: none; } .border_all { border: solid 1px hsl(0,0%,var(--border_lum)); } .border_top { border-top: solid 1px hsl(0,0%,var(--border_lum)); } .border_right { border-right: solid 1px hsl(0,0%,var(--border_lum)); } .border_bottom { border-bottom: solid 1px hsl(0,0%,var(--border_lum)); } .border_left { border-left: solid 1px hsl(0,0%,var(--border_lum)); } .border_top_x { border-top: solid 1px hsl(0,0%,var(--border_lum_inverted)); } .border_right_x { border-right: solid 1px hsl(0,0%,var(--border_lum_inverted)); } /* "x" = inverted for theme_dark */ .border_bottom_x { border-bottom: solid 1px hsl(0,0%,var(--border_lum_inverted)); } .border_left_x { border-left: solid 1px hsl(0,0%,var(--border_lum_inverted)); } .box_shadow_menu { box-shadow:0px 4px 6px -3px #000; } .display_grid, .info_list:hover li, .has_flyout_menu:hover ul { display:grid; } .display_none, .error_display_none { display:none; } .display_block { display:block; } .display_flex { display:flex; } .display_inline_flex { display:inline-flex; } .flex_column { flex-direction:column; } flex-direction:column; } .flex_row { flex-direction:row; } .flex_justify_center { display:flex; flex-direction:column; justify-content:center; flex-grow:1; align-items:center; align-self:stretch; text-align:center; } .flex_justify_center_row { display:flex; flex-direction:row; justify-content:center; flex-grow:1; align-items:center; } .flex_justify_contents { justify-content:space-between; } .flex_grow_1 { flex-grow:1; } .font_size_small { font-size:var(--font_size_small); } .has_flyout_menu { outline:none; justify-content:center; align-content:center; } .has_flyout_menu ul li { width:100%; margin:0; padding:4px 6px; text-align:right; box-sizing:border-box; white-space:pre; grid-column:1; } .has_flyout_menu ul div { grid-column:2; padding-top:8px; } .has_flyout_menu .item_1 { grid-row:1; } .has_flyout_menu .item_2 { grid-row:2; } .height_100 { height:100%; } .hyphens_none { hyphens:none; } .info_list { background-color:hsl(0,0%,var(--percent_80)); color:hsl(0,0%,var(--percent_10)); } .info_list li { grid-template-columns:minmax(33%,100%) min(66%); border-top:solid 1px hsl(0,0%,var(--border_lum)); } .info_list li.info_list_header { border-top:none; } .info_list li .col_1 { font-weight:bold; text-align:right; border-right:solid 1px hsl(0,0%,var(--border_lum)); } .info_list span { display:inline-block; padding:4px 6px; } .line_height_1 { line-height:1; } .line_height_1_2, .info_list span { line-height:1.2; } .line_height_1_4 { line-height:1.4; } .margin_0, header, footer, nav, ol, ul, li { margin:0; } .media.local input { cursor:not-allowed; } .normal { font-weight:normal; } .overflow_auto { overflow:auto; } .overflow_hidden { overflow:hidden; } .overflow_visible { overflow:visible; } .overflow_x_hidden { overflow-x:hidden; } .padding_0, header, footer, nav, a, ol, ul, li { padding:0; } .padding_4_6 { padding:4px 6px; } .padding_4_8 { padding:4px 8px; } .padding_6_8 { padding:6px 8px; } .padding_top_1rem { padding-top:1rem; } .padding_bottom_1rem { padding-bottom:1rem; } .pointer, label, input { cursor:pointer; } .cursor_default { cursor:default; } input[disabled], input[disabled] + label { opacity:0.66; } div:has(> input[disabled]), input[disabled], input[disabled] + label { cursor:not-allowed; } .position_absolute { position:absolute; } .position_relative { position:relative; } .position_fixed { position:fixed; } .position_0 { top:0; right:0; bottom:0; left:0; } .position_LR_0 { left:0; right:0; } .resize_none { resize:none; } .theme_dark .invert { filter:invert(1); } .transform_rotate_90, .transform_rotate_90_contents > * { transform:rotate(90deg); } .transform_rotate_180, .transform_rotate_180_contents > * { transform:rotate(180deg); } .transform_rotate_270, .transform_rotate_270_contents > * { transform:rotate(270deg); } .whitespace_pre { white-space:pre; } .width_10px, .width_10px_contents > * { width:10px; max-width:10px; min-width:10px; } .width_12px, .width_12px_contents > * { width:12px; max-width:12px; min-width:12px; } .width_14px, .width_14px_contents > * { width:14px; max-width:14px; min-width:14px; } .width_16px, .width_16px_contents > * { width:16px; max-width:16px; min-width:16px; } .width_18px, .width_18px_contents > * { width:18px; max-width:18px; min-width:18px; } .width_24px, .width_24px_contents > * { width:24px; max-width:24px; min-width:24px; } .width_100 { width:100% !important; } .z_index_1 { z-index:1; } .z_index_2 { z-index:2; } .z_index_3 { z-index:3; } .z_index_9997 { z-index:9997; } .z_index_9998 { z-index:9998; } .z_index_9999 { z-index:9999; } /* HIGHLIGHT COLORS: selected & hovered media and non_media items */ .theme_light { --non_media_item_background_h:216deg; --non_media_item_background_s:100%; --non_media_item_background_l:50%; --non_media_item_background_a:0.8; --media_item_background_h:180deg; --media_item_background_s:100%; --media_item_background_l:33%; --media_item_background_a:1; --texteditor_item_background_h:250deg; --texteditor_item_background_s:66%; --texteditor_item_background_l:66%; --texteditor_item_background_a:1.00; } .theme_dark { --non_media_item_background_h:216deg; --non_media_item_background_s:80%; --non_media_item_background_l:60%; --non_media_item_background_a:0.8; --media_item_background_h:180deg; --media_item_background_s:50%; --media_item_background_l:40%; --media_item_background_a:1; --texteditor_item_background_h:250deg; --texteditor_item_background_s:50%; --texteditor_item_background_l:60%; --texteditor_item_background_a:1.00; } li, div { --non_media_background: hsla(var(--non_media_item_background_h), var(--non_media_item_background_s), var(--non_media_item_background_l), var(--non_media_item_background_a)); --media_background: hsla(var(--media_item_background_h), var(--media_item_background_s), var(--media_item_background_l), var(--media_item_background_a)); --texteditor_item_background: hsla(var(--texteditor_item_background_h), var(--texteditor_item_background_s), var(--texteditor_item_background_l), var(--texteditor_item_background_a)) } /* NON-MEDIA ITEMS BACKGROUND , li:not(.media):not(.no_highlight):hover, li.hovered */ li.selected:not(.media), li:not(.media):not(.no_highlight):hover, li.hovered, li.content_loaded { background-color:var(--non_media_background) !important; } /* all selected items, hovered non-dirlist items */ #dir_nav li:not(.media):hover { --non_media_item_background_a:0.5; background-color:var(--non_media_background); } /* hovered dirlist items */ li.grid_item.selected { --non_media_item_background_a:0.75; background-color:var(--non_media_background); } /* selected grid items */ li.grid_item:hover, li.grid_item.hovered { --non_media_item_background_a:0.40; background-color:var(--non_media_background); } /* hovered grid items */ body.no_hover li.grid_item:is(:not(.selected):hover,.hovered), body.no_hover li.grid_item:is(:not(.selected):hover,.hovered) * { background-color:transparent !important; color:initial !important; } body.no_hover.theme_dark li.grid_item:is(:not(.selected):hover,.hovered), body.no_hover.theme_dark li.grid_item:is(:not(.selected):hover,.hovered) * { color:hsl(0,0%,var(--percent_10)) !important; } /* MEDIA ITEMS BACKGROUND */ li.audio_loaded, li.video.selected { background-color:var(--media_background) !important; } /* loaded audio, selected video */ li.selected.audio { --media_item_background_a:0.80; background-color:var(--media_background) !important; } /* selected audio */ li.media:hover { --media_item_background_a:0.60; background-color:var(--media_background) !important; } /* hovered media */ li.selected + li.selected:nth-of-type(even), li.dir.hovered + li.hovered:nth-of-type(even), li.file.hovered + li.hovered:nth-of-type(odd), .info_list li:nth-of-type(even) { --non_media_item_background_a:0.60; } /* alternate highlight background with multiple selections, show stats*/ /* UNHIGHLIGHTED ITEMS: menu visible, .focus_content, .no_hover */ body[class*="has_menu"] #dir_nav, body.focus_content #dir_nav { --non_media_item_background_s:0%; --media_item_background_s:0%; } body.theme_light[class*="has_menu"] #dir_nav, body.focus_content #dir_nav { --media_item_background_l:50%; --non_media_item_background_l:50%; } body.theme_dark[class*="has_menu"] #dir_nav, body.focus_content #dir_nav { --media_item_background_l:40%; --non_media_item_background_l:30%; } body.no_hover #dir_nav li:nth-of-type(even):not(.selected):hover { background-color:hsl(0,0%,var(--percent_80)) !important; } body.no_hover #dir_nav li:nth-of-type(odd):not(.selected):hover { background-color:hsl(0,0%,var(--percent_85)) !important; } body.no_hover #dir_nav li:not(.selected):hover { color:unset !important; } /* TEXTEDITOR ITEM*/ body:is(.has_texteditor,.texteditor_edited) #show_texteditor li { background-color:var(--texteditor_item_background); } #show_texteditor li:hover { --texteditor_item_background_a:0.7; background-color:var(--texteditor_item_background) !important; } /* text color */ li:is(.selected,:hover,.hovered), li:hover li:is(:hover,.selected), li.hovered li.selected, .content_loaded, .audio_loaded, body.has_texteditor #show_texteditor, body.texteditor_edited #show_texteditor, .no_hover .grid_item:is(.selected,:hover,.hovered), .no_hover .grid_item:is(.selected,:hover,.hovered) *, .grid_item:is(.selected,:hover,.hovered), .grid_item:is(.selected,:hover,.hovered) *, .grid_item.selected::before, .grid_item.selected::after { color:var(--text_color_selected) !important; } /* white */ li:is(.selected,:hover,.hovered) li, .text_color_default, .no_highlight, .no_highlight:hover, .no_highlight > li:hover, :hover:not(#svg_container) > svg, .font_glyph_item::before, .font_glyph_item::after, #font_specimen_viewer::before, .has_font_specimen_glyph #font_specimen_viewer::after, #font_file_glyph_viewer::before, #font_file_glyph_viewer::after { color:hsl(0,0%,var(--percent_10)) !important; } /* default */ /* font weight */ li:hover li, li.hovered li, li.selected li, body.no_hover li:hover, li:not(.grid_item).no_hover:hover { font-weight:normal !important; } .bold, li:not(.grid_item):hover, li.hovered, li.hovered li:is(:hover,.selected), li:not(.grid_item).selected, li.selected li:hover, li.media[class*="_loaded"], #show_image_grid:hover, #show_font_grid:hover, dt { font-weight:bold !important; } #content_pane[data-content="has_ignored"]::before { opacity:0.3; } .has_warning #dir_wrapper, .has_warning #content_pane, .focus_content .dirlist_item, body:is(.has_menu,.has_menu_parents,.has_menu_stats,.has_menu_grid.has_images.has_fonts) .dirlist_item:not(.hovered), body:is(.has_menu,.has_menu_parents,.has_menu_stats,.has_menu_grid.has_images.has_fonts) #content_pane, #dir_menu_parent:not(:hover), #dir_menu_main_container:not(:hover) nav, #show_grid_btn, #dir_footer_utilities, .split_btn span, .disabled:not(.local) { opacity:0.75; } body.has_menu_footer .dirlist_item.hovered, .disabled:not(.local).selected { opacity:0.84; } #show_grid_btn:hover, #prev_next_btns span:hover, #dir_footer_utilities:hover, .split_btn span:hover { opacity:1.0; } `; const utilities_styles = ` #utilities { top:0; justify-content:center; } #warnings_container { width:26em; flex-direction:column; border-radius:0 0 3px 3px; box-shadow:0px 2px 12px #333; font-size:0.875em; color:#111; display:none; } #warnings_header { padding:1rem 1.5rem; background-position:left 1.25rem center; background-repeat:no-repeat; background-size:24px; } #warnings_container:not(.warning_make_playlist) #warnings_header { background-image:${ get_SVG_UI_Icon("error") }; } #warnings_header h3 { text-indent:2.25em; } #warnings_container:not(.warning_make_playlist) h3#warning_header, #warnings_container.warning_make_playlist h3#make_playlist_header, .warning_button.show, #warnings div.show, .has_warning #utilities, .has_warning #warnings_container, .has_help #utilities, .has_help #help_container { display:flex;} #warnings .warning { padding:0 1.5rem 1rem; display:none; } #warning_buttons_container { padding:1rem 1.5rem; } button.focus, button:focus { background-color:#0E4399; color:#EEE; outline:none; } .warning_button { min-width:4em; display:none; font-size:1em; justify-content:center; } #warnings_container.warning_local_file #warning_local_file, #warning_btn_ok { margin-left:auto; } #warning_btn_cancel + #warning_btn_save, #warning_btn_dont_save + #warning_btn_cancel, #warning_btn_clear { margin-right:auto; } #warning_btn_cancel, #warning_btn_clear, #warning_btn_save { margin-left:0.5rem; } #warnings_container.clear #warning_buttons { justify-content:space-between; } #warning_make_playlist fieldset div { padding:0 0 2px; } #warning_make_playlist .indent { text-indent:2em; } #warning_make_playlist input { margin-right:6px; } #warnings_container.warning_local_playlist #warning_local_playlist, #warnings_container.warning_local_playlist #warning_btn_ok { display:inline-block; margin-left:auto; } .has_warning::before, .has_overlay::before { content:""; position:fixed; top:0; right:0; bottom:0; left:0; z-index:9998;-webkit-user-select:none;-moz-user-select:none; user-select:none; } #help_container { padding:0 1em 1em; overflow:auto; } #help_container > header { grid-template-columns:5em auto fit-content(100%); } #help_container > section { padding-top:2rem; } #help_container > section > div { margin-top:1rem; padding-top:1rem; } #help_container dd { margin-inline-start:1em; } #help_container dd:before { content:"\u2219"; margin-right:6px; } #help_container dl + p { margin-top:1rem; padding-top:1rem; } #help_container ol li { list-style:decimal; } #help_container kbd { min-width:1em; height:fit-content; padding:2px 6px; display:inline-block; border:solid 1px #888; border-radius:3px; text-align:center; font-family:inherit; font-size:0.875em; background-color:hsl(0,0%,var(--percent_90)); } #help_bookmarks::before { background-image: ${ get_SVG_UI_Icon("bookmark") }; } .has_help #utilities, .has_help #help_container { bottom:0; } `; const dir_header_menu_styles = ` /* PARENTS MENU */ #parent_dir_nav #svg_chevron { width:18px; } #parent_dir_nav #svg_multiply { width:14px; } #parent_dir_nav #svg_multiply, body:is(.has_playlist,.has_filelist) #svg_chevron, body:is(:not(.has_playlist),:not(.has_filelist)) #dir_header #close_playlist_container { display:none; } body.has_playlist #parent_dir_nav #svg_multiply, body.has_filelist #parent_dir_nav #svg_multiply, body:is(.has_playlist,.has_filelist) #dir_header #close_playlist_container { display:flex; } #current_dir_path { padding:3px 6px; word-break:break-word; } /* MAIN MENU */ #dir_menu_main li { display:flex; } #dir_menu_main li.has_submenu.selected .submenu { display:block; } #dir_menu_main li.has_submenu { position:relative; justify-content:space-between; } #dir_menu_main li.bookmark a::before { content:""; width:24px; max-width:24px; min-width:24px; height:12px; background-size:12px; } .submenu { width:100%; max-width:240px; display:none; margin:0; padding:0; position:absolute; top:-1px !important; left:100%; right:0; } #dir_menu_main ul.submenu li a { padding:6px 8px 6px 0; } #dir_menu_main input { width:0; float:left; } .menu_item { margin:0; padding:5px 8px 5px 0; display:flex; flex-grow:1; text-align:left; } #dir_menu_main .selected ~ li:hover .submenu, #dir_menu_main .selected ~ li .submenu:hover, .has_open, #dir_menu_main .show_input span.menu_item { display:none; } #dir_menu_main .show_input input { display:unset; margin:2px 6px; width:100%; } #dir_menu_main svg { margin: 0 6px; width:12px; } #dir_menu_main li.selected svg, #dir_menu_main li:hover svg, #dir_menu_main li.hovered svg { filter:invert(1); } #ui_scale span.menu_item::after { content:attr(data-value); } #ui_scale_input_container, #ui_scale.show_input span + span { display:flex; } #ui_scale_input_container { padding-left:18px; padding-right:8px; } /* IFRAME MENUS */ #parent { padding:5px 3px 5px 0; } #parent span { padding:0px 1px; } #open_in_sidebar { padding:5px 2px 5px 3px; } `; const dir_header_styles = ` /* for both sidebar and content_iframe */ #dir_wrapper { font-variant-numeric:tabular-nums; } #dir_wrapper.top_body { min-width:200px; } #dir_wrapper.iframe { min-width:500px; flex-basis:100%; } #dir_header { user-select:none; -webkit-user-select:none; } .dir_header_title_div { letter-spacing:0.5em; text-indent:0.75em; flex-basis:100%; } .dir_header_title_div:before { content:"INDEX OF"; } .has_playlist .dir_header_title_div:before { content:"PLAYLIST"; } .has_filelist .dir_header_title_div:before { content:"FILELIST"; } ${ dir_header_menu_styles } /* SIDEBAR BUTTONS */ #directory_buttons_left { padding:6px; } #show_details { margin-top:0; margin-right:8px; padding:0 4px; } #show::before { content:"Show "; } /* GRID BTN ---> combine style with save_btn */ #show_grid_btn { margin:0 0 0 auto; } #show_grid_btn ul { display:none; padding-left:0px; top:-1px; right:-1px; } #show_grid_btn ul:after { content:""; position:absolute; z-index:-1; top:0; bottom:0; left:0; right:0; background-color:hsl(0,0%,var(--percent_80)); } #show_grid_btn ul:not(:has(li:hover)):hover { background-color:var(--non_media_background); } #show_grid_btn ul:not(:has(li:hover)):hover svg { color:white !important; } #show_grid_btn.has_grid div { color:#118888; } #top_body:is(.has_images,.has_fonts) #show_grid_btn { display:flex; } #top_body.has_images.has_fonts #show_grid_btn:hover ul { display:grid; } /* SORTING ITEMS */ #sorting .sorting { grid-row:1; } body:not(.show_details_false) #sorting_row_2 { display:grid; } #sorting_row_1 span, #sorting_row_2 span, .sorting span::before, .sorting span::after { display:inline-block; } #sorting_row_1 span, #sorting_row_2 span { padding:6px 0; } #sorting_row_1.iframe span, #sorting_row_2.iframe span { padding:4px 0; } #sorting span::before, #sorting span::after, .sorting .menu_item::after { content:""; width:16px; height:8px; color:#CCC; background-position:center; background-repeat:no-repeat; background-size:10px; } .sorting.down span::after, .sort_direction_descending .sorting span::after { transform:rotate(0deg) !important; } #sort_by_name input { margin:-2px 6px -2px 0; bottom:-2px; } #sort_by_ext { grid-column: span 2; } .has_media #sort_by_ext { grid-column: span 1; } .has_media #sort_by_default { text-align:center; } #sort_by_default.iframe, .iframe #sort_by_size, .iframe #sort_by_date { text-align:right; } .has_media #sort_by_duration, .has_playlist #sort_by_duration, #content_body.has_media #sorting_row_2 #sort_by_duration { display:unset; } #content_body #sorting_row_1 #sort_by_duration, #top_body #sorting_row_2 #sort_by_duration { display:none; } /* TEXT EDITOR ITEM */ body:not(.show_details_false) #show_texteditor, body.has_texteditor #show_texteditor { display:flex; } #show_texteditor a { padding-left:10px; } `; const dir_nav_styles = ` /* for both sidebar and content dirlists */ #dir_nav { overflow-y:hidden; flex-basis:100%; } #dir_nav_inner { overflow:auto; margin-bottom:-1px; } #dir_nav ol { -webkit-margin-before:0em !important; -webkit-margin-after:0em !important; -webkit-padding-start:0em; } #directory_list { counter-reset:item; transition:opacity .125s; } #directory_list:empty { border-bottom:0; padding:100%; } .dirlist_item_input, .dirlist_item_details, .dirlist_item_details span, .dirlist_item_media_duration, .details.ext, .dirlist_item.error::before, .dirlist_item_name_a::before, body.show_invisibles_false:not(.has_menu_stats) .dirlist_item.invisible.ignored, body.show_invisibles_false:not(.show_ignored_false):not(.has_menu_stats) .dirlist_item.invisible:not(.ignored), body.show_invisibles_false.show_ignored_items_false:not(.has_menu_stats) .dirlist_item.ignored, body.show_invisibles_false.show_ignored_items_false:not(.has_menu_stats) .dirlist_item.invisible, body.show_ignored_items_false:not(.show_invisibles_false):not(.has_menu_stats) .dirlist_item.ignored:not(.invisible) { display:none; } .dirlist_item { margin-inline-start:0; display:grid; grid-gap:0; } .top_item { grid-template-columns:minmax(8rem,auto) minmax(6em,1fr) minmax(auto,6em); } .dirlist_item_name { grid-row:1; display:flex; -webkit-padding-start:0; -moz-padding-start:0; word-break:break-word; } .top_item .dirlist_item_name { grid-column:1 / span 3; padding:6px 12px 6px 0; } .dirlist_item_name::before { counter-increment:item; content:counter(item); min-width:36px; height:14px; max-height:14px; min-height:14px; text-align:right; padding:0 3px 0 0; text-indent:6px; } .dirlist_item_input { margin:1px 6px 0 0; max-height:13px; } .dirlist_item .desc.dirlist_item_details { padding:0 6px 4px 40px; grid-column:1 / span 3; text-align:left; white-space:unset; } .has_icon_before::before, .has_icon_before_before { content:""; display:inline-block; background-position:center; background-repeat:no-repeat; background-size:14px,0px; } .has_icon_before::before, .has_icon_before_before, .show_large_image_thumbnails_false .dirlist_item.image .has_icon_before_before, .show_image_thumbnails_false .dirlist_item.image .has_icon_before_before { width:14px; height:14px; max-width:20px; max-height:14px; min-width:14px; min-height:14px; margin:0 6px 0 6px; } .dirlist_item.image .has_icon_before_before { width:56px; height:56px; max-width:56px; max-height:56px; min-width:56px; min-height:56px; margin:0 6px; background-position:top; background-size:contain,0px; } .ignored:not(.selected) .has_icon_before::before, .ignored:not(.selected) .has_icon_before_before, .focus_content .has_icon_before_before, .has_quicklook #dir_wrapper { filter:grayscale(100%); } .focus_content li:hover .has_icon_before_before, .focus_content li:is(.selected,.hovered) .has_icon_before_before { filter:grayscale(0%); } /* MEDIA ITEMS */ .top_item.media .dirlist_item_name { grid-column:1 / span 2; padding-right:0; } .top_item.media .dirlist_item_media_duration { grid-column:3; padding:6px 12px 6px 0; } .dirlist_item.media .dirlist_item_media_duration { grid-row:1; } .iframe_item.media .dirlist_item_media_duration { grid-column:2; } .media:not(.local) .dirlist_item_media_duration { display:unset; } .dirlist_item.media .dirlist_item_media_duration:empty { background-image:${ get_SVG_UI_Icon('spinner') } !important; background-position:top 3px right 10px; background-repeat:no-repeat; background-size:20px; } .theme_dark .dirlist_item_media_duration:empty { filter:invert(1); } /* SORTING BORDERS */ .sort_by_default:not(.show_invisibles_false) .dir.invisible + .dir:not(.invisible), .sort_by_default:not(.show_invisibles_false) .dir:not(.invisible) + .dir.invisible { border-top:solid 1px hsl(0,0%,var(--border_lum)); } /* ITEM DETAILS */ .dirlist_item_details { text-align:right; white-space:nowrap; } .top_item .dirlist_item_details { padding:0 12px 4px 0; } .dirlist_item_details.size { padding-left:12px; } .dirlist_item_details.date { padding-bottom:0; height:1em; max-height:1em; overflow-wrap:break-word; } .dirlist_item_details.kind::first-letter { text-transform:uppercase; } #content_body .iframe_item { grid-template-columns: minmax(20em,100%) minmax(4em,6em) minmax(6em,8em) minmax(6em,14em) minmax(6em,8em); } #content_body .iframe_item.non_media .dirlist_item_name { grid-column:1 / span 2; } #content_body .iframe_item .dirlist_item_details { grid-row:1; height:1ex; } #content_body .iframe_item .desc.dirlist_item_details { grid-row:2; grid-column:1 / span 6; height:auto; padding:0 6px 4px 40px; } #content_body .iframe_item .dirlist_item_name_a, #content_body .iframe_item > span { padding:5px 16px 5px 0; } body:not(.show_numbers_false) .dirlist_item_name_a::before { display:initial; } body:not(.show_details_false) .dirlist_item_details, .media .dirlist_item_input { display:unset; } .disabled, .ignore_ignored_items li.ignored, .has_filelist [id$="sort_by_size"], .has_playlist [id$="sort_by_size"], .has_filelist [id$="sort_by_date"], .has_playlist [id$="sort_by_date"] { cursor:not-allowed; opacity:0.75; } .dirlist_item.error { display:block; padding:6px 8px; } .dirlist_item.ignored.local .dirlist_item_name_a::after { content:"\\00a0[local file]"; display:contents; font-style:italic; } .is_error #is_error { display:block !important; grid:none !important; grid-template-columns:none !important; } .is_error #is_error_items { display:block; } `; const iframe_dir_styles = `${ global_styles } #content_body { overflow-x:auto; font-size:${ (parseFloat(UI_Prefs_Non_Bool.ui_font_size) * 0.875) + UI_Prefs_Non_Bool.ui_font_size.replace(/\d*/,'') }; } .theme_dark .sorting span::before, .theme_dark .sorting span::after { filter:invert(1); } #content_body:not(.show_details_false) #show::before { content:"Hide "; } #content_body.show_details_false .iframe_item { grid-template-columns:auto; } #content_body.show_details_false .media .dirlist_item_media_duration { display:none; } #content_body #content_pane,#content_body .content_el { display:none; } #content_body.has_quicklook #dir_nav { opacity:0.8; } #content_body.has_quicklook #content_pane { display:flex; padding:2em; position:absolute; z-index:1; left:0; right:0; top:0; bottom:0; justify-content:center; } #content_body.has_quicklook #content_header { padding: 0; background-color:hsl(0,0%,var(--percent_85)); border-radius: 3px 3px 0 0; border:solid 1px hsl(0,0%,var(--border_lum)); border-bottom:0; } #content_body.has_quicklook #content_title { padding:4px 6px 0; } #content_body.has_quicklook #content_title_container { border-bottom:0; } #content_body.has_quicklook #content_container { padding:6px; background-color:hsl(0,0%,var(--percent_85)); box-shadow:0 0 12px #111; border-radius: 0 0 3px 3px; border:solid 1px hsl(0,0%,var(--border_lum)); border-top:0; contain:unset; flex-basis:unset; } #content_body.has_quicklook .content_el { width:100%; } #content_body.has_quicklook .content_el.has_content { border:solid 1px hsl(0,0%,var(--border_lum)); } #content_body.has_quicklook .content_el.has_content,#content_body.has_quicklook .content_el:has(.has_content) { display:flex; z-index:1; } #content_body.has_quicklook #content_container:has(#content_font.has_content, #content_pdf.has_content,#content_iframe.has_content),#content_body.has_quicklook #content_pane[data-content="has_ignored"] #content_container { height:50%; flex-basis:unset; } #content_body.has_quicklook #content_container:has(#content_image.has_content) { display:table; flex-basis:unset; } #content_body.has_quicklook #content_video.has_content { position:static; } #content_body.has_quicklook div[id^="title_buttons"], #content_body.has_quicklook #content_pane.has_audio :is(#content_title_container,#content_container), #content_body.has_quicklook #content_pane[data-content="has_ignored"] #content_iframe, #content_body.has_quicklook #content_pane[data-content="has_pdf"] #content_pdf { display:none; } #content_body.has_quicklook #content_pane:not([data-content="has_ignored"]) #content_font.has_content { display:grid; } #content_body.has_quicklook #content_pane[class*="has_font_specimen"] #font_specimen_viewer { display:flex; } #content_body.has_quicklook #content_image_container, #content_body.has_quicklook #content_iframe { max-height:88vh; } #content_header, #content_body.has_quicklook #content_image_container, #content_body.has_quicklook #content_container:has(#content_video.has_content) { padding:0; } #content_pane[data-content="has_pdf"] #content_container { background-image:${ get_SVG_UI_File_Icon('file_icon_ignored') }; background-size:28px; } `; const dir_footer_styles = ` /* for both sidebar and content_iframe */ .has_menu_stats #stats_summary, .stats_kind span.file, .stats_kind span.media, #top_body.no_hover #dir_footer_utilities { display:none; } #dir_footer { user-select:none; -webkit-user-select:none; } #stats_container { max-height:33vh; } .theme_light #dir_footer_utilities:hover ul, .theme_light #dir_footer:hover, .theme_light #stats_details_summary { box-shadow:0px -4px 4px 0px rgba(128,128,128,0.6); } .theme_dark #dir_footer_utilities:hover ul, .theme_dark #dir_footer:hover, .theme_dark #stats_details_summary { box-shadow:0px -4px 4px 0px rgba(32,32,32,0.6); } #stats_details_summary_dirs .stats_kind::before { background-image:${ get_SVG_UI_File_Icon("file_icon_dir") }; } #stats_details_summary_files .stats_kind::before { background-image:${ get_SVG_UI_File_Icon("file_icon_file_default") }; } #stats_details_summary, #stats_details_items_container { overflow-y:scroll; } #stats_summary_totals, .has_media #total_duration { display:flex; text-align:left; white-space:normal; padding-right:1em; } #stats a { padding:3px 12px 3px 0; } #stats a::before { content:attr(data-count); width:36px; text-align:right; } .stats_kind span { margin-right:0.5em; white-space:pre; display:flex; } .stats_kind > span::first-letter { text-transform:uppercase; } #stats_details_items li.audio a span span::after { content:attr(data-audio_duration); white-space:pre; } #stats_details_items li.video a span span::after { content:attr(data-video_duration); white-space:pre; } #total_duration::after { content:attr(data-time_remaining); white-space:pre; } .has_media #total_duration::before { content:"Total Time:\\00a0"; } .stats_list_item_name_a { -webkit-padding-start:0; padding:1px 0; } .stats_list_item span::first-letter { text-transform:uppercase; } #stats_summary, #stats_details_summary { margin-block-start:0; margin-block-end:0; } #stats a.dirlist_item_name_a:before { display:inline-block; } #stats_details_items { max-height:25vh; } #stats_container, .has_menu_stats #stats_details_summary, .has_menu_stats #stats_details_items { display:block; } #dir_footer_utilities { right:-1px; bottom:-1px; } #dir_footer_utilities ul { bottom:0; right:0; white-space:nowrap; box-shadow:-0px -3px 6px -3px #333; } #dir_footer_utilities:hover ul { display:block; } .has_menu_stats #dir_footer_utilities { display:none; } `; const directory_utilities_styles = ` #show_sidebar { top:0; right:0; height:21px; opacity:0.6; } #show_sidebar:hover { opacity:1; } body.show_sidebar_false #handle { display:none; } body.show_sidebar_false #show_sidebar { left:2px; transform:rotate(180deg); } body.show_sidebar_false #dir_wrapper { width:0 !important; min-width:0; position:absolute; top:2px; left:-1px; } body.show_sidebar_false #dir_header { z-index:unset; display:none; } body.show_sidebar_false #dir_nav { visibility:hidden; } body.show_sidebar_false #directory_list_outer { min-width:0; } body.show_sidebar_false #content_pane { width:100% !important; } body.show_sidebar_false #title_buttons_left { padding-left:24px; } #handle { top:0; bottom:0; right:-4px; width:7px; cursor:col-resize; } .has_overlay #handle { z-index:9999; } `; const sidebar_styles = `${ dir_header_styles } ${ dir_nav_styles } ${ dir_footer_styles } ${ directory_utilities_styles }`; /* CONTENT PANE STYLES */ const content_pane_header_styles = ` /***** CONTENT TITLE *****/ #content_title_container { overflow-x:scroll; } #content_title { min-width:16em; min-height:18px; padding:4px 8px; word-break:break-word; } #content_title span::before { font-weight:normal; margin-bottom:-3px; } #content_pane.has_font_specimen #content_title div::before { content:"Font"; } #content_pane.has_font_file #content_title div::before, #content_pane.has_font_file_glyph #content_title div::before { content:"Glyphs from font"; } .has_directory_source #content_title div::before { content:"Source of" !important; } .has_directory_source #content_title span::before { background-image:${ get_SVG_UI_File_Icon("file_icon_dir_default") }; height:14px !important; background-size:contain; } #content_pane[data-content="has_grid"] #content_title div::before { content:"Fonts and Images from"; } #content_pane[data-content="has_grid"].has_font_grid #content_title div::before { content:"Fonts from"; } #content_pane[data-content="has_grid"].has_image_grid #content_title div::before { content:"Images from"; } #content_pane[data-content="has_ignored"] #content_title div::before { content:"Ignored content"; } #content_pane[data-content="has_dir"] #content_title div::before { content:"Index of"; } body.has_texteditor .texteditor_view_raw.texteditor_split_view_false #content_title div::after { content:" (Source Text)"; } body.has_texteditor .texteditor_view_preview.texteditor_split_view_false #content_title div::after { content:" (Text Preview)"; } body.has_texteditor .texteditor_view_html.texteditor_split_view_false #content_title div::after { content:" (HTML Preview)"; } body.has_texteditor #content_title div::before { content:"Text Editor" !important ; font-weight:bold; } body.texteditor_edited.has_texteditor #content_title div::before { content:"Text Editor (edited)" !important; font-weight:bold; } body.has_texteditor #content_title span { display:none; } body.has_texteditor #content_title span::before { background-image:${ get_SVG_UI_File_Icon("file_icon_markdown") }; } #content_pane[data-loaded="unloaded"] #content_title { display:flex; justify-content:center; align-items:center; } #content_pane[data-loaded="unloaded"] #content_title div::before { content:"Loading..." } #content_pane[data-loaded="unloaded"] #content_title span { display:none; } #content_pane[data-content="has_grid"] #content_title span::before { background-image:${ get_SVG_UI_File_Icon("file_icon_dir") }; height:14px !important;} #content_pane[data-content="has_image"] #content_title span::after { content:attr(data-after); font-weight:normal; white-space:pre; } #content_pane.content_error #content_title span::before, #content_pane.content_error #content_container, #content_pane.has_audio_error #content_audio_title span::before { background-image:${ get_SVG_UI_Icon("error") }; } body.is_error:not(.has_directory_source) #content_title span::before, #content_pane.content_error #content_title div::before { content:"ERROR:"; white-space:pre; display:inline; } /* CONTENT TITLE BUTTONS LEFT */ #reload_btn { width:52px; } #reload_btn::before { content:"Reload"; } #prev_next_btns { margin-left:4px; } #prev_next_btns span { width:2em; height:16px; } #prev_next_btns span:active { background-color:#0E4399; } #prev_next_btns:focus { background-color:white; } #prev_next_btns svg { width:12px; } /* CONTENT TITLE BUTTONS RIGHT */ #scale { margin-right:4px; background-color:#FFF; } #scale span { width:2em; } #close_btn { width:52px; } #close_btn::before { content:"Close"; } body.has_texteditor #close_btn::before { content:"Hide"; } #content_pane[data-content="has_null"] #close_btn { display:none !important; } .split_btn::after { content:""; position:absolute; top:0; bottom:0; left:calc(50% - 1px); border-left:solid 1px #333; } .split_btn span { display:inline-flex; } #open_in_texteditor { margin-right:4px; } `; const content_pane_audio_styles = ` /* CONTENT AUDIO TITLE */ #content_audio_title span { padding:4px 6px 0; } #content_audio_title span::before { content:""; padding-right:22px; height:14px !important; font-weight:normal; background-image:${ get_SVG_UI_File_Icon("file_icon_audio") }; background-position:center; background-position:right 4px center; background-repeat:no-repeat; } #content_pane.has_audio #content_audio_title span::before, #content_pane[data-content="has_video"] #content_title div::before { content:"Playing:"; } #content_pane.has_audio.has_audio_error #content_audio_title span::before { content:"ERROR:"; } #content_pane.has_audio.has_audio_error #content_audio { padding-top:0; } #content_pane.has_audio.has_audio_error #audio_container { display:none; } /* CONTENT AUDIO PLAYER */ #content_audio { justify-content:center; padding:2px 6px 6px; overflow-x:auto; } #audio_container { height:32px; background-color:rgb(241, 243, 244); } #prev_track, #next_track { width:2rem; } #audio { height:32px; } audio::-webkit-media-controls-enclosure { border-radius:0; } #close_audio { width:32px; } #audio_options { margin-top:0; margin-right:calc(-6em - 8px); padding:0 4px; width:6em; justify-content:start; } #loop_label input { margin:0px 4px 2px} #shuffle_label input { margin:2px 4px 0px} #shuffle_label::after { content:attr(data-shufflecount); } /* CUE SHEET MENU */ .cuesheet_track_list_container { background-image:${ get_SVG_UI_File_Icon("file_icon_playlist") }; background-repeat:no-repeat; background-size:18px; background-color:inherit; display:none; } .cuesheet_track_list_container:hover > div { display:flex; flex-direction:column; margin-top:-1px; overflow:auto; } #cuesheet_track_list_container_audio { width:32px; background-position:center; } #cuesheet_track_list_container_video { width:24px; background-position:top left; } #cuesheet_track_list_container_audio > div { padding-top:13px; } #cuesheet_track_list_container_video > div { padding-top:10px; } .cuesheet_track { justify-content:space-between; grid-template-columns: 2rem minmax(6rem,1fr) minmax(6em,1fr) minmax(auto,6em); } .cuesheet_track.selected .cue_track_id::before { content:""; width:16px; height:8px; display:flex; } .cuesheet_track span { padding:4px 0 4px 8px; font-variant-numeric:tabular-nums; } #cuesheet_title { padding:4px 8px; font-variant-numeric:tabular-nums; text-align:center; } /* CONTENT TITLE PLAYLIST ENTRY (#content_playlist_item and #content_audio_playlist_item) */ .playlist_entry_container { flex-direction:row; } .playlist_entry_container textarea { resize:vertical; background-color:transparent; } .theme_light .playlist_entry_container:has(textarea:focus) { box-shadow:inset 0px 0px 2px 2px var(--non_media_item_background); } .theme_dark .playlist_entry_container:has(textarea:focus) { box-shadow:inset 0px 0px 4px 1px hsl(0,0%,var(--percent_95)); } #content_pane.has_audio #audio_wrapper, .playlist_entry_container.has_content { display:flex; flex-direction:column; } audio::-webkit-media-controls-panel { padding:0; } `; const content_pane_styles = `${ content_pane_header_styles } ${ content_pane_audio_styles } #content_pane { transform:scale(1); contain:strict; } #content_container { align-items:center; justify-content:center; bottom:0; background-position:center; background-repeat:no-repeat; background-size:33.33%; contain:strict; flex-basis:100%; overflow:auto; } .content_el { width:100%; height:100%; margin:0; padding:0; overflow:auto; display:none; } #content_pane[data-loaded="unloaded"] .content_el { display:none !important; } #content_pane[data-loaded="unloaded"]:not([data-content="has_ignored"]) #loading_spinner { display:block; } /* CONTENT DISPLAY */ #content_pane:not([data-content="has_ignored"]) #content_font.has_content, #content_pane[data-content="has_image"] #content_image_container, #content_pane[data-content="has_grid"] #content_grid { display:grid; } #content_pane[data-content="has_grid"] .split_btn, #content_pane[data-content="has_image"] .split_btn, #content_pane[data-content="has_font"] .split_btn, #content_body:not(.text_editing_enable_false) #content_pane[data-content="has_htm"] #open_in_texteditor, #content_pane:not([data-content="has_ignored"]) .content_el:not(#content_font).has_content, body.has_texteditor #content_texteditor, #content_pane[class*="has_font_specimen"] #font_specimen_viewer, .has_font_specimen_glyph #font_specimen_glyph_viewer, #content_pane[class*="has_font_file"] #font_file_viewer, .has_font_file_glyph #font_file_glyph_viewer { display:flex; } /* CONTENT GRID (div) */ #content_grid { font-size:1rem; grid-gap:0; grid-template-columns:repeat(auto-fill, minmax(${ ( UI_Prefs_Non_Bool.grid_image_size + 16) }px, auto)); grid-auto-rows:minmax(min-content, max-content); } #content_pane.has_hidden_grid #content_grid { max-height:100%; overflow:hidden; visibility:hidden; } /* FONT & IMAGE GRID ITEMS */ .image_grid_item { padding:6px; grid-column:auto; line-height:0; } .image_grid_item img { width:auto; max-width:${ (UI_Prefs_Non_Bool.grid_image_size).toString() }px; max-height:${ (UI_Prefs_Non_Bool.grid_image_size) }px; position:relative; opacity:0.9; } .image_grid_item img[src$=".svg"] { height:100%; } .image_grid_item.selected { box-shadow:inset 0px 0px 4px hsl(0,0%,var(--percent_60)); } .font_grid_item.selected p { font-weight:bold; } .font_grid_item.selected a { font-weight:unset; } .image_grid_item.selected img, .font_grid_item.selected, .image_grid_item:hover, .font_grid_item:hover { opacity:1; } .font_grid { font-size:4em !important; margin:0 0 20px; grid-gap:0; grid-template-columns:repeat(auto-fit, minmax(max(60px,1.33em), 1.5fr)); grid-auto-rows:minmax(max(60px,1.33em), max-content); line-height:unset !important; letter-spacing:unset !important; } .font_grid_item { line-height:1; padding:8px 20px; grid-column:1 / -1; opacity:0.9; } .font_grid_item_info { padding:0 0 6px 0; letter-spacing:0.1em; text-indent:0.1em; } .font_grid_item h2 { font-size:${ UI_Prefs_Non_Bool.grid_font_size * 4 }em; font-weight:normal; } .image_grid_item + .font_grid_item { margin-top:-1px; border-top:solid 1px hsl(0,0%,var(--border_lum_inverted)); } /* CONTENT FONT.content */ #content_font { font-size:${ UI_Prefs_Non_Bool.grid_font_size }em; overflow-wrap:break-word; align-content:start; flex-direction:column; } #content_pane.has_font_specimen #content_container, .has_font_specimen_glyph #content_container, .has_font_specimen_glyph #font_specimen, .has_font_file_glyph #content_container { overflow:hidden; } #content_pane[data-content*="has_font"] #font_toolbar { display:grid; overflow-x:scroll; overflow-y:hidden; -webkit-user-select:none;-moz-user-select:none; user-select:none; } #content_pane.has_font_specimen #font_specimen_variants { display:flex; } #content_pane.has_font_specimen #font_specimen_adjustments li.display_none { display:unset; } #content_pane.has_font_file_glyph #content_font { background-color:hsl(0,0%,var(--percent_100)); } #font_toolbar li { margin:2px; padding:0 4px; white-space:pre; } #font_toolbar li.text { width:50%; font-size:var(--font_size_small); } #font_variant_select { width:13em; } #unicode_char_ranges_select { width:12em; } #font_specimen_adjustments { font-size:0.75rem; padding-bottom:2px; } #font_specimen_adjustments input { width:8em; } #font_specimen_viewer { min-width:100%; flex-direction:column; } #font_specimen_viewer .specimen { padding:20px; outline:none; color:inherit; font-weight:normal; } #font_specimen_viewer .specimen:focus, #font_specimen_viewer .specimen:focus-visible { box-shadow:inset 0 0 2px 2px hsl(212deg 50% 60%); border-radius:3px; outline:none !important; } .specimen:focus, specimen:focus-visible { background-color: hsl(0,0%,var(--percent_100)); } #font_specimen_grid:empty, #font_specimen_glyph:empty, #font_specimen_grid:empty + hr { display:none; } .font_glyph_item { grid-column:auto; display:flex; justify-content:center; position:relative; cursor:pointer; -webkit-text-stroke:inherit !important; letter-spacing:initial; line-height:initial; } .font_glyph_item div { color:inherit; } .font_glyph_item::before, .font_glyph_item::after, #font_specimen_viewer::before, #font_specimen_viewer::after { display:inline-block; position:absolute; font-size:0.75rem; top:0; font-family:${UI_Prefs_Non_Bool.ui_font}; opacity:0.75; font-feature-settings:normal; font-variant:normal; line-height:1.2; letter-spacing:normal; -webkit-text-stroke:0 !important; } .font_glyph_item::before, #font_specimen_viewer::before { content:attr(data-unicode_dec); left:2px; } .font_glyph_item::after, #font_specimen_viewer::after { content:attr(data-unicode_hex); right:2px; } .has_font_specimen_glyph #font_specimen_viewer::before, .has_font_specimen_glyph #font_specimen_viewer::after, .has_font_file_glyph #font_file_glyph_viewer::before, .has_font_file_glyph #font_file_glyph_viewer::after { display:inline-block; padding:4px 6px; font-size:0.875rem; position:fixed; white-space:pre; opacity:1; z-index:2; } #font_specimen_1 { font-size:4em;} #specimen_2 { font-size:8em; } #specimen_3 { font-size:6em; } #specimen_2H4 { font-size:1.618em; } #specimen_3H3 { font-size:2em; } .lorem { font-size:1em; column-gap:1.5em; overflow-wrap:normal; } #lorem::first-line { letter-spacing:0.1em; text-indent:0.1em; font-size:${ UI_Prefs_Non_Bool.grid_font_size * 1.33 }em; font-variant:small-caps; } #lorem_2 { padding:12px 0 0; columns:2; } #lorem_3 { padding:12px 0 0; columns:3; } /* FONT GLYPHS */ #font_specimen_viewer, #font_file_viewer { line-height:1.5; background-color:inherit; } .glyph_container:hover, .glyph_container.selected { z-index:1; } #font_specimen_glyph, #font_specimen_glyph:not(:empty) + #font_specimen_glyph_overlay { display:flex; justify-content:center; font-size:64vw; overflow:visible; user-select:none; } #font_file_viewer { font-family:unset; flex-direction:column; } #content_pane.has_font_file_glyph #font_file_grid { visibility:hidden; } #content_pane.has_font_file_glyph #font_file_viewer { overflow:hidden; } #font_file_grid { margin-bottom:21px; } .font_glyph_item svg { width:1em; height:1em; display:block; overflow:visible; } .font_glyph_item g, #font_file_glyph_viewer svg g { transform-origin:center; } #font_file_glyph_viewer { background-color:#FFF; } #font_file_glyph_viewer::before, #font_file_glyph_viewer::after { position:absolute; color:hsl(0,0%,var(--percent_65)); } #font_file_glyph_viewer::before { content:attr(data-unicode_dec); } #font_file_glyph_viewer::after { content:attr(data-unicode_hex); right:0; } .has_font_file_glyph #save_svg { display:initial; margin-right:4px; } #save_svg_hidden { float:left; visibility:hidden; } #font_info { max-height:${ (window.innerHeight * 0.75) }px; left:-1px; right:0; bottom:-1px; overflow-y:auto; } #font_info:hover { box-shadow:0px 4px 6px 3px #333; } /* OTHER CONTENT ELEMENTS */ #content_image_container { padding:2rem 2.5rem; box-sizing:border-box; } .has_zoom_image #content_image_container, .has_scaled_image #content_image_container { padding:0; } #content_image { margin:auto; width:auto; max-width:100%; height:auto; max-height:100%; object-fit:contain; cursor:zoom-in; } #content_image:focus-visible { outline:none; } #content_pane.has_zoom_image #content_image { width:fit-content; height:fit-content; max-width:unset; max-height:unset; cursor:zoom-out; } #content_video { background:transparent; height:auto; max-width:calc(100% - 4em); max-height:calc(100% - 4em); } #content_iframe { background:white; } #content_pane.has_emptycontent #content_iframe { background:unset; } `; const main_styles = `${ global_styles } .image_grid_item img[src$=".svg"] { width:100%; } .cuesheet_track_list_container:hover .cuesheet_track_list, #content_grid a { display:block; } button { background-color:hsl(0,0%,95%); border:solid 1px #333; border-radius:3px; height:18px; font-size:0.875em; font-family:${UI_Prefs_Non_Bool.ui_font} !important; cursor:pointer; } button.focus, button:focus { outline:none; border-radius:3px !important; border-style:solid !important; border-width:1px !important; border-color:#222 !important; } textarea:focus, audio:focus { outline:none; } #content_title *:empty { display:none; } /* VARIOUS CLASSES AND ELEMENTS */ /* combine with has_flyout_menu or add background color classes to elements: */ /* .has_popout_menu { background-color:#C0C0C0; border:solid 1px #666; } .has_popout_menu li { background-color:#D0D0D0; } .theme_dark #dir_wrapper .has_popout_menu { border:solid 1px #111; } .theme_dark #dir_wrapper .has_popout_menu, .theme_dark #dir_wrapper .has_popout_menu li { background-color:#505050; } */ /***** APPEND STYLES *****/ ${ sidebar_styles } ${ content_pane_styles } ${ utilities_styles } `; const conditional_styles = ` /* PSEUDO-ELEMENTS */ #reload_btn.reset::before, #content_pane:is(.has_font_specimen,.has_font_specimen_glyph,.has_font_file,.has_font_file_glyph,.has_zoom_image,.has_scaled_image) #reload_btn::before { content:"Reset"; } .texteditor_edited #show_texteditor span:after, .iframe_edited:not(.has_texteditor) #content_pane.has_iframe #content_title div::after { content:" (edited)"; } .theme_light #menu_theme span::before { content:"Light "; } .theme_dark #menu_theme span::before { content:"Dark "; } body:not(.show_details_false) #show::before { content:"Hide "; } body.text_editing_enable_false #disable::after { content:"Disabled"; } #disable::after { content:"Enabled"; } .is_error #dir_header_utilities { border-bottom:0; } #is_error { display:block !important; grid:none !important; grid-template-columns:none !important; } .theme_dark #is_error_items, .theme_dark #dir_menu_main li > span::before, .theme_dark #sorting span::before, .theme_dark #sorting span::after, .theme_light #dir_menu_main li.selected > span::before { filter:invert(1); } /* CONDITIONAL DISPLAY */ body:not(.alternate_background_false).is_error #alternate_background, .is_error #dir_header_utilities > div:not(:first-of-type), .is_non_local #show_invisibles_container { display:none; } .has_media #play_toggle, .theme_dark #theme_dark, .theme_light #theme_light, #content_pane[class^="has_"] #close_btn, #content_pane[data-content="has_texteditor"] #close_btn { display:unset; } .has_playlist #stats_summary_playlist_files, .has_filelist #stats_summary_playlist_files { display:table-row; } .has_menu #dir_menu_main, .has_menu_parents #parents_links, body:not(.no_hover) #dir_menus .has_submenu:hover .submenu, #dir_menu_main .has_submenu.hovered .submenu, #dir_footer li, .has_warning #overlay_container, .cuesheet_track_list_container.has_cue_sheet, .has_playlist #close_playlist_container, .has_filelist #close_playlist_container { display:block; } .has_menu_stats .dirlist_item.invisible, .has_menu_stats .dirlist_item.ignored, .has_menu_stats .dirlist_item.ignored.hovered, body:not(.show_ignored_items_false).has_menu_stats .dirlist_item.ignored, body:not(.show_ignored_items) .dirlist_item.ignored:not(.invisible) { display:grid; } #content_pane[data-content="has_texteditor"] .content_el.has_content, #content_pane[data-content="has_texteditor"] #content_grid, #content_pane[data-content="has_grid"] #content_texteditor, #content_pane[data-content="has_grid"] .content_el.has_content { display:none !important; } `; const texteditor_styles = ` html, body, #content_body { margin:0; padding:0; height:100%; overflow:hidden; position:relative; font-family:${ UI_Prefs_Non_Bool.ui_font }; font-size:${ UI_Prefs_Non_Bool.ui_font_size }; } button.focus, button:focus { outline:none; border-radius:3px !important; border-style:solid !important; border-width:1px !important; border-color:#222 !important; } .is_texteditor #content_texteditor, body.is_text #content_texteditor { display:flex; } /* TOOLBAR */ #toolbar { overflow:visible; z-index:100; font-size:${ parseFloat(UI_Prefs_Non_Bool.ui_font_size) * 0.875 + UI_Prefs_Non_Bool.ui_font_size.replace(/\d*/,'') }; -webkit-user-select:none; -moz-user-select:none; user-select:none; } #content_body.text_editing_enable_false #toolbar, .texteditor_split_view_false #texteditor_sync_scroll { display:none; } .toolbar_icon { margin:0 4px; padding:4px; min-width:16px; height:16px; cursor:pointer; opacity:0.5; } #texteditor_sync_scroll { opacity:1; height:24px; padding:0 8px; flex-grow:unset; } #texteditor_sync_scroll input { margin:0 4px 0 0; z-index:-1; } #save_btn ul { top:-3px; right:-4px; } #save_html, #save_text { grid-column:1; } #save_btn_icon { grid-column:2; grid-row:span 2; width:32px; } #save_btn_icon svg { margin:3px; } .texteditor_edited #save_btn svg { color:red !important; } #toolbar li:hover, .texteditor_view_raw #toggle_texteditor_view_raw, body:not(.texteditor_split_view_false) #toggle_texteditor_view_raw, body:not(.texteditor_split_view_false):not(.texteditor_view_html) #toggle_texteditor_view_preview, .texteditor_view_preview #toggle_texteditor_view_preview, .texteditor_view_html #toggle_texteditor_view_html, body:not(.texteditor_split_view_false) #toggle_texteditor_split_view { opacity:1; } /* TEXT CONTENT CONTAINERS */ .texteditor_pane { padding:1em; overflow-y:scroll; box-sizing:border-box; background:transparent; font-size:${ parseFloat(UI_Prefs_Non_Bool.ui_font_size) + UI_Prefs_Non_Bool.ui_font_size.replace(/\d*/,'') }; } body:not(.text_editing_enable_false) .texteditor_pane, body:not(.texteditor_split_view_false) .texteditor_pane { width:50%; } body:is(.text_editing_enable_false,.texteditor_split_view_false) .texteditor_pane { width:100% !important; } #text_container .texteditor_pane:focus { background-color:hsl(0,0%,var(--percent_90)); outline:none; box-shadow:inset 0px 0px 4px hsl(0,0%,var(--percent_95)); } #text_container textarea { font-family:monospace; } /* EDITOR PANES */ .texteditor_view_raw #texteditor_txt_pane, .texteditor_view_preview #texteditor_preview_pane, .texteditor_view_html #texteditor_html_pane, .texteditor_view_html.texteditor_view_raw.texteditor_split_view_false #texteditor_txt_pane, .texteditor_view_preview.texteditor_view_raw.texteditor_split_view_false #texteditor_txt_pane, .texteditor_view_html:not(.texteditor_split_view_false) #texteditor_txt_pane, .texteditor_view_preview:not(.texteditor_split_view_false) #texteditor_txt_pane, #content_body.text_editing_enable_false #texteditor_preview_pane { display:block !important; } #content_body.text_editing_enable_false :is(#text_editing_handle,#texteditor_txt_pane,#texteditor_html_pane,#save_btn), .texteditor_split_view_false #text_editing_handle, .texteditor_split_view_false.texteditor_view_preview #texteditor_txt_pane, .texteditor_split_view_false.texteditor_view_preview.texteditor_view_raw #texteditor_preview_pane, .texteditor_split_view_false.texteditor_view_html #texteditor_txt_pane, .texteditor_split_view_false.texteditor_view_html.texteditor_view_raw #texteditor_html_pane, .texteditor_split_view_false.texteditor_view_raw #texteditor_preview_pane { display:none !important; } /* THEMES & COLORS */ .texteditor_theme_default #content_texteditor .background_grey_95, .background_grey_90:focus, #texteditor_preview_pane table th, #text_container { background-color:hsl(0,0,var(--percent_95)); } .theme_dark.texteditor_theme_light #content_texteditor .text_color_default, .theme_light.texteditor_theme_default #content_texteditor .text_color_default { color:hsl(0,0%,var(--percent_05)); } .theme_dark #content_texteditor .text_color_default, .texteditor_theme_dark #content_texteditor .text_color_default { color:#EEE; } /* custom previewed text styles */ #texteditor_preview_pane { word-break:break-word; } #texteditor_preview_pane pre { border:solid 1px #CCC; border-radius:3px; white-space:pre-wrap; word-break:break-word; font-size:${ parseFloat(UI_Prefs_Non_Bool.ui_font_size) + UI_Prefs_Non_Bool.ui_font_size.replace(/\d*/,'') }; } #texteditor_preview_pane th, #texteditor_preview_pane td { vertical-align:top; } #texteditor_preview_pane blockquote { margin-top:1em; margin-bottom:1em; color:#555; } #texteditor_preview_pane blockquote + blockquote { margin-top:0; } #texteditor_preview_pane img { max-width:100%; height:auto; } .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 { display:inline-block; font-size:0.875em; transition:opacity 0.25s; opacity:0; cursor:pointer; margin:0; padding: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; } #texteditor_preview_pane table { font-size:inherit; } .markdown_body table tr, .markdown_body .highlight pre, .markdown_body pre { background-color:transparent !important; } .markdown_body::before, .markdown_body::after { display:none !important; background:transparent; } #content_body.has_warning::after { content:""; position:absolute; top:0; right:0; bottom:0; left:0; background:rgba(0,0,0,0.33); z-index:9998; } #text_editing_handle { width:8px; top:0; bottom:0; left:calc(50% - 4px); cursor:col-resize; } #text_editing_handle::before { content:""; width:1px; background:hsl(0,0%,var(--border_lum)); position:absolute; top:0; bottom:0; left:calc(50%); } .texteditor_theme_dark #text_editing_handle::before, .theme_dark.texteditor_theme_default #text_editing_handle::before { background:#111; } `; // Gecko (Firefos) Styles: const gecko_style_rules = ` .dir::before { content:"" !important; display:none !important; } .is_gecko button { padding:revert; } .is_gecko #show_grid_btn .menu { top:-7px; left:-120px; } .is_gecko thead { font-size:100%; } .is_gecko .dirlist_item.dir::before { position:absolute; } .is_gecko .dirlist_item_name span { display:-webkit-box; width:auto; white-space:normal; } .dirlist_item.dir td:not(:first-child), .dirlist_item.file td:not(:first-child) { width:unset !important; } .is_gecko .dirlist_item td { min-width:calc(100% - 24px); } .is_gecko .dir::before { content:"" !important; display:none !important; } .is_gecko.use_default_icons:not(.is_converted_list) .dirlist_item.file .icon { padding-left:4px; background:none; } .is_gecko.use_default_icons .dirlist_item.file .icon img { margin-right:6px; height:14px; } .is_gecko #directory_list > tr > td:not(:first-of-type) { float:left } .is_gecko #content_audio_title span { padding-top:6px;, padding-bottom:0; } .is_gecko #audio,.is_gecko #audio_container { background-color:rgba(26,26,26,1); } .is_gecko #prev_track, .is_gecko #next_track, .is_gecko #close_audio { filter:invert(1); border:none !important; } .is_gecko #content_pane.has_zoom_image #content_image_container { display:block !important; } `; const safari_style_rules = ` .is_safari button { background-color:#FFF; } .is_safari.theme_dark #prev_track, .is_safari.theme_dark #next_track, .is_safari.theme_dark #close_audio { filter:invert(1); } `; const chrome_style_rules = `video::-webkit-media-controls-enclosure { border-radius:0 !important; }`; const html_style_rules = `a:focus, a:focus-visible { font-weight:bold; border-radius:1px; outline:currentcolor solid 1px; outline-offset:1px; display:inline-block; padding:0 2px; text-decoration:none; }` //==============================// function addStyles(user_agent) { // ===> ADD STYLES let default_styles = ` `; switch(user_agent) { case user_agent === 'is_gecko': default_styles += ``; break; case user_agent === 'is_safari': default_styles += ``; break; case user_agent === 'is_chrome': default_styles += ``; break; } return default_styles // return styles } // ***** END STYLES ***** // //==============================// // ***** INDEX PREP ***** // // Try to determine index type from parent directory link container, with fallbacks for indexes that don't have parent directories, or for parent directory links that aren't siblings or ancestors of the index itself. function getIndexType() { // ===> GET INDEX TYPE let index_el = getEls('body > ul, body ul, body > pre, body > table:last-of-type, body div table'); if ( index_el.length > 1 ) { index_el = ( Array.from(index_el).filter( el => el?.nodeName?.toLowerCase() === 'table') || index_el.reverse()[0] ) } // some index pages have pre and table elements; list is usually table index_el = index_el[0]; let node_name = ( index_el !== undefined ? index_el.nodeName.toLowerCase() : 'body' ); // "body" is likely to be an error page let types = {'gecko':'gecko','ul':'list','pre':'pre','table':'table','th':'table','td':'table','div':'default','error':'error','body':'error','permission_denied':'permission_denied'}; // object array of types return types[node_name]; // return index type } function getIndexItems(agent) { let type = getIndexType(agent), items; // ===> GET INDEX ITEMS // get index type, define items switch(type) { case 'error': items = document.getElementsByTagName('html')[0].outerHTML; break; // error type case 'pre': items = getEl('body > pre').innerHTML; break; // pre type case 'list': items = getEls('body > ul li, body > * > ul li'); break; // list type case 'table': case 'td': // table types switch(true) { case elExists('table > tbody'): items = getEls('body table > tbody tr'); break; // ordinary tables case !elExists('table > tbody'): items = getEls('body table tr'); break; // tables without tbody element } break; case 'gecko': items = getEls('body > table > tbody > tr'); break; // gecko type case 'default': items = getEls('body > table > tbody tr'); break; // default: how is this different from table type? } return [items,type]; // return index items and index type } //==============================// function prepPreType(items_str) { // ===> PREP PRE TYPE let prepped_index = [], parser = new DOMParser(), items_HTML = parser.parseFromString(items_str, "text/html"); // convert items_str to DOM html items_HTML.querySelectorAll('hr,img').forEach( el => el.remove() ); // remove junk elements items_HTML.querySelectorAll('a').forEach( // remove junk links (sorting and parent links) or define item_link el => { if ( /^\?|^\./m.test(el.getAttribute('href')) || /^Parent$|^Parent Directory$|^\s*Up\s*$|^\s*Root\s*$/im.test(el.innerText) ) { el.remove(); } } ); items_str = items_HTML.querySelector('body').innerHTML; // convert DOM html back to str // remove header elements | link text nodes | links with empty text nodes (which are sometimes duplicated) | name, last modified, size, description) items_str = items_str.replace(/\<dir\>/gm,' ').replace(/
          /gi,'\n').replace(/[ ]*[^<]*<\/h\d>[ ]*/gmi,'').replace(/[ ]*(]+?>)[^<]*(<\/a>)/g,'$1$2 ').replace(/(\w) 0 && cell.trim() !== '-' ) { if ( !cell.startsWith(' 0 ) { prepped_index.push(prepped_item); } // add prepped item to index } return prepped_index; // return prepped index } function prepListType(items) { // ===> PREP LIST TYPE let prepped_index = []; for ( let i = items.length; i--; ) { let item = items[i]; if ( item.innerHTML.indexOf('Parent Directory') === -1 ) { let prepped_item = [], link = item.querySelector('a')?.href; item.querySelector('a')?.remove(); Array.from(item.children).forEach( child => { if ( child.innerText === '' ) { child.remove(); } }) // remove link and empty child elements let cells = item.innerHTML.split(' '); // create array from remaining elements for ( let cell of cells ) { prepped_item.push(cell); } if ( link === undefined || ( /^\.\.$|^\.\.\/$|^\/$|^\?|\?sort=|\?path=\&/mi.test(link) ) ) { prepped_item = []; } else { prepped_item.unshift(link); } // exclude some items (e.g., parent directory links) if ( prepped_item.length > 0 ) { prepped_index.push(prepped_item); } } } return prepped_index; // return prepped index } function prepGeckoType(items) { // ===> PREP GECKO TYPE let prepped_index = []; for ( let item of items ) { let prepped_item = [], cellContents = '', cells = item.cells, link = item.innerHTML.split('href=\"')[1].split('\">')[0]; for ( let cell of cells ) { cellContents = cell.innerText; cellContents = ( cellContents !== undefined ? cellContents.trim() : ''); prepped_item.push(cellContents); } prepped_item[1] = prepped_item[1].replace(/\s*KB/,'000'); // convert reported size in KB to total bytes prepped_item[2] = prepped_item[2] + ' '+ prepped_item[3]; prepped_item = prepped_item.slice(1,-1); if ( link === undefined || ( /^\.\.$|^\.\.\/$|^\/$|^\?|\?sort=|\?path=\&/mi.test(link) ) ) { prepped_item = []; } else { prepped_item.unshift(link); } // exclude some items (e.g., parent directory links) if ( prepped_item.length > 0 ) { prepped_index.push(prepped_item); } } return prepped_index; // return prepped index } function prepTableType(items) { //*** for local chrome indexes and server-generated table-type indexes // ===> PREP TABLE TYPE let prepped_index = [], prepped_item, item, cell, cell_text; for ( item of items ) { if ( item.querySelector('td a') !== null ) { let link; prepped_item = []; // get legitimate items (i.e., those containing a link) for ( cell of item.cells ) { // get text from remaining cells (date & size) switch(true) { case cell.querySelector('a') !== null && link === undefined: link = item.querySelector('a')?.getAttribute('href'); // get link; add to prepped_item; ignore if link already defined if ( !/^\?|^\.\.\/$|^\|\"\/\".$/m.test(link) && !/^\s*parent directory\*$|^\*up\s*$/m.test(item.innerText.toLowerCase()) ) { prepped_item.unshift(link); }// else { prepped_item.unshift(''); } break; default: cell_text = cell.innerText.trim().replace(/(^[ ]*-[ ]*$|[ ]*-[ ]*\ [ ]*$)|\ /m,''); // prep cells and clean cell text if ( !/]*>dir|directory|file<\/td>|>\w*\s*file<|>\w*\s*unknown 1 && prepped_item[0] !== '' ) { prepped_index.push(prepped_item); } // prepped_item.length > 2 in order to omit parent directory item } } return prepped_index; // return prepped index } function prepErrorType(items) { return items; } // ===> PREP ERROR TYPE; receives and returns html string function prepPlaylist(items) { // ===> PREP PLAYLIST items let prepped_index = []; let prepped_item, link, duration, name, info; let items_arr, type; items = items.replace(/\s*#EXTM3U.*\s*/g,'').replace(/^\*\n{2,}/gm,'\n').replace(/\.pdf\?.+?\n/g,'.pdf\n');//.replace(/\?/g,'%3F'); // remove header comment and multiple returns switch(true) { // determine playlist type; case ( /#EXTINF:/i.test(items) ): type = 'extm3u'; items_arr = items.split('#EXTINF:'); break; // rows made by splitting at "#EXTIMG:" prefix default: type = 'm3u'; items_arr = items.split('\n'); break; // rows are just naked links } items_arr.forEach( (item) => { switch(true) { // get entry information: title, link, etc. case type === 'extm3u': item = item.trim().split('\n'); link = item[1]; info = item[0].split(','); duration = info.shift(); name = info.join(','); if ( item[1] !== undefined ) { prepped_item = [link,duration,'',name]; } break; case type === 'm3u': prepped_item = [item,'','']; break; // m3u with urls only } if ( prepped_item !== undefined ) { prepped_index.push(prepped_item); } }); return prepped_index; // return prepped index } function convertIndexItems(items,type) { let converted = []; // ===> CONVERT INDEX ITEMS by type; returns [prepped_index] switch(type) { case 'gecko': converted = prepGeckoType(items); break; case 'list': converted = prepListType(items); break; case 'pre': converted = prepPreType(items); break; case 'table': case 'default': converted = prepTableType(items,type); break; case 'error': converted = prepErrorType(items); break; } return converted; } //==============================// function buildNewIndex(id,prepped_index,sort,type,body_id) { // ===> BUILD NEW INDEX from prepped rows let i, new_index_items = [], body_classes = new Set(); let index_html = ''; let new_item, item, item_info = [], item_link, item_name, item_sort_name, item_size_and_date, item_size, item_sort_size, item_date, item_sort_date, item_ext, item_description, item_sort_kind, item_classes; let name_span, cell_link, cell_name, cell_size, cell_date, cell_kind, cell_ext, cell_time, prepped_index_length = prepped_index.length, item_disabled, item_input; let stats, stats_classes = [], stats_kinds = [], stats_total_size = 0, media_count = 0; let dir_list_parent_class = ( ( body_id === ( null || 'top_body') || type === 'playlist' ) ? 'top_item' : 'iframe_item' ); // body_id used to set dir list details style let parent_id = ( getCurrentUIPref('parent_id') || '' ), connector = ( getCurrentUIPref('parent_id') ? '_' : '' ), level = ( Number(getCurrentUIPref('level')) || 0 ), level_style = ( level === 0 ? '' : `style="padding-left:${ Number(level) * 22 }px;"` ); // ensure unique ids (with parent_id) and set indents for subdirectory items if ( prepped_index_length > 5000 ) { if ( confirm(`This directory contains ${prepped_index_length} items; it may take a long time to process and could cause your browser to crash. Are you sure you want to open it?`) === false ) { return } } switch(type) { // add body classes according to index type case 'error': body_classes.add('is_error'); break; case 'pre': body_classes.add('is_converted_pre'); break; case 'list': body_classes.add('is_converted_list'); break; case 'table': case 'td': body_classes.add('is_converted_table'); break; case 'default': body_classes.add('is_default'); break; } // create and format directory item for ( i = 0; i < prepped_index_length; i++ ) { item = prepped_index[i]; item_info = getLinkInfo(item[0]); // returns [link,name,ext,kind,item_classes,body_classes]; item_link = item_info[0]; item_name = item_info[1] || item[3]; // prep display name, with word breaks added after unbreakable chars item_sort_name = item_name.toLocaleLowerCase(); item_size_and_date = getItemSizeAndDate(item); item_size = item_size_and_date[0]; item_sort_size = item_size_and_date[1]; item_date = item_size_and_date[2]; item_sort_date = item_size_and_date[3]; item_ext = item_info[2]; item_sort_kind = item_info[3]; item_classes = item_info[4] +" "+ dir_list_parent_class; item_disabled = ( /local/.test(item_classes) ? ' disabled="disabled"' : '' ); // disable media if local file on non_local page or vice versa item_input = ( /audio|video/.test(item_sort_kind) && /top/.test(body_id) || type === 'playlist' ? `` : '' ); // Assemble item elements name_span = `${ item_input }${ item_name }`; cell_link = `${ name_span }`; cell_name = `${ cell_link }`; cell_time = ``; cell_size = `${ item_size }`; cell_date = `${ item_date }`; cell_kind = `${ item_sort_kind }`; cell_ext = ``; item_description = ( item[3] !== undefined ? `Description: ${ item[3] } ` : '' ); // some servers provide a description of the item // Assemble item new_item = `
        1. ${ cell_name } ${ cell_time } ${ cell_size } ${ cell_date } ${ cell_kind } ${ cell_ext } ${ item_description }
        2. \n`; if ( /audio|video/.test(item_sort_kind) ) { media_count += 1; // if media item... let media_kind = item_sort_kind, media_item_id = parent_id + connector +'rowid-'+ ( prepped_index.length - i), is_subdir = ( /subdirectory/.test(window.location.search) ? true : false ); if ( media_count < 1000 ) { getMediaDuration( item_link, media_kind, media_item_id, is_subdir ); } else { new_item = new_item.replace(/data-duration="">/,'data-duration="0">[Error]'); } // get media duration (limit to 1000 calls) } new_index_items.push(new_item); // add item to index items body_classes.add(item_info[5].join(' ')); // add item classes to body_classes stats_kinds.push(item_sort_kind); stats_total_size += Number(item_sort_size); stats_classes.push(item_info[6]); // STATS: add item kind; update total size; add to stats classes } body_classes = [...body_classes].filter(body_class => body_class).sort(); // BODY CLASSES: body_classes to array, filter empty items, sort stats = buildStats(stats_classes,stats_kinds,stats_total_size); // STATS: build stats if ( sort === '' || sort === undefined ) { sort = getCurrentUIPref('sort_by'); } // SORT ITEMS: get sort_by pref let sort_direction = getCurrentUIPref('sort_direction'); // get sort_direction pref let sorted_index_items = sortDirListItems(new_index_items, 'sort_by_'+ sort, sort_direction); // make initial sort return [sorted_index_items, body_classes.join(' '),stats,index_html]; // RETURN [sorted_index_items, body_classes, stats, index_html] } //==============================// function getLinkInfo(link) { // ===> GET LINK INFO; returns [link,name,ext,kind,item_classes,body_classes,link_protocol] switch(true) { case link === undefined: return; // return if link undefined case link === null: link = getEl('#content_iframe').src; break; // link from opening local link files links in iframe case link.startsWith('file://') && window.location.protocol === 'file:': link = link.split('file://')[1]; break; // local links case link.startsWith('/') && window.location.protocol === 'file:': link = 'file://'+ link; break; // local links case !link.startsWith('/') && !link.endsWith('/') && !/\./.test(link): link = '/'+ link +''; break; } link = link.replace(/%3C/g,'\<').replace(/\.pdf\..+/,'.pdf'); // fix and sanitize links // if ( /\.php\?(\w+)=/.test(link) ) { link = link.split('\.php')[1]; } // attempt to deal with some php links let URL = newURL(decodeURIComponentSafe(encodeURIComponent(link))); let prepped_link, display_name, kind, ext, item_classes = [], body_classes = [], stats_classes = [], aliases = new RegExp(/(symlink|alias|symbolic link)$/,'m'), link_protocol = URL.protocol; switch(true) { // prep link case window_protocol !== 'file:': // for non-local pages switch(true) { case URL.protocol === 'file:': case URL.protocol === undefined: prepped_link = link; item_classes.push('local','ignored'); break; // local links from non-local pages default: prepped_link = URL.href; // non-local pages } break; case window_protocol === 'file:': // for non-local pages switch(true) { case URL.protocol !== 'file:': prepped_link = URL.href; item_classes.push('non_local'); break; default: prepped_link = URL.pathname; } } switch(true) { // prepare display name, body_classes, and item_classes case ( /youtube.com|youtu.be/.test(link) && !link.indexOf('/.') ): prepped_link = link.replace(/watch%3F/,'watch?'); kind = 'video'; item_classes.push('video','media'); display_name = undefined; break; // youtube videos from playlists case URL.pathname.endsWith('/'): case ( /\.php\?/.test(link) ): // nobreak; dirs, apps and index.php? links display_name = ( URL.pathname.endsWith('/') ? URL.pathname.split('/').reverse()[1] + '/' : /\.php\?/.test(link) ? link : null ); switch(true) { case ( /\.app$|\.app\/$|\.exe$/m.test(display_name) ): ext = 'app'; kind = ext; // apps if ( UI_Prefs_Bool.apps_as_dirs === false ) { item_classes.sort().unshift('file','app'); } else { item_classes.sort().unshift('dir','app'); } break; default: ext = 'dir'; kind = 'dir'; item_classes.unshift(kind); // dirs; remove kind from item_classes } item_classes.push('non_media'); // add "non_media" to item_classes if ( display_name.startsWith('.') ) { item_classes.push('invisible'); stats_classes.push('invisible'); } break; default: // files display_name = prepped_link.trim().split('/?')[0].split('/').reverse()[0]; switch(true) { case display_name.toLowerCase().endsWith('symlink'): ext = 'symlink'; break; case !/\./.test(display_name): ext = display_name.toLowerCase(); break; // if no '.' in link (typical for bin files), ... default: // find the last . and get the remaining characters ext = display_name.slice(display_name.lastIndexOf('.') + 1).toLowerCase(); for ( let item_kind in Item_Kinds ) { if ( Item_Kinds[item_kind].includes( ext ) ) { kind = item_kind; } } // kind = types if ( /url|url\/|webloc|webloc\//.test(ext) ) { kind = 'link'; } // links switch(true) { case kind === 'audio': item_classes.push('media'); body_classes.push('has_media','has_audio'); break; case kind === 'video': item_classes.push('media'); body_classes.push('has_media','has_video'); break; case kind === 'font' : body_classes.push('has_fonts'); break; case kind === 'image': body_classes.push('has_images'); break; } if ( Item_Settings.ignored.includes( ext ) ) { item_classes.push('ignored'); stats_classes.push('ignored'); } if ( display_name.startsWith('.') ) { item_classes.push('invisible'); stats_classes.push('invisible'); } } if ( kind === undefined ) { kind = 'other'; } if ( !/audio|video/.test(kind) ) { item_classes.push('non_media'); } item_classes.unshift(kind); item_classes.unshift('file'); prepped_link = decodeURIComponentSafe(encodeURIComponent(prepped_link))?.trim(); } stats_classes.push(kind); if ( ext === undefined ) { ext = ''; } if ( aliases.test(display_name) ) { item_classes.push('alias'); } for ( let item_kind_system of Item_Kinds.system ) { if ( display_name?.endsWith(item_kind_system) ) { item_classes.push('ignored'); } } // ignore various system items item_classes = Array.from(new Set(item_classes)).filter(item => item).join(' '); // remove dupe or empty classes, join return [prepped_link,decodeURIComponentSafe(display_name)?.trim(),ext,kind,item_classes,body_classes,stats_classes.join(' '),link_protocol,URL.origin + URL.pathname]; } //==============================// function getItemSizeAndDate(item) { // ===> GET ITEM SIZE AND DATE let item_size_and_date = [], item_display_size, item_sort_size, item_display_date, item_sort_date, size_units = /[BYTES|B|K|KB|MB|GB|TB|PB|EB|ZB|YB]/; if ( item.length > 1 ) { // test for typical date/time separators. if ( /[-:\/]/.test(item[1]) ) { item_display_date = item[1]; item_display_size = item[2]; } else { item_display_date = item[2]; item_display_size = item[1]; } } switch(true) { // get size case item_display_size !== undefined && item_display_size.toLowerCase() === 'dir': case ( /undefined|—|-|,|\*/.test(item_display_size) ): case item_display_size === '': item_display_size = '—'; item_sort_size = '0'; break; // if size is undefined, empty, or punctuation, use these defaults default: item_sort_size = getItemSortSize(item_display_size); switch(true) { case !item_display_size.toUpperCase().match(size_units) : item_display_size = formatBytes(item_display_size,1); break; // if provided size is only numeric, format byte size default: item_display_size = item_display_size.replace('K','k').replace(/(\d+)\s*([A-z])/,'$1 $2'); // default: format and ensure display size has space between number and units } break; } if ( item_display_size === 'NaN undefined' ) { item_display_size = '0 B'; } // get date if ( [undefined,'','-'].includes(item_display_date) ) { item_display_date = '—'; item_sort_date = '0'; } else { item_sort_date = getItemDate(item_display_date); } item_display_date = item_display_date.replace(/, (.+)/,', $1').replace(/ (AM|PM)$/im,' $1').replace(/\s/g,' '); // ensure that time acts as a block for wrapping in narrow sidebar item_size_and_date.push( item_display_size, item_sort_size, item_display_date, item_sort_date ); return item_size_and_date; } function getItemSortSize(val) { // GET ITEM SORT SIZE let sort_size, values = val.replace(/(\d+)\s*([A-z]+)/,'$1 $2').split(' '), size = values[0], unit = values[1]; const factor = { undefined:1, '':1, B:1, K:1000, KB:1000, M:1000000, MB:1000000, G:1000000000, GB:1000000000, T:1000000000000, TB:1000000000000, P:1000000000000000, PB:1000000000000000, E:1000000000000000000, EB:1000000000000000000, Z:1000000000000000000000, ZB:1000000000000000000000 }; // unit to file size if ( unit !== undefined ) { unit = unit.toUpperCase(); } sort_size = size * factor[unit]; // convert byte size to multiplication factor return sort_size; } function formatBytes(val, decimals) { // ===> FORMAT BYTES: format numeric sizes for display const k = 1024, dm = (decimals < 0 ? 0 : decimals), sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], i = Math.floor(Math.log(val) / Math.log(k)); if (val === 0) { return '0 Bytes'; } else { return parseFloat((val / Math.pow(k, i)).toFixed(dm)) +' '+ sizes[i]; } } function processDate(match,p1,p2,p3) { //***date formats: 2017-10-09 13:12 || 2015-07-25T02:02:57.000Z || 12-Mon-2017 21:11 ***// // ===> PROCESS DATE const mo = 'JanFebMarAprMayJunJulAugSepOctNovDec'.indexOf(p2)/3 + 1; // e.g., convert month into number, or use number return p3 +'-'+ mo +'-'+ p1; // return assembled date: YYYY-MM-DD } function getItemDate(val) { // ===> GET ITEM DATE: for sorting (YYYY-MM-DD) let sort_date = val.replace(/^(\d{2})-(\w{3})-(\d{4})/m, processDate) // convert Month to number .replace(/\b(\d{1})[-:/]/g,'0$1/') // add leading 0 for single digit numbers .replace(/(\d{2})\/(\d{2})\/(\d{2}),/,'$3$1$2') // reorder MM/DD/YY dates to YY/MM/DD .replace(/-|:|\s+|\//g,''); // remove spacing characters return sort_date; } //==============================// var getFormattedDuration = (secs) => { // ===> GET FORMATTED TIME if ( isNaN(secs) ) { return '[Error]'; } // if server refuses to load media let sec_num = parseInt(secs, 10), hours = Math.floor(sec_num / 3600), minutes = Math.floor(sec_num / 60) % 60, seconds = sec_num % 60; let formattedTime = [hours,minutes,seconds].map( v => v < 10 ? "0" + v : v ).filter( (v,i) => v !== "00" || i > 0 ).join(":"); formattedTime = formattedTime.replace(/^0/m,''); return formattedTime; // remove initial 0 and return formatted time }; async function fetchAudioDuration(link,kind) { return new Promise((resolve, reject) => { const media = ( kind === 'audio' ? new Audio() : document.createElement('video') ); media.addEventListener('loadedmetadata', () => { resolve(media.duration); }); media.addEventListener('error', reject); media.src = link.replace(/\&/g,'&'); }); } async function getMediaDuration(link,media_kind,id,is_subdir) { try { const duration = await fetchAudioDuration(link,media_kind); switch(true) { case is_subdir === true: messageSend('top_body','set_media_duration','', [ id,media_kind,duration ] ); break; // if subdir, send message to top with duration default: setMediaDuration( id,media_kind,duration ); // else set media duration } } catch (error) { setMediaDuration( id,media_kind,Number.NaN ); } // if error, set duration error } function setMediaDuration(id,kind,duration) { // ===> SET MEDIA DURATION try { if ( id === 'content_iframe_file' || /youtube.com|youtu.be/.test(getEl('#'+id+' a').href) ) { return; } // do not attempt to set duration for iframe files or youtube playlist items setAttribute('#'+id +' .dirlist_item_media_duration','data-duration',duration); switch(true) { case duration !== 0: // if duration !== 0, add time to dir_list item details; else show spinner getEl('#'+ id +' .dirlist_item_media_duration').innerText = getFormattedDuration(duration); removeClass('#'+ id,'disabled'); getEl('#'+id).querySelector('input').removeAttribute('disabled'); break; default: addClass('#'+ id,'disabled'); // if duration === 0, disable media item } let totalDurationEl = getEl('#total_duration'), total_duration; if ( totalDurationEl !== null ) { total_duration = Number( totalDurationEl.getAttribute('data-total_duration') ); total_duration += Number(duration); setAttribute('#total_duration','data-total_duration',total_duration); getEl('#total_duration').innerText = getFormattedDuration(total_duration); } } catch (error) { null } } function updateMediaDurations(id,link,kind) { let media_items; switch(true) { case id === 'refresh_media_durations': // click refresh media durations menu item media_items = Array.from(getEls('.dirlist_item.media')); media_items = media_items.filter(el => el.querySelector('.dirlist_item_media_duration').dataset.duration === "0"); media_items.forEach( el => updateMediaDurations(el.id,el.querySelector('a').href,el.dataset.kind) ); // send each media item with id back to function for default processing if ( isTopWindow() ) { messageSend('iframe','refresh_media_durations'); } break; default: if ( getEl('#'+id)?.querySelector('.dirlist_item_media_duration')?.dataset.duration === '0' ) { getMediaDuration( link,kind,( duration ) => { setMediaDuration( id,kind,duration ); }); } break; } } function updateDurations(bool) { // bool === true: don't bother updating stats details, since they aren't visible // ===> UPDATE DURATIONS let media_items = getEls('.dirlist_item.media'); if (media_items.length === 0 ) { removeClass('body','has_media has_audio has_video'); return; } let kind, total_duration = 0, duration = 0, audio_duration = 0, video_duration = 0; for ( let i = 0; i < media_items.length; i++ ) { // get classes and kind for each item kind = media_items[i].getAttribute('data-kind'); // = [link,name,ext,kind,item_classes,body_classes]; duration = Number(media_items[i].getElementsByClassName('dirlist_item_media_duration')[0].getAttribute('data-duration')); setMediaDuration(media_items[i].getAttribute('id'),kind,duration ); total_duration += duration; setAttribute('#total_duration','data-total_duration',total_duration); getEl('#total_duration').innerText = getFormattedDuration(total_duration); addClass('body','has_media'); switch(true) { // update stats details case bool === true: break; case kind === 'audio': addClass('body','has_audio'); audio_duration += Number(duration); getEl('#stats_details_items').querySelectorAll('span.audio')[0].setAttribute('data-audio_duration',' (Total Time: '+ getFormattedDuration(audio_duration) +')'); break; case kind === 'video': addClass('body','has_video'); video_duration += Number(duration); getEl('#stats_details_items').querySelectorAll('span.video')[0].setAttribute('data-video_duration',' (Total Time: '+ getFormattedDuration(video_duration) +')'); break; } } } //==============================// function buildStats(stats_classes,stats_kinds,stats_total_size) { //*** BUILD STATS stats_classes.sort(); let total_items = stats_classes.length, counts = {}, kinds = [], stats_items = [], total_dirs = 0, total_files = 0, total_dirs_invisible = 0, total_files_invisible = 0, total_invisibles = ''; for ( let i = 0; i < total_items; i++ ) { // Get counts stats_classes[i] = stats_classes[i].split(' ').reverse().join(' ') // reorder classes to make invisible/ignored last counts[stats_classes[i]] = 1 + ( counts[stats_classes[i]] || 0 ); // get key/value pairs for item_classes/total counts switch(true) { case ( !/invisible|ignored/.test(stats_classes[i]) ): break; // don't count :not(.invisible) and :not(.ignored) case (getCurrentUIPref('show_invisibles') === 'true' ) && ( getCurrentUIPref('show_ignored_items') === 'false' ): // show_invisibles && hide_ignored if ( /invisible/.test(stats_classes[i]) && /ignored/.test(stats_classes[i]) ) { break; } // don't count .invisible.ignored if ( /dir/.test(stats_classes[i]) ) { total_dirs_invisible++; } else { total_files_invisible++; } break; // else count .ignored case (getCurrentUIPref('show_invisibles') === 'false' ) && ( getCurrentUIPref('show_ignored_items') === 'false' ): // hide_invisibles && hide_ignored (hide all) if ( /dir/.test(stats_classes[i]) ) { total_dirs_invisible++; } else { total_files_invisible++; } break; // count .invisible and .ignored (count all) case (getCurrentUIPref('show_invisibles') === 'true' ) && ( getCurrentUIPref('show_ignored_items') === 'true' ): break; // don't count .invisible or .ignored (count none) case (getCurrentUIPref('show_invisibles') === 'false' ) && ( getCurrentUIPref('show_ignored_items') === 'true' ): // hide_invisibles && show_ignored if ( !/invisible/.test(stats_classes[i]) && /ignored/.test(stats_classes[i]) ) { break; } // don't count .ignored:not(.invisible) if ( /dir/.test(stats_classes[i]) ) { total_dirs_invisible++; } else { total_files_invisible++; } break; // else count .invisible and .invisible.ignored } } for ( let i = 0; i < stats_kinds.length; i++ ) { kinds[stats_kinds[i]] = 1 + ( kinds[stats_kinds[i]] || 0 ); } // get key/value pairs for item kinds/counts total_dirs = ( kinds.dir || 0 ); total_files = ( total_items - total_dirs ); // total dirs && files count if ( getCurrentUIPref('show_invisibles') === 'false' || getCurrentUIPref('show_ignored_items') === 'false' ) { total_invisibles = ' (+'+ (total_dirs_invisible + total_files_invisible) +')'; total_items = total_items - (total_dirs_invisible + total_files_invisible); total_dirs = total_dirs - total_dirs_invisible; total_files = total_files - total_files_invisible; } for ( let count in counts ) { // make detail item for each kind of dirlist item --> doesn't preserve order let kinds_items = count.split(' '), temp_items = [], stats_Item_Kinds = ''; kinds_items.forEach( item => ( !/ignored|invisible/.test(item) ? temp_items.unshift(item) : temp_items.push(item) ) ); kinds_items = temp_items; kinds_items.forEach( item => ( stats_Item_Kinds += (``+ (/ignored|invisible/.test(item) ? ' ('+item+')' : item.trim() ) +``)) ); let stats_item = `
        3. ${ stats_Item_Kinds }
        4. `; stats_items.push(stats_item); } stats_items.sort(); return ``; } function updateStats(bool) { // ===> UPDATE STATS (bool: add or subtract size from total) let items = getEls('.dirlist_item'); // get all dir_list items let stats_classes = [], stats_kinds = [], item_classlist = [], total_size = 0; // define various arrays getEls('.dirlist_item_details.size').forEach(el => total_size += Number(el.dataset.size)); let total_item_size = ( bool === false ? total_size : Number(getData('#stats_summary_totals','size')) ); let item_info; for ( let i = 0; i < items.length; i++ ) { // get classes and kind for each item item_info = getLinkInfo( items[i].getElementsByClassName('dirlist_item_name_a')[0].href ); // get item info = [link,name,ext,kind,item_classes,body_classes]; item_classlist = item_info[4]; // get item_classlist item_classlist = item_classlist.replace(/file|media|audio_loaded|content_loaded|has_subdirectory|selected|non_/g,'').trim(); // remove unwanted classes --> why file and media? stats_classes.push(item_classlist); // add item_classlist to stats_classes stats_kinds.push( item_info[3] ); // add Item_Kinds to stats_kinds total_item_size += Number(items[i].querySelector('.size').dataset.size); } getEl('#stats_container').remove(); // remove old stats getEl('#dir_footer').insertAdjacentHTML( 'afterbegin',buildStats(stats_classes,stats_kinds,total_item_size,2) ); // build new stats and add to dir_footer updateDurations(true); // update after building stats initStatsEvents(); // initial event listeners for new stats items } // ***** END DIR_LIST SETUP ***** // //============================// // ***** UI SETUP ***** // function prepDocHead(agent) { // ===> PREP DOC HEAD document.title = 'Index of '+ window_location; // change the doc title to current location for ( let attr_name of getEl('html').getAttributeNames() ) { getEl('html').removeAttribute(attr_name); } // remove html attributes, if any getEl('head title').removeAttribute('id'); getEls('head meta, head base, head link, head style, head script, head noscript').forEach( headEl => headEl.remove() ); // remove various head elements let head_content = '' + getEl('head').innerHTML.replace(//g,''); // add meta and remove conditional comments if ( window.location.protocol.startsWith('file') ) { head_content = get_SVG_UI_File_Icon('favicon') + head_content; } // add custom favicon for local directories getEl('head').innerHTML = head_content + addStyles(agent); // replace head content with prepped content } function getUIPrefBodyClasses(agent) { // ===> GET UI PREF BODY CLASSES and other initial settings let queries = new URLSearchParams(window.location.search).entries(); // make new search params from window.location.search queries = Object.fromEntries(queries); let body_classes = [], settings = Object.assign({},queries,UI_Settings); // merge UI_Settings and query settings for ( let key in settings ) { switch(true) { case ['grid_font_size','grid_image_size','ui_font','ui_scale','show_image_thumbnails'].includes(key): break; // ignore these keys (values set in css or by buildTextEditorUI) case ['sort_by','sort_direction','theme','texteditor_view'].includes(key): body_classes.push( key +'_'+ getCurrentUIPref(key) ); break; // other non-booleans: class = key + value case getCurrentUIPref(key) === 'false': body_classes.push( key +'_false' ); break; // booleans: only add false values } } body_classes.push(agent); body_classes.push('is_'+getOS()); // add browser and os classes return body_classes.sort().join(' '); } function makeNewIndex(el,sort,agent,body_id) { // ===> MAKE NEW INDEX const index_items = getIndexItems(agent), items = index_items[0], type = index_items[1]; const converted_index = convertIndexItems( items, type ); // = array of rows: ["link","date","size"] switch(type) { case 'error': return [[[''+ ( items === undefined ? '' : items ) +''],'is_error'],'','',index_items]; default: return [buildNewIndex( el.id, converted_index, sort, type, body_id )]; } } // ===> BUILD IFRAME DIR LIST UI, with utility iframe for subdirectories add function buildIframeUI(src,file_name,agent) { let parent_link = src.split('/').slice(0,-2).join('/') + '/', query_str = new URLSearchParams(window.location.search.toString().slice(1)); let subdirectory = query_str.get('subdirectory') || null, body_id = query_str.get('body_id'); let iframe_directory, iframe_head, iframe_dir_list, content_body, gecko_styles, body_classes, iframe_utility_iframe, new_index, make_new_index, additional_classes; window.onmessage = function(e) { messageReceive(e); return; } // init receive messages switch(true) { case window.location.search === "": // nobreak; case is true when opening dirs from sidebar source dir case ( query_str.get('show_directory_source') || query_str.get('is_error') ) === 'true': if ( elExists('#iframe_dir_styles') ) { getEl('#iframe_dir_styles').remove(); } break; // do nothing when viewing directory source or if error page... default: // ...else set up iframe directory: iframe_head = getEl('head'); content_body = getEl('body'); iframe_dir_list = ''; gecko_styles = ''; body_classes = []; iframe_utility_iframe = ''; if ( /\.php\?/.test(src) ) { query_str = new URLSearchParams(makeSrcSearchParams('dir')); } // define default params for index.php?folder=... pages for ( let key of query_str.keys() ) { // add various body_classes... switch(true) { case ( /show_details|ui_font/.test(key) ): break; // show details by default case query_str.get(key) === 'true': break; // ignore true booleans case query_str.get(key) === 'false': body_classes.push(key+'_false'); break; // add body classes for false boolean params default: body_classes.push(key+'_'+getCurrentUIPref(key)); break; // non-boolean params (theme, sort) } } if ( agent === 'is_gecko' ) { gecko_styles = (''); } new_index = makeNewIndex(content_body, query_str.get('sort_by'),'',body_id); // make new index make_new_index = new_index[0]; additional_classes = (new_index[0][1].trim().split(/\s+/)).concat(body_classes); // define additional body classes if ( !/is_error/.test(new_index[0][1]) ) { // if not an a error page...build the ui iframe_head.querySelectorAll('style,script,meta,link[rel="stylesheet"],link[href$="css"]').forEach( el => el.remove() ); // remove any existing directory index styles iframe_head.insertAdjacentHTML('beforeend',`${gecko_styles}`); // assemble the iframe head switch(true) { // Assemble content_iframe and utility_iframe content case subdirectory === 'true': iframe_dir_list = `
            ${ make_new_index[0] }
          `; break; default: iframe_directory = Directory_Elements('iframe',parent_link); // create iframe directory elements iframe_dir_list = iframe_directory.replace(/insert_prepped_index/,make_new_index[0]).replace(/insert_stats/,make_new_index[2]); // assemble iframe directory content_body.removeAttribute('style'); content_body.style.fontFamily = getCurrentUIPref('ui_font'); // remove any body inline styles; set ui_font content_body.classList.add(...additional_classes); // add body styles } content_body.innerHTML = iframe_dir_list + Content_Pane_Elements; // append iframe_dir_list and content_pane for quicklook } if ( subdirectory === null ) { content_body.insertAdjacentHTML('beforeend',iframe_utility_iframe); initIframeEvents(); } // don't multiply utility_iframes; init iframe event listeners if ( subdirectory === 'true' ) { messageSend('top_body','dirlist_subdir_loaded','',[getEl('#directory_list').innerHTML,make_new_index[1],getCurrentUIPref('parent_id')] ); // send prepped subdir to parent window } else { messageSend('top_body','iframe_loaded','',[src,file_name,'dir']); // else send iframe_loaded message } } } // ===> BUILD TEXT EDITOR UI function buildTextEditorUI(kind) { let raw_markdown, body_classes = [], content; if ( !hasClass('body','has_texteditorUI') ) { // add classes, styles, and scripts; only add once getEl('head').insertAdjacentHTML('beforeend',''); getEl('head').insertAdjacentHTML('beforeend',''); if ( isTopWindow() ) { getEl('#content_title span').innerHTML = ''; } body_classes.push('has_texteditorUI', 'texteditor_view_'+getCurrentUIPref('texteditor_view')); } switch(true) { // get source text and append UI elements case !isTopWindow(): // iframe text editing UI window.onmessage = function(e) { messageReceive(e); return false; } // init receive messages is_link getEl('head').insertAdjacentHTML('afterbegin',''); getEl('head').insertAdjacentHTML('beforeend',''); // add iframe text editing styles if ( kind === 'link' ) { tempHideTexteditor(); } // prevent FOUC for some kinds of content... raw_markdown = decodeURIComponentSafe( getEl('body').innerText ); // get source text and decode Unicode chars. document.body.innerHTML = Content_Text_Elements + Utilities_Elements('texteditor'); // add the UI getEl('#texteditor_txt_pane').value = raw_markdown; // set the source text value getEl('#texteditor_txt_pane').setSelectionRange(0,0); // set the insertion point to the beginning of the text if ( /^\#EXTM3U/m.test(getEl('#texteditor_txt_pane').value) ) { content = getEl('#texteditor_txt_pane').value.trim(); messageSend('top_body','iframe_playlist','',content); } // playlists & filelists addClass('body','is_text'); getSearchParams().forEach((key, value) => { addClass('body',value+"_"+key); }); // add text editor body classes break; } switch(true) { // assemble text editing body classes case getCurrentUIPref('text_editing_enable') === 'false' && !isTopWindow(): // if text editing disabled... removeClass('body','texteditor_view_preview texteditor_view_html'); // remove preview and html classes body_classes.push('texteditor_view_raw','text_editing_enable_false','texteditor_split_view_false'); // show the raw text, no split view getEl('#texteditor_txt_pane').disabled = true; break; // disable textarea editing default: // ...otherwise set up text editing if ( getCurrentUIPref('texteditor_split_view') === 'false' ) { body_classes.push('texteditor_split_view_false'); } else { body_classes.push('texteditor_view_raw'); } if ( getCurrentUIPref('texteditor_sync_scroll') === 'false' ) { body_classes.push('texteditor_sync_scroll_false'); getEl('#texteditor_sync_scroll input').checked = false; } if ( getCurrentUIPref('texteditor_sync_scroll') === 'true' ) { getEl('#texteditor_sync_scroll input').checked = true; } } TextEditing(); initTextEditorEvents(); // text editing functions & init text editor event listeners } // ===> BUILD UI: Append all assembled elements to body function buildUI() { let make_new_index, body_classes, main_content, agent = getBrowser(), link_info, file_name, kind, iframe_src; switch(true) { case isTopWindow(): // if it's not an iframe... make_new_index = makeNewIndex('body','',agent,'top_body'); // make index if ( make_new_index[0] === undefined ) { return; } // in case user cancels processing of large directory > 5000 items body_classes = make_new_index[0][1] +' '+ getUIPrefBodyClasses(agent); // delete extra spaces, create array of body class names main_content = `${ Directory_Elements('top_body') } ${ Content_Pane_Elements } ${ Utilities_Elements('top_body') }`; // assemble html elements if ( make_new_index[0][1] !== 'is_error' ) { main_content = main_content.replace(/insert_prepped_index/,make_new_index[0][0]).replace(/insert_stats/,make_new_index[0][2]); // add dir_index and stats to MainContent } else { main_content = main_content.replace(/insert_prepped_index/,'').replace(/