Supercharged Local Directory File Browser (Chrome browsers only)

Make file:/// directory ("Index of...") pages actually useful. Adds navigation links, file preview pane, user-defined shortcuts, filtering, keyboard navigation, more.

目前為 2018-02-24 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Supercharged Local Directory File Browser (Chrome browsers only)
// @version      1.1
// @description  Make file:/// directory ("Index of...") pages actually useful. Adds navigation links, file preview pane, user-defined shortcuts, filtering, keyboard navigation, more.
// @author       Gaspar Schott
// @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.

// @namespace https://gf.qytechs.cn/users/16170
// ==/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 user name
        						'MacBookPro',
                                // Shortcuts: add directories and files here; you may also 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','Applications/AMPPS/www'],
                                // ['C:/Users','C:/Program Files','C:/Windows'],
			user_shortcuts:     // User directories; you must enter your user_name above.
        						['Documents','Documents/02 Library','Documents/02 Library/P Literature','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.
								['Applications/AMPPS/www/timeline/Timeline.html','Applications/AMPPS/www/invoicing/html5-invoice/index.html'],
	        hide_invisibles:    // Mac OS only: Files beginning with a "." will be ignored.
								true,
            ignoreFiles:       	// If true, ignored file types will not be loaded in the content pane;
            					// If false, they will be treated as normal files, meaning the browser will attempt to download file types it can't handle.
								true,
            ignoreFile_types:   // ignore files with these extensions
            					['exe','.doc','.docx','ppt','pptx','xls','xlsx','odt','odp','msi','dll','rtf','indd','idml','.pages','.tif','.zip','pkg','.swf','.pls','.ics','.ds_store','alias','.dmg','.gz','.qxp','icon.jpg','thumbs.db'], // lowercase
            show_ignored_files: // If true, show ignored files grayed out, if false, don't show them at all.
								true,
            apps_as_dirs:       // Mac OS only: if true, treat apps as directories; allows app contents to be examined
								false,
            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,'/<wbr>').replace(/_/g,'_<wbr>').replace(/—/g,'—<wbr>').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 = '<li><a href="file:///' + x[i] + '" style="margin:0;padding:4px 6px;display:block;text-indent:0;text-decoration:none;color:#333;">' + y[i] + '</a></li>';
        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(/<a /g,'<a class="file_shortcut" ').replace(/%20/g,' ');
            return $file_shortcut_items;
		}
	};

    // ***** END BUILD MENUS ***** //


    // ***** BUILD UI ELEMENTS ***** //

    // ***** SIDEBAR ELEMENTS ***** //

	// 1. Parent Directory Menu
    var $parent_dir_menu = $(
    	'<nav id="parent_dir_menu" style="margin:0;padding:0;display:table;width:100%;">' +
	    	'<a href="" style="width:100%;padding:0;display:table-cell;text-align:center;vertical-align:middle;text-decoration:none;">&and;</a>' +
    	'</nav>'
    	);
    $parent_dir_menu.find('a').attr('href',$parent_dir_link);

    // 2. Current Directory Name and Parents Directory Menu
	var $parents_dir_menu = $(
		'<nav id="parents_dir_menu" style="margin:0;padding:0;text-align:center;">' +
			'<div style="padding:4px 6px;display:inline-block;text-align:center;vertical-align:middle;overflow:hidden;cursor:pointer;hyphens:none;"></div>' +
			'<ul class="menu" style="display:none;margin:0;padding:0;position:absolute;top:;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;"></ul>' +
		'</nav>'
		);
	$parents_dir_menu.find('div').append( $current_dir_path );
	$parents_dir_menu.find('ul').append( $parents_dir_menu_arr() );

    // 3. Shortcuts Menu
    var $divider = $(
    	'<li><hr style="margin:0;border-bottom:0;"></li>'
    	);
    var $bookmark_this_dir = $('<li><a id="add_to_bookmarks" href="#" style="margin:0;padding:4px 6px;display:block;text-indent:0;text-decoration:none;color:#333;">Add directory to bookmarks</a></li>');
    var $settings_menu_item = $('<li><a id="show_settings" href="#" style="margin:0;padding:4px 6px;display:block;text-indent:0;text-decoration:none;color:#333;">Settings</a></li>)');
	var $shortcuts_menu = $(
		'<nav id="shortcuts_menu" style="margin:0;padding:0;">' +
			'<div style="width:6em;display:table-cell;text-align:center;vertical-align:middle;font-size:18px;cursor:pointer;">' +
				'&equiv;' +
			'</div>' +
			'<ul class="menu" style="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;"></ul>' +
		'</nav>'
		);
	$shortcuts_menu.find('ul').append( $root_shortcuts_menu_arr(), $divider, $user_shortcuts_menu_arr(), $divider.clone(), $file_shortcuts_menu_arr(), $divider.clone(), $bookmark_this_dir, $settings_menu_item );

    // 4. Details Button
	var $details_btn = $(
		'<button id="details_btn" style="margin:1em 0.5em 0.5em;clear:both" tabindex="-1">' +
			'<span id="show">Show details</span><span id="hide" style="display:none">' +
				'Hide details' +
			'</span>' +
		'</button>'
		);

    // 5. Invisibles Checkbox
	var $inv_checkbox = $(
		'<label id="inv_checkbox" for="inv_checkbox">' +
			'<input type="checkbox" name="inv_checkbox" tabindex="-1" />' +
			'Hide Invisibles' +
		'</label>'
		);

    // 6. Image Grid Button
    var $content_grid_btn = $(
    	'<div id="grid_btn" style="margin:0 0 -0.5em 1em;width:16px;height:16px;display:none;position:absolute;top:1em;right:0.5em;line-height:0;cursor:pointer;outline:0;opacity:0.7;" tabindex="-1" title="Show Image Grid">' +
    		'<span style="width:7px;height:7px;display:inline-block;box-sizing:border-box;border:solid 2px #666;margin-right:2px;margin-bottom:2px;"></span>' +
	    	'<span style="width:7px;height:7px;display:inline-block;box-sizing:border-box;border:solid 2px #666;margin-bottom:2px;"></span>' +
    		'<span style="width:7px;height:7px;display:inline-block;box-sizing:border-box;border:solid 2px #666;margin-right:2px;"></span>' +
    		'<span style="width:7px;height:7px;display:inline-block;box-sizing:border-box;border:solid 2px #666;"></span>' +
	    '</div>'
	    );

    // ASSEMBLE SIDEBAR HEADER
	var $sidebar_header = $(
		'<table id="sidebar_header" style="width:100%;position:relative;border:0;">' +
			'<thead>' +
				'<tr style="border-bottom:solid 1px grey;background-color:#BBB;">' +
					'<th colspan="3" style="padding:4px;font-weight:normal;font-size:0.875em;letter-spacing:0.5em;cursor:default;">' +
						'INDEX OF' +
					'</th>' +
				'</tr>' +
			'</thead>' +
			'<tbody>' +
				'<tr style="border-bottom:solid 1px grey;background-color:#BBB;">' +
					'<td style="width:24px;max-width:24px;min-width:24px;padding:0;"></td>' +
					'<td style="padding:0;border-left:solid 1px grey;border-right:solid 1px grey;"></td>' +
					'<td style="width:24px;max-width:24px;min-width:24px;padding:0;"></td>' +
				'</tr>' +
				'<tr>' +
					'<td colspan="3" style="position:relative;"></td>' +
				'</tr>' +
			'</tbody>' +
		'</table>'
	);
	$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 = $(
    	'<div id="sidebar" style="background-color:lightgray;height:100%;min-height:100%;overflow-wrap:break-word;box-sizing:border-box;border-right:solid 1px gray;font-size:0.875em;"></div>'
    	);
    $sidebar.append($sidebar_header);

    // 8. Resize Handle
    var $handle = $(
    	'<div id="handle" style="width:8px;position:absolute;top:0;right:-4px;bottom:0;z-index:1000;cursor:col-resize"></div>'
    	);

    // Assemble Sidebar Elements
	var $sidebar_wrapper = $(
		'<td id="sidebar_wrapper" class="focused" style="width:25%;will-change:width;padding:0;position:relative;border:0;background:lightgray"></td>'
		);
	$sidebar_wrapper.append( $sidebar, $handle );

    // ***** END SIDEBAR ELEMENTS ***** //

	// ***** BUILD CONTENT PANE ELEMENTS ***** //

    // 1. Edit Button Element
	var $content_edit_btn = $(
		'<td style="width:4em;padding:4px 6px 3px;vertical-align:middle;">' +
			'<button id="edit_btn" style="display:none;" tabindex="-1">Edit</button>' +
		'</td>'
		);

    // 2. Title Element
    var $content_title = $(
    	'<td id="content_title" style="padding:4px 1em 3px;vertical-align:middle;word-break:break-word;"></td>'
	    );

    // 3. Close Button Element
	var $content_close_btn = $(
		'<td style="width:4em;padding:4px 6px 3px;vertical-align:middle;">' +
			'<button id="close_btn" tabindex="-1">Close</button>' +
		'</td>'
		);

    // 4. Content Header Element
    var $content_header = $(
	    '<header id="content_header" style="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;text-transform:uppercase;">' +
    		'<table style="width:100%;padding:7px 12px 5px;"><tbody><tr></tr></tbody></table>' +
	    '</header>'
	    );
    $content_header.find('tr').append($content_edit_btn, $content_title, $content_close_btn);

    // 5. Content Mask Element
    var $content_mask = $(
    	'<div id="content_mask" style="position:absolute;top:0;right:0;bottom:0;left:0;display:none;z-index:2000;"></div>'
    	);
    	$content_mask.css({'height':window.innerHeight + 'px'});

    // 6. Image Grid Element
    var $content_grid = $(
    	'<div id="content_grid" style="width:auto;padding:0;display:none;position:absolute;right:0;bottom:0;left:0;overflow:auto;background:#333;grid-gap:0;grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));grid-template-rows: repeat(auto, 150px);"></div>'
    	);

    // 7. Image Element
    var $image = $(
	   	'<img class="default" style="width:auto;height:auto;max-width:100%;max-height:calc(100% - 3px);cursor:zoom-in;-webkit-user-select:none;position:relative;top:50%;transform:translateY(-50%);" />'
    	);
    var $content_image = $(
	    '<div id="content_image" style="padding:2em;position:absolute;top:0;right:0;bottom:0;left:0;display:none;background:#333;overflow:auto;text-align:center;"></div>'
    	);
    $content_image.append($image);

    // 8. Pdf (embed) Element
    var $content_embed = $(
        '<embed id="content_embed" style="width:100%;height:100%;position:absolute;0;right:0;bottom:0;left:0;display:none;" name="plugin" id="plugin" type="application/pdf" tabindex="0"></embed>'
        );

    // 9. Iframe Element
    var $content_iframe = $(
        '<iframe id="content_iframe" style="width:100%;height:100%;padding:0;position:absolute;top:0;right:0;bottom:0;left:0;display:none;border:0;" sandbox="allow-scripts allow-same-origin allow-modals" tabindex="0"></iframe>'
    );

    // 10. Object Element
//	var $content_object = $(
//		'<object id="content_object" style="width:100%;height:100%;padding:0;position:absolute;top:0;right:0;bottom:0;left:0;display:none;border:0;" tabindex="0"></object>'
//    );

    // 9. Next/Prev Elements
    var $prev_btn = $('<div id="prev_btn" style="padding:0 1em;display:none;position:absolute;top:0;bottom:0;left:0;z-index:100;opacity:0.6;"></div>');
    var $next_btn = $('<div id="next_btn" style="padding:0 1em;display:none;position:absolute;top:0;bottom:0;right:0;z-index:100;opacity:0.6;"></div>');
    var $svg_arrow = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' 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>")';
    $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 = $('<section id="content_container" style="width:100%;height:100%;position:relative;top:0;overflow:visible;"></section>');
	$content_container.append( $content_header, $content_mask, $content_grid, $content_image, $content_embed, $content_iframe );

    // Assemble Content Pane Elements
	var $content_pane = $('<td id="content_pane" class="unfocused" style="width:75%;will-change:width;padding:0;border:0;background:white;position:relative;"></td>');
	$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 = $('<table id="main_content" style="width:100%;height:100%;border:0;"><tbody><tr></tr></tbody></table>');
	$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);

    // SETTINGS

    $settings_menu_item.find('a').on('click',function(){
//        GM_config.open();
//        $('#settings_dialog').css({'position':'absolute','top':'4em','left':'15%'});
//        $('#settings_dialog_field_blacklist_terms').focus().add('#gnf_settings_dialog_field_blacklist_sources').css({'font-family':'monospace'});
//        $('#settings_dialog_closeBtn').text('Cancel');
//        return false;
    });


    // ***** 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();

    // Sidebar header menus hover styles
	$parents_dir_menu.add($shortcuts_menu).hover(function() {
        $(this).find('.menu:not(:empty)').show();
    }, function() {
        $(this).find('.menu').hide();
	});

	$parents_dir_menu.add($shortcuts_menu).find('li').hover(function() {
        $(this).css({'background-color':'#BBB'});
    }, function() {
        $(this).css({'background-color':'lightgrey'});
	});

    // Sidebar header invisibles button
    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').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.ignoreFiles === true ) {
            for ( var i = 0; i < $settings.ignoreFile_types.length; i++ ) {
                if ( $this_href.endsWith( $settings.ignoreFile_types[i] ) ) {
                    $(this).addClass('ignore').find('a').css({'color':'#888'});
                    if ( $settings.show_ignored_files === false ) {
                        $(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(' <span style="text-transform:lowercase;">(' + width + 'px &times; ' + height + 'px</span>)' );
            });
        } 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');

        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();
		}

        // 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;
	});

    // 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',function() {
        contentFocus();
    });

    // ***** KEYBOARD EVENTS ***** //

    $body.on('keydown',$dir_table,function(e) {

        $dir_table_row = $dir_table_row.filter(':visible');
        var $selected = $dir_table_row.filter('.selected');
        var $selected_href = $selected.find('a').attr('href');
        var $first_item = $dir_table_row.first();
        var $last_item = $dir_table_row.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.last('.img') );
    	            } else {
        	            selectItem($prev_image);
                	}
                } else if ( $content_image.hasClass('visible') ) {
                    $prev_image.find('a').click();
                }
                break;

            case 'ArrowRight':

                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.first('.img') );
    	            } else {
        	            selectItem($next_image);
                	}
                } else if ( $content_image.hasClass('visible') ) {
                    $next_image.find('a').click();
                } else // Open directory
                if ( $selected.hasClass('dir') ) {
                    window.location = $selected_href;
                }
                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

        // Show Grid: Cmd/Ctrl + g, 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();
        }
    });

    // ***** 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_items_arr = [];
    function gridItems() {
        $dir_table_link.each(function() {
            var $this_link = $(this).attr('href');
            var $this_ext = $this_link.toLowerCase().slice($this_link.lastIndexOf('.'));
            var $grid_item_el = $(
            	'<div class="grid_item" style="display:inline-block;width:150px;height:150px;float:left;text-align:center;vertical-align:middle;">' +
            		'<a href="">' +
            			'<img src="" style="width:auto;height:auto;max-width:128px;max-height:128px;position:relative;top:50%;transform:translateY(-50%);opacity:0.8;" />' +
	            	'</a>' +
	            '</div>'
	            );
            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);
            }
            return $grid_items_arr;
        });
    }

    // Grid Button Click
    $content_grid_btn.on('click',function() {
        $content_grid.empty();

        gridItems();
        $content_grid.append( $grid_items_arr );
        // end create grid items

		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');
        });
    });

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址