Supercharged Local Directory File Browser

Makes file:/// directory ("Index of...") pages (and many server-generated index pages) actually useful. Adds navigation links, file preview pane, keyboard navigation, user-defined shortcuts, filtering, more.

Verze ze dne 20. 04. 2018. Zobrazit nejnovější verzi.

  1. // ==UserScript==
  2. // @name Supercharged Local Directory File Browser
  3. // @version 2.4.1
  4. // @description Makes file:/// directory ("Index of...") pages (and many server-generated index pages) actually useful. Adds navigation links, file preview pane, keyboard navigation, user-defined shortcuts, filtering, more.
  5. // @author Gaspar Schott
  6. // @license GPL-3.0
  7. // @match file:///*
  8. // @require http://code.jquery.com/jquery-latest.min.js
  9.  
  10. // This script was developed in Vivaldi, running on Mac OS High Sierra. It has been tested in various Chrome and Gecko-based browsers. It has only been minimally tested on Windows, however. It should work, but please report any issues.
  11. // It does not work in Safari because Safari does not allow local directories to be browsed.
  12.  
  13. // NOTE: By default, Greasemonkey and Tampermonkey will not run scripts on file:/// urls, so for this script to work, you will have to enable it first.
  14. // For Greasemonkey, open about:config and change greasemonkey.fileIsGreaseable to true.
  15. // For Tampermonkey, go to Chrome extension page, and tick the 'Allow access to file URLs' checkbox at the Tampermonkey extension section.
  16.  
  17. // CHANGELOG:
  18.  
  19. // 2.4.1
  20. // Added: Loop and Shuffle playback for audio files.
  21. // Added: Wrap-around keyboard navigation for audio tracks.
  22. // Added: Default background image for audio directories containing no image files.
  23. // Fixed some scrollIntoView issues.
  24. // Fixed auto-cover image selection issue in Firefox.
  25. // Bug-fixes. Yep, bug-fixes.
  26.  
  27. // 2.4.0
  28. // Major update for audio files!
  29. // New: Play all audio files in a directory.
  30. // New: Autoload cover art files (if available) in the preview pane. The script will look in the directory for image files titled "cover.[ext]" or "front.[ext]"; if they are not found, it will load the first image file it finds.
  31. // New: Audio file keyboard controls: Left/Right Arrows to navigate tracks, ignoring other files in the directory. Up/Down Arrows to navigate and preview all non-audio files in the directory (e.g., cover art or lyrics). Space bar to pause/play. (Note: grid-view is available in directories containing audio files, but the left/right arrow keys will not select grid items.)
  32. // New user setting: autoplay audio files. Default is false, but if true, the first audio file will start playing as soon as the directory is loaded. Again, don't delete it when pasting in exported settings.
  33. // Some code cleanup and bugfixes.
  34.  
  35. // 2.3.0
  36. // Added: New user settings: default grid image and font sizes. Don't delete them when pasting in your old exported settings!
  37. // Added: Scale grid image items.
  38. // Improved: Better image zooming. Zoomed images now scroll to the area clicked.
  39. // Fixed: Keybinding to toggle invisibles wasn't working.
  40. // Fixed: Image zoom not working.
  41. // Fixed: Hovered background for grid items in dark mode.
  42. // Fixed: Font scaling in dual grids.
  43.  
  44. // 2.2.0
  45. // Added: Export settings menu item. This will make it easier to save your user settings before updating the script. (Remember, scripts running on local files cannot set cookies or use localStorage, which would make it possible to save user settings automatic.) Unfortunately, there is no mechanism for importing the settings: you'll still have to open the script editor and paste in the exported data.
  46. // Fixed: File extensions were case sensitive, so some valid files wouldn't load if the extension contained capital letters.
  47. // Fixed: File and Dir names were also being lowercased.
  48.  
  49. // v. 2.1.1
  50. // Fixed: Can't type "r" in font previews.
  51. // Other minor bug fixes.
  52.  
  53. // v. 2.1.0
  54. // Added: Toggle Default/Dark modes menu item while browsing current directory; mode reverts to saved setting on dir change.
  55. // Added: White background for images so that images with transparency are visible against the grey background
  56. // Removed trailing "/" from directory display names.
  57. // Fixed an issue where font and image grid display got confused about what content to display.
  58. // Fixed directory names display in dark mode in server pages that use lists instead of tables.
  59. // Better styling for grid button.
  60. // Better styling for grid items in dark mode.
  61. // Bug fixes.
  62. // Remember to copy your user settings before updating!
  63.  
  64. // v. 2.0.2
  65. // Various fixes suggested by "Zorg":
  66. // Dark mode now ignores html files (and media files), but inverts all plain text files. This solution is not perfect: there is a flash of inverted content when navigating from an html or media file to a non-html or media file; will look for a fix.
  67. // Fixed display of non-Latin characters in sidebar header.
  68. // Add support for linux "home" directory for user profile shortcuts
  69. // Made entire up directory button clickable.
  70.  
  71. // v. 2.0.1
  72. // Fixed wonky font preview scaling.
  73.  
  74. // v. 2.0
  75. // NEW! Not just for local directories anymore! Added support for *many* server-generated directory index pages (It's impossible to check every server configuration, needless to say, so it might not work in every case; let me know if you encounter problems.// NEW! Preview font files (otf, ttf, woff, woff2). Great for designers: preview fonts without installing them. Hint: To install previewed fonts, just type Cmd/Ctrl + O or right-click the link and save it to your fonts folder. Font preview pane is content-editable.
  76. // NEW! Preview font files (otf, ttf, woff, woff2). Great for designers: preview fonts without installing them. Hint: To install previewed fonts, just type Cmd/Ctrl + Shift + O or right-click the link and save it to your fonts folder. Font preview pane is content-editable.
  77. // Added: Now use the Left and Right arrow keys to navigate through images and fonts in a folder, skipping other files. Use up and down arrow keys to navigate all files normally.
  78. // Added: Basic dark mode user setting.
  79. // Added: Wrap-around keyboard navigation.
  80. // Added: Cmd/Ctr-D to toggle details.
  81. // Added: Cmd/Ctr-Shift-. and Cmd/Ctr-Shift-, to scale font previews text size.
  82. // Changed: Moved dynamically-added in-line styles to appended stylesheet.
  83. // Changed: Extensive refactoring of code for better separation of concerns. (More needs to be done.... Sigh.)
  84. // Removed: ScrollIntoView for Grid views. Scrolling didn't work reliably when the sidebar was also being scrolled. Will restore when bug fixed.
  85. // Many small bug fixes.
  86.  
  87. // v. 1.4
  88. // Added: Initial support for Firefox. Tested in Firefox 59, Waterfox 56.
  89. // Changed: Use SVG for menu icons
  90. // Changed: Code cleanup, reorganization
  91. // Renamed script to "Supercharged Local Directory File Browser"
  92.  
  93. // v. 1.3
  94. // Fixed: Keyboard navigation of ignored or invisible items fails if "Hide Invisibles" is toggled off after loading a directory.
  95. // Added: Also hide ignored files if "Hide Invisibles" is checked.
  96. // Added: Content reload button.
  97. // Changed: Reorganized settings to reduce confusion about how ignored files are treated.
  98.  
  99. // v. 1.2
  100. // Click to show menus instead of hover.
  101. // Added Cmd/Crl+Shift+O keybinding to open selected item in new window
  102. // Arrow navigation bugfixes
  103.  
  104. // TO-DO:
  105. // Fix grid scrollIntoView
  106. // Automatically how cover art again in Audio dirs after closing other previewed files
  107. // Show default "music" image if no cover images found?
  108. // Sort by file extension?
  109. // Select two items for split pane view?
  110.  
  111. // @namespace https://greatest.deepsurf.us/users/16170
  112. // ==/UserScript==
  113.  
  114. (function() {
  115. 'use strict';
  116. var $ = jQuery;
  117.  
  118. // ***** USER SETTINGS ***** //
  119.  
  120. var $settings = {
  121.  
  122. // Paste your exported settings between these two lines:
  123. //----------------------------------------------------//
  124.  
  125. user_name: // Your computer user name
  126. 'MacBookPro',
  127. // Shortcuts: add directories and files here. (You can use your browser's bookmarks, of course.)
  128. root_shortcuts: // Root directories: add or remove as you please (but at leave empty brackets). These defaults are applicable to Mac OS.
  129. ['Applications','Library','Users','Volumes'],
  130. // ['C:/Users','C:/Program Files','C:/Windows'],
  131. user_shortcuts: // User directories; you must enter your user_name above.
  132. ['Documents','Downloads','Library','Movies','Music','Pictures'],
  133. file_shortcuts: // Add specific file paths, e.g.: 'Users/MyUserName/Documents/MyDocument.html'
  134. // These files will be selected (loaded) automatically when their containing directory is loaded
  135. // Limitations: only works for one file per directory; if more than one file per directory is listed, the last item will be selected.
  136. // ['path/to/file.ext','path/to/another/file.ext'],
  137. ignore_files: // If true (default), ignored files (see below) will be greyed-out (default) in the file list and will not be loaded in the content pane when selected;
  138. // If false, they will be treated as normal files, so if they are selected, the browser will attempt to download any file types it can't handle (which makes keyboard navigation inconvenient).
  139. true,
  140. ignore_file_types: // Files with these extensions will be ignored:
  141. ['exe','.doc','.docx','ppt','pptx','xls','xlsx','odt','odp','.csv','msi','dll','rtf','indd','idml','.pages','.tif','tiff','.eps','.psd','.ai','.afm','.pfb','.pfm','.tfm','.zip','pkg','.swf','.pls','.ics','.DS_Store','.ds_store','ds_store','alias','.dmg','.gz','.qxp','icon.jpg','thumbs.db','.ape','.srf'], // lowercase
  142. hide_ignored_files: // If true, ignored files will be hidden in the file list;
  143. // if false (default), they will appear greyed-out.
  144. false,
  145. hide_invisibles: // Mac OS only: If true (default), files or directories beginning with a "." will be hidden.
  146. true,
  147. apps_as_dirs: // Mac OS only: if true, treat apps as directories; allows app contents to be browsed. This is the default behavior for Chrome.
  148. // If false (default), treat apps as ignored files.
  149. false,
  150. dark_mode: // If true, gives the content pane a dark background, and inverts html and text content.
  151. true,
  152. grid_image_size: // Default = 150
  153. 150,
  154. grid_font_size: // Default = 1
  155. 1,
  156. // Automatically play media
  157. autoplay: false
  158.  
  159. //----------------------------------------------------//
  160. // Paste your exported settings between these two lines.
  161.  
  162. };
  163.  
  164. // ***** END USER SETTINGS ***** //
  165.  
  166. // ***** SETUP ***** //
  167.  
  168. var $userAgent = navigator.userAgent;
  169.  
  170. function platformIsMac() {
  171. return navigator.platform.indexOf('Mac') > -1;
  172. }
  173. function platformIsWin() {
  174. return navigator.platform.indexOf('Win') > -1;
  175. }
  176. function platformIsLinux() {
  177. return navigator.platform.indexOf('Linux') > -1;
  178. }
  179.  
  180. // Don't run script in iframes or files (only directories)
  181. // if ( window.top != window.self ) {
  182. if ( window.frameElement !== null ) {
  183. return;
  184. }
  185. if ( window.location.pathname.slice(-1) != '/') {
  186. // $('body').attr('contentEditable','true');
  187. return;
  188. }
  189.  
  190. // Arrays of supported file types
  191. var $audio_ext_arr = ['.mp3','.mp4','.m4a','.ogg','.flac','.wav','webm'];
  192. var $video_ext_arr = ['.mpeg','.mov'];
  193. var $image_ext_arr = ['.jpg','.jpeg','.png','apng','.gif','.bmp','webp'];
  194. var $font_ext_arr = ['.otf','.ttf','.woff','.woff2'];
  195. var $font_family_arr = [];
  196.  
  197. var $body = $('body');
  198. // add lang attr, remove some unneeded default elements
  199. $body.attr('lang','en').find('> h1:contains("Index of"),> #parentDirLinkBox,> #UI_goUp,#UI_showHidden').remove();
  200.  
  201. var $location = decodeURIComponent(window.location.pathname);
  202. var $current_dir_path = $location.replace(/%20/g,' ').replace(/\//g,'/<wbr>').replace(/_/g,'_<wbr>').replace(/—/g,'—<wbr>').replace(/\\/g,'/');
  203. var $current_dir_name = $location.replace(/%20/g,' ').slice(0,-1);
  204. $current_dir_name = $current_dir_name.slice($current_dir_name.lastIndexOf('/') + 1);
  205. var $location_arr = $location.split('/');
  206. var $parent_dir_link = $location_arr.slice(0,-2).join('/') + '/';
  207.  
  208. var e, i, n;
  209. var $this_text;
  210. var $this_link;
  211. var $this_ext;
  212.  
  213. var $dir_table;
  214. var $dir_table_type;
  215. var $dir_table_head;
  216. var $dir_table_head_cell;
  217. var $dir_table_head_name;
  218. var $dir_table_head_details;
  219. var $dir_table_body;
  220. var $dir_table_row;
  221. var $dir_table_cell;
  222. var $dir_table_item_name;
  223. var $dir_table_details;
  224. var $dir_table_item_icon;
  225. var $dir_table_link;
  226. var $dir_table_rule;
  227. var $selected;
  228. var $playing;
  229.  
  230. if ( $body.find('> table').length > 0 ) {
  231. $dir_table = $body.find('> table');
  232. $dir_table.addClass('table');
  233. } else {
  234. $dir_table = $body.find('> ul');
  235. $dir_table.add('body').addClass('list');
  236. }
  237.  
  238. // ***** BUILD UI ELEMENTS ***** //
  239.  
  240. // ***** SIDEBAR ELEMENTS ***** //
  241.  
  242. // 1. SIDEBAR: Parent Directory Menu
  243. var $parent_dir_menu = $('<nav id="parent_dir_menu"><a href="">&nbsp;</a></nav>');
  244. $parent_dir_menu.find('a').attr('href',$parent_dir_link);
  245. // 2. SIDEBAR: Current Directory Name and Parents Directory Menu
  246. var $parents_dir_menu = $('<nav id="parents_dir_menu"><div></div></nav><ul class="menu"></ul>');
  247. $parents_dir_menu.find('div').append( $current_dir_path );
  248. // 3A. SIDEBAR: Shortcuts Menu
  249. var $divider = $('<li><hr></li>');
  250. var $shortcuts_menu = $('<nav id="shortcuts_menu"><div>&nbsp;</div></nav><ul class="menu"></ul>');
  251. // 3B. SIDEBAR: Other Menu Items
  252. var $toggle_dark_mode = $('<li id="toggle_dark_mode_menu_item"><a href="#"><span id="dark_theme">Dark Theme</span><span id="default_theme">Default Theme</span></a></li>');
  253. var $export_settings = $('<li><a id="export_settings" href="#">Export Settings</a></li>');
  254. // 4. SIDEBAR: Details Button
  255. var $details_btn = $('<button id="details_btn" tabindex="-1"><span>Show details</span><span>Hide details</span></button>');
  256. // 5. SIDEBAR: Invisibles Checkbox
  257. var $inv_checkbox = $('<label ><input type="checkbox" id="inv_checkbox" for="inv_checkbox" name="inv_checkbox" tabindex="-1" />Hide Invisibles</label>');
  258. // 6. SIDEBAR: Image Grid Button
  259. var $grid_btn = $('<div id="grid_btn" tabindex="-1" title="Show Grid"><ul class="menu"><li id="show_image_grid">Show Image Grid</li><li id="show_font_grid">Show Font Grid</li></ul></div>');
  260. // 7. SIDEBAR: Header Element
  261. var $sidebar_header = $('<table id="sidebar_header"><thead><tr><th colspan="3">INDEX OF</th></tr></thead><tbody><tr><td></td><td></td><td></td></tr><tr><td colspan="3"></td></tr></tbody></table>');
  262. $sidebar_header.find('tbody tr:nth-child(1)').find('td').first().append( $parent_dir_menu ).next().append( $parents_dir_menu ).next().append( $shortcuts_menu );
  263. $sidebar_header.find('tbody tr:last-child td').append( $details_btn, $inv_checkbox, $grid_btn );
  264.  
  265. var $dir_table_wrapper = $('<div id="dir_table_wrapper"></div>');
  266. // 8. SIDEBAR:
  267. var $sidebar = $('<div id="sidebar"></div>');
  268. $sidebar.append($sidebar_header);
  269. // 9. SIDEBAR: Resize Handle
  270. var $handle = $('<div id="handle"></div>');
  271. // 10. ASSEMBLE Sidebar Elements
  272. var $sidebar_wrapper = $('<td id="sidebar_wrapper"></td>');
  273. $sidebar_wrapper.append( $sidebar, $handle );
  274.  
  275. // ***** END SIDEBAR ELEMENTS ***** //
  276.  
  277. // ***** CONTENT PANE ELEMENTS ***** //
  278.  
  279. // 1. CONTENT: Overlay Element
  280. var $content_overlay = $('<div id="content_overlay""></div>');
  281. // 2. CONTENT: Image Grid Element
  282. var $content_grid = $('<div id="content_grid" data-grid-scale-factor="0"></div>');
  283. // 3. CONTENT: grid items
  284. var $image_grid_item_el = $('<div class="image_grid_item"><a href=""><img src="" /></a></div>');
  285. var $font_grid_item_el = $('<div class="font_grid_item"></div>');
  286. var $content_font_size = $('<div id="font_size"><span id="increase"></span><span id="decrease"></span></div>');
  287. // 4. CONTENT: Image Element
  288. var $image = $('<img src="" class="" />');
  289. var $content_image = $('<div id="content_image"></div>');
  290. $content_image.append($image);
  291. // 5. CONTENT: Embed (pdfs) Element
  292. var $content_embed = $('<embed id="content_embed" name="plugin" type="application/pdf" tabindex="0"></embed>');
  293. // 6. CONTENT: Iframe Element
  294. var $content_iframe = $('<iframe id="content_iframe" sandbox="allow-scripts allow-same-origin allow-modals" tabindex="0"></iframe>');
  295. // 7. CONTENT: Media Elements
  296. var $content_media = $('<td id="content_media" colspan="3"></td>');
  297. var $prev_track = $('<div id="prev_track"></div>');
  298. var $next_track = $('<div id="next_track"></div>');
  299. var $audio = $('<audio id="audio" preload="auto" tabindex="0" controls><source id="sound_src" src="" type="audio/mpeg"><source type="audio/mp3" src="">Sorry, your browser does not support HTML5 audio.</audio>');
  300. var $loop = $('<label><input type="checkbox" id="loop" for="loop" name="loop" tabindex="0" />Loop</label>');
  301. var $shuffle = $('<label><input type="checkbox" id="shuffle" for="shuffle" name="shuffle" tabindex="0" />Shuffle</label>');
  302. var $checkbox_cont = $('<div id="checkbox_div"></div>');
  303. $checkbox_cont.append( $loop, $shuffle );
  304. $content_media.append( $prev_track, $next_track, $audio, $checkbox_cont );
  305. // 8. CONTENT: Font Elements
  306. var $sample_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ<br />abcdefghijklmnopqrstuvwxyz<br />0123456789 [(!@#$%^&*;:)]';
  307. var $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.';
  308. var $specimen = $('<div class="specimen" style="font-size:3em;">'+ $sample_string +'</div><hr><div class="lorem first" style="font-size:1em;">'+ $lorem_string +'</div><div class="lorem" style="font-size:1em;">'+ $lorem_string +'</div><div class="lorem" style="font-size:1em;">'+ $lorem_string +'</div>');
  309. var $lorem = $('.lorem');
  310. var $content_font = $('<div id="content_font" spellcheck="false" contenteditable="true"></div>');
  311. $content_font.append($specimen);
  312. // 9. CONTENT: Header Reload Button Element
  313. var $content_reload_btn = $('<td><button id="reload_btn" tabindex="-1">Reload</button></td>');
  314. // 10. CONTENT: Header Title Element
  315. var $content_title = $('<td id="content_title"></td>');
  316. // 11. CONTENT: Header Close Button Element
  317. var $content_close_btn = $('<td><button id="close_btn" tabindex="-1">Close</button></td>');
  318. // 12. CONTENT: Header Element
  319. var $content_header = $('<header id="content_header"><table><tbody><tr></tr><tr></tr></tbody></table></header>');
  320. $content_header.find('tr').first().append($content_reload_btn, $content_title, $content_close_btn);
  321. $content_header.find('tr').last().append($content_media);
  322. // 13. CONTENT: Next/Prev Elements
  323. var $prev_btn = $('<div id="prev_btn"></div>');
  324. var $next_btn = $('<div id="next_btn"></div>');
  325.  
  326. // ASSEMBLE Content Container Elements
  327. var $content_container = $('<section id="content_container"></section>');
  328. $content_container.append( $content_header, $content_font_size, $content_overlay, $content_grid, $content_image, $content_embed, $content_iframe, $content_font );
  329.  
  330. // ASSEMBLE Content Pane Elements
  331. var $content_pane = $('<td id="content_pane"></td>');
  332. $content_pane.append( $content_container, $prev_btn, $next_btn );
  333.  
  334. // ***** END BUILD UI ELEMENTS ***** //
  335.  
  336. // ***** STYLES ***** //
  337.  
  338. // Create Custom Font Styles element
  339. var $custom_font_styles = document.createElement('style');
  340. $custom_font_styles.appendChild(document.createTextNode(""));
  341. document.head.append($custom_font_styles);
  342.  
  343. var $font_styles = '';
  344. $custom_font_styles.append( $font_styles );
  345.  
  346. // Create Custom Styles element
  347. var $custom_styles = document.createElement("style");
  348. $custom_styles.appendChild(document.createTextNode(""));
  349.  
  350. // SVG IMAGES
  351. var $up_arrow = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'12.728px\' height=\'7.779px\' viewBox=\'0 0 12.728 7.779\' enable-background=\'new 0 0 12.728 7.779\' xml:space=\'preserve\'><path fill=\'%23444444\' d=\'M6.364,2.828l4.95,4.949l1.414-1.414L6.364,0l0,0L0,6.363l1.413,1.416L6.364,2.828\'/></svg>")';
  352. var $svg_arrow = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'11px\' height=\'16px\' viewBox=\'234.5 248 11 16\' enable-background=\'new 234.5 248 11 16\' xml:space=\'preserve\'><path d=\'M245.5,261l-3,3l-8-8l8-8l3,3l-5,5L245.5,261z\'/></svg>")';
  353. var $menu_icon = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'13px\' height=\'10px\' viewBox=\'0 0 13 10\' enable-background=\'new 0 0 13 10\' xml:space=\'preserve\'><rect fill=\'%23444444\' width=\'13\' height=\'2\'/><rect y=\'4\' fill=\'%23444444\' width=\'13\' height=\'2\'/><rect y=\'8\' fill=\'%23444444\' width=\'13\' height=\'2\'/></svg>")';
  354. var $grid_icon = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' enable-background=\'new 0 0 16 16\' xml:space=\'preserve\'><g><path fill=\'%23666666\' d=\'M5,2v3H2V2H5 M7,0H0v7h7V0L7,0z\'/></g><g><path fill=\'%23666666\' d=\'M14,2v3h-3V2H14 M16,0H9v7h7V0L16,0z\'/></g><g><path fill=\'%23666666\' d=\'M5,11v3H2v-3H5 M7,9H0v7h7V9L7,9z\'/></g><g><path fill=\'%23666666\' d=\'M14,11v3h-3v-3H14 M16,9H9v7h7V9L16,9z\'/></g></svg>")';
  355. var $plus_sign = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' baseProfile=\'basic\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' xml:space=\'preserve\'><polygon points=\'16,6.5 9.5,6.5 9.5,0 6.5,0 6.5,6.5 0,6.5 0,9.5 6.5,9.5 6.5,16 9.5,16 9.5,9.5 16,9.5 \'/></svg>")';
  356. var $minus_sign = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' baseProfile=\'basic\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' xml:space=\'preserve\'> <rect x=\'1\' y=\'6.499\' width=\'14\' height=\'3.001\'/> </svg>")';
  357. var $next_track_arrow = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' baseProfile=\'basic\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'10.873px\' height=\'14.017px\' viewBox=\'0 0 10.873 14.017\' xml:space=\'preserve\'><polygon fill=\'%23999999\' points=\'10.873,14.017 0,7.01 10.872,0 \'/></svg>")';
  358. var $music = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' baseProfile=\'basic\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'143.717px\' height=\'199.404px\' viewBox=\'0 0 143.717 199.404\' xml:space=\'preserve\'><g><path fill=\'%23757679\' d=\'M143.717,143.82c0,10.033-4.573,18.425-13.717,25.183c-8.394,6.142-17.776,9.211-28.15,9.211 c-6.073,0-11.055-1.432-14.943-4.297c-4.301-3.276-6.45-7.849-6.45-13.719c0-9.279,4.403-17.437,13.204-24.466 c8.327-6.616,17.266-9.929,26.821-9.929c8.051,0,13.921,1.605,17.606,4.812V25.487L63.26,45.654v119.355 c0,10.03-4.573,18.426-13.717,25.18c-8.394,6.142-17.778,9.215-28.148,9.215c-6.077,0-11.055-1.436-14.947-4.302 C2.151,191.827,0,187.253,0,181.387c0-9.283,4.401-17.436,13.206-24.465c8.323-6.616,17.262-9.929,26.817-9.929 c8.051,0,13.921,1.605,17.606,4.812V23.237L143.717,0V143.82z\'/></g></svg>")';
  359.  
  360. // DEFINE STYLES
  361. var $styles = '';
  362.  
  363. $styles += 'html, body, :root { margin:0; padding:0; max-width:100%; height:100%; font-family:lucidagrande,"fira sans",helvetica,sans-serif; font-size:13px !important; hyphens:auto; overflow:hidden; border-radius:0; box-sizing:border-box; }';
  364. $styles += 'ul { -webkit-margin-before:0em !important; -webkit-margin-after:0em !important; -webkit-padding-start:0em; }';
  365. $styles += 'hr { margin:0; border-bottom:0; }';
  366.  
  367. // SIDEBAR
  368. $styles += '#sidebar_wrapper { width:25%; min-width:220px; will-change:width; padding:0; position:relative; border:0; background:lightgray; overflow:hidden; }';
  369. $styles += '#sidebar { background-color:lightgray; height:'+ window.innerHeight +'px; min-height:100%; overflow-wrap:break-word; box-sizing:border-box; border-right:solid 1px gray; font-size:0.875em; color:#333; overflow:hidden; }';
  370. $styles += '#handle { width:8px; position:absolute; top:0; right:-4px; bottom:0; z-index:1000; cursor:col-resize; }';
  371.  
  372. // Sidebar Header
  373. $styles += '#sidebar_header { width:100%; height:auto; position:relative; border:0; user-select:none; border-collapse:collapse; font-size:0.875rem; }';
  374. $styles += '#sidebar_header thead tr, #sidebar_header tbody tr:first-of-type { border-bottom:solid 1px grey; background-color:#BBB; }';
  375. $styles += '#sidebar_header thead th { padding:4px; font-weight:normal; font-size:0.875em; letter-spacing:0.5em; cursor:default; }';
  376. $styles += '#sidebar_header tbody tr { position:relative; }';
  377. $styles += '#sidebar_header tbody tr:first-of-type td:hover { cursor:pointer; }';
  378. $styles += '#sidebar_header tbody tr:first-of-type td:first-of-type { position:relative; }';
  379. $styles += '#sidebar_header tbody tr:first-of-type td:nth-of-type(odd) { width:24px; max-width:24px; min-width:24px; padding:0; }';
  380. $styles += '#sidebar_header tbody tr:first-of-type td:nth-of-type(even) { width:100%; padding:0; border-left:solid 1px grey; border-right:solid 1px grey; }';
  381. $styles += '#sidebar_header tbody tr:last-of-type td { padding:1em 0; vertical-align:middle; position:relative; white-space:normal; }';
  382.  
  383. // Sidebar Parent Menu
  384. $styles += '#parent_dir_menu { margin:0; padding:0; display:block; position:absolute; top:0; right:0; bottom:0; left:0; }';
  385. $styles += '#parent_dir_menu a { width:100%; height:100%; padding:0; display:block; text-align:center; vertical-align:middle; text-decoration:none; opacity:0.7; background:' + $up_arrow + 'center no-repeat; }';
  386. // Sidebar Parents Menu
  387. $styles += '#parents_dir_menu { margin:0; padding:0; height:auto; text-align:center; }';
  388. $styles += '#parents_dir_menu div { padding:4px 6px; height:auto; display:inline-block; text-align:center; vertical-align:middle; overflow:hidden; cursor:pointer; hyphens:none; white-space:normal; }';
  389. $styles += '#parents_dir_menu + ul { display:none; margin:0; padding:0; position:absolute; right:0; left:0; z-index:100; text-indent:0; text-align:left; background:lightgray; border-top:solid 1px gray; border-bottom:solid 1px gray; list-style-type:none; box-shadow: 0px 2px 3px -2px #888; }';
  390. $styles += '#parents_dir_menu + ul li:hover, #shortcuts_menu + ul li:hover { background:#BBB; }';
  391. $styles += '#parents_dir_menu + ul li a, #shortcuts_menu + ul li a { margin:0; padding:4px 6px; display:block; text-indent:0; text-decoration:none; color:#333; white-space:normal; }';
  392. // Sidebar Shortcuts Menu
  393. $styles += '#shortcuts_menu { margin:0; padding:0; }';
  394. $styles += '#shortcuts_menu div { width:6em; display:table-cell; text-align:center; vertical-align:middle; font-size:18px; cursor:pointer; opacity:0.7; background:'+ $menu_icon + 'center no-repeat; }';
  395. $styles += '#shortcuts_menu + ul { margin:0; padding:0; -webkit-margin-before:0em !important; -webkit-margin-after:0em !important; -webkit-padding-start:0em; position:absolute; right:0; left:0; z-index:100; text-indent:0; text-align:left; background:lightgray; border-top:solid 1px gray; border-bottom:solid 1px gray; list-style-type:none; box-shadow: 0px 2px 3px -2px #888; display:none; }';
  396. $styles += '#shortcuts_menu div, #parent_dir_menu, #prev_btn, #next_btn { opacity:0.7; }';
  397. $styles += '#dark_theme { display:block; }';
  398. $styles += '#default_theme { display:none; }';
  399.  
  400. // Sidebar Details Button
  401. $styles += '#details_btn { margin:0 0.5em; }';
  402. $styles += '#details_btn span:last-of-type { display:none; }';
  403. $styles += 'body.list #details_btn { color:#999; background:#EEE; outline:none; }';
  404.  
  405. // Sidebar Grid Button
  406. $styles += '#grid_btn { margin:0; width:28px; height:18px; display:none; float:right; cursor:pointer; outline:0; background:'+ $grid_icon +' no-repeat center 100%; }';
  407. $styles += '#grid_btn .menu { padding-right:29px; padding-left:0; position:absolute; top:-1px; right:0; border:solid grey; border-width: 1px 0 1px 1px; display:none; }';
  408. $styles += '#grid_btn .menu li { width:100%; padding:4px 6px; background:#CCC; display:block; float:right; clear:both; text-align:right; list-style:none; border-right:solid 1px grey; box-sizing:border-box; white-space:pre;}';
  409. $styles += '#grid_btn .menu li:first-of-type { border-bottom:solid 1px grey; }';
  410. $styles += '#grid_btn:hover, #sidebar_header tbody tr:first-of-type td:last-of-type:hover div, #parent_dir_menu:hover, #prev_btn:hover, #next_btn:hover { opacity:1; }';
  411. $styles += '#grid_btn.has_images, #grid_btn.has_fonts { display:inline-block; }';
  412. $styles += '#grid_btn.has_images.has_fonts:hover ul.menu { display:block !important; }';
  413. $styles += '#grid_btn.has_images.has_fonts:hover ul.menu li:hover { background:#BBB; }';
  414.  
  415. // DIR_TABLE
  416. $styles += '#dir_table.table { width:100%; min-wdth:100px; border:0; position:relative; overflow:hidden; table-layout:fixed; border-collapse:collapse; font-size:0.875rem; }';
  417. $styles += '#dir_table.table thead { width:100%; position:absolute; left:0; right:0; text-align:left; }';
  418. $styles += '#dir_table.table thead th { padding:0 24px 4px; }';
  419. $styles += '#dir_table.table thead .name { padding-left:2em; display:block; }';
  420. $styles += '#dir_table.table > tbody { width:100%; position:absolute; right:0; bottom:0; left:0; overflow-y:auto; outline:0; }';
  421. $styles += '#dir_table.table tbody .name { display:block; clear:right; text-align:left; }';
  422. $styles += '#dir_table.table tbody tr { display:block; margin-inline-start:0; clear:both; }';
  423. $styles += '#dir_table.table tbody a { margin:0; display:block; background-size:auto 13px; -webkit-padding-start:2m; padding: 4px 6px 4px 24px; color:#333; text-decoration:none; outline:none; overflow:hidden; background-position:6px 4px; white-space:normal; }';
  424. $styles += '#dir_table.table #thead .name a { padding:0; }';
  425. $styles += '#dir_table.table .icon img { margin-left:1rem; height:16px; }';
  426. $styles += '#dir_table.table .icon + td.name a { -webkit-padding-start:1em; padding-left:6px; }';
  427. $styles += '#dir_table.table .details, #dir_table.table.firefox #tbody > tr > td:not(:first-of-type) { display:none; padding:0 0 4px 24px; font-size:0.875em; text-align:left; vertical-align:top; float:left; }';
  428. $styles += '#dir_table.table .details a { padding:0; }';
  429. $styles += '#dir_table.table .rule { display:none; }';
  430. $styles += '#dir_table.table.show_details .details, #dir_table.table.firefox.show_details #tbody > tr > td:not(:first-of-type) { display:block; }';
  431. $styles += '#dir_table.table.headless > tbody { top:0 !important; }';
  432. $styles += '#dir_table.table.headless .icon { vertical-align:middle; float:left; }';
  433. $styles += '#dir_table.table.firefox #tbody > tr > td:not(:first-of-type) { padding:0 24px 4px; }';
  434. $styles += '#dir_table.table.firefox #tbody > tr > td:last-of-type { text-indent:6px; }';
  435.  
  436. // dir_table.list
  437. $styles += '#dir_table_wrapper { width:100%; min-width:100px; border:0; position:relative; overflow-y:auto; }';
  438. $styles += '#dir_table.list #dir_table_wrapper { padding-top:6px; }';
  439. $styles += '#dir_table.list { width:100%; position:absolute; overflow-y:auto; list-style:none; -webkit-margin-before:0; -webkit-margin-after:0; -webkit-padding-start:0; font-size:0.875rem; line-height:1.4; }';
  440. $styles += '#dir_table.list li a { display:block; padding:3px 1rem; text-decoration:none; color:#333; }';
  441. $styles += '#dir_table.list li.dir a { padding-left:24px; background: 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= ") 6px 4px no-repeat; background-size:auto 13px; }';
  442. $styles += '#dir_table.list li.file a { padding-left:24px; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC") 6px 4px no-repeat; background-size:auto 13px; }';
  443.  
  444. $styles += '#dir_table tr, #dir_table li { background:transparent; }';
  445. $styles += '#dir_table > tbody tr:hover, #dir_table li:hover, #dir_table .hovered { background:#BBB; }';
  446. // dir_table: Selected and Playing items
  447. $styles += '#dir_table .selected, #dir_table .playing { background:lightsteelblue; }';
  448. $styles += '#dir_table .selected a, #dir_table .playing a { font-weight:bold; color:#333; }';
  449. $styles += 'body.blur_sidebar .selected { background-color:#BBB; }';
  450. $styles += 'body.blur_sidebar .selected a { font-weight:normal; color:#444; }';
  451. $styles += '#dir_table .playing { background:#9FC4C6; }';
  452. // dir_table: Invisibles and Ignored items
  453. $styles += '#dir_table tr.ignore a, #dir_table tr.ignore.app a { color:#888; }';
  454. $styles += '#dir_table.hide_invisibles .invisible { display:none !important; }';
  455. $styles += '#dir_table.hide_ignored tr.ignore { display:none !important; }';
  456.  
  457. // CONTENT PANE STYLES
  458.  
  459. $styles += '#content_pane { width:75%; will-change:width; padding:0; border:0; background:#FFF; position:relative; }';
  460. $styles += '#content_container { width:100%; height:100%; top:0; overflow:visible; }';
  461.  
  462. // CONTENT: Header
  463. $styles += '#content_header { width:100%; display:none; position:absolute; top:0; right:0; left:0; z-index:200; background:lightgray; border-bottom:solid 1px #AAA; font-size:0.875em; color:#333; text-align:center; }';
  464. $styles += '#content_header table { width:100%; padding:7px 12px 5px; border-collapse:collapse; font-size:0.875rem; }';
  465. $styles += '#content_header tr:first-of-type td:first-of-type, #content_header tr:first-of-type td:last-of-type { width:6em; padding:4px 6px 3px; vertical-align:middle; }';
  466. $styles += '#content_header tr:first-of-type td:first-of-type { float:left; text-align:left; }';
  467. $styles += '#content_header tr:first-of-type td:last-of-type { float:right; text-align:right; }';
  468. $styles += '#content_header tr:last-of-type { border-top:solid #888 1px; }';
  469. $styles += '#content_header td button { word-break:none; hyphens:none; }';
  470. $styles += '#content_title { padding:4px 1em 3px; vertical-align:middle; word-break:break-word; text-align:center; }';
  471. $styles += '#content_pane[class*="content"] #content_header { display:block !important; }';
  472.  
  473. // CONTENT: Overlay
  474. $styles += '#content_overlay { height:'+ window.innerHeight + 'px; position:absolute; top:0; right:0; bottom:0; left:0; display:none; z-index:9998; }';
  475.  
  476. // CONTENT: Grid styles
  477. // Default Image and Font sizes
  478. var $grid_image_size = $settings.grid_image_size ? $settings.grid_image_size : 150;
  479. var $grid_font_size = $settings.grid_font_size ? $settings.grid_font_size : 1;
  480. $styles += '#content_grid { width:auto; display:none; position:absolute; right:0; bottom:0; left:0; overflow:auto; font-size:1em; background:#333; grid-gap:0; grid-template-columns:repeat(auto-fit, minmax('+ $grid_image_size +'px, 1fr)); grid-template-rows:repeat(auto, minmax('+ $grid_image_size +'px, 1fr)); z-index:1; }';
  481. $styles += '#content_grid .image_grid_item { display:inline-block; width:'+ $grid_image_size +'px; height:'+ $grid_image_size +'px; float:left; text-align:center; vertical-align:middle; }';
  482. $styles += '#content_grid.not(.has_grid) .image_grid_item.selected { background:#666; }';
  483. $styles += '#content_grid div img { width:auto; height:auto; max-width:'+ ($grid_image_size - $grid_image_size/8) +'px; max-height:'+ ($grid_image_size - $grid_image_size/8) +'px; position:relative; top:50%; transform:translateY(-50%); opacity:0.8; } ';
  484. $styles += '#content_grid:not(.has_grid) .image_grid_item:hover, #content_grid:not(.has_grid) div.image_grid_item.hovered { background:#555; }';
  485. $styles += '#content_grid .font_grid_item { width:calc(100% - 2rem); padding:0rem 1rem 0.5rem; display:block; font-size:'+ $grid_font_size * 3 +'em; text-align:left; outline:none; clear:both; }';
  486. $styles += 'body #content_grid .font_grid_item:hover, body #content_grid div.font_grid_item.hovered { background:#DDD; }';
  487. $styles += 'body #content_grid .font_grid_item.selected { background:#CCC; }';
  488. $styles += 'body #content_grid div.selected { background:#CCC; }';
  489. $styles += 'body #content_grid div:hover, body #content_grid div.hovered { background:#DDD; }';
  490.  
  491. // CONTENT: Image preview styles
  492. $styles += '#content_image {padding:2em; position:absolute; top:0; right:0; bottom:0;left:0; display:none; background:#333; overflow:auto; text-align:center;}';
  493. $styles += '#content_image img:not(.zoom_img) {width:auto; height:auto; max-width:100%; max-height:100%; max-height:calc(100% - 3px); cursor:zoom-in; -webkit-user-select:none; position:relative; top:50%; transform:translateY(-50%); background:#FFF; };';
  494. $styles += '#content_image img.zoom_img { max-width:none; max-height:none; cursor:zoom-out; top:0; transform:translateY(0); background:"FFF" }';
  495.  
  496. // CONTENT: Image Prev and Next buttons
  497. $styles += '#prev_btn, #next_btn { padding:0 1em; display:none; top:0; bottom:0; z-index:100; opacity:0.6; filter:invert(50%); background: ' + $svg_arrow + ' no-repeat center; }';
  498. $styles += '#prev_btn { position:absolute; left:0 !important; }';
  499. $styles += '#next_btn { position:absolute; right:0; transform:rotate(180deg); }';
  500. $styles += 'body:not(.has_audio) #content_pane.has_image_content #prev_btn, body:not(.has_audio) #content_pane.has_image_content #next_btn { display:block; }';
  501.  
  502. // CONTENT: Embed (pdf) and iframe styles
  503. $styles += '#content_embed, #content_iframe { width:100%; height:100%; padding:0; position:absolute; top:0; right:0; bottom:0; left:0; border:0; display:none; }';
  504.  
  505. // CONTENT: Font preview styles
  506. $styles += '#content_font { padding:1rem; display:none; position:absolute; right:0; bottom:0; left:0; overflow:auto; font-size:'+ $grid_font_size +'em; word-break:break-all; overflow-wrap:break-word; hyphens:none; outline:none; }';
  507. $styles += '.specimen { padding-bottom:0.25em; white-space:normal; text-align:left; }';
  508. $styles += '.lorem { margin-bottom:1em; text-align:justify; word-break:normal; white-space:normal; overflow-wrap:normal; hyphens:auto; line-height: 1.4; }';
  509. $styles += '.lorem.first { margin-top:0.5em; }';
  510. $styles += '.lorem.first:first-line { letter-spacing:1pt; font-variant:small-caps; font-size:'+ $grid_font_size*1.33 +'em; }';
  511. $styles += '.lorem + .lorem { columns:2; column-gap:1em;}';
  512. $styles += '.lorem + .lorem + .lorem { margin-bottom:2em; columns:3; }';
  513.  
  514. // CONTENT: Font size button
  515. $styles += '#font_size { background:rgba(128,128,128,0.3); position:absolute; right:1rem; opacity:0; transition:opacity 1s ease-in-out; display:block; z-index:10; }';
  516. $styles += '#font_size span { width:2rem; height:2rem; font-size:2rem; display:block; text-align:center; cursor:pointer; }';
  517. $styles += '#font_size span:first-of-type { opacity:0.3; background:'+ $plus_sign +' center no-repeat; }';
  518. $styles += '#font_size span:last-of-type { opacity:0.3; background:'+ $minus_sign +' center no-repeat; }';
  519. $styles += '#font_size span:hover { opacity:0.5; filter:invert(100%); background-color:#666; }';
  520. $styles += '#content_pane.has_font_content:hover #font_size, #content_pane.has_grid_content:hover #font_size { display:block; opacity:1; }';
  521.  
  522. // CONTENT: Media Content
  523. $styles += '#content_media { padding: 6px; text-align:center; }';
  524. $styles += '#checkbox_div { padding-left:6px; display:inline-block; }';
  525. $styles += '#checkbox_div label { display:block; float:left; clear:both; }';
  526. $styles += '#checkbox_div label input { margin-top:0; }';
  527. $styles += 'body:not(.has_audio) #content_media { display:none; }';
  528. $styles += 'body.has_audio #content_header { display:table-cell; }';
  529.  
  530. // CONTENT: Media Prev and Next Track buttons
  531. $styles += '#prev_track, #next_track { width:2em; height:2em; padding:0 0 0 8px; display:inline-block; background: #F8F8F8 '+ $next_track_arrow +' no-repeat center;}';
  532. $styles += '#next_track { transform:rotate(180deg); }';
  533. $styles += '#prev_track:hover, #next_track:hover { background-blend-mode:difference; }';
  534.  
  535. // CONTENT: Display preview content
  536. $styles += '#content_pane.has_font_content #content_font { display:block; }';
  537. $styles += '#content_pane.has_image_content #content_image { display:block; }';
  538. $styles += '#content_pane.has_pdf_content #content_embed { display:block; }';
  539. $styles += '#content_pane.has_file_content #content_iframe { display:block; }';
  540. $styles += '#content_grid.has_image_grid { padding-bottom:1rem; display:grid !important; }';
  541. $styles += '#content_grid.has_font_grid, #content_grid.has_grid { background:#FFF; display:block !important; }';
  542. $styles += '#content_pane[class*="hidden"] #content_grid { display:none !important; z-index:auto; }';
  543.  
  544.  
  545. // DARK THEME STYLES
  546. $styles += 'body.dark_mode #sidebar, body.dark_mode #content_header { background:#555; }';
  547. $styles += 'body.dark_mode #sidebar ul.menu { background:#444; box-shadow-color:#111; }';
  548. $styles += 'body.dark_mode #sidebar ul.menu li:hover { background:#666; }';
  549. $styles += 'body.dark_mode #sidebar { border-right-color:#111; }';
  550. $styles += 'body.dark_mode #sidebar_header thead tr, body.dark_mode #sidebar_header tbody tr:first-of-type { border-bottom:solid 1px black; background-color:#444; }';
  551. $styles += 'body.dark_mode #sidebar_header tbody tr:first-of-type td:nth-of-type(even) { border-left-color:#111; border-right-color:#111; }';
  552. $styles += 'body.dark_mode #sidebar_header .menu { border-top-color:#111; }';
  553. $styles += 'body.dark_mode #sidebar_header .menu, body.dark_mode #content_header { border-bottom-color:#111; }';
  554. $styles += 'body.dark_mode #sidebar tr *, body.dark_mode #sidebar li, body.dark_mode #sidebar li a, body.dark_mode #content_header tr { color:#EEE !important; }';
  555. $styles += 'body.dark_mode #details_btn span { color:#333 !important; }';
  556. $styles += 'body.dark_mode #dark_theme { display:none; }';
  557. $styles += 'body.dark_mode #default_theme { display:block; }';
  558.  
  559. // SIDEBAR DARK: Grid Buttons
  560. $styles += 'body.dark_mode #sidebar #grid_btn, body.dark_mode #grid_btn .menu, body.dark_mode #parent_dir_menu, body.dark_mode #shortcuts_menu { filter:invert(100%); }';
  561. $styles += 'body.dark_mode #sidebar #grid_btn ul.menu { background:transparent; border: solid #111; border-width: 1px 0 1px 1px; box-shadow:none !important; }';
  562. $styles += 'body.dark_mode #sidebar #grid_btn .menu li { background:#555; border-right-color: #111; }';
  563. $styles += 'body.dark_mode #sidebar #grid_btn .menu li:first-of-type { border-bottom-color: #111; }';
  564. $styles += 'body.dark_mode #sidebar #grid_btn .menu li:hover { background:#777; }';
  565.  
  566. // SIDEBAR DARK: Selected and Playing items
  567. $styles += 'body.dark_mode #dir_table .selected { background:slategray !important; }';
  568. $styles += 'body.dark_mode #dir_table tr:hover, body.dark_mode #dir_table li:hover { background:#777 !important; }';
  569. $styles += 'body.dark_mode #dir_table .playing { background: #4C7E80 !important; }';
  570.  
  571. // CONTENT DARK
  572. $styles += 'body.dark_mode #content_pane, body.dark_mode #content_grid { background:#333; }';
  573. $styles += 'body.dark_mode #content_header tr:last-of-type { border-top: solid #333 1px; }';
  574. $styles += 'body.dark_mode #content_font, body.dark_mode .font_grid_item { color:#CCC; }';
  575. $styles += 'body.dark_mode #content_grid .font_grid_item.selected, body.dark_mode #content_grid .image_grid_item.selected { background:#666 !important }';
  576. $styles += 'body.dark_mode .font_grid_item:hover, body.dark_mode .font_grid_item.hovered, body.dark_mode .image_grid_item:hover, body.dark_mode .image_grid_item.hovered { background:#555 !important; }';
  577. $styles += 'body.dark_mode #content_pane.has_font_content hr { border-bottom-color:#CCC; }';
  578. $styles += 'body.dark_mode #content_iframe { filter:invert(87.5%); }';
  579. var $excluded = ['.htm','.xhtm','.mp3','.m4a','.m4v','.mp4','.ogg','.ogm','.oga','.webm','.wav','.mpeg','.flac']; // Files with these extensions in iframes should not be inverted in dark mode:
  580. for ( i = 0, n = $excluded.length; i < n; i += 1) {
  581. $styles += 'body.dark_mode #content_iframe[src*="'+ $excluded[i] +'" i] { background:white; filter:unset; }';
  582. }
  583. // MAIN CONTENT
  584. $styles += '#main_content { width:100%; height:100%; border:0; border-collapse:collapse; overflow:hidden; }';
  585.  
  586. // APPEND CUSTOM STYLES
  587. $custom_styles.append($styles);
  588. document.head.appendChild($custom_styles);
  589.  
  590. // Conditional Styles:
  591. var $gecko_styles = document.createElement("style");
  592. var $custom_gecko_styles = '';
  593. $custom_gecko_styles += '<style type="text/css">html, body { border: solid 1px gray !important; } button { padding:0; } #grid_btn .menu {top:-24px;} thead {font-size:100%;} #dir_table .dir::before {position:absolute;} #prev_track, #next_track { background: #3F3F3F '+ $next_track_arrow +' no-repeat center; } body.dark_mode #prev_track, body.dark_mode #next_track { background: #252525 '+ $next_track_arrow +' no-repeat center; #prev_track:hover, #next_track:hover { background-blend-mode:difference; } </style>';
  594. $gecko_styles.append($custom_gecko_styles);
  595.  
  596. // for scrollIntoView
  597. var $block = '';
  598.  
  599. if( $userAgent.indexOf('Firefox') > -1 ){
  600. document.head.appendChild($gecko_styles);
  601. $block = 'start';
  602. } else {
  603. $block = 'nearest';
  604. }
  605. // if( $userAgent.indexOf('Chrome') > -1 ){
  606. // Do something
  607. // }
  608.  
  609. // Sidebar Header: Hide invisibles checkbox user setting
  610. if ( $settings.hide_invisibles === true ) {
  611. $inv_checkbox.find('input').prop('checked',true);
  612. $dir_table.addClass('hide_invisibles');
  613. }
  614. // Sidebar Header: Toggle Invisibles checkbox
  615. $inv_checkbox.on('click','input', function(e){
  616. $dir_table.toggleClass('hide_invisibles');
  617. $('.selected').removeClass('selected');
  618. });
  619.  
  620. // Dir_Table: Hide Ignored Files
  621. if ( $settings.hide_ignored_files === true ) {
  622. $dir_table.addClass('hide_ignored');
  623. }
  624.  
  625. // Dark Mode
  626. if ( $settings.dark_mode === true ) {
  627. $body.addClass('dark_mode');
  628. }
  629. $toggle_dark_mode.on('click',function(e) {
  630. e.preventDefault();
  631. $body.toggleClass('dark_mode');
  632. });
  633.  
  634. // Hide hide invisibles chceckbox
  635. if ( platformIsWin() || window.location.href.indexOf('file:') < 0 ) {
  636. $inv_checkbox.hide();
  637. }
  638.  
  639. // ***** END STYLES ***** //
  640.  
  641. // HELPER FUNCTIONS
  642.  
  643. // get item link
  644. var thisLink = function(x) {
  645. return $(x).find('a').attr('href') != undefined ? $(x).find('a').attr('href') : $(x).attr('href') ;
  646. };
  647.  
  648. var thisText = function(x) {
  649. return $(x).find('a').text() ? $(x).find('a').text() : $(x).text();
  650. };
  651.  
  652.  
  653. // ***** BUILD MENUS ***** //
  654.  
  655. // MENUS: Parents Link Menu Items
  656.  
  657. var parentLinksArr = function() {
  658. var $paths_arr = [];
  659. for ( i = 1, n = $location_arr.length; i < n - 1; i+=1 ) {
  660. $paths_arr[0] = ''; // root
  661. $paths_arr[i] = $paths_arr[i - 1] + $location_arr[i] + '/';
  662. }
  663. return $paths_arr;
  664. };
  665.  
  666. // MENUS: function to build menu list items
  667. var menuItems = function(x,y,i) { // (link, name, count)
  668. var $menu_item = '<li><a href="file:///' + x[i] + '">' + y[i] + '</a></li>';
  669. return $menu_item;
  670. };
  671. // MENUS: Parents Directory Menu Items
  672. var parents_dir_menu_arr = function() {
  673. var $parents_dir_menu_items = [];
  674. for ( var i = 1, n = parentLinksArr().length; i < n; i+=1 ) {
  675. $parents_dir_menu_items[0] = menuItems('/','/',0); // root
  676. $parents_dir_menu_items[i] = menuItems( parentLinksArr(), parentLinksArr(), i);
  677. }
  678. $parents_dir_menu_items.pop(); // remove current directory
  679. $parents_dir_menu_items = $parents_dir_menu_items.reverse().join('').replace(/%20/g,' ');
  680. return $parents_dir_menu_items;
  681. };
  682. $parents_dir_menu.siblings('ul').append( parents_dir_menu_arr() );
  683.  
  684. // MENUS: Root Shortcuts Menu Items
  685. $settings.root_shortcuts = $settings.root_shortcuts.map(i => i + '/'); // append '/' to directory name
  686.  
  687. var root_shortcuts_menu_arr = function() {
  688. if ( $settings.root_shortcuts.length ) {
  689. var $root_shortcut_items = [];
  690. for ( i = 0, n = $settings.root_shortcuts.length; i < n; i+=1 ) {
  691. $root_shortcut_items[i] = menuItems($settings.root_shortcuts,$settings.root_shortcuts,i);
  692. }
  693. $root_shortcut_items = $root_shortcut_items.join('');
  694. return $root_shortcut_items;
  695. }
  696. };
  697.  
  698. // MENUS: User Shortcuts Menu Items
  699. var $working_user_shortcuts = $settings.user_shortcuts;
  700.  
  701. var $user_shortcuts_display_name = $working_user_shortcuts.map(i => $settings.user_name + '/' + i + '/' ); // build display names
  702. var $home = '';
  703. if ( platformIsLinux() ) {
  704. $home = 'home/';
  705. } else {
  706. $home = 'users/';
  707. }
  708. $working_user_shortcuts = $working_user_shortcuts.map(i => $home + $settings.user_name + '/' + i + '/'); // build link fragments
  709.  
  710. var userShortcutsMenuArr = function() {
  711. if ( $settings.user_name && $working_user_shortcuts.length ) {
  712. var $user_shortcut_items = [];
  713. for ( i = 0, n = $working_user_shortcuts.length; i < n; i+=1 ) {
  714. $user_shortcut_items[i] = menuItems( $working_user_shortcuts, $user_shortcuts_display_name, i );
  715. }
  716. $user_shortcut_items = $user_shortcut_items.join('');
  717. return $user_shortcut_items;
  718. }
  719. };
  720.  
  721. // MENUS: File Shortcuts Menu Items
  722. var $file_shortcuts_display_name = $settings.file_shortcuts.map(i => i.split('/').pop()); // get file names from paths
  723.  
  724. var fileShortcutsMenuArr = function() {
  725. if ( $settings.file_shortcuts.length ) {
  726. var $file_shortcut_items = [];
  727. for ( i = 0, n = $settings.file_shortcuts.length; i < n; i+=1 ) {
  728. $file_shortcut_items[i] = menuItems( $settings.file_shortcuts, $file_shortcuts_display_name, i );
  729. }
  730. $file_shortcut_items = $file_shortcut_items.join('').replace(/\/<\/a>/g,'<\/a>').replace(/<a\s/g,'<a class="file_shortcut" ').replace(/%20/g,' ');
  731. return $file_shortcut_items;
  732. }
  733. };
  734. $shortcuts_menu.siblings('ul').append( root_shortcuts_menu_arr(), $divider, userShortcutsMenuArr(), $divider.clone(), fileShortcutsMenuArr(), $divider.clone() );
  735.  
  736. // MENUS: Additional Menu Items
  737. $shortcuts_menu.siblings('ul').append($toggle_dark_mode, $export_settings);
  738.  
  739. // MENUS: Show Menu on click
  740. function showMenus(el) {
  741. var $position = $(el).position();
  742. $(el).find('ul').css({'top':$position.top + $(el).innerHeight() + 'px'}).toggle().parent('td').siblings('td').find('.menu').hide();
  743. }
  744. $parents_dir_menu.add($shortcuts_menu).parent('td').on('click',function(e) {
  745. e.stopPropagation();
  746. showMenus(this);
  747. });
  748.  
  749. // ***** END BUILD MENUS ***** //
  750.  
  751. // ***** END BUILD UI ***** //
  752.  
  753. // ***** SIDEBAR ***** //
  754.  
  755. // DIRECTORY TABLE
  756.  
  757. // DIRECTORY TABLE VARIABLES
  758. if ( $dir_table.hasClass('table') ) {
  759.  
  760. $dir_table_head = $dir_table.find('> thead').length ? $dir_table.find('> thead') : $dir_table.addClass('headless').find('> tbody > tr:first-of-type') ;
  761. $dir_table_head.attr('id','thead');
  762. $dir_table_head_cell = $dir_table_head.find('th');
  763. $dir_table_head_name = $dir_table_head.find('th:contains("Name")');
  764. $dir_table_head_name.addClass('name');
  765. $dir_table_head_details = $dir_table_head_name.nextAll();
  766. $dir_table_head_details.addClass('details');
  767.  
  768. $dir_table_body = $dir_table.find('> tbody');
  769. $dir_table_body.attr('id','tbody');
  770. $dir_table_rule = $dir_table_body.find('hr').closest('tr');
  771. $dir_table_rule.addClass('rule');
  772. $dir_table_row = $dir_table_body.find('> tr').not('#thead').not('.rule');
  773. $dir_table_cell = $dir_table_row.find('td');
  774. $dir_table_link = $dir_table_cell.find('a');
  775. $dir_table_item_name = $dir_table_link.parent('td');
  776. $dir_table_item_name.addClass('name');
  777. $dir_table_item_icon = $dir_table_item_name.add($dir_table_head_name).prev();
  778. $dir_table_item_icon.addClass('icon'); // for directory lists with separate td for icons
  779. $dir_table_details = $dir_table_item_name.nextAll();
  780. $dir_table_details.addClass('details');
  781. }
  782. if( $userAgent.indexOf('Firefox') > -1 ) {
  783. $dir_table.addClass('firefox');
  784. }
  785. if ( $dir_table.hasClass('list') ) { // Apache server
  786. $dir_table_wrapper.addClass('headless');
  787. $dir_table_head = '';
  788. $dir_table_head_cell = '';
  789. $dir_table_head_name = '';
  790. $dir_table_head_details = '';
  791. $dir_table_body = '';
  792. $dir_table_row = $dir_table.find('li');
  793. $dir_table_cell = '';
  794. $dir_table_details = '';
  795. $dir_table_link = $dir_table_row.find('a');
  796. // $dir_table_link.addClass('name');
  797. $dir_table_item_name = thisText($dir_table_link);
  798. $sidebar.append($dir_table_wrapper);
  799. }
  800. $dir_table.detach().attr('id','dir_table');
  801.  
  802. // ***** DIR_TABLE SETUP ***** //
  803.  
  804. // Sidebar Header: Show details button click function
  805. function detailsButton() {
  806. $dir_table.toggleClass('show_details');
  807. $dir_table_body.css({'top':$dir_table_head.height() + 1 +'px'});
  808. $details_btn.find('span').toggle();
  809. }
  810. $details_btn.on('click', detailsButton );
  811.  
  812. // Dir_table: Row hover effects
  813. $dir_table_row.hover(function() {
  814. // Highlight corresponding grid item
  815. if ( $content_grid.is(':visible') ) {
  816. $this_link = thisLink(this);
  817. $content_grid.find('[href="' + $this_link + '"]').closest('div').addClass('hovered');
  818. }
  819. }, function() {
  820. if ( $content_grid.is(':visible') ) {
  821. $content_grid.find('.hovered').removeClass('hovered');
  822. }
  823. });
  824.  
  825. // Dir_table: create link arrays
  826. var $dir_table_dir_link_arr = [];
  827. var $dir_table_file_link_arr = [];
  828. var $dir_table_file_ext_arr = [];
  829. $dir_table_row.not('.ignore,.invisible').find('a').each(function() {
  830. $this_link = thisLink(this).toLowerCase();
  831. if ( $this_link.endsWith('/') ) {
  832. $dir_table_dir_link_arr.push($this_link);
  833. return $dir_table_dir_link_arr;
  834. } else {
  835. var $this_link_ext = $this_link.slice($this_link.lastIndexOf('.'));
  836. $dir_table_file_link_arr.push($this_link);
  837. if ( $dir_table_file_ext_arr.indexOf($this_link_ext) < 0 ) {
  838. $dir_table_file_ext_arr.push($this_link_ext);
  839. }
  840. return $dir_table_file_link_arr, $dir_table_file_ext_arr;
  841. }
  842. });
  843. // Dir_table: array of all dir_table links
  844. var $dir_table_link_arr = [];
  845. $dir_table_link_arr = $dir_table_dir_link_arr.concat($dir_table_file_link_arr);
  846.  
  847. // Dir_table: Classify items
  848. $dir_table_row.each(function() {
  849.  
  850. $this_link = thisLink(this);
  851. $this_text = thisText(this);
  852. $this_ext = $this_text.toLowerCase().slice($this_text.lastIndexOf('.'));
  853.  
  854. if ( $this_link !== undefined ) {
  855.  
  856. $this_link = $this_link.toString().toLowerCase();
  857.  
  858. // Directories or files
  859. if ( $this_link.endsWith('/') ) {
  860. $(this).addClass('dir');
  861. } else {
  862. $(this).addClass('file');
  863. }
  864. // pdf
  865. if ( $this_link.endsWith('.pdf') ) {
  866. $(this).addClass('pdf');
  867. } else if ( $.inArray( $this_ext, $image_ext_arr ) != -1 ) {
  868. $(this).addClass('img');
  869. } else if ( $.inArray( $this_ext, $audio_ext_arr ) != -1 ) {
  870. $(this).addClass('audio');
  871. } else if ( $.inArray( $this_ext, $font_ext_arr ) != -1 ) {
  872. $(this).addClass('font');
  873. }
  874. // invisibles
  875. if ( $this_link.slice($this_link.lastIndexOf('/') + 1 ) === '.' || $this_link.startsWith('.') || thisText(this).startsWith('.') ) {
  876. $(this).addClass('invisible');
  877. }
  878. // ignored
  879. if ( $settings.ignore_files === true ) {
  880. for ( i = 0, n = $settings.ignore_file_types.length; i < n; i+=1 ) {
  881. if ( $this_link.endsWith( $settings.ignore_file_types[i] ) ) {
  882. $(this).closest('#dir_table > tbody > tr').addClass('ignore');
  883. }
  884. }
  885. }
  886.  
  887. // directories as Files and hide ignored files
  888. if ( $this_text.endsWith('.app') ) {
  889. $(this).addClass('app');
  890. if ( $settings.apps_as_dirs === false ) {
  891. $(this).addClass('ignore');
  892. }
  893. }
  894.  
  895. if ( $(this).hasClass('dir') && $(this).hasClass('app') && $this_text.endsWith('/') ) {
  896. $(this).find('a').text($this_text.slice(0,$this_text.lastIndexOf('/')));
  897. }
  898. }
  899. }); // end classify dir_table items
  900.  
  901. // Append dir_table to sidebar or wrapper, depending on directory type
  902. if ( $dir_table.hasClass('table') ) {
  903. $dir_table.appendTo($sidebar);
  904. } else {
  905. $dir_table.appendTo($dir_table_wrapper);
  906. }
  907.  
  908. // Show grid button if images or fonts are found
  909. if ( $dir_table.find('.img').length ) {
  910. $dir_table.add($grid_btn).addClass('has_images');
  911. }
  912. if ( $dir_table.find('.font').length ) {
  913. $dir_table.add($grid_btn).addClass('has_fonts');
  914. }
  915. if ( $dir_table.find('.audio').length ) {
  916. $dir_table.add($body).addClass('has_audio');
  917. }
  918.  
  919. // ***** End dir_table setup ***** //
  920.  
  921. // Cereate Main Content element and append Sidebar and Content Pane.
  922. var $main_content = $('<table id="main_content"><tbody><tr></tr></tbody></table>');
  923. $main_content.find('tr').append( $sidebar_wrapper, $content_pane );
  924.  
  925. // Append everything to body
  926. $body.prepend($main_content);
  927.  
  928. // ***************************** //
  929.  
  930. // ***** SHOW/HIDE CONTENT ***** //
  931.  
  932. // MENUS: Hide Menu function
  933. function hideMenu() {
  934. $('.menu').hide();
  935. }
  936. $(document).on('click', hideMenu );
  937.  
  938. // Set content height
  939. function setContentHeight() {
  940. var $dir_table_head_height = $dir_table_head.length ? $dir_table_head.height() : 0;
  941. var $content_headerHeight = $content_header.outerHeight();
  942. $dir_table.add($dir_table_wrapper).css({'height':window.innerHeight - $sidebar_header.outerHeight() });
  943. $dir_table.find($dir_table_body).css({'top': $dir_table_head_height });
  944. $content_image.css({'top':$content_headerHeight });
  945. $content_grid.add($content_embed).add($content_iframe).add($content_font).css({'height':window.innerHeight - $content_headerHeight,'top':$content_headerHeight });
  946. $content_font_size.css({'top':$content_headerHeight + 13 });
  947. $content_media.find('> div').css({'height':$audio.height() });
  948. $('#checkbox_div').css({'margin-right': - $('#checkbox_div').outerWidth() });
  949. }
  950. setContentHeight();
  951. $('window').on('resize', setContentHeight );
  952.  
  953. function setContentTitle() {
  954. if ( $content_pane.hasClass('has_grid_content') && $content_grid.hasClass('has_grid') ) {
  955. $content_title.empty().prepend('Images and Fonts from: ' + $current_dir_name);
  956. } else if ( $content_pane.hasClass('has_grid_content') && $content_grid.hasClass('has_image_grid') ) {
  957. $content_title.empty().prepend('Images from: ' + $current_dir_name);
  958. } else if ( $content_pane.hasClass('has_grid_content') && $content_grid.hasClass('has_font_grid') ) {
  959. $content_title.empty().prepend('Fonts from: ' + $current_dir_name);
  960. } else if ( $body.hasClass('has_audio') ) {
  961. $content_title.empty().prepend( thisText($playing) );
  962. } else {
  963. $content_title.empty().prepend( thisText($('.selected')) );
  964. }
  965. if ( $('.selected').hasClass('ignore') ) {
  966. $content_title.append(' (Ignored content)' );
  967. }
  968. }
  969.  
  970. // Get image dimensions
  971. function getDimensions(link, callback) {
  972. var img = new Image();
  973. img.src = link;
  974. img.onload = function() { callback( this.width, this.height ); };
  975. }
  976.  
  977. function scrollSidebar(row) {
  978. row[0].scrollIntoView({ behavior:'smooth', block:$block, inline:'nearest' });
  979. }
  980. function scrollGrid(item) {
  981. item[0].scrollIntoView({ behavior:'smooth', block:$block, inline:'nearest' });
  982. }
  983.  
  984. // Select row on click and set classes for $content_pane
  985. function selectThis(row) {
  986. if ( row.hasClass('audio') ) {
  987. row.addClass('playing').siblings().removeClass('playing hovered');
  988. } else {
  989. row.addClass('selected').siblings().removeClass('selected hovered');
  990. }
  991.  
  992. $selected = $dir_table.find('.selected');
  993. $playing = $dir_table.find('.playing');
  994.  
  995. if ( $selected.length && $body.not('.has_audio') ) {
  996. // scrollSidebar( $selected );
  997. }
  998. if ( $playing.length ) {
  999. scrollSidebar( $playing );
  1000. }
  1001.  
  1002. if ( row.hasClass('dir') ) {
  1003. closeThis(); // empty content pane
  1004. setContentTitle();
  1005. $content_pane.removeClass().addClass('has_dir_content');
  1006. }
  1007.  
  1008. var $grid_selected = $content_grid.find('div.font_grid_item[href="'+ thisLink(row) +'"]').add('div.image_grid_item a[href="'+ thisLink(row) +'"]').parent('div').addBack();
  1009. if ( $content_pane.hasClass('has_grid_content') ) {
  1010. $grid_selected.addClass('selected').siblings().removeClass('selected');
  1011. $grid_selected = $content_grid.find('.selected');
  1012. // scrollGrid($grid_selected); // grid scroll is not working reliably
  1013. }
  1014. }
  1015.  
  1016. function showIgnored() {
  1017. closeThis();
  1018. $content_pane.addClass('has_ignored_content');
  1019. $content_title.append(' (Ignored content)' );
  1020. }
  1021.  
  1022. function showImage(row,link) {
  1023. $content_pane.addClass('has_image_content');
  1024. $content_image.find('img').removeClass('zoom_img').attr('src',link);
  1025. getDimensions( link, function( width, height ) {
  1026. if ( !$body.is('.has_audio') ) {
  1027. $content_title.append(' <span style="text-transform:lowercase;">(' + width + 'px &times; ' + height + 'px</span>)' );
  1028. }
  1029. });
  1030. $content_grid.find('a[href="' + thisLink(row) + '"]').parent('div').addClass('selected').siblings().removeClass('selected');
  1031. }
  1032.  
  1033. function showPdf(link) {
  1034. $content_pane.addClass('has_pdf_content');
  1035. $content_embed.attr('type','application/pdf').attr('src',link + '?#zoom=100&scrollbar=1&toolbar=1&navpanes=1');
  1036. }
  1037.  
  1038. function showFile(link) {
  1039. $content_pane.addClass('has_file_content');
  1040. $content_iframe.attr('src',link);
  1041. }
  1042.  
  1043. function showFont(row,link) {
  1044. var $font_family = row.find('.name').text();
  1045.  
  1046. addCustomStyle($font_family,link);
  1047.  
  1048. $content_pane.addClass('has_font_content');
  1049. $content_font.css({ 'font-family':'"'+ $font_family +'"' });
  1050. }
  1051.  
  1052. function addCustomStyle(font_family,link) {
  1053. if ( $font_family_arr.indexOf(font_family) == -1 ) {
  1054. $font_family_arr.push(font_family);
  1055. $custom_font_styles.append('@font-face { font-family: "'+ font_family +'"; src: url("'+ link +'"); }'); // only add style if it doesn't exist
  1056. }
  1057. }
  1058.  
  1059. // Show selected content
  1060. function showThis(row,link) {
  1061.  
  1062. if ( $content_pane.hasClass('has_grid_content') ) {
  1063. $content_pane.removeClass().addClass('has_hidden_grid'); // hide grid when showing new content
  1064. } else
  1065. if ( $content_pane.hasClass('has_hidden_grid') ) {
  1066. $content_pane.removeClass().addClass('has_hidden_grid'); // keep grid hidden when showing new content
  1067. } else {
  1068. $content_pane.removeClass();
  1069. }
  1070.  
  1071. if ( row.hasClass('ignore') ) {
  1072. showIgnored();
  1073. return;
  1074. }
  1075. if ( row.hasClass('img') ) {
  1076. showImage(row,link);
  1077. return;
  1078. }
  1079. if ( row.hasClass('pdf') ) {
  1080. showPdf(link);
  1081. return;
  1082. }
  1083. if ( row.hasClass('font') ) {
  1084. showFont(row,link);
  1085. return;
  1086. }
  1087. if ( row.hasClass('audio') ) {
  1088. $count = $dir_table.find('.audio').index(row);
  1089. playThis( $count, 'play' );
  1090. return;
  1091. }
  1092. if ( row.hasClass('file') ) {
  1093. showFile(link);
  1094. return;
  1095. }
  1096. }
  1097.  
  1098. // ***** MAIN CLICK FUNCTION FOR SHOWING CONTENT ***** //
  1099.  
  1100. function clickDirTableLink(link) {
  1101. var $this_row = link.closest('#dir_table > tbody > tr, #dir_table > li');
  1102. $this_link = thisLink(link);
  1103.  
  1104. if ( $this_row.hasClass('dir') ) {
  1105. window.location = $this_link;
  1106. }
  1107. hideMenu();
  1108. showThis( $this_row, $this_link );
  1109. selectThis( $this_row );
  1110. setContentTitle();
  1111. setContentHeight();
  1112. }
  1113.  
  1114. $dir_table_row.on('click','a',function(e) {
  1115. e.preventDefault();
  1116. closeContent();
  1117. clickDirTableLink($(this));
  1118. });
  1119.  
  1120. // Auto-select file from file shortcut list;
  1121. // Limitations: only loads last file from list found in directory, doesn't know anything about which actual file shortcut was selected
  1122. function autoSelectFile() {
  1123. if ( $settings.file_shortcuts.length ) {
  1124. for ( i = 0, n = $settings.file_shortcuts.length; i < n; i+=1 ) {
  1125. if ( $.inArray($settings.file_shortcuts[i], $dir_table_link_arr ) ) {
  1126. $dir_table.find( 'a[href*="/' + $settings.file_shortcuts[i] + '"]').click();
  1127. }
  1128. }
  1129. }
  1130. }
  1131. autoSelectFile();
  1132.  
  1133. // File shortcuts: load directory then auto-select file
  1134. function showFileShortcut(item) {
  1135. e.preventDefault();
  1136. $this_link = thisLink(item);
  1137. var $this_dir = $this_link.slice(0,$this_link.lastIndexOf('/') );
  1138. window.location = $this_dir;
  1139. }
  1140. $('.file_shortcut').on('click',showFileShortcut );
  1141.  
  1142. function reloadThis() {
  1143. if ( $content_pane.hasClass('has_grid_content') ) {
  1144. $grid_btn.click();
  1145. $content_grid.css({'font-size':'1em','grid-template-columns':'repeat(auto-fit, minmax(150px, 1fr))'});
  1146. return;
  1147. }
  1148. if ( $content_pane.is('[class*="content"]') ) {
  1149. $('.selected').find('a').click();
  1150. $content_font.css({'font-size':'1em'});
  1151. } else {
  1152. return;
  1153. }
  1154. }
  1155. $content_reload_btn.on('click', reloadThis );
  1156.  
  1157. function closeContent() {
  1158. $content_image.find('img').removeAttr('src');
  1159. $content_embed.removeAttr('src');
  1160. $content_iframe.removeAttr('src');
  1161. $content_font.css({'font-family':''});
  1162. }
  1163.  
  1164. function closeThis() {
  1165. hideMenu();
  1166. if ( $content_pane.hasClass('has_grid_content') ) {
  1167. $content_pane.removeClass('has_grid_content');
  1168. $content_grid.removeClass().empty().css({'font-size':'1em'});
  1169. } else if ( $content_pane.hasClass('has_hidden_grid') ) {
  1170. $content_pane.removeClass().addClass('has_grid_content');
  1171. closeContent();
  1172. } else {
  1173. $content_pane.removeClass();
  1174. closeContent();
  1175. }
  1176. setContentTitle();
  1177. }
  1178. // Close content button
  1179. $content_close_btn.on( 'click', closeThis );
  1180.  
  1181.  
  1182. // ***** KEYBOARD EVENTS ***** //
  1183. function navigateToThis(row) {
  1184. if ( $content_pane.hasClass('has_grid_content') ) {
  1185. selectThis(row);
  1186. } else {
  1187. row.find('a').click();
  1188. }
  1189. }
  1190.  
  1191. $body.on('keydown',$dir_table,function(e) {
  1192.  
  1193. var $selected = $dir_table_row.filter('.selected');
  1194. var $selected_href = thisLink($selected);
  1195. var $playing = $dir_table_row.filter('.playing');
  1196. var $first_item = $dir_table_row.filter(':visible').not('.audio').first();
  1197. var $last_item = $dir_table_row.filter(':visible').not('.audio').last();
  1198. var $prev_item = $selected.prevAll(':visible').not('.audio').first();
  1199. var $next_item = $selected.nextAll(':visible').not('.audio').first();
  1200. var $first_image = $dir_table_row.filter('.img:visible').first();
  1201. var $last_image = $dir_table_row.filter('.img:visible').last();
  1202. var $prev_image = $selected.prevAll('.img:visible').first();
  1203. var $next_image = $selected.nextAll('.img:visible').first();
  1204. var $first_font = $dir_table_row.filter('.font:visible').first();
  1205. var $last_font = $dir_table_row.filter('.font:visible').last();
  1206. var $prev_font = $selected.prevAll('.font:visible').first();
  1207. var $next_font = $selected.nextAll('.font:visible').first();
  1208.  
  1209. switch ( e.key ) {
  1210.  
  1211. case 'ArrowUp':
  1212.  
  1213. // Go to parent folder
  1214. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) {
  1215. window.location = $parent_dir_link;
  1216. break;
  1217. }
  1218. // Allow arrow navigation within
  1219. if ( $('*[contentEditable="true"').is(':focus') ) {
  1220. return;
  1221. }
  1222.  
  1223. e.preventDefault();
  1224. if ( $first_item.hasClass('selected') || $selected.length < 1 ) {
  1225. $last_item.hasClass('dir') ? selectThis($last_item) : $last_item.find('a').click();
  1226. } else {
  1227. $prev_item.hasClass('dir') ? selectThis($prev_item) : $prev_item.find('a').click();
  1228. }
  1229. scrollSidebar( $selected.length ? $selected : $last_item );
  1230.  
  1231. break;
  1232.  
  1233. case 'ArrowDown':
  1234.  
  1235. if ( (e.ctrl || e.metaKey) && $selected.hasClass('app') && $settings.apps_as_dirs === false ) {
  1236. return;
  1237. } else if ( $('*[contentEditable="true"').is(':focus') ) {
  1238. return;
  1239. } else if ( (e.ctrl || e.metaKey) && $selected.hasClass('dir') ) {
  1240. window.location = $selected_href;
  1241. break;
  1242. }
  1243.  
  1244. e.preventDefault();
  1245. if ( $last_item.hasClass('selected') || $selected.length < 1 ) {
  1246. $first_item.hasClass('dir') ? selectThis($first_item) : $first_item.find('a').click();
  1247. } else {
  1248. $next_item.hasClass('dir') ? selectThis($next_item) : $next_item.find('a').click();
  1249. }
  1250. scrollSidebar( $selected.length ? $selected : $first_item );
  1251.  
  1252. break;
  1253.  
  1254. case 'ArrowLeft':
  1255.  
  1256. if ( (e.ctrl || e.metaKey) || ( e.ctrl && e.metaKey ) ) {
  1257. return;
  1258. } else if ( $('*[contentEditable="true"').is(':focus') ) {
  1259. return;
  1260. }
  1261. // Navigate Grid or Images
  1262. if ( $playing.length ) {
  1263. prevTrack();
  1264. } else if ( $selected.length < 1 ) {
  1265. $last_image.length ? navigateToThis($last_image) : navigateToThis($last_font);
  1266. } else if ( $first_image.hasClass('selected') || $selected.length < 1 ) {
  1267. $last_font.length ? navigateToThis($last_font) : navigateToThis($last_image);
  1268. } else if ( $first_font.hasClass('selected') || $selected.length < 1 ) {
  1269. $last_image.length ? navigateToThis($last_image) : navigateToThis($last_font);
  1270. } else if ( $selected.hasClass('img') && $prev_image.length ) {
  1271. navigateToThis($prev_image);
  1272. } else {
  1273. navigateToThis($prev_font);
  1274. }
  1275. break;
  1276.  
  1277. case 'ArrowRight':
  1278.  
  1279. if ( (e.ctrl || e.metaKey) || ( e.ctrl && e.metaKey ) ) {
  1280. return;
  1281. } else if ( $('*[contentEditable="true"').is(':focus') || $selected.hasClass('dir ignore') ) {
  1282. return;
  1283. }
  1284. // Navigate Grid or Images
  1285. if ( $selected.hasClass('dir') && !$body.hasClass('has_audio') ) {
  1286. window.location = $selected_href; // Open directory
  1287. } else if ( $playing.length ) {
  1288. nextTrack();
  1289. } else if ( $selected.length < 1 ) {
  1290. $first_image.length ? navigateToThis($first_image) : navigateToThis($first_font);
  1291. } else if ( $last_image.hasClass('selected') || $selected.length < 1 ) {
  1292. $first_font.length ? navigateToThis($first_font) : navigateToThis($first_image);
  1293. } else if ( $last_font.hasClass('selected') || $selected.length < 1 ) {
  1294. $first_image.length ? navigateToThis($first_image) : navigateToThis($first_font);
  1295. } else if ( $selected.hasClass('img') && $next_image.length ) {
  1296. navigateToThis($next_image);
  1297. } else {
  1298. navigateToThis($next_font);
  1299. }
  1300. break;
  1301.  
  1302. case ' ':
  1303. // Play/pause audio
  1304. if ( $body.hasClass('has_audio') ) {
  1305. playPause();
  1306. }
  1307. break;
  1308.  
  1309. case 'Enter':
  1310. // Open directories (or ignore)
  1311. if ( $selected.hasClass('app') && $settings.apps_as_dirs === false ) {
  1312. break;
  1313. } else {
  1314. $selected.find('a').click();
  1315. }
  1316. break;
  1317.  
  1318. case 'd':
  1319. // Toggle Invisibles with Command-i
  1320. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) {
  1321. e.preventDefault();
  1322. e.stopPropagation();
  1323. $details_btn.click();
  1324. }
  1325. break;
  1326.  
  1327. case 'g':
  1328. // Show image Grid
  1329. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) {
  1330. e.preventDefault();
  1331. e.stopPropagation();
  1332. $grid_btn.click();
  1333. }
  1334. break;
  1335.  
  1336. case 'i':
  1337. // Toggle Invisibles with Command-i
  1338. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) {
  1339. e.preventDefault();
  1340. e.stopPropagation();
  1341. $inv_checkbox.find('input').click();
  1342. }
  1343. break;
  1344.  
  1345. case 'o':
  1346. // Cmd/Ctrl + Shift + O: Open selected item in new window
  1347. if ( (navigator.platform.match("Mac") ? e.metaKey && e.shiftKey : e.ctrlKey && e.shiftKey ) ) {
  1348. window.open($selected_href);
  1349. }
  1350. break;
  1351.  
  1352. case 'r':
  1353. // Cmd/Ctrl + Shift + R: Refresh
  1354. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) {
  1355. if ( $content_pane.is('[class*="has_"]') ) {
  1356. e.preventDefault();
  1357. $content_reload_btn.click();
  1358. } else {
  1359. return;
  1360. }
  1361. }
  1362. break;
  1363.  
  1364. case 'w':
  1365. // Close content pane if Close button visible with Command-w
  1366. // Doesn't work in Firefox: can't override default keybinding
  1367. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && ($content_pane.is('[class*="has_"]')) ) {
  1368. e.preventDefault();
  1369. e.stopPropagation();
  1370. $content_close_btn.click();
  1371. }
  1372. break;
  1373.  
  1374. case '.':
  1375. // Increase font preview size
  1376. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.shiftKey ) {
  1377. $('#increase').click();
  1378. }
  1379. break;
  1380.  
  1381. case ',':
  1382. // Dencrease font preview size
  1383. if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && e.shiftKey ) {
  1384. $('#decrease').click();
  1385. }
  1386. break;
  1387.  
  1388. case 'tab':
  1389. break;
  1390.  
  1391. } // end switch
  1392.  
  1393. });
  1394.  
  1395. // ***** END KEYBOARD EVENTS ***** //
  1396.  
  1397. // ***** IMAGE NAVIGATION ***** //
  1398.  
  1399. $prev_btn.on( 'click', function(event) {
  1400. e = $.Event("keydown");
  1401. $playing.length ? e.key = 'ArrowUp' : e.key = 'ArrowLeft';
  1402. $dir_table.trigger(e);
  1403. });
  1404.  
  1405. $next_btn.on( 'click', function(event) {
  1406. e = $.Event("keydown");
  1407. $playing.length ? e.key = 'ArrowDown' : e.key = 'ArrowRight';
  1408. $dir_table.trigger(e);
  1409. });
  1410.  
  1411. // Zoom Images
  1412. $content_image.find('img').on('click',function(e) {
  1413. $this_link = $(this).attr('src');
  1414. var $offset = $(this).offset();
  1415. var $this_width = $(this).width();
  1416. var $this_height = $(this).height();
  1417.  
  1418. $(this).toggleClass('zoom_img');
  1419.  
  1420. getDimensions( $this_link, function( width, height ) {
  1421. $content_image.scrollLeft( (e.pageX - $offset.left) * width/($this_width + 13) - ( e.pageX - $offset.left ) - 52 ) ;
  1422. $content_image.scrollTop( (e.pageY - $offset.top) * height/($this_height + 13) - ( e.pageY - $offset.top ) - 52 );
  1423. });
  1424.  
  1425. });
  1426.  
  1427. // ***** GRIDS ***** //
  1428.  
  1429. var $font_family;
  1430.  
  1431. var imageGridItems = function() {
  1432. var $image_grid_items_arr = [];
  1433. $dir_table_row.filter('.img').each(function() {
  1434.  
  1435. $this_link = thisLink(this);
  1436. $this_ext = $this_link.toLowerCase().slice($this_link.lastIndexOf('.'));
  1437.  
  1438. if ( $.inArray( $this_ext, $image_ext_arr ) != -1 ) { // if this row file ext is in the image extension array
  1439. $image_grid_item_el.find('a').attr('href',$this_link).find('img').attr('src',$this_link);
  1440. $image_grid_items_arr.push( $image_grid_item_el.clone() );
  1441. }
  1442. });
  1443. return $image_grid_items_arr;
  1444. };
  1445.  
  1446. var fontGridItems = function() {
  1447. var $font_grid_items_arr = [];
  1448. $dir_table_row.filter('.font').each(function() {
  1449.  
  1450. $this_link = thisLink(this);
  1451. $font_family = $(this).find('.name').text();
  1452.  
  1453. addCustomStyle( $font_family, $this_link );
  1454.  
  1455. $font_grid_item_el.attr('href',$this_link).css({ 'font-family':'"'+ $font_family +'"' }).empty().append( $font_family.slice( 0,$font_family.lastIndexOf('.') ) );
  1456. $font_grid_items_arr.push($font_grid_item_el.clone());
  1457. });
  1458. return $font_grid_items_arr;
  1459. };
  1460.  
  1461. // Grid Button Click
  1462. function showGrid() {
  1463. $content_pane.removeClass('has_hidden_grid').addClass('has_grid_content');
  1464.  
  1465. if ( $dir_table.hasClass('has_images') && ( $dir_table.hasClass('has_fonts') ) ) {
  1466. $content_grid.empty().append( imageGridItems() ).append( fontGridItems() );
  1467. $content_grid.removeClass().addClass('has_grid');
  1468. } else if ( $dir_table.hasClass('has_images') ) {
  1469. $content_grid.empty().append( imageGridItems() );
  1470. $content_grid.removeClass().addClass('has_image_grid');
  1471. } else {
  1472. $content_grid.empty().append( fontGridItems() );
  1473. $content_grid.removeClass().addClass('has_font_grid');
  1474. }
  1475. setContentTitle();
  1476. setContentHeight();
  1477. }
  1478. $grid_btn.on('click', showGrid );
  1479.  
  1480. $('#show_image_grid').on('click',function(e) {
  1481. e.stopPropagation();
  1482. $content_pane.removeClass('has_hidden_grid').addClass('has_grid_content');
  1483. $content_grid.empty().append( imageGridItems() );
  1484. $content_grid.removeClass().addClass('has_image_grid');
  1485. setContentTitle();
  1486. setContentHeight();
  1487. });
  1488.  
  1489. $('#show_font_grid').on('click',function(e) {
  1490. e.stopPropagation();
  1491. $content_pane.removeClass('has_hidden_grid').addClass('has_grid_content');
  1492. $content_grid.empty().append( fontGridItems() );
  1493. $content_grid.removeClass().addClass('has_font_grid');
  1494. setContentTitle();
  1495. setContentHeight();
  1496. });
  1497.  
  1498. // GRID ITEMS
  1499.  
  1500. // Grid Item Hover
  1501. $content_grid.on('mouseenter','> div:not(".selected")',function() {
  1502. $dir_table.find('a[href="' + thisLink(this) + '"]').closest('#dir_table > tbody > tr,#dir_table li').addClass('hovered');
  1503. }).on('mouseleave','> div:not(".selected")',function() {
  1504. $dir_table.find('a[href="' + thisLink(this) + '"]').closest('#dir_table > tbody > tr,#dir_table > li').removeClass('hovered');
  1505. });
  1506.  
  1507. // Grid Item Click
  1508. $content_grid.on('click','> div[class*="item"]',function(e) {
  1509. e.preventDefault();
  1510. $dir_table.find('a[href="' + thisLink(this) + '"]').click();
  1511. });
  1512.  
  1513. // ***** FONT PREVIEWS ***** //
  1514.  
  1515. var fontSize = function(el) {
  1516. return parseFloat(el.css('font-size'));
  1517. };
  1518.  
  1519. function setFontSize(el,x) {
  1520. el.css({'font-size':( fontSize(el)/$em * x ) +'em'});
  1521. }
  1522.  
  1523. var $em = parseInt(getComputedStyle(document.body).fontSize); // pts/em
  1524. var $factor = 1.125;
  1525.  
  1526. // Scale Image Grid Items
  1527. var $image_grid_item_size;
  1528. var $grid_scale_factor;
  1529.  
  1530. function setImageSize(x) {
  1531. $image_grid_item_size = parseInt($('.image_grid_item').width()) + x;
  1532. $grid_scale_factor = parseInt($content_grid.attr('data-grid-scale-factor'));
  1533. $content_grid.attr('data-grid-scale-factor',parseInt($grid_scale_factor) + x).css({'grid-template-columns':'repeat(auto-fit, minmax('+ ($image_grid_item_size) +'px, 1fr))', 'grid-template-rows':'repeat(auto, minmax('+ ($image_grid_item_size) +'px))' });
  1534. $content_grid.find('.image_grid_item').css({'width':$image_grid_item_size +'px', 'height':$image_grid_item_size +'px'});
  1535. $content_grid.find('img').css({'max-width':($image_grid_item_size - $image_grid_item_size/8) +'px', 'max-height':($image_grid_item_size - $image_grid_item_size/8) +'px'});
  1536. }
  1537.  
  1538. function enlargeGridItems() {
  1539. if ( $content_pane.hasClass('has_grid_content') && $content_grid.hasClass('has_font_grid') || $content_pane.hasClass('has_grid_content') && $content_grid.hasClass('has_grid') ) {
  1540. setFontSize($content_grid,$factor);
  1541. setImageSize(25);
  1542. return;
  1543. }
  1544.  
  1545. if ( $content_pane.is('.has_hidden_grid.has_font_content') ) {
  1546. setFontSize($content_font,$factor);
  1547. return;
  1548. }
  1549. if ( $content_pane.is('.has_font_content') ) {
  1550. setFontSize($content_font,$factor);
  1551. return;
  1552. }
  1553. if ( $content_pane.is('.has_grid_content') && $content_grid.is('.has_image_grid') ) {
  1554. setImageSize(25);
  1555. return;
  1556. }
  1557. }
  1558.  
  1559. function reduceGridItems() {
  1560. if ( $content_pane.is('.has_grid_content') && $content_grid.is('.has_font_grid') || $content_pane.is('.has_grid_content') && $content_grid.is('.has_grid') ) {
  1561. setFontSize($content_grid,1/$factor);
  1562. setImageSize(-25);
  1563. return;
  1564. }
  1565. if ( $content_pane.is('.has_hidden_grid.has_font_content') ) {
  1566. setFontSize($content_font,1/$factor);
  1567. return;
  1568. }
  1569. if ( $content_pane.is('.has_font_content') ) {
  1570. setFontSize($content_font,1/$factor);
  1571. return;
  1572. }
  1573. if ( $content_pane.is('.has_grid_content') && $content_grid.is('.has_image_grid') ) {
  1574. setImageSize(-25);
  1575. return;
  1576. }
  1577. }
  1578.  
  1579. $('#font_size').on('click','span',function() {
  1580. if ( $(this).attr('id') === 'increase' ) {
  1581. enlargeGridItems();
  1582. }
  1583. if ( $(this).attr('id') === 'decrease' ) {
  1584. reduceGridItems();
  1585. }
  1586. });
  1587.  
  1588. // ***** END FONT PREVIEWS ***** //
  1589.  
  1590. // ***** AUDIO CONTENT ***** //
  1591.  
  1592. var $count = 0;
  1593. var $playlist = [];
  1594. var $unplayed = [];
  1595. var $reset = [];
  1596. var $next;
  1597. var $task;
  1598.  
  1599. // SEE LINE 833
  1600. $dir_table_row.filter('.audio').each(function() {
  1601. $this_link = thisLink(this);
  1602. $playlist.push($this_link);
  1603. return $playlist;
  1604. });
  1605.  
  1606. function playThis( count, task ) {
  1607. $audio.find('source').attr('src', $playlist[count] );
  1608. $audio.trigger('load');
  1609.  
  1610. playAudio(task);
  1611.  
  1612. selectThis( $dir_table.find('a[href="' + $playlist[count] + '"]').closest('#dir_table > tbody > tr,#dir_table > li') );
  1613. setContentTitle();
  1614. }
  1615.  
  1616. function playAudio( task ) {
  1617. if ( task == 'play' ) {
  1618. $audio.trigger('play');
  1619. }
  1620. if ( task == 'stop' ) {
  1621. $audio.trigger('pause');
  1622. $audio.prop('currentTime',0);
  1623. }
  1624. }
  1625.  
  1626. function playPause() {
  1627. $('#audio').get(0).paused ? $('#audio').get(0).play() : $('#audio').get(0).pause();
  1628. }
  1629.  
  1630. $shuffle.on('click',function() {
  1631. $unplayed = [];
  1632. for ( i = 0; i < $playlist.length; i += 1 ) {
  1633. $unplayed[i] = i;
  1634. $reset[i] = i;
  1635. }
  1636. if ( $shuffle.find('input').prop('checked') === true ) {
  1637. $unplayed.splice(0); // reset the unplayed list
  1638. $unplayed = $unplayed.concat($reset); // reset the unplayed list;
  1639. $count = Math.floor( Math.random() * $unplayed.length );
  1640. playThis($count,'stop');
  1641. }
  1642. });
  1643.  
  1644. function shuffle() {
  1645. if ( $unplayed.length <= 1 && $loop.find('input').prop('checked') ) { // If loop is checked, and all songs have been shuffled...
  1646. $unplayed.splice(0); // reset the unplayed list
  1647. $unplayed = $unplayed.concat($reset); // reset the unplayed list;
  1648. $task = 'play';
  1649. } else if ( $unplayed.length === 0 ) { // else if all songs have been shuffled, select the first song and stop;
  1650. $count = 0;
  1651. $task = 'stop';
  1652. } else { // else
  1653. $next = Math.floor( Math.random() * $unplayed.length ) ; // choose a random index number from the remaining unplayed songs,
  1654. $count = $unplayed[ $next ]; // set the playing $count to the index
  1655. $unplayed.splice( $next, 1 ); // remove the indexed value from the unplayed list,
  1656. $task = 'play';
  1657. }
  1658. }
  1659.  
  1660. function nextTrack() {
  1661. if ( $shuffle.find('input').prop('checked') ) {
  1662. shuffle();
  1663. } else if ( $loop.find('input').prop('checked') == false && $count === $playlist.length - 1) {
  1664. $count = 0;
  1665. $task = 'stop';
  1666. } else if ( $loop.find('input').prop('checked') && $count === $playlist.length - 1 ) {
  1667. $count = 0;
  1668. $task = 'play';
  1669. } else if ( $count < $playlist.length - 1 ) {
  1670. $count += 1;
  1671. $task = 'play';
  1672. }
  1673. playThis($count, $task);
  1674. }
  1675.  
  1676. function prevTrack() {
  1677. if ( $shuffle.find('input').prop('checked') ) {
  1678. shuffle();
  1679. } else if ( $count === 0 ) {
  1680. $count = ($playlist.length - 1);
  1681. } else if ( $count > 0 ) {
  1682. $count -= 1;
  1683. }
  1684. playThis($count,'play');
  1685. }
  1686.  
  1687. $prev_track.on( 'click', prevTrack );
  1688. $next_track.on( 'click', nextTrack );
  1689.  
  1690. // Audio setup
  1691. if ( $body.is('.has_audio') ) {
  1692.  
  1693. $audio.find('source').attr('src', $playlist[0] );
  1694. $audio.trigger('load');
  1695.  
  1696. // Select Dir_table item and set content title
  1697. selectThis($dir_table.find('a[href="' + $playlist[$count] + '"]').closest('#dir_table > tbody > tr, #dir_table > li'));
  1698. setContentTitle();
  1699.  
  1700. autoLoadCover();
  1701. // Background for music directories w/o image files?
  1702. if ( !$dir_table.find('.img').length ) {
  1703. $content_image.css({'display':'block','background':$music +' no-repeat center','background-size':'33.33%','opacity':'0.2'});
  1704. } else {
  1705. $content_image.css({'background':'none'});
  1706. }
  1707. if ( $settings.autoplay == true ) {
  1708. $audio.trigger('play');
  1709. }
  1710.  
  1711. $audio.on('ended', nextTrack );
  1712. }
  1713.  
  1714. function autoLoadCover() {
  1715. if ( $dir_table_row.filter('.img').length ) {
  1716. var $this_title;
  1717. var $cover_titles = ['/cover.','/front.'];
  1718. $dir_table_row.filter('.img').each(function() {
  1719.  
  1720. $this_title = thisLink(this).toLowerCase();
  1721.  
  1722. if ( !$this_title.startsWith('/') ) {
  1723. $this_title = '/'+ $this_title; // Firefox
  1724. }
  1725. for ( i = 0; i < $cover_titles.length; i+=1 ) {
  1726. if ( $this_title.indexOf( $cover_titles[i] ) != -1) {
  1727. showImage( $(this), thisLink(this) );
  1728. break;
  1729. } else {
  1730. showImage( $dir_table_row.filter('.img').first(), thisLink( $dir_table_row.filter('.img').first() ) );
  1731. }
  1732. }
  1733. });
  1734. }
  1735. }
  1736.  
  1737. // ***** END AUDIO CONTENT ***** //
  1738.  
  1739. // OTHER FUNCTIONS
  1740.  
  1741. // Resize Sidebar/Content Pane
  1742. $handle.on('mousedown',function(f) {
  1743. f.stopPropagation();
  1744. var $startX = f.pageX;
  1745. var $sidebar_width = $sidebar_wrapper.width();
  1746. var $window_width = window.innerWidth;
  1747. $content_overlay.show(); // needed to prevent interactions with iframe
  1748. $sidebar_wrapper.css({'-webkit-user-select':'none','-moz-user-select':'none','user-select':'none'});
  1749.  
  1750. $(document).on('mousemove',function(e) {
  1751. e.stopPropagation();
  1752. var $deltaX = e.pageX - $startX;
  1753. if ( e.pageX > 200 && e.pageX < $window_width - 200 ) {
  1754. $sidebar_wrapper.css({'width':$sidebar_width + $deltaX + 'px'});
  1755. $content_pane.css({'width':($window_width - $sidebar_width) - $deltaX + 'px'});
  1756. }
  1757. setContentHeight();
  1758. });
  1759. $(document).on('mouseup',function() {
  1760. $content_overlay.hide();
  1761. $sidebar_wrapper.css({'-webkit-user-select':'auto','-moz-user-select':'auto','user-select':'auto'});
  1762. $(document).off('mousemove');
  1763. });
  1764. });
  1765.  
  1766.  
  1767. // Export Settings
  1768. var $settings_string = unescape( $settings.toSource() );
  1769. $settings_string = $settings_string.replace('JSON.parse\(unescape\("\{','').replace('\}"))','').replace(/\/",/g,'",').replace(/\/"],/g,'"],').replace(/"(\w+?)":/g,'\n\n$1:\t');
  1770.  
  1771. var save = function(filename, data) {
  1772. var blob = new Blob([data], {type: 'text/html'});
  1773. if(window.navigator.msSaveOrOpenBlob) {
  1774. window.navigator.msSaveBlob(blob, filename);
  1775. }
  1776. else{
  1777. var elem = window.document.createElement('a');
  1778. elem.href = window.URL.createObjectURL(blob);
  1779. elem.download = filename;
  1780. document.body.appendChild(elem);
  1781. elem.click();
  1782. document.body.removeChild(elem);
  1783. URL.revokeObjectURL(blob);
  1784. }
  1785. };
  1786.  
  1787. $export_settings.on('click','a',function(e) {
  1788. e.preventDefault();
  1789. save("settings.txt",$settings_string);
  1790. });
  1791.  
  1792.  
  1793. })();