// ==UserScript== // @name Supercharged Local Directory File Browser (Chrome browsers only) // @version 1.3 // @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.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 // @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; Windows users should add the drive letter. ['Applications','Library','Users','Volumes'], // ['C:/Users','C:/Program Files','C:/Windows'], user_shortcuts: // User directories; you must enter your user_name above. ['Documents','Downloads','Library'], file_shortcuts: // Add specific file paths, e.g.: 'Users/MyUserName/Documents/MyDocument.html' // These files will be selected 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], 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 true }; // ***** 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(/' + '' + '' ); $parent_dir_menu.find('a').attr('href',$parent_dir_link); // 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 $shortcuts_menu = $( '' ); $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 $content_grid_btn = $( '' ); // 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 = $(''); if ( $settings.dark_mode === true ) { $content_pane.css({'background':'#333'}); } $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 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','height':'100%','font-family':'lucidagrande,"fira sans",helvetica,sans-serif','font-size':'13px','hyphens':'auto','overflow':'hidden'}); $body.prepend($main_content); // ***** SIDEBAR ***** // // Sidebar 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'); // ***** Sidebar Header ***** // // Sidebar header menus 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(); // MENUS // Show menus on click function showMenu(x) { if ( $(x).parents('td').siblings('td').find('.clicked').length ) { hideMenu(); } $(x).toggleClass('clicked').find('.menu').toggle(); } function hideMenu() { $('.clicked').removeClass('clicked').find('.menu').hide(); } $parents_dir_menu.add($shortcuts_menu).on('click',function(e) { e.stopPropagation(); showMenu(this); }); $(document).on('click',function() { hideMenu(); }); // Menu hover effects $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 if ( $settings.hide_invisibles === true ) { $inv_checkbox.find('input').prop('checked',true); } $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'); }); // Sidebar header details button $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 setup ***** // $dir_table.detach().attr('id','dir_table'); // 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'}); $dir_table_head.css({'text-align':'left'}); $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'}); $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'}); $dir_table_item_name.css({'display':'block'}); $dir_table_details.add($dir_table_head_details).css({'font-size':'0.875em','text-align':'left','height':'1.5em','vertical-align':'top'}).hide(); $dir_table_details.not('th').css({'padding':'0 24px 4px'}); // Directory Table Hover $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 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; } }); // 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); // array of image types var $image_ext_arr = ['.jpg','.jpeg','.png','apng','.gif','.bmp','webp']; // Classify dir_table items $dir_table_row.each(function() { var $this_href = $(this).find('a').text().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.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).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('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'); } function scrollGrid() { if ( $content_grid.hasClass('visible') && $content_grid.find('.selected').length ) { $content_grid.find('.selected')[0].scrollIntoView({ behavior:'smooth',block:'nearest',inline:'nearest' }); } } function scrollSidebar() { if ( $sidebar.find('.selected').length ) { $sidebar.find('.selected')[0].scrollIntoView({ behavior:'smooth',block:'nearest',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() { for (var i = 0; i < $image_ext_arr.length; i++ ) { if ( $dir_table_file_ext_arr.indexOf($image_ext_arr[i]) != -1 ) { $content_grid_btn.show(); } } } show_grid_btn(); // Grid Button Hover $content_grid_btn.hover(function() { $(this).css({'opacity':1}); }, function() { $(this).css({'opacity':0.7}); }); // 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'); }); }); })();