| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX NOTE: the widget itself does not need a title, that's the job for
 | 
					
						
							|  |  |  | //		a container widget (dialog, field, ...)
 | 
					
						
							|  |  |  | //		...it can be implemented trivially via an attribute and a :before
 | 
					
						
							|  |  |  | //		CSS class...
 | 
					
						
							|  |  |  | var BrowserClassPrototype = { | 
					
						
							|  |  |  | 	// construct the dom...
 | 
					
						
							|  |  |  | 	make: function(options){ | 
					
						
							|  |  |  | 		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() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(options.path == null || options.show_path){ | 
					
						
							|  |  |  | 			browser | 
					
						
							|  |  |  | 				.append($('<div>') | 
					
						
							|  |  |  | 					   .addClass('v-block path')) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		browser | 
					
						
							|  |  |  | 			.append($('<div>') | 
					
						
							|  |  |  | 				   .addClass('v-block list')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return browser | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX Q: should we make a base list dialog and build this on that or
 | 
					
						
							|  |  |  | //		simplify this to implement a list (removing the path and disbling
 | 
					
						
							|  |  |  | //		traversal)??
 | 
					
						
							|  |  |  | // XXX need a search/filter field...
 | 
					
						
							|  |  |  | // XXX need base events:
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | //		- open
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | //		- update
 | 
					
						
							|  |  |  | //		- select (???)
 | 
					
						
							|  |  |  | // XXX add "current selection" to the path...
 | 
					
						
							|  |  |  | var BrowserPrototype = { | 
					
						
							|  |  |  | 	dom: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	options: { | 
					
						
							|  |  |  | 		//path: null,
 | 
					
						
							|  |  |  | 		//show_path: null,
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX this should prevent event handler deligation...
 | 
					
						
							|  |  |  | 	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...
 | 
					
						
							|  |  |  | 	// XXX does the path includes the currently selected element?
 | 
					
						
							|  |  |  | 	get path(){ | 
					
						
							|  |  |  | 		var skip = false | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 		return this.dom.find('.path .dir:not(.cur)') | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			.map(function(i, e){ return $(e).text() }) | 
					
						
							|  |  |  | 			.toArray() | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	set path(value){ | 
					
						
							|  |  |  | 		// XXX normalize path...
 | 
					
						
							|  |  |  | 		return this.update(value) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// update path...
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	// 	- build the path
 | 
					
						
							|  |  |  | 	// 	- build the element list
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	// XXX trigger an "update" event...
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	// XXX current path click shoud make it editable and start a live 
 | 
					
						
							|  |  |  | 	// 		search/filter...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	update: function(path){ | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 		path = path || this.path | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var p = browser.find('.path').empty() | 
					
						
							|  |  |  | 		var l = browser.find('.list').empty() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 		var c = [] | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		// fill the path field...
 | 
					
						
							|  |  |  | 		path.forEach(function(e){ | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 			c.push(e) | 
					
						
							|  |  |  | 			var cur = c.slice() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			p.append($('<div>') | 
					
						
							|  |  |  | 				.addClass('dir') | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 				.click(function(){ | 
					
						
							|  |  |  | 					that | 
					
						
							|  |  |  | 						.update(cur.slice(0, -1))  | 
					
						
							|  |  |  | 						.select('"'+cur.pop()+'"') | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 				.text(e)) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 		// add current selction indicator...
 | 
					
						
							|  |  |  | 		p.append($('<div>') | 
					
						
							|  |  |  | 			.addClass('dir cur') | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 			// XXX start search/filter...
 | 
					
						
							|  |  |  | 			// 		- on click / letter set content editable
 | 
					
						
							|  |  |  | 			// 		- triger filterig on modified
 | 
					
						
							|  |  |  | 			// 		- disable nav in favor of editing
 | 
					
						
							|  |  |  | 			// 		- enter/blur to exit edit mode
 | 
					
						
							|  |  |  | 			// 		- esc to cancel and reset
 | 
					
						
							| 
									
										
										
										
											2015-03-30 17:42:48 +03:00
										 |  |  | 			// XXX add a filter mode...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 			.click(function(){ | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 				//that.update(path.concat($(this).text())) 
 | 
					
						
							|  |  |  | 				$(this) | 
					
						
							|  |  |  | 					.text('') | 
					
						
							|  |  |  | 					.attr('contenteditable', true) | 
					
						
							|  |  |  | 					.keyup(function(){ | 
					
						
							|  |  |  | 						that.filter($(this).text()) | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 			})) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		// fill the children list...
 | 
					
						
							|  |  |  | 		this.list(path) | 
					
						
							|  |  |  | 			.forEach(function(e){ | 
					
						
							|  |  |  | 				l.append($('<div>') | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 					.click(function(){ | 
					
						
							|  |  |  | 						that.update(that.path.concat([$(this).text()]))  | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 					.text(e)) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	// XXX should have two non_matched modes:
 | 
					
						
							|  |  |  | 	// 		- hide			- hide non-matching content
 | 
					
						
							|  |  |  | 	// 		- shadow		- shadow non-matching content
 | 
					
						
							|  |  |  | 	// XXX pattern modes:
 | 
					
						
							|  |  |  | 	// 		- lazy match
 | 
					
						
							|  |  |  | 	// 			abc		-> *abc*		-> ^.*abc.*$
 | 
					
						
							|  |  |  | 	// 			ab cd	-> *ab*cd*		-> ^.*ab.*cd.*$
 | 
					
						
							|  |  |  | 	// 		- glob
 | 
					
						
							|  |  |  | 	// 		- regex
 | 
					
						
							|  |  |  | 	// XXX sort:
 | 
					
						
							|  |  |  | 	// 		- as-is
 | 
					
						
							|  |  |  | 	// 		- best match
 | 
					
						
							|  |  |  | 	filter: function(pattern, mode, non_matched, sort){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-30 17:42:48 +03:00
										 |  |  | 		// show all...
 | 
					
						
							|  |  |  | 		if(pattern == null || pattern.trim() == '*'){ | 
					
						
							|  |  |  | 			this.update() | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-30 17:42:48 +03:00
										 |  |  | 		// basic filter...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var l = browser.find('.list>div') | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-30 17:42:48 +03:00
										 |  |  | 			l.each(function(i, e){ | 
					
						
							|  |  |  | 				e = $(e) | 
					
						
							|  |  |  | 				var t = e.text() | 
					
						
							|  |  |  | 				var i = t.search(pattern) | 
					
						
							|  |  |  | 				if(i < 0){ | 
					
						
							|  |  |  | 					e.remove() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					e.html(t.replace(pattern, pattern.bold())) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	// internal actions...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Select a list element...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	//	Get selected element if it exists, otherwise select and return 
 | 
					
						
							|  |  |  | 	//	the first...
 | 
					
						
							|  |  |  | 	//	.select()
 | 
					
						
							|  |  |  | 	//		-> elem
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get selected element if it exists, null otherwise...
 | 
					
						
							|  |  |  | 	//	.select('!')
 | 
					
						
							|  |  |  | 	//		-> elem
 | 
					
						
							|  |  |  | 	//		-> $()
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	//	Select first/last child
 | 
					
						
							|  |  |  | 	//	.select('first')
 | 
					
						
							|  |  |  | 	//	.select('last')
 | 
					
						
							|  |  |  | 	//		-> elem
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	//	Select previous/next child
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	//	.select('prev')
 | 
					
						
							|  |  |  | 	//	.select('next')
 | 
					
						
							|  |  |  | 	//		-> elem
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Deselect
 | 
					
						
							|  |  |  | 	//	.select('none')
 | 
					
						
							|  |  |  | 	//		-> 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...
 | 
					
						
							|  |  |  | 	// XXX Q: should this trigger a "select" event???
 | 
					
						
							|  |  |  | 	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'){ | 
					
						
							| 
									
										
										
										
											2015-03-21 21:35:12 +03:00
										 |  |  | 			browser.find('.path .dir.cur').empty() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			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') | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 			browser.find('.path .dir.cur').text(elem.text()) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			return elem.addClass('selected') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	// Select next element...
 | 
					
						
							|  |  |  | 	next: function(elem){ | 
					
						
							|  |  |  | 		if(elem != null){ | 
					
						
							|  |  |  | 			this.select(elem) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.select('next') | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// Select previous element...
 | 
					
						
							|  |  |  | 	prev: function(elem){ | 
					
						
							|  |  |  | 		if(elem != null){ | 
					
						
							|  |  |  | 			this.select(elem) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.select('prev') | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Push an element to path / go down one level...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var path = this.path | 
					
						
							|  |  |  | 		path.push(elem.text()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// if not traversable call the action...
 | 
					
						
							|  |  |  | 		if(this.isTraversable != null  | 
					
						
							|  |  |  | 				&& (this.isTraversable !== false | 
					
						
							|  |  |  | 					|| ! this.isTraversable(path))){ | 
					
						
							|  |  |  | 			return this.action(path) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.path = path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.select() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	// Pop an element off the path / go up one level...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	pop: function(){ | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 		var path = this.path | 
					
						
							|  |  |  | 		var dir = path.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.update(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.select('"'+dir+'"') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	focus: function(){ | 
					
						
							|  |  |  | 		this.dom.focus() | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 		return this | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX think about the API...
 | 
					
						
							|  |  |  | 	// XXX trigger an "open" event...
 | 
					
						
							|  |  |  | 	action: function(){ | 
					
						
							|  |  |  | 		var elem = this.select('!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// nothing selected, select first and exit...
 | 
					
						
							|  |  |  | 		if(elem.length == 0){ | 
					
						
							|  |  |  | 			this.select() | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var path = this.path.push(elem.text()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var res = this.open(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// extension methods...
 | 
					
						
							|  |  |  | 	open: function(path){  | 
					
						
							|  |  |  | 		var m = this.options.list | 
					
						
							|  |  |  | 		return m ? m.call(this, path) : path | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	list: function(path){ | 
					
						
							|  |  |  | 		var m = this.options.list | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 		return m ? m.call(this, path) : [] | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	isTraversable: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX need to get a container....
 | 
					
						
							|  |  |  | 	// XXX prepare/merge options...
 | 
					
						
							|  |  |  | 	// XXX setup instance events...
 | 
					
						
							|  |  |  | 	__init__: function(parent, options){ | 
					
						
							|  |  |  | 		// XXX merge options...
 | 
					
						
							|  |  |  | 		// XXX
 | 
					
						
							|  |  |  | 		this.options = options | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// build the dom...
 | 
					
						
							|  |  |  | 		var dom = this.dom = this.constructor.make(options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// add keyboard handler...
 | 
					
						
							|  |  |  | 		dom.keydown( | 
					
						
							|  |  |  | 			keyboard.makeKeyboardHandler( | 
					
						
							|  |  |  | 				this.keyboard, | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 				function(k){ window.DEBUG && console.log(k) }, | 
					
						
							|  |  |  | 				this)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// attach to parent...
 | 
					
						
							|  |  |  | 		if(parent != null){ | 
					
						
							|  |  |  | 			parent.append(dom) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// load the initial state...
 | 
					
						
							|  |  |  | 		this.update(this.path) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | var Browser =  | 
					
						
							|  |  |  | //module.Browser = 
 | 
					
						
							|  |  |  | object.makeConstructor('Browser',  | 
					
						
							|  |  |  | 		BrowserClassPrototype,  | 
					
						
							|  |  |  | 		BrowserPrototype) | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ |