Supercharged Local Directory File Browser

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

Version vom 23.03.2018. Aktuellste Version

// ==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://greatest.deepsurf.us/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 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,'/<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;white-space:normal;">' + 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 $up_arrow = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\'	 width=\'12.728px\' height=\'7.779px\' viewBox=\'0 0 12.728 7.779\' enable-background=\'new 0 0 12.728 7.779\' xml:space=\'preserve\'><path fill=\'%23444444\' d=\'M6.364,2.828l4.95,4.949l1.414-1.414L6.364,0l0,0L0,6.363l1.413,1.416L6.364,2.828\'/></svg>")';
    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;opacity:0.7"></a>' +
    	'</nav>'
    	);
    $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 = $(
		'<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;white-space:normal;"></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;box-shadow: 0px 2px 3px -2px #888;"></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 $menu_icon = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'13px\' height=\'10px\' viewBox=\'0 0 13 10\' enable-background=\'new 0 0 13 10\' xml:space=\'preserve\'><rect fill=\'%23444444\' width=\'13\' height=\'2\'/><rect y=\'4\' fill=\'%23444444\' width=\'13\' height=\'2\'/><rect y=\'8\' fill=\'%23444444\' width=\'13\' height=\'2\'/></svg>")';
    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;opacity:0.7"></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;box-shadow: 0px 2px 3px -2px #888;"></ul>' +
		'</nav>'
		);
    $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 = $(
		'<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 $grid_icon = 'url("data:image/svg+xml;utf8,<svg version=\'1.1\' id=\'Layer_1\' xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' x=\'0px\' y=\'0px\' width=\'16px\' height=\'16px\' viewBox=\'0 0 16 16\' enable-background=\'new 0 0 16 16\' xml:space=\'preserve\'><g><path fill=\'%23666666\' d=\'M5,2v3H2V2H5 M7,0H0v7h7V0L7,0z\'/></g><g><path fill=\'%23666666\' d=\'M14,2v3h-3V2H14 M16,0H9v7h7V0L16,0z\'/></g><g><path fill=\'%23666666\' d=\'M5,11v3H2v-3H5 M7,9H0v7h7V9L7,9z\'/></g><g><path fill=\'%23666666\' d=\'M14,11v3h-3v-3H14 M16,9H9v7h7V9L16,9z\'/></g></svg>")';
    var $content_grid_btn = $(
    	'<div id="grid_btn" style="margin:0 0 -0.5em 1em;width:17px;height:17px;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">' +
	    '</div>'
	    );
    $content_grid_btn.css({'background':$grid_icon + 'no-repeat center 100%'});

    // ASSEMBLE SIDEBAR HEADER
	var $sidebar_header = $(
		'<table id="sidebar_header" style="width:100%;position:relative;border:0;user-select:none;border-collapse:collapse;">' +
			'<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;float:left;"></td>' +
					'<td style="width:100%;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;float:right;"></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:'+ window.innerHeight +'px;min-height:100%;overflow-wrap:break-word;box-sizing:border-box;border-right:solid 1px gray;font-size:0.875em;color:#333;"></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%;min-width:220px;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. Reload Button Element
	var $content_reload_btn = $(
		'<td style="width:6em;padding:4px 6px 3px;vertical-align:middle;float:left;">' +
			'<button id="reload_btn" style="hyphens:none;" tabindex="-1">Reload</button>' +
		'</td>'
		);

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

    // 3. Close Button Element
	var $content_close_btn = $(
		'<td style="width:6em;padding:4px 6px 3px;vertical-align:middle;float:right;">' +
			'<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;">' +
    		'<table style="width:100%;padding:7px 12px 5px;border-collapse:collapse;"><tbody><tr></tr></tbody></table>' +
	    '</header>'
	    );
    $content_header.find('tr').append($content_reload_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%;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;border-collapse:collapse;"><tbody><tr></tr></tbody></table>');
	$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 = '<style type="text/css">button { padding:0; } thead {font-size:100%;} #dir_table .dir::before {position:absolute;} </style>';
    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(' <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');
        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 = $(
        '<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>'
    );
    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');
        });
    });

})();