mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 11:20:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			769 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			769 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			HTML
		
	
	
		
			Executable File
		
	
	
	
	
| <!DOCTYPE html>
 | |
| <html>
 | |
| <style>
 | |
| 
 | |
| .container {
 | |
| 	display: inline-block;
 | |
| 	position: absolute;
 | |
| 
 | |
| 	top: 100px;
 | |
| 	left: 100px;
 | |
| 
 | |
| 	box-shadow: rgba(0,0,0,0.5) 0.1em 0.1em 0.4em;
 | |
| 
 | |
| 	/* make the container expand only to a certain size, then scroll */
 | |
| 	/* XXX need to:
 | |
| 		- auto-scroll vertically
 | |
| 		- use custom scroll bars
 | |
| 		- shorten path to fit width
 | |
| 			i.e. manage width manually when at max-width...
 | |
| 	*/
 | |
| 	max-height: 60vh;
 | |
| 	max-width: 60vw;
 | |
| 	height: auto;
 | |
| 	width: auto;
 | |
| 	overflow-y: auto;
 | |
| 	overflow-x: hidden;
 | |
| }
 | |
| 
 | |
| .browse {
 | |
| 	display: inline-block;
 | |
| 	min-width: 300px;
 | |
| 	width: initial;
 | |
| 	background: gray;
 | |
| 	color: rgba(255,255,255,0.8);
 | |
| 	padding: 5px;
 | |
| 	font-family: sans-serif;
 | |
| }
 | |
| /*
 | |
| .browse:not(:focus) {
 | |
| 	opacity: 0.8;
 | |
| }
 | |
| */
 | |
| .browse .v-block {
 | |
| 	width: 100%;
 | |
| 	height: auto;
 | |
| 
 | |
| 	box-sizing: border-box;
 | |
| 
 | |
| 	border-top: 1px solid rgba(255,255,255, 0.3);
 | |
| }
 | |
| .browse .v-block:first-of-type {
 | |
| 	border-top: none;
 | |
| }
 | |
| .browse .v-block:empty {
 | |
| 	display: none;
 | |
| }
 | |
| 
 | |
| .browse .title {
 | |
| 	font-weight: bold;
 | |
| 	color: rgba(255,255,255,0.9);
 | |
| 	padding: 5px;
 | |
| 	padding-left: 10px;
 | |
| 	padding-right: 10px;
 | |
| }
 | |
| 
 | |
| .browse .path {
 | |
| 	padding: 5px;
 | |
| 	padding-left: 10px;
 | |
| 	padding-right: 10px;
 | |
| 	white-space: nowrap;
 | |
| }
 | |
| .browse .path:empty {
 | |
| 	display: block;
 | |
| }
 | |
| .browse .path:before {
 | |
| 	content: "/";
 | |
| }
 | |
| .browse .path .dir {
 | |
| 	display: inline-block;
 | |
| }
 | |
| .browse .path .dir:after {
 | |
| 	content: "/";
 | |
| }
 | |
| /* XXX need to make this resizable up but only to a certain size (~80vh) */
 | |
| /*
 | |
| .browse .list {
 | |
| 	max-height: 50vh;
 | |
| }
 | |
| .browse .list:empty {
 | |
| 	display: block;
 | |
| }
 | |
| */
 | |
| .browse .list div {
 | |
| 	padding: 5px;
 | |
| 	padding-left: 10px;
 | |
| 	padding-right: 10px;
 | |
| }
 | |
| 
 | |
| .browse:focus .list div.selected,
 | |
| .browse .path .dir:hover,
 | |
| .browse .list div:hover {
 | |
| 	color: white;
 | |
| 	background: rgba(0,0,0, 0.05);
 | |
| }
 | |
| 
 | |
| .browse:focus .list div.selected {
 | |
| 	background: rgba(0,0,0, 0.1);
 | |
| 	box-shadow: rgba(0,0,0,0.2) 0.1em 0.1em 0.2em; 
 | |
| }
 | |
| 
 | |
| .browse .list div.selected {
 | |
| 	background: rgba(0,0,0, 0.08);
 | |
| }
 | |
| 
 | |
| 
 | |
| </style>
 | |
| 
 | |
| <script src="../ext-lib/jquery.js"></script>
 | |
| <script src="../ext-lib/jquery-ui.js"></script>
 | |
| 
 | |
| <script src="../lib/jli.js"></script>
 | |
| 
 | |
| <script src="../ext-lib/require.js"></script>
 | |
| 
 | |
| <script>
 | |
| 
 | |
| var TREE = {
 | |
| 	dir_a: {},
 | |
| 	dir_b: {
 | |
| 		file1: 'this is a file',
 | |
| 		file2: 'this is a file',
 | |
| 		file3: 'this is a file',
 | |
| 	},
 | |
| 	dir_c: {
 | |
| 		file1: 'this is a file',
 | |
| 		dir_b: {
 | |
| 			file1: 'this is a file',
 | |
| 		},
 | |
| 		dir_c: {},
 | |
| 		dir_d: {},
 | |
| 		dir_e: {},
 | |
| 		dir_f: {},
 | |
| 		dir_g: {},
 | |
| 		dir_h: {},
 | |
| 		dir_i: {},
 | |
| 		dir_j: {},
 | |
| 		dir_k: {},
 | |
| 		dir_l: {},
 | |
| 		dir_m: {},
 | |
| 		dir_o: {},
 | |
| 		dir_p: {},
 | |
| 		dir_q: {},
 | |
| 		dir_r: {},
 | |
| 		dir_s: {},
 | |
| 		dir_t: {},
 | |
| 		dir_u: {},
 | |
| 	},
 | |
| 	file: 'this is a file',
 | |
| }
 | |
| // add some recursion for testing...
 | |
| TREE.dir_d = TREE.dir_c.dir_b
 | |
| TREE.dir_a.tree = TREE
 | |
| TREE.dir_c.tree = TREE
 | |
| TREE.dir_c.dir_b.tree = TREE
 | |
| 
 | |
| 
 | |
| function skipFiles(e, v){
 | |
| 	return typeof(v) != typeof('str')
 | |
| }
 | |
| 
 | |
| function make(title){
 | |
| 	var browser = $('<div>')
 | |
| 		.addClass('browse')
 | |
| 		// make thie widget focusable...
 | |
| 		// NOTE: tabindex 0 means automatic tab indexing and -1 means 
 | |
| 		//		focusable bot not tabable...
 | |
| 		//.attr('tabindex', -1)
 | |
| 		.attr('tabindex', 0)
 | |
| 		// focus the widget if something inside is clicked...
 | |
| 		.click(function(){
 | |
| 			$(this).focus()
 | |
| 		})
 | |
| 		.append($('<div>')
 | |
| 		       .addClass('v-block title')
 | |
| 		       .text(title))
 | |
| 		.append($('<div>')
 | |
| 		       .addClass('v-block path'))
 | |
| 		.append($('<div>')
 | |
| 		       .addClass('v-block list'))
 | |
| 		.append($('<div>')
 | |
| 		       .addClass('v-block info'))
 | |
| 		.append($('<div>')
 | |
| 		       .addClass('v-block actions'))
 | |
| 	return browser
 | |
| }
 | |
| 
 | |
| // low level update...
 | |
| function update(browser, path, list){
 | |
| 	browser = browser || $('.browse')
 | |
| 	var p = browser.find('.path').empty()
 | |
| 	var l = browser.find('.list').empty()
 | |
| 
 | |
| 	path.forEach(function(e){
 | |
| 		p.append($('<div>')
 | |
| 			.addClass('dir')
 | |
| 			.click(popDir)
 | |
| 			.text(e))
 | |
| 	})
 | |
| 	list.forEach(function(e){
 | |
| 		l.append($('<div>')
 | |
| 			.click(pushDir)
 | |
| 			.text(e))
 | |
| 	})
 | |
| 	return browser
 | |
| }
 | |
| 
 | |
| 
 | |
| function showPath(browser, path, tree, skip){
 | |
| 	// XXX remove for pruduction...
 | |
| 	skip = skip || skipFiles
 | |
| 
 | |
| 	browser = browser || $('.browse')
 | |
| 	path = path.constructor !== Array ? path.split(/[\\\/]+/g) : path
 | |
| 	path = path.filter(function(e){ return e != '' })
 | |
| 
 | |
| 	var dir = tree
 | |
| 	path.forEach(function(d){
 | |
| 		dir = dir[d]
 | |
| 	})
 | |
| 
 | |
| 	// XXX do error checking...
 | |
| 
 | |
| 	dir = skip != null
 | |
| 		// skip files....
 | |
| 		? Object.keys(dir).filter(function(e){ return skip(e, dir[e]) }) 
 | |
| 		: Object.keys(dir)
 | |
| 
 | |
| 	update(browser, path, dir)
 | |
| }
 | |
| 
 | |
| // XXX this will skip incuding the current dir...
 | |
| //	...this might work and might not work...
 | |
| function getPath(browser, to){
 | |
| 	var skip = false
 | |
| 	return browser.find('.path .dir')
 | |
| 		.filter(function(i, e){
 | |
| 			if(e === to){
 | |
| 				skip = true
 | |
| 			}
 | |
| 			return !skip
 | |
| 		})
 | |
| 		.map(function(i, e){ return $(e).text() })
 | |
| 		.toArray()
 | |
| }
 | |
| 
 | |
| 
 | |
| function pushDir(){
 | |
| 	var dir = $(this).text()
 | |
| 	var browser = $(this).parents('.browse')
 | |
| 	var path = getPath(browser)
 | |
| 	path.push(dir)
 | |
| 
 | |
| 	showPath(browser, path, TREE)
 | |
| }
 | |
| function popDir(){
 | |
| 	var dir = $(this).text()
 | |
| 	var browser = $(this).parents('.browse')
 | |
| 	var path = getPath(browser, this)
 | |
| 
 | |
| 	showPath(browser, path, TREE)
 | |
| 
 | |
| 	select('"'+dir+'"')
 | |
| }
 | |
| 
 | |
| 
 | |
| // base control actions...
 | |
| // XXX add keywords:
 | |
| //	'first'
 | |
| //	'prev'
 | |
| //	'next'
 | |
| //	'last'
 | |
| //	'none'		-- deselect
 | |
| //	'!'			-- return selected element if it exists...
 | |
| //	<number>	-- select by sequence number...
 | |
| //	<elem>		-- select a specific element...
 | |
| function select(elem, browser){
 | |
| 	browser = browser || $('.browse')
 | |
| 	var elems = browser.find('.list div')
 | |
| 
 | |
| 	if(elems.length == 0){
 | |
| 		return $()
 | |
| 	}
 | |
| 
 | |
| 	elem = elem || select('!')
 | |
| 	// if none selected get the first...
 | |
| 	elem = elem.length == 0 ? 'first' : elem
 | |
| 
 | |
| 	// first/last...
 | |
| 	if(elem == 'first' || elem == 'last'){
 | |
| 		return select(elems[elem](), browser)
 | |
| 	
 | |
| 	// prev/next...
 | |
| 	} else if(elem == 'prev' || elem == 'next'){
 | |
| 		var to = select('!', browser)[elem]('.list div')
 | |
| 		if(to.length == 0){
 | |
| 			return select(elem == 'prev' ? 'last' : 'first', browser)
 | |
| 		}
 | |
| 		select('none')
 | |
| 		return select(to, browser)
 | |
| 
 | |
| 	// deselect...
 | |
| 	} else if(elem == 'none'){
 | |
| 		return elems
 | |
| 			.filter('.selected')
 | |
| 			.removeClass('selected')
 | |
| 
 | |
| 	// strict...
 | |
| 	} else if(elem == '!'){
 | |
| 		return elems.filter('.selected')
 | |
| 
 | |
| 	// number...
 | |
| 	} else if(typeof(elem) == typeof(123)){
 | |
| 		return select($(elems[elem]), browser)
 | |
| 
 | |
| 	// string...
 | |
| 	} else if(typeof(elem) == typeof('str') && /^'.*'$|^".*"$/.test(elem.trim())){
 | |
| 		elem = elem.trim().slice(1, -1)
 | |
| 		return select(browser.find('.list div').filter(function(i, e){
 | |
| 			return $(e).text() == elem
 | |
| 		}))
 | |
| 
 | |
| 	// element...
 | |
| 	} else {
 | |
| 		select('none', browser)
 | |
| 		return elem.addClass('selected')
 | |
| 	}
 | |
| }
 | |
| function push(browser){
 | |
| 	browser = browser || $('.browse')
 | |
| 	var elem = select('!', browser)
 | |
| 
 | |
| 	if(elem.length == 0){
 | |
| 		return select()
 | |
| 	}
 | |
| 
 | |
| 	var path = getPath(browser)
 | |
| 
 | |
| 	path.push(elem.text())
 | |
| 
 | |
| 	var res = showPath(browser, path, TREE)
 | |
| 
 | |
| 	select(null, browser)
 | |
| 
 | |
| 	return res
 | |
| }
 | |
| function pop(browser){
 | |
| 	browser = browser || $('.browse')
 | |
| 	var path = getPath(browser)
 | |
| 	var dir = path.pop()
 | |
| 
 | |
| 	var res = showPath(browser, path, TREE)
 | |
| 
 | |
| 	select('"'+dir+'"')
 | |
| 
 | |
| 	return res
 | |
| }
 | |
| function next(browser){
 | |
| 	return select('next', browser)
 | |
| }
 | |
| function prev(browser){
 | |
| 	return select('prev', browser)
 | |
| }
 | |
| 
 | |
| 
 | |
| // default action...
 | |
| function action(browser){
 | |
| 	browser = browser || $('.browse')
 | |
| 
 | |
| 	var cur = select('!', browser).text()
 | |
| 	alert('/' + getPath(browser).concat(cur == '' ? [cur] : [cur, '']).join('/'))
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| var KB = {
 | |
| 	'*':{
 | |
| 		F5: function(){ window.location.reload() },
 | |
| 	},
 | |
| 	//'.browse:focus':{
 | |
| 	'.browse':{
 | |
| 		Up: prev,
 | |
| 		Backspace: 'Up',
 | |
| 		Down: next,
 | |
| 		Left: pop,
 | |
| 		Right: push,
 | |
| 
 | |
| 		Enter: action,
 | |
| 	},
 | |
| }
 | |
| 
 | |
| 
 | |
| //---
 | |
| 
 | |
| var BrowserClassPrototype = {
 | |
| 	// construct the dom...
 | |
| 	make: function(){
 | |
| 		var browser = $('<div>')
 | |
| 			.addClass('browse')
 | |
| 			// make thie widget focusable...
 | |
| 			// NOTE: tabindex 0 means automatic tab indexing and -1 means 
 | |
| 			//		focusable bot not tabable...
 | |
| 			//.attr('tabindex', -1)
 | |
| 			.attr('tabindex', 0)
 | |
| 			// focus the widget if something inside is clicked...
 | |
| 			.click(function(){
 | |
| 				$(this).focus()
 | |
| 			})
 | |
| 			.append($('<div>')
 | |
| 				   .addClass('v-block title')
 | |
| 				   .text(title))
 | |
| 			.append($('<div>')
 | |
| 				   .addClass('v-block path'))
 | |
| 			.append($('<div>')
 | |
| 				   .addClass('v-block list'))
 | |
| 			.append($('<div>')
 | |
| 				   .addClass('v-block info'))
 | |
| 			.append($('<div>')
 | |
| 				   .addClass('v-block actions'))
 | |
| 		return browser
 | |
| 	},
 | |
| }
 | |
| 
 | |
| var BrowserPrototype = {
 | |
| 	dom: null,
 | |
| 
 | |
| 	keyboard: {
 | |
| 		'.browse':{
 | |
| 			Up: 'prev',
 | |
| 			Backspace: 'Up',
 | |
| 			Down: 'next',
 | |
| 			Left: 'pop',
 | |
| 			Right: 'push',
 | |
| 
 | |
| 			Enter: 'action',
 | |
| 			Esc: 'close',
 | |
| 		},
 | |
| 	},
 | |
| 
 | |
| 	// base api...
 | |
| 	// NOTE: to avoid duplicating and syncing data, the actual path is 
 | |
| 	//		stored in DOM...
 | |
| 	get path(){
 | |
| 		var skip = false
 | |
| 		return this.dom.find('.path .dir')
 | |
| 			.map(function(i, e){ return $(e).text() })
 | |
| 			.toArray()
 | |
| 	},
 | |
| 	set path(value){
 | |
| 		// XXX normalize path...
 | |
| 		return this.update(path)
 | |
| 	},
 | |
| 
 | |
| 	// update path...
 | |
| 	update: function(path){
 | |
| 		var browser = this.dom
 | |
| 
 | |
| 		var p = browser.find('.path').empty()
 | |
| 		var l = browser.find('.list').empty()
 | |
| 
 | |
| 		// fill the path field...
 | |
| 		path.forEach(function(e){
 | |
| 			p.append($('<div>')
 | |
| 				.addClass('dir')
 | |
| 				.click(popDir)
 | |
| 				.text(e))
 | |
| 		})
 | |
| 
 | |
| 		// fill the children list...
 | |
| 		this.list(path)
 | |
| 			.forEach(function(e){
 | |
| 				l.append($('<div>')
 | |
| 					.click(pushDir)
 | |
| 					.text(e))
 | |
| 			})
 | |
| 
 | |
| 		return this
 | |
| 	},
 | |
| 
 | |
| 	// internal actions...
 | |
| 
 | |
| 	//
 | |
| 	//	Select first/last child
 | |
| 	//	.select('first')
 | |
| 	//	.select('last')
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	//	Select previous/lext child
 | |
| 	//	.select('prev')
 | |
| 	//	.select('next')
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	//	Deselect
 | |
| 	//	.select('none')
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	//	Get selected element if it exists, null otherwise...
 | |
| 	//	.select('!')
 | |
| 	//		-> elem
 | |
| 	//		-> $()
 | |
| 	//
 | |
| 	//	Select element by sequence number
 | |
| 	//	.select(<number>)
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	//	Select element by its text...
 | |
| 	//	.select('"<text>"')
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	//	.select(<elem>)
 | |
| 	//		-> elem
 | |
| 	//
 | |
| 	// This will return a jQuery object.
 | |
| 	//
 | |
| 	//
 | |
| 	// XXX revise return values...
 | |
| 	select: function(elem){
 | |
| 		var browser = this.dom
 | |
| 		var elems = browser.find('.list div')
 | |
| 
 | |
| 		if(elems.length == 0){
 | |
| 			return $()
 | |
| 		}
 | |
| 
 | |
| 		elem = elem || this.select('!')
 | |
| 		// if none selected get the first...
 | |
| 		elem = elem.length == 0 ? 'first' : elem
 | |
| 
 | |
| 		// first/last...
 | |
| 		if(elem == 'first' || elem == 'last'){
 | |
| 			return this.select(elems[elem]())
 | |
| 		
 | |
| 		// prev/next...
 | |
| 		} else if(elem == 'prev' || elem == 'next'){
 | |
| 			var to = this.select('!', browser)[elem]('.list div')
 | |
| 			if(to.length == 0){
 | |
| 				return this.select(elem == 'prev' ? 'last' : 'first', browser)
 | |
| 			}
 | |
| 			this.select('none')
 | |
| 			return this.select(to)
 | |
| 
 | |
| 		// deselect...
 | |
| 		} else if(elem == 'none'){
 | |
| 			return elems
 | |
| 				.filter('.selected')
 | |
| 				.removeClass('selected')
 | |
| 
 | |
| 		// strict...
 | |
| 		} else if(elem == '!'){
 | |
| 			return elems.filter('.selected')
 | |
| 
 | |
| 		// number...
 | |
| 		} else if(typeof(elem) == typeof(123)){
 | |
| 			return this.select($(elems[elem]))
 | |
| 
 | |
| 		// string...
 | |
| 		} else if(typeof(elem) == typeof('str') 
 | |
| 				&& /^'.*'$|^".*"$/.test(elem.trim())){
 | |
| 			elem = elem.trim().slice(1, -1)
 | |
| 			return this.select(browser.find('.list div')
 | |
| 					.filter(function(i, e){
 | |
| 						return $(e).text() == elem
 | |
| 					}))
 | |
| 
 | |
| 		// element...
 | |
| 		} else {
 | |
| 			this.select('none')
 | |
| 			return elem.addClass('selected')
 | |
| 		}
 | |
| 	},
 | |
| 
 | |
| 	// XXX check if we need to do the ,action when the element id not traversable...
 | |
| 	push: function(elem){
 | |
| 		var browser = this.dom 
 | |
| 		var elem = this.select(elem || '!')
 | |
| 
 | |
| 		// nothing selected, select first and exit...
 | |
| 		if(elem.length == 0){
 | |
| 			this.select()
 | |
| 			return this
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		this
 | |
| 			.update(this.path.push(elem.text()))
 | |
| 			.select()
 | |
| 
 | |
| 		return this
 | |
| 	},
 | |
| 	// pop an element off the path / go up one level...
 | |
| 	pop: function(){
 | |
| 		var browser = this.dom
 | |
| 		var path = this.path
 | |
| 		var dir = path.pop()
 | |
| 
 | |
| 		this.update(path)
 | |
| 
 | |
| 		this.select('"'+dir+'"')
 | |
| 
 | |
| 		return this
 | |
| 	},
 | |
| 	next: function(elem){
 | |
| 		if(elem != null){
 | |
| 			this.select(elem)
 | |
| 		}
 | |
| 		this.select('next')
 | |
| 		return this
 | |
| 	},
 | |
| 	prev: function(elem){
 | |
| 		if(elem != null){
 | |
| 			this.select(elem)
 | |
| 		}
 | |
| 		this.select('prev')
 | |
| 		return this
 | |
| 	},
 | |
| 
 | |
| 	// XXX think about the API...
 | |
| 	action: function(){
 | |
| 		var res = this.open(this.path)
 | |
| 
 | |
| 		// XXX close the dialog if everything is OK...
 | |
| 		// XXX
 | |
| 
 | |
| 		return res
 | |
| 	},
 | |
| 	// close the dialog...
 | |
| 	// XXX
 | |
| 	close: function(){
 | |
| 	},
 | |
| 
 | |
| 	// extension methods...
 | |
| 	// XXX think about the API...
 | |
| 	//		needs to control closing of the dialog
 | |
| 	open: function(){
 | |
| 	},
 | |
| 	list: function(){
 | |
| 	},
 | |
| 	isTraversable: null,
 | |
| 
 | |
| 	// XXX
 | |
| 	__init__: function(parent){
 | |
| 		// build the dom...
 | |
| 		var dom = this.dom = this.constructor.make()
 | |
| 
 | |
| 		// add keyboard handler...
 | |
| 		dom.keydown(
 | |
| 			keyboard.makeKeyboardHandler(
 | |
| 				this.keyboard,
 | |
| 				function(k){ window.DEBUG && console.log(k) },
 | |
| 				this))
 | |
| 
 | |
| 		// attach to parent...
 | |
| 		if(parent != null){
 | |
| 			parent.append(dom)
 | |
| 		}
 | |
| 	},
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| var Browser = 
 | |
| //module.Browser = 
 | |
| object.makeConstructor('Browser', 
 | |
| 		BrowserClassPrototype, 
 | |
| 		BrowserPrototype)
 | |
| */
 | |
| 
 | |
| 
 | |
| 
 | |
| //---
 | |
| 
 | |
| 
 | |
| requirejs(['../lib/keyboard', '../object'], function(k, o){
 | |
| 	keyboard = k
 | |
| 	object = o
 | |
| 
 | |
| 	// setup base keyboard for devel, in case something breaks...
 | |
| 	//$(document)
 | |
| 	$('.browse')
 | |
| 		.keydown(
 | |
| 			keyboard.makeKeyboardHandler(
 | |
| 				KB,
 | |
| 				function(k){ window.DEBUG && console.log(k) }))
 | |
| 
 | |
| })
 | |
| 
 | |
| $(function(){
 | |
| 	var browser = make()
 | |
| 	$('.container')
 | |
| 		.empty()
 | |
| 		.append(browser)
 | |
| 	showPath(browser, '/', TREE)
 | |
| 
 | |
| 	$('.container').draggable({ 
 | |
| 			cancel: ".path .dir, .list div" 
 | |
| 		})
 | |
| 
 | |
| 	browser.focus()
 | |
| })
 | |
| 
 | |
| </script>
 | |
| 
 | |
| <body>
 | |
| 
 | |
| <button onclick="pop()"><</button>
 | |
| <button onclick="push()">></button>
 | |
| <button onclick="prev()">^</button>
 | |
| <button onclick="next()">v</button>
 | |
| 
 | |
| 
 | |
| <div class="container">
 | |
| 	<div class="browse">
 | |
| 		<!-- title, optional -->
 | |
| 		<div class="v-block title">
 | |
| 			[title]
 | |
| 		</div>
 | |
| 
 | |
| 		<!-- the actual list -->
 | |
| 		<div class="v-block path">
 | |
| 			<div class="dir">
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 			<div class="dir">
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 			<div class="dir">
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 		</div>
 | |
| 
 | |
| 		<!-- the actual list -->
 | |
| 		<div class="v-block list">
 | |
| 			<div>
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 			<div>
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 			<div>
 | |
| 				[dir]
 | |
| 			</div>
 | |
| 		</div>
 | |
| 
 | |
| 		<!-- info, optional -->
 | |
| 		<div class="v-block info">
 | |
| 			[info]
 | |
| 		</div>
 | |
| 
 | |
| 		<!-- buttons, optional -->
 | |
| 		<div class="v-block actions">
 | |
| 			[actions]
 | |
| 		</div>
 | |
| 	</div>
 | |
| </div>
 | |
| 
 | |
| 
 | |
| </body>
 | |
| </html>
 | |
| <!-- vim:set ts=4 sw=4 : -->
 |