// ==UserScript== // @name Supercharged Local Directory File Browser // @version 1.4 // @description Makes file:/// directory ("Index of...") pages actually useful. Adds navigation links, file preview pane, user-defined shortcuts, filtering, keyboard navigation, more. // @author Gaspar Schott // @license GPL-3.0 // @match file:///* // @require http://code.jquery.com/jquery-latest.min.js // This script was developed in Vivaldi, running on Mac OS High Sierra. It has been tested in Chromium, Opera Next, Iridium, and in general it should work in all Chrome-based browsers. // It does not work in Safari because Safari does not allow local directories to be browsed. // In theory, it should work in Firefox, but because Firefox uses a different DOM for building the Index pages, the script would have to be rewritten. // NOTE: By default, Greasemonkey and Tampermonkey will not run scripts on file:/// urls, so for this script to work, you will have to enable it first. // For Greasemonkey, open about:config and change greasemonkey.fileIsGreaseable to true. // For Tampermonkey, go to Chrome extension page, and tick the 'Allow access to file URLs' checkbox at the Tampermonkey extension section. // CHANGELOG: // v. 1.4 // Added: Initial support for Firefox. Tested in Firefox 59, Waterfox 56. // Changed: Use SVG for menu icons // Changed: Code cleanup, reorganization // v. 1.3 // Fixed: Keyboard navigation of ignored or invisible items fails if "Hide Invisibles" is toggled off after loading a directory. // Added: Also hide ignored files if "Hide Invisibles" is checked. // Added: Content reload button. // Changed: Reorganized settings to reduce confusion about how ignored files are treated. // v. 1.2 // Click to show menus instead of hover. // Added Cmd/Crl+Shift+O keybinding to open selected item in new window // Arrow navigation bugfixes // TODO: // Resize elements on window resize (e.g. menus) // Add dark mode: better to use UserStyle instead? // Fix Scroll into view -- dir_table doesn't scroll // Support for Apache index pages (uses ul and li instead of tables) // Support for Firefox index pages (uses embedded tables) // if invisible item is selected when "hide invisibles" is unchecked, select nearest previous visible item when hide invisible is checked agagin? // @namespace https://greasyfork.org/users/16170 // @downloadURL none // ==/UserScript== (function() { 'use strict'; var $ = jQuery; function platformIsMac() { return navigator.platform.indexOf('Mac') > -1; } function platformIsWin() { return navigator.platform.indexOf('Win') > -1; } // Don't run script in iframes or files (only directories) // if ( window.top != window.self ) { if ( window.frameElement !== null ) { return; } else if ( window.location.pathname.slice(-1) != '/') { return; } // ***** USER SETTINGS ***** // var $settings = { user_name: // Your computer user name '', // Shortcuts: add directories and files here. (You can use your browser's bookmarks, of course.) root_shortcuts: // Root directories: add or remove as you please (but at leave empty brackets). These defaults are applicable to Mac OS. ['Applications','Library','Users','Volumes'], // ['C:/Users','C:/Program Files','C:/Windows'], user_shortcuts: // User directories; you must enter your user_name above. ['Documents','Photos'], file_shortcuts: // Add specific file paths, e.g.: 'Users/MyUserName/Documents/MyDocument.html' // These files will be selected (loaded) automatically when their containing directory is loaded // Limitations: only works for one file per directory; if more than one file per directory is listed, the last item will be selected. ['path/to/file.ext'], ignore_files: // If true, ignored files (see below) will be greyed-out (default) in the file list and will not be loaded in the content pane when selected; // If false, they will be treated as normal files, so if they are selected, the browser will attempt to download any file types it can't handle (which makes keyboard navigation inconvenient). true, hide_ignored_files: // If true, ignored files will be hidden in the file list; // if false, they will appear greyed-out (default). false, ignore_file_types: // ignore files with these extensions: ['exe','.doc','.docx','ppt','pptx','xls','xlsx','odt','odp','msi','dll','rtf','indd','idml','.pages','.tif','tiff','.eps','.psd','.ai','.zip','pkg','.swf','.pls','.ics','.ds_store','alias','.dmg','.gz','.qxp','icon.jpg','thumbs.db'], // lowercase hide_invisibles: // Mac OS only: Files beginning with a "." will be ignored. true, 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. // If false, treat apps as ignored files. true, dark_mode: // To be implemented false }; // ***** END USER SETTINGS ***** // // ***** BUILD MENUS ***** // // PATHS var $location = window.location.pathname; var $current_dir_path = $location.replace(/%20/g,' ').replace(/\//g,'/').replace(/_/g,'_').replace(/—/g,'—').replace(/\\/g,'/'); var $current_dir_name = $location.replace(/%20/g,' ').slice(0,-1); $current_dir_name = $current_dir_name.slice($current_dir_name.lastIndexOf('/') + 1); var $location_arr = $location.split('/'); var $parent_dir_link = $location_arr.slice(0,-2).join('/') + '/'; // Parents Link Menu Items var $parent_links_arr = function() { var $paths_arr = []; for ( var i = 1; i < $location_arr.length - 1; i++ ) { $paths_arr[0] = ''; // root $paths_arr[i] = $paths_arr[i - 1] + $location_arr[i] + '/'; } return $paths_arr; }; // function to build menu list items function menu_items(x,y,i) { var $menu_item = '
  • ' + y[i] + '
  • '; return $menu_item; } // Parents Directory Menu Items var $parents_dir_menu_arr = function() { var $parents_dir_menu_items = []; for ( var i = 1; i < $parent_links_arr().length; i++ ) { $parents_dir_menu_items[0] = menu_items('/','/',0); // root $parents_dir_menu_items[i] = menu_items($parent_links_arr(),$parent_links_arr(),i); } $parents_dir_menu_items.pop(); // remove current directory $parents_dir_menu_items = $parents_dir_menu_items.reverse().join('').replace(/%20/g,' '); return $parents_dir_menu_items; }; // Root Shortcuts Menu Items $settings.root_shortcuts = $settings.root_shortcuts.map(i => i + '/'); // add '/' var $root_shortcuts_menu_arr = function() { if ( $settings.root_shortcuts.length ) { var $root_shortcut_items = []; for ( var i = 0; i < $settings.root_shortcuts.length; i++ ) { $root_shortcut_items[i] = menu_items($settings.root_shortcuts,$settings.root_shortcuts,i); } $root_shortcut_items = $root_shortcut_items.join(''); return $root_shortcut_items; } }; // User Shortcuts Menu Items var $user_shortcuts_display_name = $settings.user_shortcuts.map(i => $settings.user_name + '/' + i + '/' ); // build display names $settings.user_shortcuts = $settings.user_shortcuts.map(i => 'users/' + $settings.user_name + '/' + i + '/'); // build link fragments var $user_shortcuts_menu_arr = function() { if ( $settings.user_name && $settings.user_shortcuts.length ) { var $user_shortcut_items = []; for ( var i = 0; i < $settings.user_shortcuts.length; i++ ) { $user_shortcut_items[i] = menu_items($settings.user_shortcuts,$user_shortcuts_display_name,i); } $user_shortcut_items = $user_shortcut_items.join(''); return $user_shortcut_items; } }; // File Shortcuts Menu Items var $file_shortcuts_display_name = $settings.file_shortcuts.map(i => i.split('/').pop()); // get file names from paths var $file_shortcuts_menu_arr = function() { if ( $settings.file_shortcuts.length ) { var $file_shortcut_items = []; for ( var i = 0; i < $settings.file_shortcuts.length; i++ ) { $file_shortcut_items[i] = menu_items($settings.file_shortcuts,$file_shortcuts_display_name,i); } $file_shortcut_items = $file_shortcut_items.join('').replace(/\/<\/a>/g,'<\/a>').replace(/")'; var $parent_dir_menu = $( '' ); $parent_dir_menu.find('a').attr('href',$parent_dir_link).css({'background':$up_arrow + 'center no-repeat'}); // 2. Current Directory Name and Parents Directory Menu var $parents_dir_menu = $( '' ); $parents_dir_menu.find('div').append( $current_dir_path ); $parents_dir_menu.find('ul').append( $parents_dir_menu_arr() ); // 3. Shortcuts Menu var $divider = $( '

  • ' ); var $menu_icon = 'url("data:image/svg+xml;utf8,")'; var $shortcuts_menu = $( '' ); $shortcuts_menu.find('div').css({'background':$menu_icon + 'center no-repeat'}); $shortcuts_menu.find('ul').append( $root_shortcuts_menu_arr(), $divider, $user_shortcuts_menu_arr(), $divider.clone(), $file_shortcuts_menu_arr(), $divider.clone() ); // 4. Details Button var $details_btn = $( '' ); // 5. Invisibles Checkbox var $inv_checkbox = $( '' ); // 6. Image Grid Button var $grid_icon = 'url("data:image/svg+xml;utf8,")'; var $content_grid_btn = $( '' ); $content_grid_btn.css({'background':$grid_icon + 'no-repeat center 100%'}); // ASSEMBLE SIDEBAR HEADER var $sidebar_header = $( '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' ); $sidebar_header.find('tbody tr:nth-child(1)').find('td:nth-child(1)').append( $parent_dir_menu ); $sidebar_header.find('tbody tr:nth-child(1)').find('td:nth-child(2)').append( $parents_dir_menu ); $sidebar_header.find('tbody tr:nth-child(1)').find('td:nth-child(3)').append( $shortcuts_menu ); $sidebar_header.find('tbody tr:last-child td').append( $details_btn, $inv_checkbox, $content_grid_btn ); if ( platformIsWin() ) { $inv_checkbox.hide(); } // 7. Sidebar var $sidebar = $( '' ); $sidebar.append($sidebar_header); // 8. Resize Handle var $handle = $( '
    ' ); // Assemble Sidebar Elements var $sidebar_wrapper = $( '' ); $sidebar_wrapper.append( $sidebar, $handle ); // ***** END SIDEBAR ELEMENTS ***** // // ***** BUILD CONTENT PANE ELEMENTS ***** // // 1. Reload Button Element var $content_reload_btn = $( '' + '' + '' ); // 2. Title Element var $content_title = $( '' ); // 3. Close Button Element var $content_close_btn = $( '' + '' + '' ); // 4. Content Header Element var $content_header = $( '' ); $content_header.find('tr').append($content_reload_btn, $content_title, $content_close_btn); // 5. Content Mask Element var $content_mask = $( '' ); $content_mask.css({'height':window.innerHeight + 'px'}); // 6. Image Grid Element var $content_grid = $( '' ); // 7. Image Element var $image = $( '' ); var $content_image = $( '' ); $content_image.append($image); // 8. Pdf (embed) Element var $content_embed = $( '' ); // 9. Iframe Element var $content_iframe = $( '' ); // 10. Object Element // var $content_object = $( // '' // ); // 9. Next/Prev Elements var $prev_btn = $(''); var $next_btn = $(''); var $svg_arrow = 'url("data:image/svg+xml;utf8,")'; $prev_btn.css({'filter':'invert(50%)','background':$svg_arrow + ' no-repeat center'}); $next_btn.css({'filter':'invert(50%)','background':$svg_arrow + ' no-repeat center','transform':'rotate(180deg)'}); // 10. Content container var $content_container = $('
    '); $content_container.append( $content_header, $content_mask, $content_grid, $content_image, $content_embed, $content_iframe ); // Assemble Content Pane Elements var $content_pane = $(''); $content_pane.append( $content_container, $prev_btn, $next_btn ); // Set content height function setContentHeight() { var $content_headerHeight = $content_header.outerHeight(); $content_image.css({'top':$content_headerHeight }); $content_grid.add($content_embed).add($content_iframe).css({'height':window.innerHeight - $content_headerHeight,'top':$content_headerHeight }); } setContentHeight(); // resize head and content header $('window').on('resize', function() { headerHeight(); setContentHeight(); }); // ***** END BUILD CONTENT PANE ELEMENTS ***** // // ASSEMBLE MAIN CONTENT = SIDEBAR + CONTENT PANE var $main_content = $('
    '); $main_content.find('tr').append( $sidebar_wrapper, $content_pane ); // END BUILD UI ELEMENTS // DEFAULT HTML, BODY STYLES // Conditional Styles: var $userAgent = navigator.userAgent; var $gecko_styles = ''; if( $userAgent.indexOf('Firefox') > -1 ){ document.querySelector('head').innerHTML += $gecko_styles; } if( $userAgent.indexOf('Chrome') > -1 ){ } var $body = $('body'); var $dir_table = $body.find('> table'); $body.find('> h1:contains("Index of"),> #parentDirLinkBox,> #UI_goUp').remove(); $body.attr('lang','en').parents('html').addBack().css({'margin':'0','padding':'0','max-width':'100%','height':'100%','font-family':'lucidagrande,"fira sans",helvetica,sans-serif','font-size':'13px','hyphens':'auto','overflow':'hidden','border-radius':0}); $body.prepend($main_content); // ***** SIDEBAR ***** // // ***** SIDEBAR HEADER ***** // // Sidebar Header: Set menu container heights function headerHeight() { $sidebar_header.find('nav').find('*').addBack().css({'height': 'auto' }); $shortcuts_menu.find('div').add($parent_dir_menu).find('a').addBack().css({'height': ($shortcuts_menu.closest('tr').height() ) +'px' }); } headerHeight(); // Sidebar Header: Show Menu function function showMenu(x) { if ( $(x).parents('td').siblings('td').find('.clicked').length ) { hideMenu(); } $(x).toggleClass('clicked').find('.menu').toggle(); } // Sidebar Header: Show Menu on click $parents_dir_menu.add($shortcuts_menu).on('click',function(e) { e.stopPropagation(); showMenu(this); }); // Sidebar Header: Hide Menu function function hideMenu() { $('.clicked').removeClass('clicked').find('.menu').hide(); } // Sidebar Header: Hide Menu on click $(document).on('click',function() { hideMenu(); }); // Sidebar Header: Menu Icons Hover $('#grid_btn,#shortcuts_menu div,#parent_dir_menu').hover(function() { $(this).css({'opacity':1}); }, function() { $(this).css({'opacity':0.7}); }); // Sidebar Header: Menu item Hover $parents_dir_menu.add($shortcuts_menu).find('li').hover(function() { $(this).css({'background-color':'#BBB'}); }, function() { $(this).css({'background-color':'lightgrey'}); }); // Sidebar Header: Hide invisibles checkbox user setting if ( $settings.hide_invisibles === true ) { $inv_checkbox.find('input').prop('checked',true); } // Sidebar Header: Toggle Invisibles checkbox $inv_checkbox.on('click', function(){ if ( $(this).find('input').is(':checked') ) { $(this).find('input').prop('checked',false); } else { $(this).find('input').prop('checked',true); } $('.invisible').add('.ignore').toggle().filter('.selected').removeClass('selected'); }); // ***** DIR_TABLE SETUP ***** // $dir_table.detach().attr('id','dir_table'); // DIR_TABLE: Variables var $dir_table_head = $dir_table.find('> thead'); var $dir_table_head_cell = $dir_table_head.find('th'); var $dir_table_head_name = $dir_table_head_cell.filter(':first-of-type'); var $dir_table_head_details = $dir_table_head_name.nextAll(); var $dir_table_body = $dir_table.find('> tbody'); var $dir_table_row = $dir_table_body.find('> tr'); var $dir_table_cell = $dir_table_row.find('td'); var $dir_table_item_name = $dir_table_cell.filter(':nth-of-type(1)'); var $dir_table_details = $dir_table_item_name.nextAll(); var $dir_table_link = $dir_table_item_name.find('a'); // Dir_table: Styles $dir_table.css({'width':'100%','min-width':'100px','height':'calc(100% - ' + $sidebar_header.height() + 'px)','border':'0','position':'relative','overflow':'hidden','table-layout':'fixed','border-collapse':'collapse'}); $dir_table_head.css({'text-align':'left','position':'absolute'}); $dir_table_head_name.css({'padding-left':'2em'}); $dir_table_head_cell.css({'padding':'0 24px 4px;'}); $dir_table_body.css({'width':'100%','position':'absolute','top':'18px','right':'0','bottom':'0','left':'0','overflow-y':'auto','outline':'0'});//.attr('tabindex','0'); $dir_table_row.css({'display':'block','margin-inline-start':'0','clear':'both'}); $dir_table_cell.css({'padding':'0px'}); $dir_table_link.css({'margin':'0px','display':'block','background-size':'auto 13px','-webkit-padding-start':'2em','padding':'4px 6px 4px 24px','color':'#333','text-decoration':'none','overflow':'hidden','background-position':'6px 4px','white-space':'normal'}); $dir_table_item_name.css({'display':'block','clear':'right'}); $dir_table_details.add($dir_table_head_details).css({'font-size':'0.875em','text-align':'left','vertical-align':'top'}).hide(); $dir_table_details.not('th').css({'padding':'0 24px 4px','float':'left'}); // Sidebar Header: Show details button click function $details_btn.on('click',function() { $dir_table_details.add($dir_table_head_details).toggle(); $dir_table_body.css({'top':$dir_table_head.height() + 1 + 'px'}); $(this).find('span').toggle(); }); // Dir_table: Row hover effects $dir_table_row.hover(function() { $(this).not('.selected').css({'background-color':'#BBB'}); // Highlight corresponding grid item if ( $content_grid.hasClass('visible') ) { var $this_href = $(this).find('a').attr('href'); $content_grid.find('a[href="' + $this_href + '"]').parent('div').css({'background':'#555'}).siblings('div:not(".selected")').css({'background':'transparent'}); } }, function() { $(this).not('.selected').css({'background-color':'transparent'}); if ( $content_grid.is(':visible') ) { $content_grid.find('div:not(".selected")').css({'background':'transparent'}); } }); // Dir_table: create link arrays var $dir_table_dir_link_arr = []; var $dir_table_file_link_arr = []; var $dir_table_file_ext_arr = []; $dir_table_row.not('.ignore,.invisible').find('a').each(function() { var $this_link = $(this).attr('href').toLowerCase(); if ( $this_link.endsWith('/') ) { $dir_table_dir_link_arr.push($this_link); return $dir_table_dir_link_arr; } else { var $this_link_ext = $this_link.slice($this_link.lastIndexOf('.')); $dir_table_file_link_arr.push($this_link); if ( $dir_table_file_ext_arr.indexOf($this_link_ext) < 0 ) { $dir_table_file_ext_arr.push($this_link_ext); } return $dir_table_file_link_arr, $dir_table_file_ext_arr; } }); // Dir_table: array of all dir_table links var $dir_table_link_arr = []; $dir_table_link_arr = $dir_table_dir_link_arr.concat($dir_table_file_link_arr); // Dir_table: array of image types var $image_ext_arr = ['.jpg','.jpeg','.png','apng','.gif','.bmp','webp']; // Dir_table: Classify items $dir_table_row.each(function() { var $this_href = $(this).find('a').attr('href').toString().toLowerCase(); // Directories or files if ( $this_href.endsWith('/') ) { $(this).addClass('dir'); } else { $(this).addClass('file'); } // pdf if ( $this_href.endsWith('.pdf') ) { $(this).addClass('pdf'); } else // images if ( $.inArray( $this_href.slice($this_href.lastIndexOf('.') ), $image_ext_arr ) != -1 ) { $(this).addClass('img'); } // invisibles if ( $this_href.slice($this_href.lastIndexOf('/') + 1 ) === '.' || $this_href.startsWith('.') || $(this).find('a').text().startsWith('.') ) { $(this).addClass('invisible'); if ( $settings.hide_invisibles === true ) { $(this).hide(); } } // ignored if ( $settings.ignore_files === true ) { for ( var i = 0; i < $settings.ignore_file_types.length; i++ ) { if ( $this_href.endsWith( $settings.ignore_file_types[i] ) ) { $(this).closest('#dir_table > tbody > tr').addClass('ignore').find('a').css({'color':'#888'}); if ( $settings.hide_ignored_files === true || $settings.hide_invisibles == true ) { $(this).hide(); } } } } // directories as Files and hide ignored files if ( $settings.apps_as_dirs === false ) { if ( $this_href.endsWith('.app/') ) { $(this).addClass('ignore app').find('a').css({'color':'#888'}); var $app_name = $(this).find('a').text().slice(0,-1); $(this).find('a').text($app_name); } } }); // end classify dir_table items $dir_table.appendTo('#sidebar'); // ***** End dir_table setup ***** // // ***************************** // // ***** SHOW/HIDE CONTENT ***** // function setContentTitle(el) { if ( el == $content_grid ) { $content_title.empty().prepend('Images from: /' + $current_dir_name); } else { $content_title.empty().prepend( $('.selected').find('a').text() ); } if ( $('.selected').hasClass('ignore') ) { $content_title.append(' (Ignored content)' ); } } function getDimensions(link, callback) { var img = new Image(); img.src = link; img.onload = function() { callback( this.width, this.height ); }; } function showThis(el,link) { if ( el == $content_image ) { el.find('img').attr('src',link); getDimensions( link, function( width, height ) { $content_title.append(' (' + width + 'px × ' + height + 'px)' ); }); } else if ( el == $content_embed ) { el.attr('type','application/pdf').attr('src',link + '?#zoom=100&scrollbar=1&toolbar=1&navpanes=1'); } else { el.attr('src',link); } unhideThis(el); } function showContentHeader() { $content_header.css({'display':'table'}); } function showPrevNextBtns() { if ( $dir_table.find('.img').length > 1 ) { $prev_btn.add($next_btn).css({'display':'block'}); } } function hidePrevNextBtns() { $prev_btn.add($next_btn).css({'display':'none'}); } function hideThis(el) { el.removeClass('visible').addClass('hidden').css({'z-index':'-1'}).hide(); } function unhideThis(el) { el.removeClass('hidden').addClass('visible').css({'z-index':'auto'}); if ( el == $content_grid ) { el.css({'display':'grid'}); showPrevNextBtns(); } else if ( el == $content_image) { el.show(); showPrevNextBtns(); } else { el.show(); } setContentTitle(el); showContentHeader(); } function closeThis(el) { if ( el == $content_grid ) { $content_grid.hide().empty(); } else if ( el == $content_image ) { $content_image.hide().find('img').removeAttr('src'); } else { el.removeClass('visible').hide().removeAttr('src'); hidePrevNextBtns(); $content_header.hide(); } } function emptyContentPane() { closeThis($content_image); closeThis($content_embed); closeThis($content_iframe); } $content_close_btn.on('click',function() { var $visible = $content_container.find('.visible'); var $hidden = $content_container.find('.hidden'); hideMenu(); if ( $visible == $content_grid && ( $hidden == $content_iframe || $hidden == $content_embed ) ) { var $this_content_src = $hidden.attr('src');//.replace(/%20/g,' '); $dir_table.find('a[href*="' + $this_content_src + '"]').each(function() { $(this).click(); }); } else if ( $visible == $content_image && $hidden == $content_grid ) { $content_grid.find('a[href="' + $dir_table.find('.selected').find('a').attr('href') + '"]').parent('div').addClass('selected').css({'background':'#666'}).siblings('div').removeClass('selected').css({'background':'transparent'}); } closeThis( $visible ); if ( $hidden.length ) { unhideThis($hidden); } scrollSidebar(); }); // ***** MAIN CLICK FUNCTION FOR SHOWING CONTENT ***** // $dir_table_row.on('click','a',function(e) { var $this_row = $(this).closest('#dir_table > tbody > tr'); var $this_link = 'file://' + $(this).attr('href'); $this_link = $this_link.slice($this_link.lastIndexOf('/') + 1 ); if ( $sidebar_wrapper.hasClass('unfocused') ) { sidebarFocus(); } hideMenu(); // if app, ignore or treat as directory if ( $this_row.hasClass('app') && $settings.apps_as_dirs === false ) { e.preventDefault(); } else if ( $this_row.hasClass('dir') ) { return; } else { e.preventDefault(); selectItem($this_row); if ( $content_grid.hasClass('visible') ) { hideThis($content_grid); } if ( $this_row.hasClass('ignore') ) { emptyContentPane(); showContentHeader(); } else if ( $this_row.hasClass('img') ) { closeThis($content_embed); closeThis($content_iframe); showThis($content_image,$this_link); showPrevNextBtns(); } else if ( $this_row.hasClass('pdf') ) { emptyContentPane(); showThis($content_embed,$this_link); } else { // iframe emptyContentPane(); showThis($content_iframe,$this_link); } } setContentTitle(); setContentHeight(); }); // File shortcuts: load directory then auto-select file $('.file_shortcut').on('click',function(e) { e.preventDefault(); var $this_link = $(this).attr('href'); var $this_dir = $this_link.slice(0,$this_link.lastIndexOf('/') ); window.location = $this_dir; }); $('#reload_btn').on('click',function() { $('.selected').find('a').click(); }); // END MAIN CLICK FUNCTIONS // Auto-select file from file shortcut list; // Limitations: only loads last file from list found in directory, doesn't know anything about which actual file shortcut was selected function autoSelectFile() { if ( $settings.file_shortcuts.length ) { for ( var i = 0; i < $settings.file_shortcuts.length; i++ ) { if ( $.inArray($settings.file_shortcuts[i], $dir_table_link_arr ) ) { $dir_table.find( 'a[href*="/' + $settings.file_shortcuts[i] + '"]').click(); } } } } autoSelectFile(); function selectItem(el) { $(el).addClass('selected').css({'background-color':'lightsteelblue'}).find('a').css({'font-weight':'bold','color':'#333'}); $(el).siblings().removeClass('selected').css({'background-color':'transparent'}).find('a').css({'font-weight':'normal'}); $(el).siblings('.ignore').find('a').css({'color':'#888'}); // select grid item var $selected_link = $(el).find('a').attr('href'); $content_grid.find('a[href="' + $selected_link + '"]').parent('div').addClass('selected').css({'background':'#666'}).siblings().removeClass('selected').css({'background':'transparent'}); scrollSidebar(); scrollGrid(); } function selectBlur(el) { $(el).css({'background-color':'#BBB'}).find('a').css({'font-weight':'normal','color':'#444'}); } function sidebarFocus() { $sidebar_wrapper.removeClass('unfocused').addClass('focused'); $content_pane.removeClass('focused').addClass('unfocused'); selectItem('.selected'); } function contentFocus() { $sidebar_wrapper.removeClass('focused').addClass('unfocused'); $content_pane.removeClass('unfocused').addClass('focused'); if ( $content_image.find('img').attr('src') !== undefined ) { $content_image.focus(); } selectBlur('.selected'); } // Scroll Behavior var $block = ''; if( $userAgent.indexOf('Firefox') > -1 ){ $block = 'start'; } else { $block = 'nearest'; } function scrollGrid() { if ( $content_grid.hasClass('visible') && $content_grid.find('.selected').length ) { $content_grid.find('.selected')[0].scrollIntoView({ behavior:'smooth',block:$block,inline:'nearest' }); } } function scrollSidebar() { if ( $sidebar.find('.selected').length ) { $sidebar.find('.selected')[0].scrollIntoView({ behavior:'smooth',block:$block,inline:'nearest' }); } } // Zoom Images $content_image.find('img').on('click',function() { if ( $(this).hasClass('default') ) { $(this).removeClass('default').css({'max-width':'','max-height':'','cursor':'zoom-out','top':'0','transform':'translateY(0%)'}); } else { $(this).addClass('default').css({'max-width':'100%','max-height':'calc(100% - 3px)','cursor':'zoom-in','top':'50%','transform':'translateY(-50%)'}); } }); // Focus content pane on click // $content_image.add($content_iframe).add($content_embed).on('click', contentFocus() ); // ***** KEYBOARD EVENTS ***** // $body.on('keydown',$dir_table,function(e) { var $selected = $dir_table.find('.selected'); var $selected_href = $selected.find('a').attr('href'); var $first_item = $dir_table_row.filter(':visible').first(); var $last_item = $dir_table_row.filter(':visible').last(); var $prev_item = $selected.prevAll('tr:visible').first(); var $next_item = $selected.nextAll('tr:visible').first(); var $prev_image = $selected.prevAll('tr.img:visible').first(); var $next_image = $selected.nextAll('tr.img:visible').first(); switch ( e.key ) { case 'ArrowUp': // Go to parent folder if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { window.location = $parent_dir_link; break; } // Default action when content pane is focused if ( $sidebar_wrapper.hasClass('unfocused') ) { return; } if ( $first_item.hasClass('selected') ) { break; } else if ( $selected.length < 1 && $last_item.hasClass('dir') ) { emptyContentPane(); selectItem($last_item); } else if ( $prev_item.length && $prev_item.hasClass('dir') ) { emptyContentPane(); selectItem($prev_item); } else if ( $selected.length < 1 ) { $last_item.find('a').click(); } else { e.preventDefault(); $prev_item.find('a').click(); } break; case 'ArrowDown': if ( (e.ctrl || e.metaKey) && $selected.hasClass('app') && $settings.apps_as_dirs === false ) { return; } else if ( $sidebar_wrapper.hasClass('unfocused') ) { return; } else if ( (e.ctrl || e.metaKey) && $selected.hasClass('dir') ) { window.location = $selected_href; break; } if ( $last_item.hasClass('selected') ) { e.preventDefault(); } else if ( $selected.length < 1 && $first_item.hasClass('dir') ) { selectItem($first_item); } else if ( $selected.length < 1 ) { $first_item.find('a').click(); } else if ( $next_item.length > 0 && $next_item.hasClass('dir') ) { e.preventDefault(); emptyContentPane(); selectItem($next_item); } else { e.preventDefault(); $next_item.find('a').click(); } break; case 'ArrowLeft': if ( (e.ctrl || e.metaKey) || ( e.ctrl && e.metaKey ) ) { return; } else if ( $sidebar_wrapper.hasClass('unfocused') ) { return; } // Navigate Grid or Images if ( $content_grid.hasClass('visible') ) { if ( $selected.length !== 1 ) { selectItem($dir_table_row.filter('.img').last() ); } else { selectItem($prev_image); } } else if ( $content_image.hasClass('visible') ) { $prev_image.find('a').click(); } else { $dir_table_row.filter('.img').last().find('a').click(); } break; case 'ArrowRight': if ( (e.ctrl || e.metaKey) || ( e.ctrl && e.metaKey ) ) { return; } else if ( $sidebar_wrapper.hasClass('unfocused') || $selected.hasClass('ignore') ) { return; } // Navigate Grid or Images if ( $selected.hasClass('dir') ) { window.location = $selected_href; // Open directory } else if ( $content_grid.hasClass('visible') ) { if ( $selected.length == 0 ) { selectItem($dir_table_row.filter('.img').first() ); } else { selectItem($next_image); } } else if ( $content_image.hasClass('visible') ) { $next_image.find('a').click(); } else { $dir_table_row.filter('.img').first().find('a').click(); } break; case 'Enter': // Open directories (or ignore) if ( $selected.hasClass('app') && $settings.apps_as_dirs === false ) { break; } else if ( $selected.hasClass('dir') ) { window.location = $selected_href; } else if ( $selected.hasClass('file') ) { $selected.find('a').click(); } else { return; } break; case 'i': // Toggle Invisibles with Command-i if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { e.preventDefault(); e.stopPropagation(); $inv_checkbox.click(); } break; case 'w': // Close content pane if Close button visible with Command-w if ( (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) && $content_close_btn.is(':visible') ) { e.preventDefault(); e.stopPropagation(); $content_close_btn.click(); } break; case 'Tab': // Tab cannot blur focussed iframe $(':focus').blur(); if ( $sidebar_wrapper.hasClass('focused') ) { contentFocus(); } else if ( $sidebar_wrapper.hasClass('unfocused') ) { $('.selected').click(); sidebarFocus(); } break; } // end switch // Cmd/Ctrl + g: Show image Grid, with override for default browser binding if ( e.key == "g" && (navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey) ) { $content_grid_btn.click(); e.preventDefault(); e.stopPropagation(); } // Cmd/Ctrl + Shift + O: Open selected item in new window if ( e.key == "o" && (navigator.platform.match("Mac") ? e.metaKey && e.shiftKey : e.ctrlKey && e.shiftKey ) ) { window.open($selected_href); } }); // ***** END KEYBOARD EVENTS ***** // // ***** IMAGE NAVIGATION ***** // $prev_btn.on('mouseenter',function() { $(this).css({'opacity':'1'}); }).on('mouseleave',function() { $(this).css({'opacity':'0.6'}); }); $next_btn.on('mouseenter',function() { $(this).css({'opacity':'1'}); }).on('mouseleave',function() { $(this).css({'opacity':'0.6'}); }); $prev_btn.on( 'click', function(event) { var e = $.Event("keydown"); e.key = 'ArrowLeft'; $dir_table.trigger(e); }); $next_btn.on( 'click', function(event) { var e = $.Event("keydown"); e.key = 'ArrowRight'; $dir_table.trigger(e); }); // Edit Button -- not implemented // $content_edit_btn.on('click',function() { // var $selected_url = $('.selected').find('a').attr('href'); // window.open($selected_url); // }); // GRID BUTTON & IMAGE GRID // Show grid button only if images are found in directory function show_grid_btn() { if ( $dir_table.find('.img').length ) { $content_grid_btn.show(); } } show_grid_btn(); // create grid items var $grid_item_el = $( '
    ' + '' + '' + '' + '
    ' ); var $grid_items_arr; function gridItems() { $grid_items_arr = []; $dir_table_link.each(function() { var $this_link = $(this).attr('href'); var $this_ext = $this_link.toLowerCase().slice($this_link.lastIndexOf('.')); if ( $.inArray($this_ext,$image_ext_arr) != -1 ) { $grid_item_el.find('a').attr('href',$this_link).find('img').attr('src',$this_link); $grid_items_arr.push($grid_item_el.clone()); } return $grid_items_arr; }); } // Grid Button Click $content_grid_btn.on('click',function() { gridItems(); $content_grid.empty().append( $grid_items_arr ); selectItem( $dir_table.find('.selected') ); hideThis($('.visible') ); unhideThis($content_grid); setContentHeight(); }); // GRID ITEMS // Grid Item Hover $content_grid.on('mouseenter','> div:not(".selected")',function() { var $this_link = $(this).find('a').attr('href'); $(this).css({'background':'#555'}); $dir_table.find('a[href="' + $this_link + '"]').css({'background':'#BBB'}); }).on('mouseleave','> div:not(".selected")',function() { var $this_link = $(this).find('a').attr('href'); $(this).css({'background':'transparent'}); $dir_table.find('a[href="' + $this_link + '"]').css({'background':'transparent'}); }); // Grid Item Click $content_grid.on('click','> div',function(e) { e.preventDefault(); var $this_link = $(this).find('a').attr('href'); $dir_table.find('a[href="' + $this_link + '"]').click(); }); // ***** END IMAGE GRID ***** // // Resize Sidebar/Content Pane $handle.on('mousedown',function(f) { f.stopPropagation(); var $startX = f.pageX; var $sidebar_width = $sidebar_wrapper.width(); var $window_width = window.innerWidth; $content_mask.show(); // needed to prevent interactions with iframe $sidebar_wrapper.css({'-webkit-user-select':'none','-moz-user-select':'none','user-select':'none'}); $(document).on('mousemove',function(e) { e.stopPropagation(); var $deltaX = e.pageX - $startX; if ( e.pageX > 200 && e.pageX < $window_width - 200 ) { $sidebar_wrapper.css({'width':$sidebar_width + $deltaX + 'px'}); $content_pane.css({'width':($window_width - $sidebar_width) - $deltaX + 'px'}); } headerHeight(); setContentHeight(); }); $(document).on('mouseup',function() { $content_mask.hide(); $sidebar_wrapper.css({'-webkit-user-select':'auto','-moz-user-select':'auto','user-select':'auto'}); $(document).off('mousemove'); }); }); })();