| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-08-21 02:19:24 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2015-06-20 14:50:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | //var promise = require('promise')
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | var toggler = require('../toggler') | 
					
						
							|  |  |  | var keyboard = require('../keyboard') | 
					
						
							|  |  |  | var object = require('../object') | 
					
						
							| 
									
										
										
										
											2015-09-07 18:44:10 +03:00
										 |  |  | var widget = require('./widget') | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // Helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | // Quote a string and convert to RegExp to match self literally.
 | 
					
						
							| 
									
										
										
										
											2015-12-12 04:29:55 +03:00
										 |  |  | // XXX this depends on jli.quoteRegExp(..)
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | function toRegExp(str){ | 
					
						
							|  |  |  | 	return RegExp('^' | 
					
						
							|  |  |  | 		// quote regular expression chars...
 | 
					
						
							| 
									
										
										
										
											2015-12-12 04:29:55 +03:00
										 |  |  | 		+quoteRegExp(str) | 
					
						
							|  |  |  | 		//+str.replace(/([\.\\\/\(\)\[\]\$\*\+\-\{\}\@\^\&\?\<\>])/g, '\\$1')
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		+'$') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | function makeBrowserMaker(constructor){ | 
					
						
							|  |  |  | 	return function(elem, list, rest){ | 
					
						
							|  |  |  | 		if(typeof(rest) == typeof('str')){ | 
					
						
							|  |  |  | 			return constructor(elem, { data: list, path: rest }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var opts = {} | 
					
						
							|  |  |  | 			for(var k in rest){ | 
					
						
							|  |  |  | 				opts[k] = rest[k] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			opts.data = list | 
					
						
							|  |  |  | 			return constructor(elem, opts) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | function makeSimpleAction(direction){ | 
					
						
							|  |  |  | 	return function(elem){ | 
					
						
							|  |  |  | 		if(elem != null){ | 
					
						
							|  |  |  | 			this.select(elem) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.navigate(direction) | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-01-22 04:42:40 +03:00
										 |  |  | // Collections of helpers...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: from a design perspective all of these constructors can and 
 | 
					
						
							|  |  |  | // 		will be called on each refresh, so maintaining state should if
 | 
					
						
							|  |  |  | // 		state is needed should be done outside of the actual call.
 | 
					
						
							|  |  |  | // 		For this reason closures can be used but only for state 
 | 
					
						
							|  |  |  | // 		relevant within a single call.
 | 
					
						
							|  |  |  | // 		So the possible ways to store the outer state:
 | 
					
						
							|  |  |  | // 			- threaded through the arguments
 | 
					
						
							|  |  |  | // 				Example:
 | 
					
						
							|  |  |  | // 					first argument of make.EditableList(..)
 | 
					
						
							|  |  |  | // 			- make.dialog attributes
 | 
					
						
							|  |  |  | // 				Example:
 | 
					
						
							|  |  |  | // 					temporary state of make.EditableList(..)
 | 
					
						
							|  |  |  | // 			- config
 | 
					
						
							|  |  |  | // 				this requires that the config is saved and maintained 
 | 
					
						
							|  |  |  | // 				by the caller
 | 
					
						
							|  |  |  | // 				This approach is not recommended.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // NOTE: all item constructors/helpers abide by either the new-style 
 | 
					
						
							|  |  |  | // 		make protocol, i.e. make(content[, options]) or their own...
 | 
					
						
							|  |  |  | var Items = module.items = function(){} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | // NOTE: this is the same as make('---'[, options])
 | 
					
						
							|  |  |  | Items.Separator =  | 
					
						
							|  |  |  | function(options){ | 
					
						
							|  |  |  | 	return this('---', options) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // NOTE: this is the same as make('...'[, options])
 | 
					
						
							|  |  |  | Items.Sepinner =  | 
					
						
							|  |  |  | function(options){ | 
					
						
							|  |  |  | 	return this('...', options) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Heading...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		doc: <text>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | Items.Heading =  | 
					
						
							|  |  |  | function(text, options){ | 
					
						
							|  |  |  | 	var attrs = (options && options.doc) ? {doc: options.doc} : {} | 
					
						
							|  |  |  | 	return this(text, options) | 
					
						
							|  |  |  | 		.attr(attrs) | 
					
						
							|  |  |  | 		.addClass('heading') } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Action...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX should this have a callback???
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | Items.Action =  | 
					
						
							|  |  |  | function(text, options){ | 
					
						
							|  |  |  | 	return this(text, options) | 
					
						
							|  |  |  | 		.addClass('action') } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // Action requiring confirmation...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		// A callback to be called when action is confirmed...
 | 
					
						
							|  |  |  | // 		callback: <function>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Time (ms) to wait for confirm before resetting...
 | 
					
						
							|  |  |  | // 		timeout: '2000ms',
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Text to use as confirm message...
 | 
					
						
							|  |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// Supported placeholders:
 | 
					
						
							|  |  |  | // 		//	${text}		- item text
 | 
					
						
							|  |  |  | // 		//	${text:l}	- item text in lowercase
 | 
					
						
							|  |  |  | // 		//	${text:u}	- item text in uppercase
 | 
					
						
							|  |  |  | // 		//	${text:c}	- item text capitalized
 | 
					
						
							|  |  |  | //		//
 | 
					
						
							|  |  |  | // 		confirm_text: 'Confirm ${text}?',
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX doc...
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | Items.ConfirmAction =  | 
					
						
							|  |  |  | function(text, options){ | 
					
						
							|  |  |  | 	options = options || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var elem = this.Action(text, options) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var callback = options.callback | 
					
						
							|  |  |  | 	var timeout = options.timeout || 2000 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 	var confirm_text = (options.confirm_text || 'Confirm ${text:l}?')  | 
					
						
							|  |  |  | 		.replace(/\$\{text\}/, text) | 
					
						
							|  |  |  | 		.replace(/\$\{text:l\}/, text.toLowerCase()) | 
					
						
							|  |  |  | 		.replace(/\$\{text:u\}/, text.toUpperCase()) | 
					
						
							|  |  |  | 		.replace(/\$\{text:c\}/, text.capitalize()) | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return elem  | 
					
						
							|  |  |  | 		.on('open', function(){ | 
					
						
							|  |  |  | 			var item = $(this) | 
					
						
							|  |  |  | 			var elem = item.find('.text') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// ready to delete...
 | 
					
						
							|  |  |  | 			if(elem.text() != confirm_text){ | 
					
						
							|  |  |  | 				text = elem.text() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				elem.text(confirm_text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				item.addClass('warn') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// reset...
 | 
					
						
							|  |  |  | 				setTimeout(function(){ | 
					
						
							|  |  |  | 					elem.text(text) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					item.removeClass('warn') | 
					
						
							|  |  |  | 				}, timeout) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// confirmed...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				callback && callback() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // Item with auto selected text on select...
 | 
					
						
							| 
									
										
										
										
											2017-01-19 03:40:22 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // 		// XXX make this generic, something like cls: ...
 | 
					
						
							|  |  |  | // 		action: false,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | // 		select_text: <number> | 'first' | 'last' | <selector>,
 | 
					
						
							| 
									
										
										
										
											2017-01-19 03:40:22 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-20 20:37:11 +03:00
										 |  |  | // NOTE: this need selection enabled in CSS...
 | 
					
						
							| 
									
										
										
										
											2017-01-19 03:40:22 +03:00
										 |  |  | Items.Selected = | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | function(text, options){ | 
					
						
							| 
									
										
										
										
											2017-01-19 03:40:22 +03:00
										 |  |  | 	var elem = (options.action ? this.Action : this).call(this, text, options) | 
					
						
							|  |  |  | 		.on('select', function(){ | 
					
						
							|  |  |  | 			var text = elem.find('.text') | 
					
						
							| 
									
										
										
										
											2017-01-21 05:24:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | 			// get the specific .text element...
 | 
					
						
							| 
									
										
										
										
											2017-01-21 05:24:31 +03:00
										 |  |  | 			text =  | 
					
						
							|  |  |  | 				// select index...
 | 
					
						
							|  |  |  | 				typeof(options.select_text) == typeof(123) ? | 
					
						
							|  |  |  | 					text.eq(options.select_text) | 
					
						
							|  |  |  | 				// first/last
 | 
					
						
							|  |  |  | 				: (options.select_text == 'first' || options.select_text == 'last') ? | 
					
						
							|  |  |  | 					text[options.select_text]() | 
					
						
							|  |  |  | 				// selector...
 | 
					
						
							|  |  |  | 				: typeof(options.select_text) == typeof('str') ? | 
					
						
							|  |  |  | 					elem.find(options.select_text) | 
					
						
							|  |  |  | 				// all...
 | 
					
						
							|  |  |  | 				: text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			text.selectText() | 
					
						
							| 
									
										
										
										
											2017-01-19 03:40:22 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	return elem | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // Editable item or it's part...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2017-01-18 00:56:08 +03:00
										 |  |  | //		// show as action (via. .Action(..))
 | 
					
						
							|  |  |  | // 		action: <bool>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | // 		// if true, set multi-line mode...
 | 
					
						
							|  |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// (see: util.makeEditable(..) for more info)
 | 
					
						
							|  |  |  | // 		multiline: false,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// .text element index to edit...
 | 
					
						
							|  |  |  | //		//
 | 
					
						
							|  |  |  | // 		// NOTE: by default this will select all the elements, if there
 | 
					
						
							|  |  |  | // 		//		are more than one, this may result in an odd element 
 | 
					
						
							|  |  |  | // 		//		state...
 | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | // 		// NOTE: the selector is used to filter text elements...
 | 
					
						
							|  |  |  | // 		edit_text: <number> | 'first' | 'last' | <selector>,
 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 		// item event to start the edit on...
 | 
					
						
							|  |  |  | // 		start_on: 'select',
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// if true, trigger abort on deselect...
 | 
					
						
							|  |  |  | // 		abort_on_deselect: true,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-18 00:56:08 +03:00
										 |  |  | //		// If true, clear text when item is selected...
 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | //		//
 | 
					
						
							|  |  |  | // 		// (see: util.makeEditable(..) for more info)
 | 
					
						
							|  |  |  | //		clear_on_edit: false,
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | //		// Events to stop propagating up...
 | 
					
						
							|  |  |  | //		//
 | 
					
						
							|  |  |  | //		// This is useful to prevent actions that start should an edit 
 | 
					
						
							|  |  |  | //		// from triggering something else in the dialog...
 | 
					
						
							|  |  |  | //		//
 | 
					
						
							|  |  |  | //		// If false, nothing will get stopped...
 | 
					
						
							|  |  |  | //		stop_propagation: 'open',
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-18 00:56:08 +03:00
										 |  |  | // 		// Called when editing is abrted... 
 | 
					
						
							|  |  |  | // 		editaborted: <func>,
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-18 00:56:08 +03:00
										 |  |  | // 		// Called when editing is done...
 | 
					
						
							|  |  |  | // 		editdone: <func>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | // 	}
 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | // XXX add option to select the element on start or just focus it...
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | Items.Editable = | 
					
						
							|  |  |  | function(text, options){ | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	options = options || {} | 
					
						
							|  |  |  | 	var dialog = this.dialog | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 	var start_on = options.start_on || 'select' | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 	var stop_propagation = options.stop_propagation === false ? false : 'open' | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 23:39:41 +03:00
										 |  |  | 	var getEditable = function(){ | 
					
						
							|  |  |  | 		var editable = elem.find('.text') | 
					
						
							|  |  |  | 		// get the specific .text element...
 | 
					
						
							|  |  |  | 		// index...
 | 
					
						
							|  |  |  | 		return typeof(options.edit_text) == typeof(123) ?  | 
					
						
							|  |  |  | 				editable.eq(options.edit_text) | 
					
						
							|  |  |  | 			// first/last...
 | 
					
						
							|  |  |  | 			: (options.edit_text == 'first' || options.edit_text == 'last') ? | 
					
						
							|  |  |  | 				editable[options.edit_text]() | 
					
						
							|  |  |  | 			// selecter...
 | 
					
						
							|  |  |  | 			: typeof(options.edit_text) == typeof('str') ? | 
					
						
							|  |  |  | 				editable.filter(options.edit_text) | 
					
						
							|  |  |  | 			// all...
 | 
					
						
							|  |  |  | 			: editable } | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 23:39:41 +03:00
										 |  |  | 	var elem = (options.action ? this.Action : this).call(this, text, options) | 
					
						
							|  |  |  | 		.on(start_on, function(evt){ | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 			event && event.preventDefault() | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// edit the element...
 | 
					
						
							| 
									
										
										
										
											2017-01-21 23:39:41 +03:00
										 |  |  | 			var editable = getEditable() | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				.makeEditable({ | 
					
						
							|  |  |  | 					activate: true, | 
					
						
							|  |  |  | 					blur_on_abort: false, | 
					
						
							|  |  |  | 					blur_on_commit: false, | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 					multiline: options.multiline, | 
					
						
							| 
									
										
										
										
											2017-01-21 23:39:41 +03:00
										 |  |  | 					clear_on_edit: options.clear_on_edit, | 
					
						
							|  |  |  | 					reset_on_commit: options.reset_on_commit, | 
					
						
							|  |  |  | 					reset_on_abort: options.reset_on_abort, | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 				// XXX not sure about this...
 | 
					
						
							|  |  |  | 				.on('blur', function(){ dialog.select(null)	}) | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// deselect on abort -- if we started with a select...
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 			start_on == 'select'  | 
					
						
							|  |  |  | 				&& editable | 
					
						
							|  |  |  | 					.on('edit-abort', function(){ dialog.select(null) }) | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 			// edit event handlers...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 			options.editaborted | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | 				&& editable.on('edit-abort', options.editaborted) | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 			options.editdone | 
					
						
							| 
									
										
										
										
											2017-01-21 05:21:41 +03:00
										 |  |  | 				&& editable.on('edit-commit', options.editdone) | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2017-01-18 20:48:30 +03:00
										 |  |  | 		.on('deselect', function(){ | 
					
						
							| 
									
										
										
										
											2017-01-21 23:39:41 +03:00
										 |  |  | 			//editable && editable.trigger(
 | 
					
						
							|  |  |  | 			getEditable() | 
					
						
							|  |  |  | 				.trigger( | 
					
						
							|  |  |  | 					options.abort_on_deselect !== false ? 'edit-abort' : 'edit-commit') | 
					
						
							| 
									
										
										
										
											2017-01-18 20:48:30 +03:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 	stop_propagation | 
					
						
							|  |  |  | 		&& elem | 
					
						
							|  |  |  | 			.on(stop_propagation, function(e){ e.stopPropagation() }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	return elem | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
					
						
							|  |  |  | // Group items...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	.Group([<item>, ...])
 | 
					
						
							|  |  |  | // 		-> <group>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will return a group element, to get the items use .children()
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Usage example:
 | 
					
						
							|  |  |  | // 		make.Group([
 | 
					
						
							|  |  |  | //			make.Heading('Group'),
 | 
					
						
							|  |  |  | //			make('---'),
 | 
					
						
							|  |  |  | //			make('Group item'),
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:36:25 +03:00
										 |  |  | //			...
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | //		])
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | Items.Group = | 
					
						
							|  |  |  | function(list){ | 
					
						
							|  |  |  | 	var res = [] | 
					
						
							|  |  |  | 	list.forEach(function(e){  | 
					
						
							|  |  |  | 		e instanceof jQuery ? (res = res.concat(e.toArray())) | 
					
						
							|  |  |  | 			: e instanceof Array ? (res = res.concat(e)) | 
					
						
							|  |  |  | 			: res.push(e) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	var group = $('<div>') | 
					
						
							|  |  |  | 		.addClass('item-group') | 
					
						
							|  |  |  | 		.appendTo($(res).parent()) | 
					
						
							|  |  |  | 		.append($(res)) | 
					
						
							|  |  |  | 	return group | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // List of elements...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // data format:
 | 
					
						
							|  |  |  | //	[
 | 
					
						
							|  |  |  | //		// single text element...
 | 
					
						
							|  |  |  | //		<item-text>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		// multi-text element...
 | 
					
						
							|  |  |  | //		[<item-text>, ...],
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		...
 | 
					
						
							|  |  |  | //	]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // or:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		<item-lext>: <function>,
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | // 		// test if item is disabled/hidden... 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | //		//
 | 
					
						
							|  |  |  | // 		// NOTE: if this is a string or regexp, this is used via 
 | 
					
						
							|  |  |  | // 		//		.replace(..) so the match will get removed from the item 
 | 
					
						
							|  |  |  | // 		//		text, unless prevented via regexp.
 | 
					
						
							|  |  |  | // 		isItemDisabled: <pattern> | <function>,
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | // 		isItemHidden: <pattern> | <function>,
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | // 		// if true, disabled/hidden items will not get created...
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | // 		skipDisabledItems: false,
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | // 		skipHiddenItems: false,
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | // 		// if true, group the items into a <span> element...
 | 
					
						
							| 
									
										
										
										
											2017-01-30 23:32:08 +03:00
										 |  |  | // 		groupList: false,
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// see: make(..) for additional option info.
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | Items.List = | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | function(data, options){ | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 	var make = this | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	var res = [] | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 	var keys = data instanceof Array ? data : Object.keys(data) | 
					
						
							| 
									
										
										
										
											2017-02-01 20:39:44 +03:00
										 |  |  | 	options = options || {} | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var predicates = { | 
					
						
							|  |  |  | 		disabled: typeof(options.isItemDisabled) == typeof('str') ? | 
					
						
							|  |  |  | 			RegExp(options.isItemDisabled)  | 
					
						
							|  |  |  | 			: options.isItemDisabled, | 
					
						
							|  |  |  | 		hidden: typeof(options.isItemHidden) == typeof('str') ? | 
					
						
							|  |  |  | 			RegExp(options.isItemHidden)  | 
					
						
							|  |  |  | 			: options.isItemHidden, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 01:39:46 +03:00
										 |  |  | 	keys.forEach(function(k){ | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		var txt | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 		var opts = Object.create(options) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		Object.keys(predicates).forEach(function(p){ | 
					
						
							|  |  |  | 			var test = predicates[p] | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 			if(test){ | 
					
						
							|  |  |  | 				// check only the first item...
 | 
					
						
							|  |  |  | 				txt = txt || (k instanceof Array ? k[0] : k) | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 				// item passes disabled predicate...
 | 
					
						
							|  |  |  | 				if(test instanceof Function  | 
					
						
							|  |  |  | 						&& test(txt)){ | 
					
						
							|  |  |  | 					opts[p] = true | 
					
						
							| 
									
										
										
										
											2017-01-21 18:26:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 				// item matches disabled test...
 | 
					
						
							|  |  |  | 				} else if(test instanceof RegExp  | 
					
						
							|  |  |  | 						&& test.test(txt)){ | 
					
						
							|  |  |  | 					var t = txt.replace(test, '') | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 					opts.disabled = true | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 					txt = k instanceof Array ?  | 
					
						
							|  |  |  | 						[t].concat(k.slice(1))  | 
					
						
							|  |  |  | 						: t | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 				// no match -- restore text...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					txt = k | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if((opts.disabled && opts.skipDisabledItems)  | 
					
						
							|  |  |  | 				|| (opts.hidden && opts.skipHiddenItems)){ | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		var elem = make(txt || k, opts) | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		keys !== data && data[k] | 
					
						
							|  |  |  | 			&& elem.on('open', data[k]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		res.push(elem[0]) | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | 	return options.groupList ? | 
					
						
							|  |  |  | 		make.Group(res).children() | 
					
						
							|  |  |  | 		: $(res) | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // Editable list of elements...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // This is like .List(..) but adds functionality to add, remove and 
 | 
					
						
							|  |  |  | // manually sort list items.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // 	Show list items...
 | 
					
						
							|  |  |  | // 	.EditableList([ <item>, .. ])
 | 
					
						
							|  |  |  | // 	.EditableList([ <item>, .. ], <options>)
 | 
					
						
							|  |  |  | // 		-> <items>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Show object keys...
 | 
					
						
							|  |  |  | // 	NOTE: editing buttons are disabled.
 | 
					
						
							|  |  |  | // 	.EditableList({ <item>: <value>, .. })
 | 
					
						
							|  |  |  | // 	.EditableList({ <item>: <value>, .. }, <options>)
 | 
					
						
							|  |  |  | // 		-> <items>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Show list provided via getter/setter function items...
 | 
					
						
							|  |  |  | // 	.EditableList(<func>)
 | 
					
						
							|  |  |  | // 	.EditableList(<func>, <options>)
 | 
					
						
							|  |  |  | // 		-> <items>
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 06:44:46 +03:00
										 |  |  | // This will edit the input list in-place but only when closing the dialog.
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | // options format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | // 		// List identifier, used when multiple lists are drawn in one 
 | 
					
						
							|  |  |  | // 		// dialog...
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// NOTE: if multiple editable lists are drawn this is required.
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | // 		list_id: <text>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// If true (default), display the "new..." item, if string set 
 | 
					
						
							|  |  |  | // 		// it as item text...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 		new_item: <text>|<bool>,
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 		length_limit: <number>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Called when an item is opend...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | //		//
 | 
					
						
							|  |  |  | //		// NOTE: this is simpler that binding to the global open event 
 | 
					
						
							|  |  |  | //		//		and filtering through the results...
 | 
					
						
							|  |  |  | //		itemopen: function(value){ ... },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// Check input value...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | // 		check: function(value){ ... },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// Normalize new input value...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// NOTE: this will replace the input with normalized value.
 | 
					
						
							| 
									
										
										
										
											2017-01-18 20:48:30 +03:00
										 |  |  | // 		normalize: function(value){ ... },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// If true only unique values will be stored...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | // 		//
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// If a function this will be used to normalize the values before
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | // 		// uniqueness check is performed...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// NOTE: this (if a function) is different from normalize above 
 | 
					
						
							|  |  |  | // 		//		in that this will not store the normalized value, rather 
 | 
					
						
							|  |  |  | // 		//		just use it for uniqueness testing...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 20:48:30 +03:00
										 |  |  | // 		unique: <bool> | function(value){ ... },
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// If true sort values...
 | 
					
						
							|  |  |  | // 		// If function will be used as cmp for sorting...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | // 		sort: <bool> || function(a, b){ ... },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | // 		// Make list sortable...
 | 
					
						
							|  |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// This can be:
 | 
					
						
							|  |  |  | // 		//	true	- enable sort (both x and y axis)
 | 
					
						
							|  |  |  | // 		//	'y'		- sort only in y axis
 | 
					
						
							|  |  |  | // 		//	'x'		- sort only in x axis
 | 
					
						
							|  |  |  | // 		//	false	- disable
 | 
					
						
							|  |  |  | // 		//
 | 
					
						
							|  |  |  | // 		// NOTE: this will force .groupList to true.
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | // 		// NOTE: this depends on jquery-ui's Sortable...
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | // 		sortable: false,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// This is called when a new value is added via new_item but 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | // 		// list length limit is reached...
 | 
					
						
							|  |  |  | // 		overflow: function(selected){ ... },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | // 		// list if items to remove, if not given this will be maintained 
 | 
					
						
							|  |  |  | // 		// internally
 | 
					
						
							|  |  |  | // 		to_remove: null | <list>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Special buttons...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //		//
 | 
					
						
							|  |  |  | //		// NOTE: these can be used only if .sort if not set.
 | 
					
						
							|  |  |  | //		//
 | 
					
						
							|  |  |  | //		// Item order editing (up/down) 
 | 
					
						
							|  |  |  | //		item_order_buttons: false,
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Up button html... (default: '⏶')
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //		shift_up_button: <html> | null,
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Down button html... (default: '⏷')
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //		shift_down_button: <html> | null,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Move to top/bottom buttons, if not false the button is enabled, 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //		// if not bool the value is set as button html.
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | //		// Defaults when enabled: '⤒' and '⤓' respectively.
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //		to_top_button: false | true | <html>,
 | 
					
						
							|  |  |  | //		to_bottom_button: false | true | <html>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 		// Delete item button...
 | 
					
						
							|  |  |  | // 		delete_button: true | false | <html>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// Item buttons...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 		buttons: [
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Placeholders that if given will be replace with the corresponding
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			// special button...
 | 
					
						
							|  |  |  | // 			// NOTE: placeholders for disabled or not activated buttons 
 | 
					
						
							|  |  |  | // 			//		will get removed.
 | 
					
						
							|  |  |  | // 			// NOTE: if button is enabled but no placeholder is preset
 | 
					
						
							|  |  |  | // 			//		it will be appended to the button list.
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:01:44 +03:00
										 |  |  | // 			// NOTE: special buttons can be set in one of two formats, 
 | 
					
						
							|  |  |  | // 			//		see UP for an example...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			//
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Up...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:01:44 +03:00
										 |  |  | // 			'UP' | ['html', 'UP'],
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Down...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			'DOWN',
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Move to top...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			'TO_TOP',
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Move to bottom...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			'TO_BOTTOM'
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// Remove item...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:01:44 +03:00
										 |  |  | // 			'REMOVE',
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // 			// See: itemButtons doc in browse.js for more info...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | // 			..
 | 
					
						
							|  |  |  | // 		],
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-22 04:42:40 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Temporary state is stored in the dialog object:
 | 
					
						
							|  |  |  | // 	.__list			- cached input list
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:37:55 +03:00
										 |  |  | // 	.__editable		- list editable status
 | 
					
						
							| 
									
										
										
										
											2017-01-22 04:42:40 +03:00
										 |  |  | // 	.__to_remove	- list of items to remove
 | 
					
						
							|  |  |  | // 	.__editable_list_handlers
 | 
					
						
							|  |  |  | // 					- indicator that the dialog handlers are set up
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:58:02 +03:00
										 |  |  | // NOTE: if at least one order button is present this will set 
 | 
					
						
							|  |  |  | // 		.groupList to true
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | // NOTE: this uses .List(..) internally, see it's doc for additional 
 | 
					
						
							|  |  |  | // 		info.
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | // NOTE: the list must contain strings.
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | // XXX should id be the first argument??
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | Items.EditableList = | 
					
						
							|  |  |  | function(list, options){ | 
					
						
							|  |  |  | 	var make = this | 
					
						
							|  |  |  | 	var dialog = make.dialog | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	var write = function(list, lst){ | 
					
						
							|  |  |  | 		// write back the list...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | 		return (list instanceof Function ? | 
					
						
							|  |  |  | 				// call the writer...
 | 
					
						
							|  |  |  | 				list(lst)  | 
					
						
							|  |  |  | 				// in-place replace list elements...
 | 
					
						
							|  |  |  | 				// NOTE: this is necessary as not everything we do with lst
 | 
					
						
							|  |  |  | 				// 		is in-place...
 | 
					
						
							| 
									
										
										
										
											2017-02-02 02:37:34 +03:00
										 |  |  | 				: list.splice.apply(list, [0, list.length].concat(lst)))  | 
					
						
							|  |  |  | 					// we need to return the list itself...
 | 
					
						
							|  |  |  | 					&& lst | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | 			// in case the list(..) returns nothing...
 | 
					
						
							|  |  |  | 			|| lst | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 	dialog.__list = dialog.__list || {} | 
					
						
							| 
									
										
										
										
											2017-01-30 05:37:55 +03:00
										 |  |  | 	dialog.__editable = dialog.__editable || {} | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 	dialog.__to_remove = dialog.__to_remove || {} | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 	dialog.__editable_list_handlers = dialog.__editable_list_handlers || {} | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 20:39:44 +03:00
										 |  |  | 	options = options || {} | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 	var id = options.list_id || 'default'  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 	var to_remove = dialog.__to_remove[id] =  | 
					
						
							|  |  |  | 		options.to_remove  | 
					
						
							|  |  |  | 			|| dialog.__to_remove[id]  | 
					
						
							|  |  |  | 			|| [] | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	// make a copy of options, to keep it safe from changes we are going
 | 
					
						
							|  |  |  | 	// to make...
 | 
					
						
							|  |  |  | 	options = options || {} | 
					
						
							|  |  |  | 	var opts = {} | 
					
						
							|  |  |  | 	for(var k in options){ | 
					
						
							|  |  |  | 		opts[k] = options[k] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	options = opts | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 04:07:10 +03:00
										 |  |  | 	if(id in dialog.__list && id in dialog.__editable){ | 
					
						
							| 
									
										
										
										
											2017-01-30 05:37:55 +03:00
										 |  |  | 		var lst = dialog.__list[id] | 
					
						
							|  |  |  | 		var editable = dialog.__editable[id] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var lst = list instanceof Function ?  | 
					
						
							|  |  |  | 			list()  | 
					
						
							|  |  |  | 			: list | 
					
						
							|  |  |  | 		var editable = dialog.__editable[id] = lst instanceof Array | 
					
						
							|  |  |  | 		// view objects...
 | 
					
						
							|  |  |  | 		// NOTE: we .slice() here to make the changes a bit better packaged
 | 
					
						
							|  |  |  | 		// 		or discrete and not done as they come in...
 | 
					
						
							|  |  |  | 		lst = !editable ? Object.keys(lst) : lst.slice() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dialog.__list[id] = lst | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	var buttons = options.buttons = (options.buttons || []).slice() | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 	// buttons: options...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 	// NOTE: the order here is important...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 05:35:11 +03:00
										 |  |  | 	// NOTE: user-added buttons take priority over these, so we do not 
 | 
					
						
							|  |  |  | 	// 		need to check if a button already exists...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:37:55 +03:00
										 |  |  | 	if(editable && !options.sort){ | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 		// up/down...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		options.item_order_buttons  | 
					
						
							|  |  |  | 			&& buttons.push('UP') | 
					
						
							|  |  |  | 			&& buttons.push('DOWN') | 
					
						
							|  |  |  | 		// top/bottom...
 | 
					
						
							|  |  |  | 		options.to_top_button | 
					
						
							|  |  |  | 			&& buttons.push('TO_TOP') | 
					
						
							|  |  |  | 		options.to_bottom_button | 
					
						
							|  |  |  | 			&& buttons.push('TO_BOTTOM') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 	// remove...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 	editable  | 
					
						
							|  |  |  | 		&& options.delete_button !== false | 
					
						
							|  |  |  | 		&& buttons.push('REMOVE') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var move = function(p, offset){ | 
					
						
							|  |  |  | 		var l = dialog.__list[id] | 
					
						
							|  |  |  | 		var i = l.indexOf(p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// not in list...
 | 
					
						
							|  |  |  | 		if(i < 0 | 
					
						
							|  |  |  | 				// first element...
 | 
					
						
							|  |  |  | 				|| (i == 0 && offset < 0)  | 
					
						
							|  |  |  | 				// last element...
 | 
					
						
							|  |  |  | 				|| (i >= l.length-1 && offset > 0)){ | 
					
						
							|  |  |  | 			return false | 
					
						
							| 
									
										
										
										
											2017-02-08 02:04:59 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		var j = i + offset | 
					
						
							|  |  |  | 		j = j < 0 ? 0 | 
					
						
							|  |  |  | 			: j >= l.length ? l.length-1 | 
					
						
							|  |  |  | 			: j | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		// update list...
 | 
					
						
							|  |  |  | 		l.splice(j, 0, l.splice(i, 1)[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// return the shift distance... 
 | 
					
						
							|  |  |  | 		return j - i | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var __buttons = { | 
					
						
							|  |  |  | 		UP: [options.shift_up_button || '⏶', | 
					
						
							|  |  |  | 			function(p, e){ | 
					
						
							|  |  |  | 				move(p, -1) | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 					&& e.prev().before(e) | 
					
						
							|  |  |  | 					// XXX hackish...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 					&& dialog | 
					
						
							|  |  |  | 						.updateItemNumbers() | 
					
						
							|  |  |  | 						.trigger('up_button', p, e) }], | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		DOWN: [options.shift_down_button || '⏷', | 
					
						
							|  |  |  | 			function(p, e){ | 
					
						
							|  |  |  | 				move(p, 1) | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 					&& e.next().after(e) | 
					
						
							|  |  |  | 					// XXX hackish...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 					&& dialog | 
					
						
							|  |  |  | 						.updateItemNumbers() | 
					
						
							|  |  |  | 						.trigger('down_button', p, e) }], | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		TO_TOP: [ | 
					
						
							|  |  |  | 			(options.to_top_button === true | 
					
						
							|  |  |  | 			 		|| buttons.indexOf('TO_TOP') >= 0) ?  | 
					
						
							|  |  |  | 				'⤒' | 
					
						
							|  |  |  | 				: options.to_top_button, | 
					
						
							|  |  |  | 			function(p, e){ | 
					
						
							|  |  |  | 				var d = move(p, -dialog.__list[id].length) | 
					
						
							| 
									
										
										
										
											2017-02-08 23:13:51 +03:00
										 |  |  | 				d != null | 
					
						
							|  |  |  | 					//&& e.prevAll().eq(Math.abs(d+1)).before(e)
 | 
					
						
							|  |  |  | 					&& e.prevAll().last().before(e) | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 					&& dialog | 
					
						
							| 
									
										
										
										
											2017-02-08 23:13:51 +03:00
										 |  |  | 						// XXX hackish...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 						.updateItemNumbers() | 
					
						
							|  |  |  | 						.trigger('to_top_button', p, e) | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 			}], | 
					
						
							|  |  |  | 		TO_BOTTOM: [ | 
					
						
							|  |  |  | 			(options.to_bottom_button === true  | 
					
						
							|  |  |  | 			 		|| buttons.indexOf('TO_BOTTOM') >= 0) ?  | 
					
						
							|  |  |  | 				'⤓'  | 
					
						
							|  |  |  | 				: options.to_bottom_button, | 
					
						
							|  |  |  | 			function(p, e){ | 
					
						
							|  |  |  | 				var d = move(p, dialog.__list[id].length) | 
					
						
							| 
									
										
										
										
											2017-02-08 23:13:51 +03:00
										 |  |  | 				d != null | 
					
						
							|  |  |  | 					//&& e.nextAll().eq(Math.abs(d-1)).after(e)
 | 
					
						
							|  |  |  | 					&& e.nextAll().last().after(e) | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 					&& dialog | 
					
						
							| 
									
										
										
										
											2017-02-08 23:13:51 +03:00
										 |  |  | 						// XXX hackish...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 22:59:16 +03:00
										 |  |  | 						.updateItemNumbers() | 
					
						
							|  |  |  | 						.trigger('to_bottom_button', p, e) | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 			}], | 
					
						
							|  |  |  | 		REMOVE: Buttons.markForRemoval( | 
					
						
							|  |  |  | 			to_remove,  | 
					
						
							|  |  |  | 			options.delete_button !== true ?  | 
					
						
							|  |  |  | 				options.delete_button  | 
					
						
							|  |  |  | 				: undefined) | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 	// replace the button placeholders...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 	// NOTE: only the first button instance is used, also not that all
 | 
					
						
							|  |  |  | 	// 		the config buttons are pushed to the end of the list thus
 | 
					
						
							|  |  |  | 	// 		they will be overridden buy user buttons...
 | 
					
						
							|  |  |  | 	var seen = [] | 
					
						
							| 
									
										
										
										
											2017-02-08 02:04:59 +03:00
										 |  |  | 	buttons = options.buttons =  | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 		buttons | 
					
						
							|  |  |  | 			.map(function(button){ | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 				var key = button instanceof Array ? button[1] : button | 
					
						
							|  |  |  | 				// skip seen buttons...
 | 
					
						
							|  |  |  | 				if(seen.indexOf(key) >= 0){ | 
					
						
							|  |  |  | 					return key | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-08 02:51:40 +03:00
										 |  |  | 				var res = button in __buttons ?  | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 						__buttons[button] | 
					
						
							|  |  |  | 					: button[1] in __buttons ?  | 
					
						
							|  |  |  | 						[button[0], __buttons[button[1]][1]] | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 					: button | 
					
						
							| 
									
										
										
										
											2017-02-08 02:51:40 +03:00
										 |  |  | 				// group if at least one sort button is present...
 | 
					
						
							|  |  |  | 				if(res !== button){ | 
					
						
							|  |  |  | 					options.groupList = true | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// avoid duplicates...
 | 
					
						
							|  |  |  | 					seen.push(key) | 
					
						
							| 
									
										
										
										
											2017-02-08 02:51:40 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-08 05:30:18 +03:00
										 |  |  | 				return res.slice() | 
					
						
							| 
									
										
										
										
											2017-02-08 02:51:40 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 			// clear out the unused button placeholders...
 | 
					
						
							|  |  |  | 			.filter(function(b){  | 
					
						
							|  |  |  | 				return ['UP', 'DOWN', 'TO_TOP', 'TO_BOTTOM', 'REMOVE'].indexOf(b) < 0 }) | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 	// if we are sortable then we will need to also be grouped...
 | 
					
						
							|  |  |  | 	options.sortable | 
					
						
							|  |  |  | 		&& (options.groupList = true) | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// make the list...
 | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | 	var res = make.List(lst, options) | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 		.attr('list-id', id) | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 	// make sortable...
 | 
					
						
							|  |  |  | 	if(options.sortable){ | 
					
						
							|  |  |  | 		// add sort handle...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 06:24:56 +03:00
										 |  |  | 		res.find('.text:first-child') | 
					
						
							|  |  |  | 			.before($('<span>') | 
					
						
							|  |  |  | 				.addClass('sort-handle') | 
					
						
							|  |  |  | 				.html('☰')) | 
					
						
							|  |  |  | 		/* | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 		res.find('.button-container') | 
					
						
							|  |  |  | 			.before($('<span>') | 
					
						
							|  |  |  | 				.addClass('sort-handle') | 
					
						
							|  |  |  | 				.html('☰')) | 
					
						
							| 
									
										
										
										
											2017-02-08 06:24:56 +03:00
										 |  |  | 		//*/
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 		// make the block sortable...
 | 
					
						
							|  |  |  | 		res.parent().sortable({ | 
					
						
							|  |  |  | 			handle: '.sort-handle', | 
					
						
							|  |  |  | 			axis: options.sortable === true ? false : options.sortable, | 
					
						
							|  |  |  | 			forcePlaceholderSize: true, | 
					
						
							|  |  |  | 			containment: 'parent', | 
					
						
							|  |  |  | 			tolerance: 'pointer', | 
					
						
							|  |  |  | 			update: function(evt, ui){ | 
					
						
							|  |  |  | 				var order = ui.item.parent() | 
					
						
							|  |  |  | 					.find('.item') | 
					
						
							|  |  |  | 						.map(function(){ return $(this).find('.text').text() }) | 
					
						
							|  |  |  | 						.toArray() | 
					
						
							|  |  |  | 				var l = dialog.__list[id] | 
					
						
							|  |  |  | 				l.splice.apply(l, [0, l.length].concat(order)) | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 				dialog.updateItemNumbers() | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-18 20:57:29 +03:00
										 |  |  | 	// mark items for removal -- if a list is given by user...
 | 
					
						
							|  |  |  | 	to_remove.forEach(function(e){ | 
					
						
							|  |  |  | 		dialog.filter('"'+ e +'"') | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 			.addClass('strike-out') | 
					
						
							| 
									
										
										
										
											2017-01-18 20:57:29 +03:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-18 03:26:43 +03:00
										 |  |  | 	options.itemopen | 
					
						
							|  |  |  | 		&& res.on('open', function(){ options.itemopen(dialog.selected) }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = res.toArray() | 
					
						
							| 
									
										
										
										
											2017-02-01 21:11:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 	// new button...
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 	if(options.new_item !== false){ | 
					
						
							|  |  |  | 		var new_item = options.new_item || true | 
					
						
							|  |  |  | 		new_item = new_item === true ? 'New...' : new_item | 
					
						
							|  |  |  | 		res.push(make.Editable( | 
					
						
							|  |  |  | 			new_item,  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				action: true,  | 
					
						
							|  |  |  | 				clear_on_edit: true, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			// update list on edit done...
 | 
					
						
							|  |  |  | 			.on('edit-commit', function(evt, txt){ | 
					
						
							|  |  |  | 				txt = options.normalize ?  | 
					
						
							|  |  |  | 					options.normalize(txt)  | 
					
						
							|  |  |  | 					: txt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// invalid format...
 | 
					
						
							|  |  |  | 				if(options.check && !options.check(txt)){ | 
					
						
							|  |  |  | 					dialog.update() | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 				lst = dialog.__list[id] | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// list length limit
 | 
					
						
							|  |  |  | 				if(options.length_limit  | 
					
						
							|  |  |  | 					&& (lst.length >= options.length_limit)){ | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 					options.overflow  | 
					
						
							|  |  |  | 						&& options.overflow.call(dialog, txt) | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// prevent editing non-arrays...
 | 
					
						
							|  |  |  | 				if(!editable || !lst){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// add new value and sort list...
 | 
					
						
							|  |  |  | 				lst.push(txt) | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// unique...
 | 
					
						
							|  |  |  | 				if(options.unique == null || options.unique === true){ | 
					
						
							|  |  |  | 					lst = lst.unique() | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// unique normalized...
 | 
					
						
							|  |  |  | 				} else if(options.unique instanceof Function){ | 
					
						
							|  |  |  | 					lst = lst.unique(options.unique)  | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// sort...
 | 
					
						
							|  |  |  | 				if(options.sort){ | 
					
						
							|  |  |  | 					lst = lst | 
					
						
							|  |  |  | 						.sort(options.sort instanceof Function ?  | 
					
						
							|  |  |  | 							options.sort  | 
					
						
							|  |  |  | 							: undefined) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 02:37:34 +03:00
										 |  |  | 				lst = dialog.__list[id] = write(list, lst) | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 05:04:40 +03:00
										 |  |  | 				// update list and select new value...
 | 
					
						
							|  |  |  | 				dialog.update() | 
					
						
							|  |  |  | 					.done(function(){ | 
					
						
							|  |  |  | 						dialog.select('"'+txt+'"') | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 			})) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// dialog handlers...
 | 
					
						
							|  |  |  | 	// NOTE: we bind these only once per dialog...
 | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 	if(dialog.__editable_list_handlers[id] == null){ | 
					
						
							|  |  |  | 		dialog.__editable_list_handlers[id] = true | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 		dialog | 
					
						
							|  |  |  | 			// update the striked-out items (to_remove)...
 | 
					
						
							|  |  |  | 			.on('update', function(){ | 
					
						
							|  |  |  | 				to_remove.forEach(function(e){ | 
					
						
							|  |  |  | 					dialog.filter('"'+ e +'"') | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 						.addClass('strike-out') | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			// clear the to_remove items + save list...
 | 
					
						
							|  |  |  | 			.on('close', function(){ | 
					
						
							|  |  |  | 				// prevent editing non-arrays...
 | 
					
						
							|  |  |  | 				if(!editable){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 06:48:24 +03:00
										 |  |  | 				lst = dialog.__list[id] | 
					
						
							| 
									
										
										
										
											2017-01-18 21:36:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				// remove items...
 | 
					
						
							|  |  |  | 				to_remove.forEach(function(e){ | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 					var i = lst.indexOf(e) | 
					
						
							|  |  |  | 					i >= 0  | 
					
						
							|  |  |  | 						&& lst.splice(i, 1) | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// sort...
 | 
					
						
							|  |  |  | 				if(options.sort){ | 
					
						
							|  |  |  | 					lst.sort(options.sort !== true ? options.sort : undefined) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 				write(list, lst) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 	return $(res) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | // Editable list of pinnable elements...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This is like .EditableList(..) but adds the ability to pin items to 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 04:13:24 +03:00
										 |  |  | // the top sub-list and either maintain that sub-list order independently
 | 
					
						
							|  |  |  | // or keep it the same as the main list...
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:16:40 +03:00
										 |  |  | // 		// Equivalent to .length_limit option in .List(..) but applies 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | // 		// only to pins...
 | 
					
						
							|  |  |  | // 		pins_length_limit: .. ,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:16:40 +03:00
										 |  |  | // 		// Equivalent to .sortable option in .List(..) but applies only
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | // 		// to pins...
 | 
					
						
							|  |  |  | // 		pins_sortable: .. ,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-08 03:16:40 +03:00
										 |  |  | // 		// Equivalent to .buttons option in .List(..) but applies only 
 | 
					
						
							|  |  |  | // 		// to pins...
 | 
					
						
							|  |  |  | // 		// If this is not given the same buttons are used for both lists.
 | 
					
						
							|  |  |  | // 		pins_buttons: .. ,
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | // XXX should id be the first argument??
 | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | Items.EditablePinnedList = | 
					
						
							|  |  |  | function(list, pins, options){ | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 	var that = this | 
					
						
							| 
									
										
										
										
											2017-02-02 04:07:10 +03:00
										 |  |  | 	pins = pins || [] | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	options = options || {} | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 	var id = options.list_id | 
					
						
							|  |  |  | 	var pins_id = id + '-pins' | 
					
						
							|  |  |  | 	var dialog = this.dialog | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	// prepare the cache...
 | 
					
						
							| 
									
										
										
										
											2017-02-02 04:07:10 +03:00
										 |  |  | 	// XXX check if either list/pins is a function...
 | 
					
						
							|  |  |  | 	dialog.__list = dialog.__list || {} | 
					
						
							|  |  |  | 	list = dialog.__list[id] = dialog.__list[id] || list | 
					
						
							|  |  |  | 	pins = dialog.__list[pins_id] = dialog.__list[pins_id] || pins | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	// link the to_remove lists of pins and the main list...
 | 
					
						
							|  |  |  | 	dialog.__to_remove = dialog.__to_remove || {} | 
					
						
							|  |  |  | 	if(dialog.__to_remove[id] == null){ | 
					
						
							|  |  |  | 		dialog.__to_remove[id] = dialog.__to_remove[pins_id] = [] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | 	// XXX redraw....
 | 
					
						
							|  |  |  | 	// 		- sort			- within one list this is trivial (history.js)
 | 
					
						
							|  |  |  | 	// 		- pin/unpin 	- remove item from one list and update the 
 | 
					
						
							|  |  |  | 	// 							other... (can we update a sub-list?)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	//------------------------------------ setup options: main/pins ---
 | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	// buttons...
 | 
					
						
							|  |  |  | 	var buttons = options.buttons = (options.buttons || []).slice() | 
					
						
							| 
									
										
										
										
											2017-02-08 06:24:56 +03:00
										 |  |  | 	var pins_buttons = (options.pins_buttons || buttons).slice() | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	// pin/unpin button...
 | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	var pin = [ | 
					
						
							|  |  |  | 		'<span class="pin-set">●</span>' | 
					
						
							|  |  |  | 		+'<span class="pin-unset">○</span>',  | 
					
						
							|  |  |  | 			function(p, cur){ | 
					
						
							| 
									
										
										
										
											2017-02-02 04:07:10 +03:00
										 |  |  | 				// XXX if this line's not here, for some reason on first
 | 
					
						
							|  |  |  | 				// 		run this sees the wrong instance of pins...
 | 
					
						
							|  |  |  | 				var pins = dialog.__list[pins_id] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 				// pin...
 | 
					
						
							|  |  |  | 				if(!cur.hasClass('pinned')){ | 
					
						
							|  |  |  | 					// XXX check pins length limit...
 | 
					
						
							|  |  |  | 					pins.splice(0, 0, p) | 
					
						
							|  |  |  | 					// sort pins...
 | 
					
						
							|  |  |  | 					sortable | 
					
						
							|  |  |  | 						|| (options.sort instanceof Function ?  | 
					
						
							|  |  |  | 							pins.sort(options.sort)  | 
					
						
							| 
									
										
										
										
											2017-02-02 04:19:43 +03:00
										 |  |  | 							: pins.sortAs(dialog.__list[id])) | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// unpin...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					pins.splice(pins.indexOf(p), 1) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX this is slow...
 | 
					
						
							| 
									
										
										
										
											2017-02-09 02:11:28 +03:00
										 |  |  | 				that.dialog | 
					
						
							|  |  |  | 					.update() | 
					
						
							|  |  |  | 					.then(function(){ | 
					
						
							|  |  |  | 						that.dialog.trigger('pin_button', p, cur) | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 			}] | 
					
						
							| 
									
										
										
										
											2017-02-08 06:24:56 +03:00
										 |  |  | 	;[buttons, pins_buttons] | 
					
						
							|  |  |  | 		.forEach(function(b){ | 
					
						
							|  |  |  | 			var i = b.indexOf('PIN') | 
					
						
							|  |  |  | 			i < 0 ?  | 
					
						
							|  |  |  | 				b.push(pin) | 
					
						
							|  |  |  | 				: (b[i] = pin)  | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 	options.isItemHidden = function(e){ return pins.indexOf(e) >= 0 } | 
					
						
							|  |  |  | 	options.skipHiddenItems = options.skipHiddenItems !== false ? true : false | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	//----------------------------------------- setup options: pins ---
 | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	var pins_options = { | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 		list_id: pins_id, | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 		new_item: false, | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 		length_limit: options.pins_length_limit || 10, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		isItemHidden: null, | 
					
						
							| 
									
										
										
										
											2017-02-08 02:49:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 06:24:56 +03:00
										 |  |  | 		buttons: pins_buttons, | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	pins_options.__proto__ = options | 
					
						
							| 
									
										
										
										
											2017-02-02 04:19:43 +03:00
										 |  |  | 	var sortable = pins_options.sortable =  | 
					
						
							|  |  |  | 		options.pins_sortable === undefined  | 
					
						
							|  |  |  | 			|| options.pins_sortable | 
					
						
							|  |  |  | 	if(!sortable){ | 
					
						
							|  |  |  | 		 pins_options.sort = options.sort instanceof Function ?  | 
					
						
							|  |  |  | 			options.sort | 
					
						
							|  |  |  | 			: pins.sortAs(dialog.__list[id]) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	//---------------------------------------------- build the list ---
 | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 	var res = this.EditableList(pins, pins_options) | 
					
						
							| 
									
										
										
										
											2017-02-01 19:25:58 +03:00
										 |  |  | 		.addClass('pinned') | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 		.toArray() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 04:07:10 +03:00
										 |  |  | 	res.length > 0  | 
					
						
							|  |  |  | 		&& res.push(this.Separator()[0]) | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	res.concat(this.EditableList( | 
					
						
							|  |  |  | 			// remove pinned from list...
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 			list,  | 
					
						
							| 
									
										
										
										
											2017-01-31 15:27:29 +03:00
										 |  |  | 			options) | 
					
						
							|  |  |  | 		.toArray()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return $(res) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Browse item buttons (button constructors)...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var Buttons =  | 
					
						
							|  |  |  | Items.buttons = | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | module.buttons = {} | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | // Mark an item for removal and add it to a list of marked items...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | Buttons.markForRemoval = function(list, html){ | 
					
						
							|  |  |  | 	return [html || '×',  | 
					
						
							|  |  |  | 		function(p, e){ | 
					
						
							|  |  |  | 			e.toggleClass('strike-out') | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 			if(list == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(e.hasClass('strike-out')){ | 
					
						
							|  |  |  | 				list.indexOf(p) < 0  | 
					
						
							|  |  |  | 					&& list.push(p) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				var i = list.indexOf(p) | 
					
						
							|  |  |  | 				i >= 0 | 
					
						
							|  |  |  | 					&& list.splice(i, 1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}] | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | // NOTE: the widget itself does not need a title, that's the job for
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | //		a container widget (dialog, field, ...)
 | 
					
						
							|  |  |  | //		...it can be implemented trivially via an attribute and a :before
 | 
					
						
							|  |  |  | //		CSS class...
 | 
					
						
							|  |  |  | var BrowserClassPrototype = { | 
					
						
							| 
									
										
										
										
											2015-09-22 22:50:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Normalize path...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This converts the path into a universal absolute array 
 | 
					
						
							|  |  |  | 	// representation, taking care of relative path constructs including
 | 
					
						
							|  |  |  | 	// '.' (current path) and '..' (up one level)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX does this need to handle trailing '/'???
 | 
					
						
							|  |  |  | 	// 		...the problem is mainly encoding a trailing '/' into an 
 | 
					
						
							|  |  |  | 	// 		array, adding a '' at the end seems both obvious and 
 | 
					
						
							|  |  |  | 	// 		artificial...
 | 
					
						
							|  |  |  | 	// XXX is this the correct name???
 | 
					
						
							|  |  |  | 	// 		...should this be .normalizePath(..)???
 | 
					
						
							|  |  |  | 	path2list: function(path){ | 
					
						
							|  |  |  | 		var splitter = /[\\\/]/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(typeof(path) == typeof('str')){ | 
					
						
							|  |  |  | 			path = path | 
					
						
							|  |  |  | 				.split(splitter) | 
					
						
							|  |  |  | 				.filter(function(e){ return e != '' }) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// we've got a relative path...
 | 
					
						
							|  |  |  | 		if(path[0] == '.' || path[0] == '..'){ | 
					
						
							|  |  |  | 			path = this.path.concat(path) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		path = path | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			// clear the '..' and markers...
 | 
					
						
							| 
									
										
										
										
											2015-09-22 22:50:18 +03:00
										 |  |  | 			// NOTE: we reverse to avoid setting elements with negative
 | 
					
						
							|  |  |  | 			// 		indexes if we have a leading '..'
 | 
					
						
							|  |  |  | 			.reverse() | 
					
						
							|  |  |  | 			.map(function(e, i){ | 
					
						
							|  |  |  | 				if(e == '..'){ | 
					
						
							|  |  |  | 					e = '.' | 
					
						
							|  |  |  | 					path[i] = '.' | 
					
						
							|  |  |  | 					path[i+1] = '.' | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return e | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.reverse() | 
					
						
							|  |  |  | 			// filter out '.'...
 | 
					
						
							|  |  |  | 			.filter(function(e){ return e != '.' }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return path | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Construct the dom...
 | 
					
						
							| 
									
										
										
										
											2015-11-09 22:48:13 +03:00
										 |  |  | 	make: function(obj, options){ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var browser = $('<div>') | 
					
						
							| 
									
										
										
										
											2017-01-06 06:58:50 +03:00
										 |  |  | 			.addClass('browse-widget '+ (options.cloudView ? 'cloud-view' : '')) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			// 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(){ | 
					
						
							| 
									
										
										
										
											2016-06-07 06:03:16 +03:00
										 |  |  | 				if($(this).find(':focus').length == 0){ | 
					
						
							|  |  |  | 					$(this).focus() | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		if(options.flat){ | 
					
						
							|  |  |  | 			browser.addClass('flat') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-03 02:55:25 +03:00
										 |  |  | 		if(options.cls){ | 
					
						
							|  |  |  | 			browser.addClass(options.cls) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		// path...
 | 
					
						
							|  |  |  | 		var path = $('<div>') | 
					
						
							|  |  |  | 			.addClass('v-block path') | 
					
						
							| 
									
										
										
										
											2015-06-22 05:57:15 +03:00
										 |  |  | 			/* | 
					
						
							|  |  |  | 			.click(function(){ | 
					
						
							|  |  |  | 				// XXX set contenteditable...
 | 
					
						
							|  |  |  | 				// XXX set value to path...
 | 
					
						
							|  |  |  | 				// XXX select all...
 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.on('blur', function(){ | 
					
						
							|  |  |  | 				// XXX unset contenteditable...
 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.keyup(function(){ | 
					
						
							|  |  |  | 				// XXX update path...
 | 
					
						
							|  |  |  | 				// 		- set /../..../ to path
 | 
					
						
							|  |  |  | 				// 		- use the part after the last '/' ad filter...
 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		  	*/ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 03:42:55 +03:00
										 |  |  | 		if(options.pathPrefix){ | 
					
						
							|  |  |  | 			path.attr('prefix', options.pathPrefix) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		if(options.show_path == false){ | 
					
						
							|  |  |  | 			path.hide() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		browser | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 			.append(path) | 
					
						
							|  |  |  | 			// list...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			.append($('<div>') | 
					
						
							|  |  |  | 				   .addClass('v-block list')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return browser | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | // XXX Q: should we make a base list dialog and build this on that or
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | //		simplify this to implement a list (removing the path and disabling
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | //		traversal)??
 | 
					
						
							| 
									
										
										
										
											2016-01-26 07:43:22 +03:00
										 |  |  | // XXX might be a good idea to add a ctrl-c/copy handler...
 | 
					
						
							|  |  |  | // 		...copy path by default but overloadable with something like 
 | 
					
						
							|  |  |  | // 		.getCopyValue() which would return .strPath by default...
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | // XXX feels a bit over-complicated...
 | 
					
						
							|  |  |  | // 		...might be a good idea to split this into:
 | 
					
						
							|  |  |  | // 			- base 
 | 
					
						
							|  |  |  | // 				- structure 
 | 
					
						
							|  |  |  | // 				- path/traversable
 | 
					
						
							|  |  |  | // 				- navigation (mouse/keyboard)
 | 
					
						
							|  |  |  | // 			- search/filtering
 | 
					
						
							|  |  |  | // 			- buttons
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | // XXX add a fast redraw mode to .update(..) (???)
 | 
					
						
							|  |  |  | // 		- do not clear items
 | 
					
						
							|  |  |  | // 		- if args did not change:
 | 
					
						
							|  |  |  | // 			- check if cur item is the same 
 | 
					
						
							|  |  |  | // 				...same text, options, signature to make(..)???
 | 
					
						
							|  |  |  | // 			- if the same, keep the element
 | 
					
						
							|  |  |  | // 			- if different find and place
 | 
					
						
							|  |  |  | // 			- if nothing found, create
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | var BrowserPrototype = { | 
					
						
							|  |  |  | 	dom: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 03:34:15 +03:00
										 |  |  | 	// option defaults and doc...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	options: { | 
					
						
							| 
									
										
										
										
											2017-01-03 02:55:25 +03:00
										 |  |  | 		// CSS classes to add to widget...
 | 
					
						
							|  |  |  | 		cls: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		// Initial path...
 | 
					
						
							| 
									
										
										
										
											2017-01-20 23:03:09 +03:00
										 |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: this can be a number indicating the item to select when
 | 
					
						
							|  |  |  | 		// 		load is done.
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		//path: null,
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		//selected: null,
 | 
					
						
							| 
									
										
										
										
											2015-05-18 03:34:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		//show_path: true,
 | 
					
						
							| 
									
										
										
										
											2015-11-28 18:15:12 +03:00
										 |  |  | 		 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		// Set the path prefix...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2015-11-28 18:15:12 +03:00
										 |  |  | 		// XXX at this time this is used only for generating paths, need
 | 
					
						
							|  |  |  | 		// 		to also use this for parsing...
 | 
					
						
							|  |  |  | 		pathPrefix: '/', | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Enable/disable user selection filtering...
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 		// NOTE: this only affects starting the filter...
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | 		filter: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 		// Enable/disable full path editing...
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 		// NOTE: as with .filter above, this only affects .startFullPathEdit(..)
 | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 		fullPathEdit: true, | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		// If false will disable traversal...
 | 
					
						
							|  |  |  | 		// NOTE: if false this will also disable traversal up.
 | 
					
						
							|  |  |  | 		// NOTE: this will not disable manual updates or explicit path 
 | 
					
						
							|  |  |  | 		// 		setting.
 | 
					
						
							|  |  |  | 		// NOTE: another way to disable traversal is to set 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 18:51:42 +03:00
										 |  |  | 		// 		.not-traversable on the .browse-widget element
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		// NOTE: if false this will also disable .toggleNonTraversableDrawing()
 | 
					
						
							|  |  |  | 		// 		as this will essentially hide/show the whole list.
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		traversable: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		// If true non-traversable items will be shown...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: setting both this and .traversable to false will hide 
 | 
					
						
							|  |  |  | 		// 		all elements in the list.
 | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 		showNonTraversable: true, | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// If true disabled items will be shown...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: this will have an effect only on items disabled via list/make
 | 
					
						
							|  |  |  | 		// 		items with .disabled CSS class set manually will not be 
 | 
					
						
							|  |  |  | 		// 		affected...
 | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 		showDisabled: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 		// XXX
 | 
					
						
							|  |  |  | 		showHidden: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		// Enable/disable disabled drawing...
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		// 
 | 
					
						
							|  |  |  | 		// If false these will disable the corresponding methods.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: these are here to let the user enable/disable these 
 | 
					
						
							|  |  |  | 		// 		without the need to go into the keyboard configuration...
 | 
					
						
							|  |  |  | 		// NOTE: non-traversable drawing is disabled/enabled by .traversable
 | 
					
						
							|  |  |  | 		// 		option above.
 | 
					
						
							|  |  |  | 		// NOTE: this will have an effect only on items disabled via list/make
 | 
					
						
							|  |  |  | 		// 		items with .disabled CSS class set manually will not be 
 | 
					
						
							|  |  |  | 		// 		affected...
 | 
					
						
							|  |  |  | 		toggleDisabledDrawing: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 		// XXX
 | 
					
						
							|  |  |  | 		toggleHiddenDrawing: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 		// Group traversable elements...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Possible values:
 | 
					
						
							|  |  |  | 		// 	null | false | 'none'	- show items as-is
 | 
					
						
							|  |  |  | 		// 	'first'					- group traversable items at top
 | 
					
						
							|  |  |  | 		// 	'last'					- group traversable items at bottom
 | 
					
						
							|  |  |  | 		sortTraversable: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		// Create item shortcuts...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// If false, no shortcuts will be created.
 | 
					
						
							|  |  |  | 		setItemShortcuts: true, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Item shortcut text marker...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// This can be a regexp string pattern or a RegExp object. This 
 | 
					
						
							|  |  |  | 		// should contain one group containing the key. 
 | 
					
						
							|  |  |  | 		// Everything outside the last group will be cleaned out of the
 | 
					
						
							|  |  |  | 		// text...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: it is best to keep this HTML compatible, this makes the
 | 
					
						
							|  |  |  | 		// 		use of chars like '&' not to be recommended...
 | 
					
						
							|  |  |  | 		itemShortcutMarker: '\\$(\\w)', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		// Controls the display of the action button on each list item...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Possible values:
 | 
					
						
							|  |  |  | 		// 	false			- disable the action button
 | 
					
						
							|  |  |  | 		// 	true			- show default action button
 | 
					
						
							|  |  |  | 		// 	<text/html>		- display <text/html> in action button
 | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 		actionButton: false, | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Controls the display of the push button on each list item...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// This has the same semantics as .actionButton so see that for 
 | 
					
						
							|  |  |  | 		// more info.
 | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 		pushButton: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | 		// A set of custom buttons to add to each item.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Format:
 | 
					
						
							|  |  |  | 		itemButtons: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		// Handle keys that are not bound...
 | 
					
						
							| 
									
										
										
										
											2015-05-18 03:34:15 +03:00
										 |  |  | 		// NOTE: to disable, set ot undefined.
 | 
					
						
							|  |  |  | 		logKeys: function(k){ window.DEBUG && console.log(k) }, | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// If set disables leading and trailing '/' on list and path 
 | 
					
						
							|  |  |  | 		// elements.
 | 
					
						
							|  |  |  | 		// This is mainly used for flat list selectors.
 | 
					
						
							|  |  |  | 		flat: false, | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 		// If set this will switch the browse dialog into cloud mode.
 | 
					
						
							|  |  |  | 		cloudView: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 		// List of events that will not get propagated outside the browser...
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:37:09 +03:00
										 |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 		// NOTE: these are local events defined on the widget, so it 
 | 
					
						
							|  |  |  | 		// 		would not be logical to propagate them up the DOM, but if
 | 
					
						
							|  |  |  | 		// 		such behavior is desired one could always change the 
 | 
					
						
							|  |  |  | 		// 		configuration ;)
 | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 		nonPropagatedEvents: [ | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 			'push', | 
					
						
							|  |  |  | 			'pop', | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 			'open', | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 			'update', | 
					
						
							|  |  |  | 			'select', | 
					
						
							|  |  |  | 			'deselect', | 
					
						
							| 
									
										
										
										
											2015-09-08 01:01:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 05:17:14 +03:00
										 |  |  | 			'keydown', | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 05:17:14 +03:00
										 |  |  | 			//'close',
 | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 		], | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 		// Shorthand elements...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Format:
 | 
					
						
							|  |  |  | 		// 	{
 | 
					
						
							|  |  |  | 		// 		<key>: {
 | 
					
						
							|  |  |  | 		// 			class: <element-class-str>,
 | 
					
						
							|  |  |  | 		// 			html: <element-html-str>,
 | 
					
						
							|  |  |  | 		// 		},
 | 
					
						
							|  |  |  | 		// 		...
 | 
					
						
							|  |  |  | 		// 	}
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// If make(..) gets passed <key> it will construct and element
 | 
					
						
							|  |  |  | 		// via <element-html-str> with an optional <element-class-str>
 | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 		// NOTE: .class is optional...
 | 
					
						
							|  |  |  | 		// NOTE: set this to null to disable shorthands...
 | 
					
						
							|  |  |  | 		elementShorthand: { | 
					
						
							|  |  |  | 			'---': { | 
					
						
							|  |  |  | 				'class': 'separator', | 
					
						
							|  |  |  | 				'html': '<hr>' | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			'...': { | 
					
						
							|  |  |  | 				'class': 'separator', | 
					
						
							|  |  |  | 				'html': '<center><div class="loader"/></center>', | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Separator class...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: if make(..) is passed an element with this class it will
 | 
					
						
							|  |  |  | 		// 		be treated as a separator and not as a list element.
 | 
					
						
							|  |  |  | 		// NOTE: to disable class checking set this to null
 | 
					
						
							|  |  |  | 		elementSeparatorClass: 'separator', | 
					
						
							| 
									
										
										
										
											2016-12-31 04:38:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Hold browse widget's size between updates...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// This prevents the element from collapsing and then growing 
 | 
					
						
							|  |  |  | 		// again on slowish loads.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Supported values:
 | 
					
						
							|  |  |  | 		// 	- null/false/undefined	- feature disabled
 | 
					
						
							|  |  |  | 		// 	- number				- number of milliseconds to hold size
 | 
					
						
							|  |  |  | 		// 								before timing out
 | 
					
						
							|  |  |  | 		// 	- true					- hold till first make is called
 | 
					
						
							|  |  |  | 		// 								without a timeout.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: recommended values are about the same value till the 
 | 
					
						
							|  |  |  | 		// 		first make(..) is called, but obviously this should be 
 | 
					
						
							|  |  |  | 		// 		as short as possible -- under 20-50ms.
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:49:08 +03:00
										 |  |  | 		holdSize: 20, | 
					
						
							| 
									
										
										
										
											2017-03-08 21:26:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		keyboardRepeatPause: 100, | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 	// XXX need a way to access buttons...
 | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	// XXX should we have things like ctrl-<number> for fast selection 
 | 
					
						
							|  |  |  | 	// 		in filter mode???
 | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 	keybindings: { | 
					
						
							| 
									
										
										
										
											2016-01-24 05:30:53 +03:00
										 |  |  | 		ItemEdit: { | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			pattern: '.list .text[contenteditable]', | 
					
						
							| 
									
										
										
										
											2016-01-24 05:30:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// keep text editing action from affecting the selection...
 | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			drop: '*', | 
					
						
							| 
									
										
										
										
											2016-01-24 05:30:53 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 			Up: 'NEXT!', | 
					
						
							|  |  |  | 			Down: 'NEXT!', | 
					
						
							|  |  |  | 			Tab: 'NEXT!', | 
					
						
							|  |  |  | 			shift_Tab: 'NEXT!', | 
					
						
							| 
									
										
										
										
											2017-01-12 21:23:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-14 16:01:17 +03:00
										 |  |  | 			Enter: 'push!', | 
					
						
							|  |  |  | 			Esc: 'update!', | 
					
						
							| 
									
										
										
										
											2016-01-24 05:30:53 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 		FullPathEdit: { | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			pattern: '.path[contenteditable]', | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// keep text editing action from affecting the selection...
 | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			drop: '*', | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Enter: 'stopFullPathEdit!', | 
					
						
							|  |  |  | 			Esc: 'abortFullPathEdit!', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 		Filter: { | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			pattern: '.path div.cur[contenteditable]', | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 05:57:15 +03:00
										 |  |  | 			// keep text editing action from affecting the selection...
 | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			drop: '*', | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 			Up: 'NEXT!', | 
					
						
							|  |  |  | 			Down: 'NEXT!', | 
					
						
							|  |  |  | 			Tab: 'NEXT!', | 
					
						
							|  |  |  | 			shift_Tab: 'NEXT!', | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 			Enter: 'push!', | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 			Esc: 'stopFilter!', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		General: { | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			pattern: '*', | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 			Up: 'up!', | 
					
						
							|  |  |  | 			Down: 'down!', | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			Left: 'left!', | 
					
						
							|  |  |  | 			ctrl_Left: 'update!: "/"', | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 			Backspace: 'Left', | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 			Right: 'right', | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			//P: 'push',
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 			// XXX should these also select buttons???
 | 
					
						
							|  |  |  | 			Tab: 'down!', | 
					
						
							|  |  |  | 			shift_Tab: 'up!', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX is this correct??
 | 
					
						
							|  |  |  | 			ctrl_Tab: 'nop!', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 			// XXX
 | 
					
						
							|  |  |  | 			PgUp: 'prevPage!', | 
					
						
							|  |  |  | 			PgDown: 'nextPage!', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			Home: 'navigate!: "first"', | 
					
						
							|  |  |  | 			End: 'navigate!: "last"', | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			Enter: 'action', | 
					
						
							| 
									
										
										
										
											2017-01-29 06:20:58 +03:00
										 |  |  | 			Space: 'Enter', | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			//O: 'action',
 | 
					
						
							| 
									
										
										
										
											2017-01-29 06:20:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 00:14:31 +03:00
										 |  |  | 			Esc: 'close: "reject"', | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			'/': 'startFilter!', | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-12 02:09:59 +03:00
										 |  |  | 			ctrl_A: 'startFullPathEdit!', | 
					
						
							| 
									
										
										
										
											2015-07-11 16:52:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			ctrl_D: 'toggleDisabledDrawing', | 
					
						
							|  |  |  | 			ctrl_H: 'toggleHiddenDrawing', | 
					
						
							|  |  |  | 			ctrl_T: 'toggleNonTraversableDrawing', | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-14 16:01:17 +03:00
										 |  |  | 			// XXX should these use .select(..)???
 | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 			// XXX should these be relative to visible area or absolute 
 | 
					
						
							|  |  |  | 			// 		to current list regardless of scroll (as is now)???
 | 
					
						
							|  |  |  | 			// XXX should these work while filtering??
 | 
					
						
							| 
									
										
										
										
											2016-04-14 16:01:17 +03:00
										 |  |  | 			'#1': 'push!: "0!"', | 
					
						
							|  |  |  | 			'#2': 'push!: "1!"', | 
					
						
							|  |  |  | 			'#3': 'push!: "2!"', | 
					
						
							|  |  |  | 			'#4': 'push!: "3!"', | 
					
						
							|  |  |  | 			'#5': 'push!: "4!"', | 
					
						
							|  |  |  | 			'#6': 'push!: "5!"', | 
					
						
							|  |  |  | 			'#7': 'push!: "6!"', | 
					
						
							|  |  |  | 			'#8': 'push!: "7!"', | 
					
						
							|  |  |  | 			'#9': 'push!: "8!"', | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			'#0': 'push!: "9!"', | 
					
						
							| 
									
										
										
										
											2017-02-10 02:19:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// handlers for standard shortcuts...
 | 
					
						
							|  |  |  | 			ctrl_C: function(){ console.log('!!!!!') }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ItemShortcuts: { | 
					
						
							|  |  |  | 			doc: 'Item shortcuts', | 
					
						
							|  |  |  | 			pattern: '*', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-24 23:43:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 	// Call the constructor's .path2list(..) and clear out shortcut markers...
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-09-22 22:50:18 +03:00
										 |  |  | 	// See: BrowserClassPrototype.path2list(..) for docs...
 | 
					
						
							| 
									
										
										
										
											2015-12-09 00:04:09 +03:00
										 |  |  | 	path2list: function(path){  | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 		var marker = this.options.itemShortcutMarker  | 
					
						
							|  |  |  | 		marker = marker && RegExp(marker, 'g') | 
					
						
							| 
									
										
										
										
											2015-12-09 00:04:09 +03:00
										 |  |  | 		// if list is flat we do not need to split it, just format...
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 		if(this.options.flat && path && path instanceof Array){ | 
					
						
							|  |  |  | 			return (path == '' || path.length == 0) ? [] : [path] | 
					
						
							| 
									
										
										
										
											2015-12-09 00:04:09 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 		return this.constructor | 
					
						
							|  |  |  | 			.path2list.apply(this, arguments)  | 
					
						
							|  |  |  | 			.map(function(e){  | 
					
						
							|  |  |  | 				return marker ? e.replace(marker, '$1') : e }) | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 	// Trigger jQuery events on Item then bubble to Browser...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will extend the event object with:
 | 
					
						
							|  |  |  | 	// 	.source		- Browser instance that triggered the event
 | 
					
						
							|  |  |  | 	// 	.type		- event type/name
 | 
					
						
							|  |  |  | 	// 	.args		- arguments passed to trigger
 | 
					
						
							| 
									
										
										
										
											2015-06-24 23:43:14 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// NOTE: event propagation for some events is disabled by binding 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// 		to them handlers that stop propagation in .__init__(..).
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// 		The list of non-propagated events in defined in 
 | 
					
						
							|  |  |  | 	// 		.options.nonPropagatedEvents
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 	trigger: function(event){ | 
					
						
							|  |  |  | 		var elem = this.select('!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// NOTE: this will propagate up to the dialog...
 | 
					
						
							|  |  |  | 		if(elem.length > 0){ | 
					
						
							|  |  |  | 			var args = [].slice.call(arguments).slice(1) | 
					
						
							|  |  |  | 			elem.trigger({ | 
					
						
							|  |  |  | 				type: arguments[0], | 
					
						
							|  |  |  | 				source: this, | 
					
						
							|  |  |  | 				args: args, | 
					
						
							|  |  |  | 			}, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// no items selected -- trigger event on main ui...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			object.superMethod(Browser, 'trigger').apply(this, arguments) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// specific events...
 | 
					
						
							| 
									
										
										
										
											2016-06-07 06:03:16 +03:00
										 |  |  | 	focus: function(handler){ | 
					
						
							|  |  |  | 		if(handler != null){ | 
					
						
							|  |  |  | 			this.on('focus', handler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// focus only if we do not have focus...
 | 
					
						
							|  |  |  | 		} else if(!this.dom.is(':focus')  | 
					
						
							|  |  |  | 				&& this.dom.find(':focus').length == 0) { | 
					
						
							|  |  |  | 			this.dom.focus() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-09-07 18:44:10 +03:00
										 |  |  | 	blur: widget.proxyToDom('blur'), | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	// base api...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 	// XXX should these set both the options and dom???
 | 
					
						
							|  |  |  | 	get flat(){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		return !this.dom.hasClass('flat') || this.options.flat }, | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 	set flat(value){ | 
					
						
							|  |  |  | 		if(value){ | 
					
						
							|  |  |  | 			this.dom.addClass('flat') | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.dom.removeClass('flat') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.flat = value | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 	get traversable(){ | 
					
						
							|  |  |  | 		return !this.dom.hasClass('not-traversable') && this.options.traversable }, | 
					
						
							|  |  |  | 	set traversable(value){ | 
					
						
							|  |  |  | 		if(value){ | 
					
						
							|  |  |  | 			this.dom.removeClass('not-traversable') | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.dom.addClass('not-traversable') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.traversable = value | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 	get cloud(){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		return this.dom.hasClass('cloud-view') || this.options.cloudView }, | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 	set cloud(value){ | 
					
						
							|  |  |  | 		if(value){ | 
					
						
							|  |  |  | 			this.dom.addClass('cloud-view') | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			this.dom.removeClass('cloud-view') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.cloudView = value | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// Get/set the listed path...
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// On more info on setting the path see .update(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// NOTE: .path = <path> is equivalent to .update(<path>) 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// NOTE: if the string path assigned does not contain a trailing '/'
 | 
					
						
							|  |  |  | 	// 		the path will be loaded up to the last item and the last item
 | 
					
						
							|  |  |  | 	// 		will be selected (see .update(..) for example).
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	// NOTE: to avoid duplicating and syncing data, the actual path is 
 | 
					
						
							|  |  |  | 	//		stored in DOM...
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// NOTE: path returned does not include the currently selected list 
 | 
					
						
							|  |  |  | 	// 		element, just the path to the current list...
 | 
					
						
							|  |  |  | 	// 		To get the path with selection use: .selectionPath prop
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	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() }) | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 			.toArray() }, | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	set path(value){ | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 		this.update(value) }, | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 	// String path...
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This is the same as .path but returns a string result.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this does not include the selected element, i.e. the returned 
 | 
					
						
							|  |  |  | 	// 		path always ends with a trailing '/'.
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 	// NOTE: the setter is just a shorthand to .path setter for uniformity...
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX need to append '/' only if traversable...
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 	get strPath(){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		return this.options.pathPrefix + this.path.join('/') + '/' }, | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 	set strPath(value){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		this.path = value }, | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	// Get/set path with selection...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// NOTE: this always returns the selected element last if one is 
 | 
					
						
							|  |  |  | 	// 		selected, if no element is selected this is equivalent to 
 | 
					
						
							|  |  |  | 	// 		.strPath
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// NOTE: the setter is just a shorthand to .path setter for uniformity...
 | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	get selectionPath(){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		return this.strPath + (this.selected || '') }, | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	set selectionPath(value){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		this.path = value }, | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 	// Get/set current selection (text)...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// NOTE: .selected = <value> is equivalent to .select(<value>) for 
 | 
					
						
							|  |  |  | 	// 		more info on accepted values see .select(..)
 | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 	get selected(){ | 
					
						
							|  |  |  | 		var e = this.select('!') | 
					
						
							|  |  |  | 		if(e.length <= 0){ | 
					
						
							|  |  |  | 			return null | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 		return e.find('.text').text() | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	set selected(value){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 		return this.select(value) }, | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// NOTE: if .options.traversable is false this will have no effect.
 | 
					
						
							|  |  |  | 	// XXX might be a good idea to toggle .non-traversable-hidden CSS 
 | 
					
						
							|  |  |  | 	// 		class here too...
 | 
					
						
							|  |  |  | 	// 		...will need to account for 1-9 shortcut keys and hints to 
 | 
					
						
							|  |  |  | 	// 		still work...
 | 
					
						
							|  |  |  | 	toggleNonTraversableDrawing: function(){ | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		var cur = this.selected  | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		if(this.options.traversable == false){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.showNonTraversable = !this.options.showNonTraversable | 
					
						
							|  |  |  | 		this.update() | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		cur && this.select(cur) | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// XXX this will not affect elements that were disabled via setting 
 | 
					
						
							|  |  |  | 	// 		the .disabled class and not via list/make...
 | 
					
						
							|  |  |  | 	// 		...is this a problem???
 | 
					
						
							|  |  |  | 	// XXX might be a good idea to toggle .disabled-hidden CSS class 
 | 
					
						
							|  |  |  | 	// 		here too...
 | 
					
						
							|  |  |  | 	// 		...will need to account for 1-9 shortcut keys and hints to 
 | 
					
						
							|  |  |  | 	// 		still work...
 | 
					
						
							|  |  |  | 	toggleDisabledDrawing: function(){ | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		var cur = this.selected  | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		if(this.options.toggleDisabledDrawing == false){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.showDisabled = !this.options.showDisabled | 
					
						
							|  |  |  | 		this.update() | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		cur && this.select(cur) | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 	toggleHiddenDrawing: function(){ | 
					
						
							|  |  |  | 		var cur = this.selected  | 
					
						
							|  |  |  | 		if(this.options.toggleHiddenDrawing == false){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.options.showHidden = !this.options.showHidden | 
					
						
							|  |  |  | 		this.update() | 
					
						
							|  |  |  | 		cur && this.select(cur) | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 	/*/ Copy/Paste actions... | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-11 22:26:06 +03:00
										 |  |  | 	// XXX use 'Text' for IE...
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 	copy: function(){ | 
					
						
							|  |  |  | 		var path = this.strPath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(NW){ | 
					
						
							|  |  |  | 			gui.Clipboard.get() | 
					
						
							|  |  |  | 				.set(path, 'text') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// browser...
 | 
					
						
							|  |  |  | 		// XXX use 'Test' for IE...
 | 
					
						
							|  |  |  | 		} else if(event != undefined){ | 
					
						
							|  |  |  | 			event.clipboardData.setData('text/plain', path) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return path | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	paste: function(str){ | 
					
						
							|  |  |  | 		// generic...
 | 
					
						
							|  |  |  | 		if(str != null){ | 
					
						
							|  |  |  | 			this.path = str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// nw.js
 | 
					
						
							|  |  |  | 		} else if(NW){ | 
					
						
							|  |  |  | 			this.path = gui.Clipboard.get() | 
					
						
							|  |  |  | 				.get('text') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// browser...
 | 
					
						
							|  |  |  | 		// XXX use 'Test' for IE...
 | 
					
						
							|  |  |  | 		} else if(event != undefined){ | 
					
						
							|  |  |  | 			this.path = event.clipboardData.getData('text/plain') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 	//*/
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	// update (load) path...
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	// 	- build the path
 | 
					
						
							|  |  |  | 	// 	- build the element list
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 	// 	- bind to control events
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 	// 	- return a deferred
 | 
					
						
							| 
									
										
										
										
											2015-03-22 02:12:30 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This will trigger the 'update' event.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 	// For uniformity and ease of access from DOM, this will also set the
 | 
					
						
							| 
									
										
										
										
											2015-09-07 18:51:42 +03:00
										 |  |  | 	// 'path' html attribute on the .browse-widget element.
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 	// If the given string path does not end with a '/' then the path
 | 
					
						
							|  |  |  | 	// up to the last item will be loaded and the last item loaded.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Examle:
 | 
					
						
							|  |  |  | 	// 		Load and select...
 | 
					
						
							|  |  |  | 	// 		'/some/path/there'		-> .update('/some/path/')
 | 
					
						
							|  |  |  | 	// 									.select('there')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		Load path only...
 | 
					
						
							|  |  |  | 	// 		'/some/path/there/'		-> .update('/some/path/there/')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	// NOTE: setting the DOM attr 'path' works one way, navigating to a
 | 
					
						
							|  |  |  | 	// 		different path will overwrite the attr but setting a new 
 | 
					
						
							|  |  |  | 	// 		value to the html attr will not affect the actual path.
 | 
					
						
							|  |  |  | 	// NOTE: .path = <some-path> is equivalent to .update(<some-path>)
 | 
					
						
							|  |  |  | 	// 		both exist at the same time to enable chaining...
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 	// NOTE: this will scroll the path to show the last element for paths
 | 
					
						
							|  |  |  | 	// 		that do not fit in view...
 | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Item constructor:
 | 
					
						
							|  |  |  | 	// 	This is passed to the lister and can be used by the user to 
 | 
					
						
							|  |  |  | 	// 	construct and extend list items.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Make an item...
 | 
					
						
							|  |  |  | 	//	make(item, options)
 | 
					
						
							|  |  |  | 	//	make(item, traversable, disabled, buttons)
 | 
					
						
							|  |  |  | 	//		-> item
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	item format:
 | 
					
						
							|  |  |  | 	//	- str					- item text
 | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 	//								NOTE: see: .options.elementShorthand
 | 
					
						
							|  |  |  | 	//									for shorthands for common elements
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//									
 | 
					
						
							|  |  |  | 	//	- [str/func, ... ]		- item elements
 | 
					
						
							|  |  |  | 	//								Each of the elements is individually
 | 
					
						
							|  |  |  | 	//								wrapped in a .text container.
 | 
					
						
							|  |  |  | 	//								If an item is a function it is called 
 | 
					
						
							|  |  |  | 	//								and the returned value is treated as
 | 
					
						
							|  |  |  | 	//								the text.
 | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | 	//								NOTE: empty strings will get replaced 
 | 
					
						
							|  |  |  | 	//									with  
 | 
					
						
							| 
									
										
										
										
											2017-01-05 04:53:46 +03:00
										 |  |  | 	//								NOTE: if one of the items or constructor
 | 
					
						
							|  |  |  | 	//									returns is "$BUTTONS" then this
 | 
					
						
							|  |  |  | 	//									item will get replaced with the 
 | 
					
						
							|  |  |  | 	//									button container
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//	- DOM/jQuery			- an element to be used as an item
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Both traversable and disabled are optional and can take bool 
 | 
					
						
							|  |  |  | 	//	values.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 	//	If item matches .options.itemShortcutMarker (default: /\$(\w)/)
 | 
					
						
							|  |  |  | 	//	then the char after the '$' will be used as a keyboard shortcut
 | 
					
						
							|  |  |  | 	//	for this item the char wrapped in a span (class: .keyboard-shortcut),
 | 
					
						
							|  |  |  | 	//	and the marker (in this case '$') will be cleaned out.
 | 
					
						
							|  |  |  | 	//	Also see: item.options.shortcut_key below.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	NOTE: only the first occurrence of key will get registered...
 | 
					
						
							|  |  |  | 	//	NOTE: shortcuts can't override Browse shortcuts...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//	options format:
 | 
					
						
							|  |  |  | 	//	{
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	//		// If true make the element traversable...
 | 
					
						
							|  |  |  | 	//		traversable: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// If true disable the element...
 | 
					
						
							|  |  |  | 	//		disabled: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// If true hide the element...
 | 
					
						
							|  |  |  | 	//		hidden: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// If true the open event will also pass the element to open...
 | 
					
						
							|  |  |  | 	//		//
 | 
					
						
							|  |  |  | 	//		// This is useful for opening traversable elements both on 
 | 
					
						
							|  |  |  | 	//		// pressing Enter or Left keys...
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:55:34 +03:00
										 |  |  | 	//		//
 | 
					
						
							|  |  |  | 	//		// This is equivalent to:
 | 
					
						
							|  |  |  | 	//		//		make(...)
 | 
					
						
							|  |  |  | 	//		//			.attr('push-on-open', 'on')
 | 
					
						
							|  |  |  | 	//		//	or:
 | 
					
						
							|  |  |  | 	//		//		make(...)
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 	//		//			.on('open', function(){ 
 | 
					
						
							|  |  |  | 	//		//				// X here is the browser object...
 | 
					
						
							|  |  |  | 	//		//				X.push(this) })
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:55:34 +03:00
										 |  |  | 	//		//
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	//		push_on_open: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 	// 		// If true this element will be uncondionally hidden on search...
 | 
					
						
							|  |  |  | 	// 		//
 | 
					
						
							|  |  |  | 	// 		// NOTE: this is equivalent to setting .hide-on-search class
 | 
					
						
							|  |  |  | 	// 		//		on the element...
 | 
					
						
							|  |  |  | 	//		hide_on_search: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// If true the item will not get searched...
 | 
					
						
							|  |  |  | 	//		//
 | 
					
						
							|  |  |  | 	// 		// NOTE: this is equivalent to setting .not-searchable class
 | 
					
						
							|  |  |  | 	// 		//		on the element...
 | 
					
						
							|  |  |  | 	//		not_searchable: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// If true item will not get hidden on filtering... 
 | 
					
						
							|  |  |  | 	//		//
 | 
					
						
							|  |  |  | 	// 		// NOTE: this is equivalent to setting .not-filtered-out class
 | 
					
						
							|  |  |  | 	// 		//		on the element...
 | 
					
						
							|  |  |  | 	//		not_filtered_out: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	//		// element button spec...
 | 
					
						
							|  |  |  | 	//		buttons: <bottons>,
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// shortcut key to open the item...
 | 
					
						
							|  |  |  | 	//		shortcut_key: <key>,
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	//	<buttons> format (optional):
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//	[ 
 | 
					
						
							|  |  |  | 	//		[<html>, <func>], 
 | 
					
						
							|  |  |  | 	//		... 
 | 
					
						
							|  |  |  | 	//	]
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: buttons will override .options.itemButtons, if this is not
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	// 		desired simply copy .itemButtons and modify it...
 | 
					
						
							| 
									
										
										
										
											2017-01-13 08:42:47 +03:00
										 |  |  | 	// 			Example:
 | 
					
						
							|  |  |  | 	// 				make(.., {
 | 
					
						
							|  |  |  | 	// 					buttons: [
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 						...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 					// dialog here refers to the browse object...
 | 
					
						
							|  |  |  | 	// 					].concat(dialog.options.itemButtons),
 | 
					
						
							|  |  |  | 	// 				})
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-04 19:26:26 +03:00
										 |  |  | 	// Finalize the dialog (optional)...
 | 
					
						
							|  |  |  | 	// 	- Call make.done() can optionally be called after all the itmes
 | 
					
						
							|  |  |  | 	// 		are created. This will update the dialog to align the 
 | 
					
						
							|  |  |  | 	// 		selected position.
 | 
					
						
							|  |  |  | 	// 		This is useful for dialogs with async loading items. 
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | 	// XXX need a way to handle path errors in the extension API...
 | 
					
						
							|  |  |  | 	// 		...for example, if .list(..) can't list or lists a different
 | 
					
						
							|  |  |  | 	// 		path due to an error, we need to be able to render the new
 | 
					
						
							|  |  |  | 	// 		path both in the path and list sections...
 | 
					
						
							|  |  |  | 	// 		NOTE: current behaviour is not wrong, it just not too flexible...
 | 
					
						
							| 
									
										
										
										
											2015-11-29 20:46:15 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX one use-case here would be to pass this a custom lister or a full
 | 
					
						
							|  |  |  | 	// 		browser, need to make this work correctly for full set of 
 | 
					
						
							|  |  |  | 	// 		events...
 | 
					
						
							|  |  |  | 	// 			- custom lister -- handle all sub-paths in some way...
 | 
					
						
							|  |  |  | 	// 			- full browser -- handle all sub-paths by the nested 
 | 
					
						
							|  |  |  | 	// 								browser...
 | 
					
						
							|  |  |  | 	// 		one way to handle nested browsers is to implement a browser 
 | 
					
						
							|  |  |  | 	// 		stack which if not empty the top browser handles all the 
 | 
					
						
							|  |  |  | 	// 		sub-paths
 | 
					
						
							|  |  |  | 	// 		...this will also need to indicate a way to split the path 
 | 
					
						
							|  |  |  | 	// 		and when to 'pop' the sub browser...
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 	// XXX should we use the button tag for item buttons???
 | 
					
						
							| 
									
										
										
										
											2017-01-29 06:20:58 +03:00
										 |  |  | 	// 		...basically for this to work we need to either reset or override
 | 
					
						
							|  |  |  | 	// 		user-agent-stylesheet...
 | 
					
						
							|  |  |  | 	// 		to override just set most of the affected options to inherit...
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 	update: function(path, list){ | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 		var focus = browser.find(':focus').length > 0 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		list = list || this.list | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		var deferred = $.Deferred() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//-------------------------- prepare the path and selection ---
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 		// string path and terminated with '/' -- no selection...
 | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		if(typeof(path) == typeof('str')  | 
					
						
							|  |  |  | 				&& !/[\\\/]/.test(path.trim().slice(-1))){ | 
					
						
							| 
									
										
										
										
											2015-07-14 16:37:14 +03:00
										 |  |  | 			path = this.path2list(path) | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 			var selection = path.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-28 21:36:17 +03:00
										 |  |  | 		// restore selection if path did not change...
 | 
					
						
							|  |  |  | 		} else if(path instanceof Array  | 
					
						
							|  |  |  | 				&& path.length == this.path.length | 
					
						
							| 
									
										
										
										
											2016-06-01 23:58:01 +03:00
										 |  |  | 				&& path.filter(function(e, i){ return e != that.path[i] }).length == 0){ | 
					
						
							| 
									
										
										
										
											2016-05-28 21:36:17 +03:00
										 |  |  | 			var selection = this.selected | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// no selection...
 | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-07-14 16:37:14 +03:00
										 |  |  | 			path = this.path2list(path) | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 			var selection = null | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//-------------------------------------- prepare for update ---
 | 
					
						
							| 
									
										
										
										
											2016-12-31 04:38:44 +03:00
										 |  |  | 		// prevent the browser from collapsing and then growing on 
 | 
					
						
							|  |  |  | 		// slow-ish loads...
 | 
					
						
							|  |  |  | 		if(this.options.holdSize){ | 
					
						
							|  |  |  | 			var _freeSize = function(){ | 
					
						
							|  |  |  | 				browser.height('') | 
					
						
							|  |  |  | 				browser.width('') | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// cleanup, just in case...
 | 
					
						
							|  |  |  | 			_freeSize() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// only fix the size if we are not empty...
 | 
					
						
							|  |  |  | 			if(browser.find('.list').children().length > 0){ | 
					
						
							|  |  |  | 				browser.height(browser.height()) | 
					
						
							|  |  |  | 				browser.width(browser.width()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// reset after a timeout...
 | 
					
						
							|  |  |  | 			typeof(this.options.holdSize) == typeof(123)  | 
					
						
							|  |  |  | 				&& setTimeout(_freeSize, this.options.holdSize) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		// clear the ui...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var p = browser.find('.path').empty() | 
					
						
							|  |  |  | 		var l = browser.find('.list').empty() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//---------------------------------------------- setup path ---
 | 
					
						
							| 
									
										
										
										
											2015-11-29 03:42:55 +03:00
										 |  |  | 		// set the path prefix...
 | 
					
						
							| 
									
										
										
										
											2016-11-27 00:02:46 +03:00
										 |  |  | 		p | 
					
						
							|  |  |  | 			.attr('prefix', this.options.pathPrefix) | 
					
						
							|  |  |  | 			.scroll(function(){ | 
					
						
							|  |  |  | 				// handle path scroll..
 | 
					
						
							|  |  |  | 				if(p[0].offsetWidth < p[0].scrollWidth){ | 
					
						
							|  |  |  | 					// scroll all the way to the right...
 | 
					
						
							|  |  |  | 					p.addClass('scrolling') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// left out of view...
 | 
					
						
							|  |  |  | 					p[0].scrollLeft > 0 ?  | 
					
						
							|  |  |  | 						p.addClass('left')  | 
					
						
							|  |  |  | 						: p.removeClass('left') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// right out of view...
 | 
					
						
							|  |  |  | 					p[0].scrollLeft + p[0].offsetWidth + 5 <= p[0].scrollWidth ?  | 
					
						
							|  |  |  | 						p.addClass('right')  | 
					
						
							|  |  |  | 						: p.removeClass('right') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// keep left aligned...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					p.removeClass('scrolling') | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-11-29 03:42:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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(){ | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 					if(that.traversable){ | 
					
						
							| 
									
										
										
										
											2015-12-13 03:18:12 +03:00
										 |  |  | 						that.update(cur.join('/'))  | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 				.text(e)) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | 		// add current selection indicator...
 | 
					
						
							| 
									
										
										
										
											2015-06-22 05:57:15 +03:00
										 |  |  | 		var txt | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 		p.append($('<div>') | 
					
						
							|  |  |  | 			.addClass('dir cur') | 
					
						
							|  |  |  | 			.click(function(){ | 
					
						
							| 
									
										
										
										
											2015-07-11 22:02:09 +03:00
										 |  |  | 				event.stopPropagation() | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 				that.toggleFilter('on') | 
					
						
							| 
									
										
										
										
											2015-06-18 01:41:57 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			.on('blur', function(){ | 
					
						
							| 
									
										
										
										
											2015-07-11 22:16:35 +03:00
										 |  |  | 				that.toggleFilter('off') | 
					
						
							| 
									
										
										
										
											2015-06-18 01:41:57 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-06-22 05:57:15 +03:00
										 |  |  | 			// only update if text changed...
 | 
					
						
							|  |  |  | 			.focus(function(){ | 
					
						
							|  |  |  | 				txt = $(this).text() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.keyup(function(){ | 
					
						
							|  |  |  | 				var cur  = $(this).text() | 
					
						
							|  |  |  | 				if(txt != cur){ | 
					
						
							|  |  |  | 					txt = cur | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 					that.filterList(cur) | 
					
						
							| 
									
										
										
										
											2015-06-22 05:57:15 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-03-21 18:20:59 +03:00
										 |  |  | 			})) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// handle path scroll..
 | 
					
						
							|  |  |  | 		// scroll to the end when wider than view...
 | 
					
						
							| 
									
										
										
										
											2016-11-27 00:02:46 +03:00
										 |  |  | 		if(p[0].offsetWidth < p[0].scrollWidth){ | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 			// scroll all the way to the right...
 | 
					
						
							|  |  |  | 			p.scrollLeft(p[0].scrollWidth) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// keep left aligned...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p.scrollLeft(0) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//---------------------------------------------------- make ---
 | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 		var sort_traversable = this.options.sortTraversable | 
					
						
							|  |  |  | 		var section_tail | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		// fill the children list...
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		// NOTE: this will be set to true if make(..) is called at least once...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 		var interactive = false | 
					
						
							| 
									
										
										
										
											2016-12-31 04:38:44 +03:00
										 |  |  | 		var size_freed = false | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//---------------------- prepare for new keyboard shortcuts ---
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		// clear previous shortcuts...
 | 
					
						
							|  |  |  | 		var item_shortcuts = this.options.setItemShortcuts ?  | 
					
						
							|  |  |  | 			(this.keybindings.ItemShortcuts = this.keybindings.ItemShortcuts || {}) | 
					
						
							|  |  |  | 			: null | 
					
						
							|  |  |  | 		// clear the shortcuts...
 | 
					
						
							|  |  |  | 		Object.keys(item_shortcuts).forEach(function(k){ | 
					
						
							|  |  |  | 			if(k != 'doc' && k != 'pattern'){ | 
					
						
							|  |  |  | 				delete item_shortcuts[k] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 		var item_shortcut_marker = this.options.itemShortcutMarker | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		item_shortcut_marker = item_shortcut_marker ?  | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			RegExp(item_shortcut_marker, 'g')  | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			: null | 
					
						
							| 
									
										
										
										
											2017-03-30 00:39:29 +03:00
										 |  |  | 		var registered_shortcuts = [] | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//--------------------------------------------- define make ---
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 		// XXX revise signature... 
 | 
					
						
							|  |  |  | 		var make = function(p, traversable, disabled, buttons){ | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 			var opts = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 			var hidden = false | 
					
						
							| 
									
										
										
										
											2016-12-31 04:38:44 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(that.options.holdSize){ | 
					
						
							|  |  |  | 				// we've started, no need to hold the size any more... 
 | 
					
						
							|  |  |  | 				// ...and we do not need to do this more than once.
 | 
					
						
							|  |  |  | 				size_freed = !size_freed ? !_freeSize() : true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 			// options passed as an object...
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 			if(traversable != null && typeof(traversable) != typeof(true)){ | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 				opts = traversable | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 				traversable = opts.traversable | 
					
						
							|  |  |  | 				disabled = opts.disabled | 
					
						
							|  |  |  | 				buttons = opts.buttons | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 				hidden = opts.hidden | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			buttons = buttons | 
					
						
							|  |  |  | 				|| (that.options.itemButtons && that.options.itemButtons.slice()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: this is becoming a bit big, so here the code is 
 | 
					
						
							|  |  |  | 			// 		split into more wieldable sections...
 | 
					
						
							|  |  |  | 			//------------------------ special case: shorthand item ---
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 			if(p && (p in (that.options.elementShorthand || {}) | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 					|| (p.hasClass  | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 						&& p in that.options.elementShorthand | 
					
						
							|  |  |  | 						&& that.options.elementShorthand[p].class | 
					
						
							|  |  |  | 						&& p.hasClass(that.options.elementShorthand[p].class)))){ | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 				var res = p | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 				var shorthand = that.options.elementShorthand[p] | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 				if(typeof(res) == typeof('str')){ | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 					res = $(shorthand.html) | 
					
						
							|  |  |  | 						.addClass(shorthand.class || '') | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				res.appendTo(l) | 
					
						
							|  |  |  | 				return res | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//------------------------------------------- item text ---
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			// array of str/func/dom...
 | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 			if(p.constructor === Array){ | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 				// resolve handlers...
 | 
					
						
							|  |  |  | 				p = p.map(function(e){  | 
					
						
							|  |  |  | 					return typeof(e) == typeof(function(){}) ?  | 
					
						
							|  |  |  | 						// XXX should this pass anything to the handler 
 | 
					
						
							|  |  |  | 						// 		and set the context???
 | 
					
						
							|  |  |  | 						e.call(that, p)  | 
					
						
							|  |  |  | 						: e}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 				var txt = p.join('') | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 				// XXX check if traversable...
 | 
					
						
							|  |  |  | 				p = $(p.map(function(t){ | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 					return t == '$BUTTONS' ?  | 
					
						
							|  |  |  | 							$('<span/>') | 
					
						
							|  |  |  | 								.addClass('button-container')[0] | 
					
						
							|  |  |  | 						: t instanceof jQuery ? | 
					
						
							|  |  |  | 							t[0] | 
					
						
							| 
									
										
										
										
											2017-01-05 04:53:46 +03:00
										 |  |  | 						: $('<span>') | 
					
						
							|  |  |  | 							.addClass('text') | 
					
						
							|  |  |  | 							// here we also replace empty strings with  ...
 | 
					
						
							|  |  |  | 							[t ? 'text' : 'html'](t || ' ')[0] | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 				})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// jQuery or dom...
 | 
					
						
							|  |  |  | 			} else if(p instanceof jQuery){ | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 				// XXX is this the correct way to do this???
 | 
					
						
							|  |  |  | 				var txt = p.text() | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 				// XXX disable search???
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 				//console.warn('jQuery objects as browse list elements not yet fully supported.')
 | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// str and other stuff...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 				var txt = p = p + '' | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// trailing '/' -- dir...
 | 
					
						
							|  |  |  | 				var dir = /[\\\/]\s*$/ | 
					
						
							|  |  |  | 				traversable = dir.test(p) && traversable == null ? true : traversable | 
					
						
							|  |  |  | 				traversable = traversable == null ? false : traversable | 
					
						
							|  |  |  | 				p = $('<span>') | 
					
						
							|  |  |  | 						.addClass('text') | 
					
						
							|  |  |  | 						.text(p.replace(dir, '')) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//---------------------------------- keyboard shortcuts ---
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 			if(item_shortcuts){ | 
					
						
							|  |  |  | 				// key set in options...
 | 
					
						
							|  |  |  | 				opts.shortcut_key && !item_shortcuts[opts.shortcut_key] | 
					
						
							|  |  |  | 					&& that.keyboard.handler( | 
					
						
							|  |  |  | 						'ItemShortcuts',  | 
					
						
							|  |  |  | 						opts.shortcut_key,  | 
					
						
							| 
									
										
										
										
											2017-02-09 16:50:26 +03:00
										 |  |  | 						//function(){ that.push(res) })
 | 
					
						
							|  |  |  | 						function(){ that.select(res) }) | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// text marker...
 | 
					
						
							|  |  |  | 				if(item_shortcut_marker){ | 
					
						
							|  |  |  | 					var _replace = function(){ | 
					
						
							|  |  |  | 						// get the last group...
 | 
					
						
							|  |  |  | 						var key = [].slice.call(arguments).slice(-3)[0] | 
					
						
							| 
									
										
										
										
											2017-03-30 00:39:29 +03:00
										 |  |  | 						!item_shortcuts[keyboard.normalizeKey(key)] | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 							// NOTE: this is a side-effect...
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 							&& that.keyboard.handler( | 
					
						
							|  |  |  | 								'ItemShortcuts',  | 
					
						
							|  |  |  | 								key, | 
					
						
							| 
									
										
										
										
											2017-02-09 16:50:26 +03:00
										 |  |  | 								//function(){ that.push(res) })
 | 
					
						
							|  |  |  | 								function(){ that.action(res) }) | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 						return key  | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 00:39:29 +03:00
										 |  |  | 					// clean out markers from text...
 | 
					
						
							|  |  |  | 					txt = txt.replace(item_shortcut_marker, '$1') | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					p.filter('.text') | 
					
						
							|  |  |  | 						.each(function(_, e){ | 
					
						
							|  |  |  | 							e = $(e) | 
					
						
							|  |  |  | 							e.html(e.html().replace(item_shortcut_marker,  | 
					
						
							|  |  |  | 								function(){  | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 									var k = _replace.apply(this, arguments)  | 
					
						
							| 
									
										
										
										
											2017-03-30 00:39:29 +03:00
										 |  |  | 									// only mark the first occurrence...
 | 
					
						
							|  |  |  | 									var mark = !!(registered_shortcuts.indexOf(k) < 0  | 
					
						
							|  |  |  | 										&& registered_shortcuts.push(k)) | 
					
						
							| 
									
										
										
										
											2017-01-29 18:22:13 +03:00
										 |  |  | 									return mark ? | 
					
						
							| 
									
										
										
										
											2017-01-29 07:32:07 +03:00
										 |  |  | 										`<span class="keyboard-shortcut">${k}</span>` | 
					
						
							|  |  |  | 										: k | 
					
						
							|  |  |  | 								})) | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//---------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			// tell the lister that we have started in interactive mode...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 			interactive = true | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 17:28:50 +03:00
										 |  |  | 			// skip drawing of non-traversable or disabled elements if
 | 
					
						
							|  |  |  | 			// .showNonTraversable or .showDisabled are false respectively...
 | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 			if((!traversable && !that.options.showNonTraversable) | 
					
						
							| 
									
										
										
										
											2016-12-30 03:21:09 +03:00
										 |  |  | 					|| (disabled && !that.options.showDisabled) | 
					
						
							|  |  |  | 					|| (hidden && !that.options.showHidden)){ | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 				return $() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//------------------------------------------ build item ---
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 			var res = $('<div>') | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 				// handle clicks ONLY when not disabled...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 				.click(function(){ | 
					
						
							| 
									
										
										
										
											2017-01-27 08:26:10 +03:00
										 |  |  | 					!$(this).hasClass('disabled') | 
					
						
							|  |  |  | 						&& that.push($(this)) }) | 
					
						
							| 
									
										
										
										
											2016-01-14 21:42:25 +03:00
										 |  |  | 				// append text elements... 
 | 
					
						
							|  |  |  | 				.append(p) | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:49:08 +03:00
										 |  |  | 			// NOTE: this is not done inline because we need access to 
 | 
					
						
							|  |  |  | 			// 		res below...
 | 
					
						
							|  |  |  | 			res.addClass([ | 
					
						
							|  |  |  | 				'item', | 
					
						
							|  |  |  | 				// XXX use the same algorithm as .select(..)
 | 
					
						
							|  |  |  | 				selection && res.text() == selection ? 'selected' : '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				!traversable ? 'not-traversable' : '', | 
					
						
							|  |  |  | 				disabled ? 'disabled' : '', | 
					
						
							|  |  |  | 				hidden ? 'hidden' : '', | 
					
						
							|  |  |  | 				opts.hide_on_search ? 'hide-on-search' : '', | 
					
						
							|  |  |  | 				(opts.hide_on_search || opts.not_searchable) ? 'not-searchable' : '', | 
					
						
							|  |  |  | 				opts.not_filtered_out ? 'not-filtered-out' : '', | 
					
						
							|  |  |  | 			].join(' ')) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			opts.push_on_open  | 
					
						
							|  |  |  | 				&& res.attr('push-on-open', 'on') | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//--------------------------------------------- buttons ---
 | 
					
						
							| 
									
										
										
										
											2017-01-05 04:53:46 +03:00
										 |  |  | 			// button container...
 | 
					
						
							|  |  |  | 			var btn = res.find('.button-container') | 
					
						
							|  |  |  | 			btn = btn.length == 0 ?  | 
					
						
							|  |  |  | 				$('<span/>') | 
					
						
							|  |  |  | 					.addClass('button-container') | 
					
						
							|  |  |  | 					.appendTo(res) | 
					
						
							|  |  |  | 				: btn | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			// action (open) button...
 | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 			if(traversable && that.options.actionButton){ | 
					
						
							| 
									
										
										
										
											2017-01-05 04:53:46 +03:00
										 |  |  | 				btn.append($('<div>') | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 					.addClass('button') | 
					
						
							|  |  |  | 					.html(that.options.actionButton === true ?  | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | 						'✓'  | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 						: that.options.actionButton) | 
					
						
							|  |  |  | 					.click(function(evt){ | 
					
						
							|  |  |  | 						evt.stopPropagation() | 
					
						
							| 
									
										
										
										
											2017-01-23 20:58:24 +03:00
										 |  |  | 						that.select(res) | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 						that.action() | 
					
						
							|  |  |  | 					})) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// push button...
 | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 			if(traversable && that.options.pushButton){ | 
					
						
							| 
									
										
										
										
											2017-01-05 04:53:46 +03:00
										 |  |  | 				btn.append($('<div>') | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 					.addClass('button') | 
					
						
							|  |  |  | 					.html(that.options.pushButton ? | 
					
						
							|  |  |  | 						'p'  | 
					
						
							|  |  |  | 						: that.options.pushButton) | 
					
						
							|  |  |  | 					.click(function(evt){ | 
					
						
							|  |  |  | 						evt.stopPropagation() | 
					
						
							| 
									
										
										
										
											2017-01-23 20:58:24 +03:00
										 |  |  | 						that.push(res) | 
					
						
							| 
									
										
										
										
											2015-11-27 05:57:06 +03:00
										 |  |  | 					})) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | 			// custom buttons...
 | 
					
						
							| 
									
										
										
										
											2016-03-26 03:00:19 +03:00
										 |  |  | 			buttons && buttons | 
					
						
							| 
									
										
										
										
											2017-01-15 00:49:19 +03:00
										 |  |  | 				.slice() | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 				// make the order consistent for the user -- first
 | 
					
						
							|  |  |  | 				// in list, first in item (from left), and should
 | 
					
						
							|  |  |  | 				// be added last...
 | 
					
						
							|  |  |  | 				.reverse() | 
					
						
							|  |  |  | 				.forEach(function(e){ | 
					
						
							|  |  |  | 					var html = e[0] | 
					
						
							|  |  |  | 					var func = e[1] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-26 20:54:24 +03:00
										 |  |  | 					btn.append($('<div>') | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 						.addClass('button') | 
					
						
							|  |  |  | 						.html(html) | 
					
						
							|  |  |  | 						.click(function(evt){ | 
					
						
							|  |  |  | 							// prevent clicks from triggering the item action...
 | 
					
						
							|  |  |  | 							evt.stopPropagation() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// action name...
 | 
					
						
							|  |  |  | 							if(typeof(func) == typeof('str')){ | 
					
						
							| 
									
										
										
										
											2017-01-13 08:42:47 +03:00
										 |  |  | 								that[func](txt, res) | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							// handler...
 | 
					
						
							|  |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2017-01-13 08:42:47 +03:00
										 |  |  | 								func.call(that, txt, res) | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						})) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//--------------------------------------- place in list ---
 | 
					
						
							| 
									
										
										
										
											2015-12-13 09:01:43 +03:00
										 |  |  | 			// as-is...
 | 
					
						
							|  |  |  | 			if(!sort_traversable || sort_traversable == 'none'){ | 
					
						
							|  |  |  | 				res.appendTo(l) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// traversable first/last...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if(sort_traversable == 'first' ? traversable : !traversable){ | 
					
						
							|  |  |  | 					section_tail == null ? | 
					
						
							|  |  |  | 						l.prepend(res) | 
					
						
							|  |  |  | 						: section_tail.after(res) | 
					
						
							|  |  |  | 					section_tail = res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					res.appendTo(l) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			//---------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 			return res | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 		make.__proto__ = Items | 
					
						
							| 
									
										
										
										
											2016-05-04 19:26:26 +03:00
										 |  |  | 		// align the dialog...
 | 
					
						
							|  |  |  | 		make.done = function(){ | 
					
						
							|  |  |  | 			var s = l.find('.selected')			 | 
					
						
							|  |  |  | 			s.length > 0 && that.select(s) | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 			return deferred | 
					
						
							| 
									
										
										
										
											2016-05-04 19:26:26 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 		make.dialog = this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 20:01:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//------------------------------------------ build the list ---
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		var res = list.call(this, path, make) | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		// second API: make is not called and .list(..) returns an Array
 | 
					
						
							|  |  |  | 		// that will get loaded as list items...
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		if(!interactive && res && res.constructor == Array){ | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 			res.forEach(make) | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		}  | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		// -------------------------------- notify that we are done ---
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		// wait for the render...
 | 
					
						
							|  |  |  | 		if(res && res.then){ | 
					
						
							|  |  |  | 			res.then(function(){ deferred.resolve() }) | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		// sync...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			deferred.resolve() | 
					
						
							| 
									
										
										
										
											2015-07-14 14:31:44 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		//return this
 | 
					
						
							|  |  |  | 		return deferred | 
					
						
							|  |  |  | 			.done(function(){ | 
					
						
							|  |  |  | 				that.dom.attr('path', this.strPath) | 
					
						
							|  |  |  | 				that.trigger('update') | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 				// select the item...
 | 
					
						
							|  |  |  | 				if(selection){ | 
					
						
							| 
									
										
										
										
											2016-05-29 05:27:31 +03:00
										 |  |  | 					that.select('"'+ selection +'"') | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// maintain focus within the widget...
 | 
					
						
							|  |  |  | 				if(focus && browser.find(':focus').length == 0){ | 
					
						
							| 
									
										
										
										
											2015-11-07 22:14:19 +03:00
										 |  |  | 					that.focus() | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// XXX hackish...
 | 
					
						
							|  |  |  | 				that.updateItemNumbers() | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2017-01-29 05:44:57 +03:00
										 |  |  | 		//-------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 07:08:36 +03:00
										 |  |  | 	// Update item shortcut key number hints...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Update hints...
 | 
					
						
							|  |  |  | 	// 	.updateItemNumbers()
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Clear hints...
 | 
					
						
							|  |  |  | 	// 	.updateItemNumbers(true)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This should be called every time the list is modified manually, 
 | 
					
						
							|  |  |  | 	// the automatic side of things is taken care of by .update(..)...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 	// XXX hackish -- move this back to CSS as soon as :nth-match(..) gets
 | 
					
						
							|  |  |  | 	// 		enough support...
 | 
					
						
							| 
									
										
										
										
											2017-02-08 07:08:36 +03:00
										 |  |  | 	updateItemNumbers: function(clear){ | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 		this.dom | 
					
						
							|  |  |  | 			.find('[shortcut-number]') | 
					
						
							|  |  |  | 				.removeAttr('shortcut-number') | 
					
						
							| 
									
										
										
										
											2017-02-08 07:08:36 +03:00
										 |  |  | 		!clear  | 
					
						
							| 
									
										
										
										
											2017-02-08 07:12:12 +03:00
										 |  |  | 			&& this.filter('*', false) | 
					
						
							| 
									
										
										
										
											2017-02-08 07:08:36 +03:00
										 |  |  | 				.slice(0, 10) | 
					
						
							|  |  |  | 				.each(function(i){  | 
					
						
							|  |  |  | 					$(this).attr('shortcut-number', (i+1)%10) }) | 
					
						
							| 
									
										
										
										
											2017-02-08 06:59:57 +03:00
										 |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// Filter the item list...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// 	General signature...
 | 
					
						
							|  |  |  | 	// 	.filter(<pattern>[, <rejected-handler>][, <ignore-disabled>])
 | 
					
						
							|  |  |  | 	// 		-> elements
 | 
					
						
							|  |  |  | 	// 	
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Get all elements...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// 	.filter()
 | 
					
						
							|  |  |  | 	// 	.filter('*')
 | 
					
						
							|  |  |  | 	// 		-> all elements
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// 	Get all elements containing a string...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// 	.filter(<string>)
 | 
					
						
							|  |  |  | 	// 		-> elements
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 	// 		NOTE: as whitespace is treated as a pattern separator, if it
 | 
					
						
							|  |  |  | 	// 			is need explicitly simply quote it...
 | 
					
						
							|  |  |  | 	// 				'a b c'		- three sub patterns: 'a', 'b' and 'c'
 | 
					
						
							|  |  |  | 	// 				'a\ b\ c'	- single pattern
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 	// 	Get element exactly matching a string...
 | 
					
						
							|  |  |  | 	// 	.filter(<quoted-string>)
 | 
					
						
							|  |  |  | 	// 		-> elements
 | 
					
						
							|  |  |  | 	// 		NOTE: this supports bot single and double quotes, e.g. 
 | 
					
						
							|  |  |  | 	// 			'"abc"' and "'abc'" are equivalent...
 | 
					
						
							|  |  |  | 	// 		NOTE: only outer quotes are considered, so if there is a 
 | 
					
						
							|  |  |  | 	// 			need to exactly match '"X"', just add a set of quotes 
 | 
					
						
							|  |  |  | 	// 			around it, e.g. '""X""' or '\'"X"\''...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// 	Get all elements matching a regexp...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:18:28 +03:00
										 |  |  | 	// 	.filter(<regexp>)
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// 		-> elements
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// 	Filter the elements via a function...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// 	.filter(<function>)
 | 
					
						
							|  |  |  | 	// 		-> elements
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	// 		NOTE: the elements passed to the <function> on each iteration
 | 
					
						
							|  |  |  | 	// 			are unwrapped for compatibility with jQuery API.
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	// 	Get specific element...
 | 
					
						
							|  |  |  | 	// 	.filter(<index>)
 | 
					
						
							|  |  |  | 	// 	.filter(<jQuery-obj>)
 | 
					
						
							|  |  |  | 	// 		-> element
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:51:11 +03:00
										 |  |  | 	//		-> $()
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	// 		NOTE: when passing a jQuery-obj it will be returned iff it's
 | 
					
						
							|  |  |  | 	// 			an element.
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:51:11 +03:00
										 |  |  | 	// 		NOTE: unlike .select(..) index overflow will produce empty 
 | 
					
						
							|  |  |  | 	// 			lists rather than to/bottom elements.
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 	// 	Get specific absolute element...
 | 
					
						
							|  |  |  | 	// 	.filter('<index>!')
 | 
					
						
							|  |  |  | 	// 		-> element
 | 
					
						
							|  |  |  | 	//		-> $()
 | 
					
						
							|  |  |  | 	//		NOTE: this is equivalent to setting ignore_disabled tp false
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// If <rejected-handler> function is passed it will get called with 
 | 
					
						
							|  |  |  | 	// every element that was rejected by the predicate / not matching 
 | 
					
						
							|  |  |  | 	// the pattern.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 	// By default, <ignore-disabled> is true, thus this will ignore 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	// disabled elements. If <ignore_disabled> is false then disabled 
 | 
					
						
							|  |  |  | 	// elements will be searched too.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-05 05:23:29 +03:00
										 |  |  | 	// If an item has .not-searchable class set, then it will neither be
 | 
					
						
							|  |  |  | 	// searched nor filtered out.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// If an item has .not-filtered-out class set, then it will not be 
 | 
					
						
							|  |  |  | 	// hidden on filtering (see: .filterList(..)).
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-29 18:49:31 +03:00
										 |  |  | 	// NOTE: this will filter every item loaded regardless of visibility.
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:18:28 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 	// Extended string patterns:
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The pattern string is split by whitespace and each resulting 
 | 
					
						
							|  |  |  | 	// substring is searched independently.
 | 
					
						
							|  |  |  | 	// Order is not considered.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Examples:
 | 
					
						
							|  |  |  | 	// 		'aaa'			- matches any element containing 'aaa'
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	// 							(Same as: /aaa/)
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 	// 		'aa bb'			- matches any element containing both 'aa'
 | 
					
						
							|  |  |  | 	// 							AND 'bb' in any order.
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	// 							(Same as: /aa.*bb|bb.*aa/)
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 	// NOTE: currently there is no way to search for whitespace explicitly,
 | 
					
						
							|  |  |  | 	// 		at this point this is "by-design" as an experiment on how
 | 
					
						
							|  |  |  | 	// 		vital this feature is.
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-20 20:51:43 +03:00
										 |  |  | 	// TODO need to support glob / nested patterns...
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	// 		..things like /**/a*/*moo/ should list all matching items in
 | 
					
						
							|  |  |  | 	// 		a single list.
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX case sensitivity???
 | 
					
						
							|  |  |  | 	// XXX invalid patterns that the user did not finish inputing???
 | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 	filter: function(pattern, a, b){ | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 		pattern = pattern == null ? '*' : pattern | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 		var ignore_disabled = typeof(a) == typeof(true) ? a : b | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		ignore_disabled = ignore_disabled == null ? true : ignore_disabled | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 		var rejected = typeof(a) == typeof(true) ? null : a | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 06:05:21 +03:00
										 |  |  | 		var elems = browser.find('.list .item'  | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 			+ (this.options.elementSeparatorClass ?  | 
					
						
							|  |  |  | 				':not('+ this.options.elementSeparatorClass +')' | 
					
						
							|  |  |  | 				: '') | 
					
						
							| 
									
										
										
										
											2015-12-15 03:58:31 +03:00
										 |  |  | 			+ (ignore_disabled ?  | 
					
						
							|  |  |  | 				':not(.disabled):not(.filtered-out)'  | 
					
						
							|  |  |  | 				: '')) | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(pattern == '*'){ | 
					
						
							|  |  |  | 			return elems  | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		// special case: absolute position...
 | 
					
						
							|  |  |  | 		if(/\d+!/.test(pattern)){ | 
					
						
							|  |  |  | 			return this.filter(parseInt(pattern), rejected, false) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		// function...
 | 
					
						
							|  |  |  | 		if(typeof(pattern) == typeof(function(){})){ | 
					
						
							|  |  |  | 			var filter = function(i, e){ | 
					
						
							| 
									
										
										
										
											2015-06-21 20:19:15 +03:00
										 |  |  | 				e = e[0] | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 				if(!pattern.call(e, i, e)){ | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 					if(rejected){ | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 						rejected.call(e, i, e) | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					return false | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// regexp...
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 		} else if(pattern.constructor == RegExp | 
					
						
							|  |  |  | 				|| (typeof(pattern) == typeof('str')  | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 					&& /^(['"]).*\1$/.test(pattern.trim()))){ | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 			if(typeof(pattern) == typeof('str')){ | 
					
						
							|  |  |  | 				pattern = toRegExp(pattern.trim().slice(1, -1)) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 			var filter = function(i, e){ | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 				if(!pattern.test($(e).find('.text').text())){ | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 					if(rejected){ | 
					
						
							| 
									
										
										
										
											2015-06-19 19:13:11 +03:00
										 |  |  | 						rejected.call(e, i, e) | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					return false | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return true | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// string...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 		// NOTE: this supports several space-separated patterns.
 | 
					
						
							| 
									
										
										
										
											2015-11-07 22:14:19 +03:00
										 |  |  | 		// NOTE: this is case-agnostic...
 | 
					
						
							|  |  |  | 		// 		...for case sensitivity remove .toLowerCase()...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		// XXX support glob...
 | 
					
						
							|  |  |  | 		} else if(typeof(pattern) == typeof('str')){ | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 			//var pl = pattern.trim().split(/\s+/)
 | 
					
						
							| 
									
										
										
										
											2015-09-22 22:50:18 +03:00
										 |  |  | 			var pl = pattern.trim() | 
					
						
							|  |  |  | 				// split on whitespace but keep quoted chars...
 | 
					
						
							|  |  |  | 				.split(/\s*((?:\\\s|[^\s])*)\s*/g) | 
					
						
							|  |  |  | 				// remove empty strings...
 | 
					
						
							|  |  |  | 				.filter(function(e){ return e.trim() != '' }) | 
					
						
							|  |  |  | 				// remove '\' -- enables direct string comparison...
 | 
					
						
							| 
									
										
										
										
											2015-11-07 22:14:19 +03:00
										 |  |  | 				.map(function(e){ return e.replace(/\\(\s)/g, '$1').toLowerCase() }) | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 			var filter = function(i, e){ | 
					
						
							|  |  |  | 				e = $(e) | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 				var t = e.find('.text').text().toLowerCase() | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 				for(var p=0; p < pl.length; p++){ | 
					
						
							| 
									
										
										
										
											2015-09-22 22:50:18 +03:00
										 |  |  | 					// NOTE: we are not using search here as it treats 
 | 
					
						
							|  |  |  | 					// 		the string as a regex and we need literal
 | 
					
						
							|  |  |  | 					// 		search...
 | 
					
						
							|  |  |  | 					var i = t.indexOf(pl[p]) | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 					if(!(i >= 0)){ | 
					
						
							|  |  |  | 						if(rejected){ | 
					
						
							|  |  |  | 							rejected.call(e, i, e) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						return false | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return true | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// number...
 | 
					
						
							|  |  |  | 		} else if(typeof(pattern) == typeof(123)){ | 
					
						
							|  |  |  | 			return elems.eq(pattern) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// jQuery object...
 | 
					
						
							|  |  |  | 		} else if(elems.index(pattern) >= 0){ | 
					
						
							|  |  |  | 			return pattern | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// unknown pattern...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return $() | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return elems.filter(filter) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	// Filter list elements...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will set the .filtered-out class on all non-matching elements.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Use .filterList('*') to clear filter and show all elements.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-05 05:23:29 +03:00
										 |  |  | 	// If an item has .not-filtered-out class set, then it will not be 
 | 
					
						
							|  |  |  | 	// hidden on filtering. 
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	// NOTE: see .filter(..) for docs on actual filtering.
 | 
					
						
							|  |  |  | 	// NOTE: this does not affect any UI modes, for list filtering mode
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 	// 		see: .toggleFilter(..)...
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 	// XXX should this be case insensitive???
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	filterList: function(pattern){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// show all...
 | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 		if(pattern == null || pattern.trim() == '*' || pattern == ''){ | 
					
						
							| 
									
										
										
										
											2015-07-29 18:49:31 +03:00
										 |  |  | 			browser.find('.filtered-out') | 
					
						
							|  |  |  | 				.removeClass('filtered-out') | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 			// clear the highlighting...
 | 
					
						
							|  |  |  | 			browser.find('.list b') | 
					
						
							| 
									
										
										
										
											2017-01-30 06:05:21 +03:00
										 |  |  | 				.replaceWith(function(){ return this.innerHTML }) | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// basic filter...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 			// hide stuff that needs to be unconditionally hidden...
 | 
					
						
							|  |  |  | 			browser.find('.hide-on-search') | 
					
						
							|  |  |  | 				.addClass('filtered-out') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 			var p = RegExp('('  | 
					
						
							|  |  |  | 				+ pattern | 
					
						
							|  |  |  | 					.trim() | 
					
						
							|  |  |  | 					// ignore trailing '\'
 | 
					
						
							|  |  |  | 					.replace(/\\+$/, '') | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 					.split(/(?=[^\\])\s/) | 
					
						
							| 
									
										
										
										
											2015-09-10 08:59:19 +03:00
										 |  |  | 					// drop empty strings...
 | 
					
						
							|  |  |  | 					.filter(function(e){ return e.trim() != '' }) | 
					
						
							|  |  |  | 					// remove escapes...
 | 
					
						
							|  |  |  | 					.map(function(e){ return e.replace(/\\(\s)/, '$1') }) | 
					
						
							|  |  |  | 					.join('|')  | 
					
						
							|  |  |  | 				+ ')', 'gi') | 
					
						
							|  |  |  | 			// XXX should this be case insensitive???
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 			this.filter(pattern, | 
					
						
							|  |  |  | 					// rejected...
 | 
					
						
							|  |  |  | 					function(i, e){ | 
					
						
							| 
									
										
										
										
											2017-01-06 05:17:14 +03:00
										 |  |  | 						!e.hasClass('not-filtered-out') | 
					
						
							| 
									
										
										
										
											2017-01-30 06:05:21 +03:00
										 |  |  | 							&& e | 
					
						
							|  |  |  | 								.addClass('filtered-out') | 
					
						
							|  |  |  | 								.removeClass('selected') | 
					
						
							| 
									
										
										
										
											2017-01-06 02:18:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-30 06:05:21 +03:00
										 |  |  | 						// clear selection...
 | 
					
						
							|  |  |  | 						e.find('b') | 
					
						
							|  |  |  | 							.replaceWith(function(){ return this.innerHTML }) | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 					// NOTE: setting this to true will not remove disabled
 | 
					
						
							|  |  |  | 					// 		elements from view as they will neither get 
 | 
					
						
							| 
									
										
										
										
											2015-07-29 18:49:31 +03:00
										 |  |  | 					// 		included in the filter nor in the filtered out
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 					// 		thus it will require manual setting of the
 | 
					
						
							|  |  |  | 					// 		.filtered-out class
 | 
					
						
							|  |  |  | 					false) | 
					
						
							| 
									
										
										
										
											2017-01-30 06:05:21 +03:00
										 |  |  | 				// skip non-searchable...
 | 
					
						
							|  |  |  | 				.filter(':not(.not-searchable)') | 
					
						
							| 
									
										
										
										
											2015-07-29 18:49:31 +03:00
										 |  |  | 				// passed...
 | 
					
						
							|  |  |  | 				.removeClass('filtered-out') | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 				// NOTE: this will mess up (clear) any highlighting that was 
 | 
					
						
							|  |  |  | 				// 		present before...
 | 
					
						
							|  |  |  | 				.each(function(_, e){ | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 					e = $(e) | 
					
						
							|  |  |  | 						.find('.text') | 
					
						
							|  |  |  | 						// NOTE: here we support multiple text elements per
 | 
					
						
							|  |  |  | 						// 		list element...
 | 
					
						
							|  |  |  | 						.each(function(i, e){ | 
					
						
							|  |  |  | 							e = $(e) | 
					
						
							|  |  |  | 							var t = e.text() | 
					
						
							|  |  |  | 							e.html(t.replace(p, '<b>$1</b>')) | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:18:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// internal actions...
 | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 	// full path editing...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	// 	start ---->	edit --(enter)--> stop (accept)
 | 
					
						
							|  |  |  | 	// 				  |
 | 
					
						
							|  |  |  | 	// 			 	 +-------(esc)--> abort (reset)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 	// NOTE: the event handlers for this are set in .__init__()...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 	// XXX should these be a toggle???
 | 
					
						
							|  |  |  | 	startFullPathEdit: function(){ | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 		if(this.options.fullPathEdit){ | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 			var browser = this.dom | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 			var path = this.strPath | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 			var orig = this.selected | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 			browser | 
					
						
							|  |  |  | 				.attr('orig-path', path) | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 				.attr('orig-selection', orig) | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			var range = document.createRange() | 
					
						
							|  |  |  | 			var selection = window.getSelection() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var e = browser.find('.path') | 
					
						
							|  |  |  | 				.text(path) | 
					
						
							|  |  |  | 				.attr('contenteditable', true) | 
					
						
							|  |  |  | 				.focus() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			range.selectNodeContents(e[0]) | 
					
						
							|  |  |  | 			selection.removeAllRanges() | 
					
						
							|  |  |  | 			selection.addRange(range) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	abortFullPathEdit: function(){ | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 		var e = browser.find('.path') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var path = '/' + browser.attr('orig-path') | 
					
						
							|  |  |  | 		var selection = browser.attr('orig-selection') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.stopFullPathEdit(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(selection != ''){ | 
					
						
							|  |  |  | 			this.select(selection)	 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	stopFullPathEdit: function(path){ | 
					
						
							|  |  |  | 		var browser = this.dom | 
					
						
							|  |  |  | 			.removeAttr('orig-path') | 
					
						
							|  |  |  | 			.removeAttr('orig-selection') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var e = browser.find('.path') | 
					
						
							|  |  |  | 			.removeAttr('contenteditable') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 		this.path = path || e.text() | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 		return this | 
					
						
							|  |  |  | 			.focus() | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	// list filtering...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	start ---->	edit / select --(enter)--> action (use selection)
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:30:58 +03:00
										 |  |  | 	// 					 |
 | 
					
						
							|  |  |  | 	// 					 +-------(blur/esc)--> exit (clear)
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 	// NOTE: the action as a side effect exits the filter (causes blur 
 | 
					
						
							|  |  |  | 	// 		on filter field)...
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// NOTE: this uses .filter(..) for actual filtering...
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 	// NOTE: on state change this will return this...
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | 	toggleFilter: toggler.CSSClassToggler( | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 		function(){ return this.dom },  | 
					
						
							|  |  |  | 		'filtering', | 
					
						
							|  |  |  | 		// do not enter filter mode if filtering is disabled...
 | 
					
						
							|  |  |  | 		function(action){ return action != 'on' || this.options.filter }, | 
					
						
							|  |  |  | 		function(action){ | 
					
						
							|  |  |  | 			// on...
 | 
					
						
							|  |  |  | 			if(action == 'on'){ | 
					
						
							|  |  |  | 				var range = document.createRange() | 
					
						
							|  |  |  | 				var selection = window.getSelection() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				var e = this.dom.find('.path .dir.cur') | 
					
						
							|  |  |  | 					//.text('')
 | 
					
						
							|  |  |  | 					.attr('contenteditable', true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// place the cursor...
 | 
					
						
							|  |  |  | 				//range.setStart(e[0], 0)
 | 
					
						
							|  |  |  | 				//range.collapse(true)
 | 
					
						
							|  |  |  | 				range.selectNodeContents(e[0]) | 
					
						
							|  |  |  | 				selection.removeAllRanges() | 
					
						
							|  |  |  | 				selection.addRange(range) | 
					
						
							|  |  |  | 					 | 
					
						
							|  |  |  | 			// off...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.filterList('*') | 
					
						
							|  |  |  | 				this.dom | 
					
						
							|  |  |  | 					.find('.path .dir.cur') | 
					
						
							|  |  |  | 						.text('') | 
					
						
							|  |  |  | 						.removeAttr('contenteditable') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// NOTE: we might select an item outside of the current visible
 | 
					
						
							|  |  |  | 				// 		area, thus re-selecting it after we remove the filter 
 | 
					
						
							|  |  |  | 				// 		will place it correctly.
 | 
					
						
							|  |  |  | 				this.select(this.select('!')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				this.focus() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-22 18:17:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 			return this | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// shorthands mostly for use as actions...
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 	startFilter: function(){ return this.toggleFilter('on') }, | 
					
						
							|  |  |  | 	stopFilter: function(){ return this.toggleFilter('off') }, | 
					
						
							| 
									
										
										
										
											2015-06-26 15:22:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Toggle filter view mode...
 | 
					
						
							|  |  |  | 	toggleFilterViewMode: function(){ | 
					
						
							| 
									
										
										
										
											2015-06-18 00:23:23 +03:00
										 |  |  | 		this.dom.toggleClass('show-filtered-out') | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	// XXX should this be a toggler???
 | 
					
						
							|  |  |  | 	disableElements: function(pattern){ | 
					
						
							|  |  |  | 		this.filter(pattern, false) | 
					
						
							|  |  |  | 			.addClass('disabled') | 
					
						
							|  |  |  | 			.removeClass('selected') | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	enableElements: function(pattern){ | 
					
						
							|  |  |  | 		this.filter(pattern, false) | 
					
						
							|  |  |  | 			.removeClass('disabled') | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	// Select an element from current list...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 	// This is like .filter(..) but:
 | 
					
						
							|  |  |  | 	// 	- adds several special case arguments (see below)
 | 
					
						
							|  |  |  | 	// 	- gets it first matched element and selects it
 | 
					
						
							|  |  |  | 	// 	- takes care of visual scrolling.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	//	Deselect
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 	//	.select(null)
 | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 	//		-> $()
 | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 	//	Select jQuery object...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	//	.select(<elem>)
 | 
					
						
							|  |  |  | 	//		-> elem
 | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 	//		-> $()
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 	// All other call configurations are like .filter(..) so see that 
 | 
					
						
							|  |  |  | 	// for more info.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	// This will return a jQuery object.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This will trigger the 'select' or 'deselect' events.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 	// For uniformity and ease of access from DOM, this will also set 
 | 
					
						
							| 
									
										
										
										
											2015-09-07 18:51:42 +03:00
										 |  |  | 	// the value attr on the .browse-widget element.
 | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 	// NOTE: this is one way and setting the html attribute "value" will
 | 
					
						
							|  |  |  | 	// 		not affect the selection, but changing the selection will 
 | 
					
						
							|  |  |  | 	// 		overwrite the attribute.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 	// NOTE: if multiple matches occur this will select the first.
 | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 	// NOTE: 'none' will always return an empty jQuery object, to get 
 | 
					
						
							|  |  |  | 	// 		the selection state before deselecting use .select('!')
 | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 	// NOTE: this uses .filter(..) for string and regexp matching...
 | 
					
						
							| 
									
										
										
										
											2017-05-20 05:28:19 +03:00
										 |  |  | 	// NOTE: this will not select disabled elements (XXX)
 | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 	select: function(elem, filtering){ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var browser = this.dom | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		var pattern = '.list .item' | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 			+ (this.options.elementSeparatorClass ?  | 
					
						
							|  |  |  | 				':not('+ this.options.elementSeparatorClass +')' | 
					
						
							|  |  |  | 				: '') | 
					
						
							|  |  |  | 			+':not(.disabled):not(.filtered-out):visible' | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 		var elems = browser.find(pattern) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		if(elems.length == 0){ | 
					
						
							|  |  |  | 			return $() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 19:42:13 +03:00
										 |  |  | 		filtering = filtering == null ? this.toggleFilter('?') == 'on' : filtering | 
					
						
							| 
									
										
										
										
											2015-07-11 16:52:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 		// empty list/string selects none...
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		elem = elem != null && elem.length == 0 ? null : elem | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		// no args -> either we start with the selected or the first...
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		if(elem === undefined){ | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 			var cur = this.select('!') | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			elem = cur.length == 0 ? 0 : cur | 
					
						
							| 
									
										
										
										
											2015-06-18 18:09:02 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		// explicit deselect...
 | 
					
						
							|  |  |  | 		if(elem === null){ | 
					
						
							| 
									
										
										
										
											2015-06-18 00:13:30 +03:00
										 |  |  | 			if(!filtering){ | 
					
						
							|  |  |  | 				browser.find('.path .dir.cur').empty() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-22 04:08:24 +03:00
										 |  |  | 			elems = elems | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 				.filter('.selected') | 
					
						
							|  |  |  | 				.removeClass('selected') | 
					
						
							| 
									
										
										
										
											2017-01-18 20:48:30 +03:00
										 |  |  | 				.trigger('deselect') | 
					
						
							| 
									
										
										
										
											2015-06-22 04:08:24 +03:00
										 |  |  | 			this.trigger('deselect', elems) | 
					
						
							| 
									
										
										
										
											2015-06-18 17:13:04 +03:00
										 |  |  | 			return $() | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// strict...
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		if(elem == '!'){ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			return elems.filter('.selected') | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		var item = elem instanceof $ ? elem : this.filter(elem).first() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		// we found a match or got an element...
 | 
					
						
							|  |  |  | 		// NOTE: if elem was a keyword it means we have an item with the
 | 
					
						
							|  |  |  | 		// 		same text on the list...
 | 
					
						
							|  |  |  | 		if(item.length != 0){ | 
					
						
							|  |  |  | 			elem = $(item).first() | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// clear selection...
 | 
					
						
							|  |  |  | 			this.select(null, filtering) | 
					
						
							|  |  |  | 			if(!filtering){ | 
					
						
							|  |  |  | 				browser.find('.path .dir.cur').text(elem.find('.text').text()) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 05:28:19 +03:00
										 |  |  | 			// XXX not sure if this is correct...
 | 
					
						
							|  |  |  | 			if(elem.hasClass('disabled')){ | 
					
						
							|  |  |  | 				return $() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// handle scroll position...
 | 
					
						
							|  |  |  | 			var p = elem.scrollParent() | 
					
						
							|  |  |  | 			var S = p.scrollTop() | 
					
						
							|  |  |  | 			var H = p.height() | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			var h = elem.height() | 
					
						
							|  |  |  | 			var t = elem.offset().top - p.offset().top | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// XXX should this be in config???
 | 
					
						
							|  |  |  | 			var D = 3 * h  | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// too low...
 | 
					
						
							|  |  |  | 			if(t+h+D > H){ | 
					
						
							|  |  |  | 				p.scrollTop(S + (t+h+D) - H) | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// too high...
 | 
					
						
							|  |  |  | 			} else if(t < D){ | 
					
						
							|  |  |  | 				p.scrollTop(S + t - D) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// now do the selection...
 | 
					
						
							|  |  |  | 			elem.addClass('selected') | 
					
						
							|  |  |  | 			browser.attr('value', elem.find('.text').text()) | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			this.trigger('select', elem) | 
					
						
							| 
									
										
										
										
											2015-06-18 02:34:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-27 00:02:46 +03:00
										 |  |  | 			// handle path scroll -- scroll to the end when wider than view...
 | 
					
						
							|  |  |  | 			var p = browser.find('.path') | 
					
						
							|  |  |  | 			if(p[0].offsetWidth < p[0].scrollWidth){ | 
					
						
							|  |  |  | 				// scroll all the way to the right...
 | 
					
						
							|  |  |  | 				p.scrollLeft(p[0].scrollWidth) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// keep left aligned...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				p.scrollLeft(0) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			return elem | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-22 04:08:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		// nothing found...
 | 
					
						
							|  |  |  | 		return $() | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 	// Navigate relative to selection...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Navigate to first/previous/next/last element...
 | 
					
						
							|  |  |  | 	// 	.navigate('first')
 | 
					
						
							|  |  |  | 	// 	.navigate('prev')
 | 
					
						
							|  |  |  | 	// 	.navigate('next')
 | 
					
						
							|  |  |  | 	// 	.navigate('last')
 | 
					
						
							|  |  |  | 	// 		-> elem
 | 
					
						
							|  |  |  | 	// 		NOTE: this will overflow, i.e. navigating 'next' when on the
 | 
					
						
							|  |  |  | 	// 				last element will navigate to the first.
 | 
					
						
							|  |  |  | 	// 		NOTE: when no element is selected, 'next' will select the 
 | 
					
						
							|  |  |  | 	// 				first, while 'prev' the last element's
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Deselect element...
 | 
					
						
							|  |  |  | 	// 	.navigate('none')
 | 
					
						
							|  |  |  | 	// 		-> elem
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Other arguments are compatible with .select(..) and then .filter(..)
 | 
					
						
							|  |  |  | 	// but note that this will "shadow" any element with the save name as
 | 
					
						
							|  |  |  | 	// a keyword, e.g. if we have an element with the text "next", 
 | 
					
						
							|  |  |  | 	// .navigate('next') will simply navigate to the next element while
 | 
					
						
							|  |  |  | 	// .select('next') / .filter('next') will yield that element by name.
 | 
					
						
							|  |  |  | 	navigate: function(action, filtering){ | 
					
						
							| 
									
										
										
										
											2017-01-27 17:33:21 +03:00
										 |  |  | 		var pattern = '.list .item' | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 			+ (this.options.elementSeparatorClass ?  | 
					
						
							|  |  |  | 				':not('+ this.options.elementSeparatorClass +')' | 
					
						
							|  |  |  | 				: '') | 
					
						
							|  |  |  | 			+':not(.disabled):not(.filtered-out):visible' | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		action = action || 'first' | 
					
						
							|  |  |  | 																    | 
					
						
							|  |  |  | 		if(action == 'none'){ | 
					
						
							|  |  |  | 			return this.select(null, filtering) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else if(action == 'next' || action == 'prev'){ | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 			var all = this.filter('*') | 
					
						
							|  |  |  | 			//var to = this.select('!', filtering)[action+'All'](pattern).first()
 | 
					
						
							|  |  |  | 			var to = all.eq(all.index(this.select('!', filtering)) + (action == 'next' ? 1 : -1)) | 
					
						
							| 
									
										
										
										
											2017-03-08 21:26:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// stop keyboard repeat...
 | 
					
						
							|  |  |  | 			to.length == 1 | 
					
						
							|  |  |  | 				&& this.options.keyboardRepeatPause > 0 | 
					
						
							|  |  |  | 				&& this.keyboard.pauseRepeat  | 
					
						
							|  |  |  | 				&& this.keyboard.pauseRepeat() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			// range check and overflow...
 | 
					
						
							|  |  |  | 			if(to.length == 0){ | 
					
						
							|  |  |  | 				action = action == 'next' ? 'first' : 'last' | 
					
						
							| 
									
										
										
										
											2017-03-08 21:26:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				return this.select(to, filtering) | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		} else if(action == 'down' || action == 'up'){ | 
					
						
							|  |  |  | 			var from = this.select('!', filtering) | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 			var all = this.filter('*') | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// special case: nothing selected -> select first/last...
 | 
					
						
							|  |  |  | 			if(from.length == 0){ | 
					
						
							|  |  |  | 				return this.navigate(action == 'down' ? 'first' : 'last') | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var t = from.offset() | 
					
						
							|  |  |  | 			var l = t.left | 
					
						
							|  |  |  | 			t = t.top | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// next lines...
 | 
					
						
							| 
									
										
										
										
											2017-01-30 05:01:50 +03:00
										 |  |  | 			//var to = from[(action == 'down' ? 'next' : 'prev') +'All'](pattern)
 | 
					
						
							|  |  |  | 			var to = (action == 'down' ? | 
					
						
							|  |  |  | 					all.slice(all.index(from)) | 
					
						
							|  |  |  | 					: $(all.slice(0, all.index(from)).toArray().reverse())) | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 				.filter(function(_, e){ return $(e).offset().top != t }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-08 21:26:37 +03:00
										 |  |  | 			// stop keyboard repeat...
 | 
					
						
							|  |  |  | 			to.length == 1 | 
					
						
							|  |  |  | 				&& this.options.keyboardRepeatPause > 0 | 
					
						
							|  |  |  | 				&& this.keyboard.pauseRepeat  | 
					
						
							|  |  |  | 				&& this.keyboard.pauseRepeat() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 			// special case: nothing below -> select wrap | last/first...
 | 
					
						
							|  |  |  | 			if(to.length == 0){ | 
					
						
							|  |  |  | 				// select first/last...
 | 
					
						
							|  |  |  | 				//return this.navigate(action == 'down' ? 'last' : 'first')
 | 
					
						
							| 
									
										
										
										
											2017-03-08 20:22:40 +03:00
										 |  |  | 				 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 				// wrap around....
 | 
					
						
							|  |  |  | 				to = this.filter('*').filter(pattern) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// when going up start from the bottom...
 | 
					
						
							|  |  |  | 				if(action == 'up'){ | 
					
						
							|  |  |  | 					to = $(to.toArray().reverse()) | 
					
						
							|  |  |  | 				}  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			t = to.eq(0).offset().top | 
					
						
							|  |  |  | 			to = to | 
					
						
							|  |  |  | 				// next line only...
 | 
					
						
							|  |  |  | 				.filter(function(_, e){ return $(e).offset().top == t }) | 
					
						
							|  |  |  | 				// sort by distance...
 | 
					
						
							|  |  |  | 				// XXX this does not account for element width...
 | 
					
						
							|  |  |  | 				.sort(function(a, b){ | 
					
						
							|  |  |  | 					return Math.abs(l - $(a).offset().left)  | 
					
						
							|  |  |  | 						- Math.abs(l - $(b).offset().left) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return this.select(to, filtering) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 05:40:11 +03:00
										 |  |  | 		return action == 'first' ? this.select(0, filtering) | 
					
						
							|  |  |  | 			: action == 'last' ? this.select(-1, filtering) | 
					
						
							|  |  |  | 			// fall back to select...
 | 
					
						
							|  |  |  | 			: this.select(action, filtering) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	// shorthand actions...
 | 
					
						
							|  |  |  | 	next: makeSimpleAction('next'), | 
					
						
							|  |  |  | 	prev: makeSimpleAction('prev'), | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 	up: makeSimpleAction('up'), | 
					
						
							|  |  |  | 	down: makeSimpleAction('down'), | 
					
						
							|  |  |  | 	left: function(elem){ | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 		if(elem != null){ | 
					
						
							|  |  |  | 			this.select(elem) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 		return this.cloud ? | 
					
						
							|  |  |  | 			this.navigate('prev') | 
					
						
							|  |  |  | 			: this.pop() | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 	right: function(elem){ | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 		if(elem != null){ | 
					
						
							|  |  |  | 			this.select(elem) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-06-01 21:39:32 +03:00
										 |  |  | 		return this.cloud ? | 
					
						
							|  |  |  | 			this.navigate('next') | 
					
						
							|  |  |  | 			: this.push() | 
					
						
							| 
									
										
										
										
											2016-06-01 21:19:24 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 	getTopVisibleElem: function(){ | 
					
						
							|  |  |  | 		var elems = this.filter('*') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var p = elems.first().scrollParent() | 
					
						
							|  |  |  | 		var S = p.scrollTop() | 
					
						
							|  |  |  | 		var T = p.offset().top | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(S == 0){ | 
					
						
							|  |  |  | 			return elems.first() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return elems | 
					
						
							|  |  |  | 			.filter(function(i, e){ | 
					
						
							|  |  |  | 				return $(e).offset().top - T >= 0 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.first() | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	getBottomVisibleElem: function(){ | 
					
						
							|  |  |  | 		var elems = this.filter('*') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var p = elems.first().scrollParent() | 
					
						
							|  |  |  | 		var S = p.scrollTop() | 
					
						
							|  |  |  | 		var T = p.offset().top | 
					
						
							|  |  |  | 		var H = p.height() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(S + H == p[0].scrollHeight){ | 
					
						
							|  |  |  | 			return elems.last() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return elems | 
					
						
							|  |  |  | 			.filter(function(i, e){ | 
					
						
							|  |  |  | 				e = $(e) | 
					
						
							|  |  |  | 				return e.offset().top + e.height() <= T + H | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.last() | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 	// NOTE: this will not give a number greater than the number of 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:09:11 +03:00
										 |  |  | 	// 		elements, thus for lists without scroll, this will always
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 	// 		return the number of elements.
 | 
					
						
							|  |  |  | 	// XXX this will not count the elements at the top if they are 
 | 
					
						
							|  |  |  | 	// 		disabled...
 | 
					
						
							|  |  |  | 	getHeightInElems: function(){ | 
					
						
							|  |  |  | 		var t = this.getTopVisibleElem() | 
					
						
							|  |  |  | 		var b = this.getBottomVisibleElem() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var res = 1 | 
					
						
							|  |  |  | 		while(!t.is(b)){ | 
					
						
							|  |  |  | 			t = t.next() | 
					
						
							|  |  |  | 			if(t.length == 0){ | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			res += 1 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX there are two modes of doing page travel:
 | 
					
						
							|  |  |  | 	// 		1) keep relative to page position
 | 
					
						
							|  |  |  | 	// 		2) travel up on top element and down on bottom (curret)
 | 
					
						
							|  |  |  | 	// 		...is this the natural choice?
 | 
					
						
							|  |  |  | 	// XXX merge with .select(..)???
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:09:11 +03:00
										 |  |  | 	// XXX still not too happy with this, item sizes will throw this
 | 
					
						
							|  |  |  | 	// 		off...
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 	prevPage: function(){ | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		var t = this.getTopVisibleElem() | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		var cur = this.select('!') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		// nothing selected...
 | 
					
						
							|  |  |  | 		if(cur.length == 0  | 
					
						
							|  |  |  | 				// element not near the top...
 | 
					
						
							|  |  |  | 				// XXX make the delta configurable (see .select(..) 
 | 
					
						
							|  |  |  | 				// 		for same issue)...
 | 
					
						
							|  |  |  | 				|| cur.offset().top - t.offset().top > (3 * t.height())){ | 
					
						
							|  |  |  | 			// select top...
 | 
					
						
							|  |  |  | 			this.select(t) | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		// make the top bottom...
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 			var p = t.scrollParent() | 
					
						
							|  |  |  | 			var S = p.scrollTop() | 
					
						
							|  |  |  | 			var H = p.height() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// rough scroll...
 | 
					
						
							|  |  |  | 			// XXX make the delta configurable (see .select(..) 
 | 
					
						
							|  |  |  | 			// 		for same issue)...
 | 
					
						
							|  |  |  | 			p.scrollTop(S - (H - 4 * t.height())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// select the element and fix scrolling errors...
 | 
					
						
							|  |  |  | 			this.select(this.getTopVisibleElem()) | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 	// XXX this is essentially identical to .prevPage(..)
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 	nextPage: function(){ | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		var b = this.getBottomVisibleElem() | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		var cur = this.select('!') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		// nothing selected...
 | 
					
						
							|  |  |  | 		if(cur.length == 0  | 
					
						
							|  |  |  | 				// element not near the top...
 | 
					
						
							|  |  |  | 				// XXX make the delta configurable (see .select(..) 
 | 
					
						
							|  |  |  | 				// 		for same issue)...
 | 
					
						
							|  |  |  | 				|| b.offset().top - cur.offset().top > (3 * b.height())){ | 
					
						
							|  |  |  | 			// select bottom...
 | 
					
						
							|  |  |  | 			this.select(b) | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 		// make the top bottom...
 | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 			var p = b.scrollParent() | 
					
						
							|  |  |  | 			var S = p.scrollTop() | 
					
						
							|  |  |  | 			var H = p.height() | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-01 03:05:05 +03:00
										 |  |  | 			// rough scroll...
 | 
					
						
							|  |  |  | 			// XXX make the delta configurable (see .select(..) 
 | 
					
						
							|  |  |  | 			// 		for same issue)...
 | 
					
						
							|  |  |  | 			p.scrollTop(S + (H - 4 * b.height())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// select the element and fix scrolling errors...
 | 
					
						
							|  |  |  | 			this.select(this.getBottomVisibleElem()) | 
					
						
							| 
									
										
										
										
											2015-10-13 02:41:47 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	// Push an element to path / go down one level...
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:06:08 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This will trigger the 'push' event.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-11 22:16:35 +03:00
										 |  |  | 	// NOTE: if the element is not traversable it will be opened.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// XXX might be a good idea to add a live traversable check...
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 	// XXX revise event...
 | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 	push: function(pattern){ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var browser = this.dom  | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 		var cur = this.select('!') | 
					
						
							| 
									
										
										
										
											2016-12-31 04:38:44 +03:00
										 |  |  | 		var elem = arguments.length == 0 ?  | 
					
						
							|  |  |  | 			cur  | 
					
						
							|  |  |  | 			: this.filter(/-?[0-9]+/.test(pattern) ? pattern | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 				// XXX avoid keywords that .select(..) understands...
 | 
					
						
							|  |  |  | 				//: '"'+pattern+'"' )
 | 
					
						
							|  |  |  | 				: pattern) | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// item not found...
 | 
					
						
							|  |  |  | 		if(elem.length == 0 && pattern != null){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 20:05:26 +03:00
										 |  |  | 		// item disabled...
 | 
					
						
							|  |  |  | 		if(elem.hasClass('disabled')){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		// nothing selected, select first and exit...
 | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 		if(cur.length == 0 && elem.length == 0){ | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 			this.select() | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// if not traversable call the action...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 		if(!this.traversable || elem.hasClass('not-traversable')){ | 
					
						
							| 
									
										
										
										
											2016-12-30 20:05:26 +03:00
										 |  |  | 			this.select(elem) | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 			return this.action() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-30 20:05:26 +03:00
										 |  |  | 		this.select(elem) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 		var path = this.path | 
					
						
							| 
									
										
										
										
											2016-02-08 03:45:48 +03:00
										 |  |  | 		// XXX do we need qotes here???
 | 
					
						
							|  |  |  | 		//path.push('"'+ elem.find('.text').text() +'"')
 | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 		path.push(elem.find('.text').text()) | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 		// XXX should this be before or after the actual path update???
 | 
					
						
							|  |  |  | 		// XXX can we cancel the update from a handler???
 | 
					
						
							|  |  |  | 		this.trigger('push', path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 		// do the actual traverse...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		this.path = path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this.select() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-06-25 05:06:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-17 03:52:21 +03:00
										 |  |  | 	// Pop an element off the path / go up one level...
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:06:08 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This will trigger the 'pop' event.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 	// XXX revise event...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	pop: function(){ | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var browser = this.dom | 
					
						
							| 
									
										
										
										
											2015-06-21 16:12:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(!this.traversable){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var path = this.path | 
					
						
							|  |  |  | 		var dir = path.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 		// XXX should this be before or after the actual path update???
 | 
					
						
							|  |  |  | 		// XXX can we cancel the update from a handler???
 | 
					
						
							| 
									
										
										
										
											2015-10-09 18:45:29 +03:00
										 |  |  | 		this | 
					
						
							|  |  |  | 			.trigger('pop', path) | 
					
						
							|  |  |  | 			.update(path) | 
					
						
							|  |  |  | 				.done(function(){ | 
					
						
							|  |  |  | 					that.select('"'+dir+'"') | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// Pre-open action...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This opens (.open(..)) the selected item and if none are selected
 | 
					
						
							|  |  |  | 	// selects the default (.select()) and exits.
 | 
					
						
							| 
									
										
										
										
											2017-02-01 23:34:03 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this ignores items with empty text...
 | 
					
						
							|  |  |  | 	// 		XXX not sure about this...
 | 
					
						
							| 
									
										
										
										
											2017-02-09 16:50:26 +03:00
										 |  |  | 	action: function(elem){ | 
					
						
							|  |  |  | 		elem = this.select(elem || '!') | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// nothing selected, select first and exit...
 | 
					
						
							|  |  |  | 		if(elem.length == 0){ | 
					
						
							|  |  |  | 			this.select() | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 		var path = this.path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 23:34:03 +03:00
										 |  |  | 		var txt = elem.find('.text').text() | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-01 23:34:03 +03:00
										 |  |  | 		// if text is empty, skip action...
 | 
					
						
							|  |  |  | 		if(txt != ''){ | 
					
						
							| 
									
										
										
										
											2017-05-20 05:28:19 +03:00
										 |  |  | 			//path.push(elem.find('.text').text())
 | 
					
						
							|  |  |  | 			path.push(txt) | 
					
						
							| 
									
										
										
										
											2017-02-01 23:34:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			var res = this.open(path) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:36:40 +03:00
										 |  |  | 	// Extension methods...
 | 
					
						
							|  |  |  | 	// ...these are resolved from .options
 | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Open action...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 	// 	Open current element...
 | 
					
						
							|  |  |  | 	// 	NOTE: if no element selected this will do nothing.
 | 
					
						
							|  |  |  | 	// 	NOTE: this will return the return of .options.open(..) or the 
 | 
					
						
							|  |  |  | 	// 		full path if null is returned...
 | 
					
						
							|  |  |  | 	// 	.open()
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	// 		-> object
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open a path...
 | 
					
						
							|  |  |  | 	// 	.open(<path>)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	// 		-> object
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Register an open event handler...
 | 
					
						
							|  |  |  | 	// 	.open(<function>)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The following signatures are relative from current context via 
 | 
					
						
							|  |  |  | 	// .select(..), see it for more details...
 | 
					
						
							|  |  |  | 	// NOTE: this will also select the opened element, so to get the full
 | 
					
						
							|  |  |  | 	// 		path from the handler just get the current path and value:
 | 
					
						
							|  |  |  | 	// 			browser.dom.attr('path') +'/'+ browser.dom.attr('value')
 | 
					
						
							| 
									
										
										
										
											2015-07-13 14:29:42 +03:00
										 |  |  | 	// 		or:
 | 
					
						
							|  |  |  | 	// 			browser.selectionPath
 | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open first/last element...
 | 
					
						
							|  |  |  | 	// 	.open('first')
 | 
					
						
							|  |  |  | 	// 	.open('last')
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open next/prev element...
 | 
					
						
							|  |  |  | 	// 	.open('next')
 | 
					
						
							|  |  |  | 	// 	.open('prev')
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open active element at index...
 | 
					
						
							|  |  |  | 	// 	.open(<number>)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open element by absolute index...
 | 
					
						
							|  |  |  | 	// 	.open('<number>!')
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Open element by full or partial text...
 | 
					
						
							|  |  |  | 	//	.open('<text>')
 | 
					
						
							|  |  |  | 	//	.open("'<text>'")
 | 
					
						
							|  |  |  | 	//	.open('"<text>"')
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Open first element matching a regexp...
 | 
					
						
							|  |  |  | 	//	.open(<regexp>)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Open an element explicitly...
 | 
					
						
							|  |  |  | 	//	.open(<elem>)
 | 
					
						
							|  |  |  | 	// 		-> this
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// This will trigger the 'open' event on the opened element and the
 | 
					
						
							|  |  |  | 	// widget.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// This is called when an element is selected and opened.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// By default this happens in the following situations:
 | 
					
						
							|  |  |  | 	// 	- an element is selected and Enter is pressed.
 | 
					
						
							|  |  |  | 	// 	- an element is not traversable and push (Left, click) is called.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// By default this only triggers the 'open' event on both the browser
 | 
					
						
							|  |  |  | 	// and the selected element if one exists.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 	// This is signature compatible with .select(..) but adds support 
 | 
					
						
							|  |  |  | 	// for full paths.
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-07-11 22:26:06 +03:00
										 |  |  | 	// The .options.open(..), if defined, will always get the full path 
 | 
					
						
							|  |  |  | 	// as first argument.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 	// If 'push-on-open' attribute is set on an element, then this will 
 | 
					
						
							|  |  |  | 	// also pass the element to .push(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// NOTE: if nothing is selected this will do nothing...
 | 
					
						
							|  |  |  | 	// NOTE: internally this is never called directly, instead a pre-open
 | 
					
						
							|  |  |  | 	// 		stage is used to execute default behavior not directly 
 | 
					
						
							|  |  |  | 	// 		related to opening an item (see: .action()).
 | 
					
						
							|  |  |  | 	// NOTE: unlike .list(..) this can be used directly if an item is 
 | 
					
						
							|  |  |  | 	// 		selected and an actual open action is defined, either in an
 | 
					
						
							|  |  |  | 	// 		instance or in .options
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	open: function(path){  | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 		// special case: register the open handler...
 | 
					
						
							|  |  |  | 		if(typeof(path) == typeof(function(){})){ | 
					
						
							|  |  |  | 			return this.on('open', path) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 17:22:01 +03:00
										 |  |  | 		var elem = this.select('!') | 
					
						
							| 
									
										
										
										
											2015-06-22 06:01:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 		// normalize and load path...
 | 
					
						
							| 
									
										
										
										
											2016-02-10 20:31:48 +03:00
										 |  |  | 		if(path && (path.constructor == Array || /[\\\/]/.test(path))){ | 
					
						
							| 
									
										
										
										
											2015-07-14 16:37:14 +03:00
										 |  |  | 			path = this.path2list(path) | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 			var elem = path.slice(-1)[0] | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// only update path if it has changed...
 | 
					
						
							|  |  |  | 			if(this.path.filter(function(e, i){ return e == path[i] }).length != path.length - 1){ | 
					
						
							|  |  |  | 				this.path = path.slice(0, -1) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-10 20:13:09 +03:00
										 |  |  | 			elem = this.select('"'+ elem +'"') | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-10 20:31:48 +03:00
										 |  |  | 		// get path + selection...
 | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-02-10 20:31:48 +03:00
										 |  |  | 			// select-compatible -- select from current context...	
 | 
					
						
							|  |  |  | 			if(!path){ | 
					
						
							|  |  |  | 				// NOTE: this is select compatible thus no need to quote 
 | 
					
						
							|  |  |  | 				// 		anything here...
 | 
					
						
							|  |  |  | 				elem = this.select(path) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-07-11 17:29:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(elem.length == 0){ | 
					
						
							|  |  |  | 				return this | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			path = this.path | 
					
						
							| 
									
										
										
										
											2016-02-10 20:31:48 +03:00
										 |  |  | 			// NOTE: we are quoting here to get a explicit element 
 | 
					
						
							|  |  |  | 			// 		selected from list...
 | 
					
						
							| 
									
										
										
										
											2015-12-14 00:00:17 +03:00
										 |  |  | 			path.push('"'+ elem.find('.text').text() +'"') | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get the options method and call it if it exists...
 | 
					
						
							|  |  |  | 		var m = this.options.open | 
					
						
							|  |  |  | 		var args = args2array(arguments) | 
					
						
							|  |  |  | 		args[0] = path | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 		var res = m ? m.apply(this, args) : this | 
					
						
							|  |  |  | 		res = res || this | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 		// XXX do we stringify the path???
 | 
					
						
							| 
									
										
										
										
											2015-11-28 18:15:12 +03:00
										 |  |  | 		// XXX should we use .strPath here???
 | 
					
						
							|  |  |  | 		path = this.options.pathPrefix + path.join('/') | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 		// trigger the 'open' events...
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 		this.trigger('open', path) | 
					
						
							| 
									
										
										
										
											2015-07-12 18:51:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 16:44:44 +03:00
										 |  |  | 		if(elem.length > 0){ | 
					
						
							| 
									
										
										
										
											2017-01-04 06:37:23 +03:00
										 |  |  | 			// push an element if attr is set... 
 | 
					
						
							|  |  |  | 			// NOTE: a good way to do this is to check if we have any 
 | 
					
						
							|  |  |  | 			// 		handlers bound, but so var I've found no non-hack-ish
 | 
					
						
							|  |  |  | 			// 		ways to do this...
 | 
					
						
							|  |  |  | 			elem.attr('push-on-open') == 'on' | 
					
						
							|  |  |  | 				&& this.push(elem) | 
					
						
							| 
									
										
										
										
											2015-06-22 17:22:01 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-22 06:01:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2015-06-21 19:58:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 	// List current path level...
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will get passed a path and an item constructor and should 
 | 
					
						
							|  |  |  | 	// return a list.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// NOTE: This is not intended for direct client use, rather it is 
 | 
					
						
							|  |  |  | 	// 		designed to either be overloaded by the user in an instance 
 | 
					
						
							|  |  |  | 	// 		or in the .options
 | 
					
						
							|  |  |  | 	//		To re-list/re-load the view use .update()
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	// There are two mods of operation:
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 1) interactive:
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:54:21 +03:00
										 |  |  | 	// 		.list(path, make)
 | 
					
						
							|  |  |  | 	// 			- for each item make is called with it's text
 | 
					
						
							|  |  |  | 	//			- make will return a jQuery object of the item
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-11-26 04:27:34 +03:00
										 |  |  | 	// 		NOTE: selection is currently done based on .find('.text').text() thus the 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	// 			modification should not affect it's output...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 2) non-interactive:
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:54:21 +03:00
										 |  |  | 	// 		.list(path) -> list
 | 
					
						
							| 
									
										
										
										
											2015-06-22 04:00:55 +03:00
										 |  |  | 	// 			- .list(..) should return an array
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:54:21 +03:00
										 |  |  | 	// 			- make should never get called
 | 
					
						
							|  |  |  | 	// 			- the returned list will be rendered
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-21 04:15:54 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// This can set the following classes on elements:
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.disabled
 | 
					
						
							|  |  |  | 	// 		an element is disabled.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.non-traversable
 | 
					
						
							|  |  |  | 	// 		an element is not traversable/listable and will trigger the
 | 
					
						
							| 
									
										
										
										
											2015-06-25 04:49:27 +03:00
										 |  |  | 	// 		.open(..) on push...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 	// XXX need a way to constructively communicate errors up...
 | 
					
						
							| 
									
										
										
										
											2015-07-14 16:29:29 +03:00
										 |  |  | 	// XXX also need a load strategy when something bad happens...
 | 
					
						
							|  |  |  | 	// 		...e.g. load up until the first error, or something like:
 | 
					
						
							|  |  |  | 	// 			while(!this.list(path, make)){
 | 
					
						
							|  |  |  | 	// 				path.pop()
 | 
					
						
							|  |  |  | 	// 			}
 | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 	list: function(path, make){ | 
					
						
							| 
									
										
										
										
											2015-05-25 20:02:47 +03:00
										 |  |  | 		path = path || this.path | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		var m = this.options.list | 
					
						
							| 
									
										
										
										
											2015-06-21 03:49:00 +03:00
										 |  |  | 		return m ? m.apply(this, arguments) : [] | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-21 20:37:32 +03:00
										 |  |  | 	// XXX need to get a container -- UI widget API....
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:57:47 +03:00
										 |  |  | 	// XXX paste does not work on IE yet...
 | 
					
						
							|  |  |  | 	// XXX handle copy...
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	__init__: function(parent, options){ | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2015-05-18 03:34:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 21:54:28 +03:00
										 |  |  | 		object.superMethod(Browser, '__init__').call(this, parent, options) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 21:54:28 +03:00
										 |  |  | 		var dom = this.dom | 
					
						
							|  |  |  | 		options = this.options | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 		// basic permanent interactions...
 | 
					
						
							|  |  |  | 		dom.find('.path') | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 			// NOTE: these are used for full-path editing and are defined
 | 
					
						
							|  |  |  | 			// 		here in contrast to other feature handlers as the
 | 
					
						
							|  |  |  | 			// 		'.path' element is long-lived and not rewritten 
 | 
					
						
							|  |  |  | 			// 		on .update(..)
 | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 			.dblclick(function(){ | 
					
						
							|  |  |  | 				that.startFullPathEdit() | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 			.keyup(function(){ | 
					
						
							|  |  |  | 				var e = $(this) | 
					
						
							| 
									
										
										
										
											2015-06-28 05:23:31 +03:00
										 |  |  | 				// clear the list on edit...
 | 
					
						
							| 
									
										
										
										
											2015-06-26 14:40:41 +03:00
										 |  |  | 				if(e.attr('contenteditable') && e.text() != dom.attr('orig-path')){ | 
					
						
							|  |  |  | 					dom.find('.list').empty() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-06-28 05:23:31 +03:00
										 |  |  | 			/* XXX  | 
					
						
							|  |  |  | 			// Handle copy/paste...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// Make the whole widget support copy/paste of current path.
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// NOTE: on nw.js mode this will handle this via keyboard 
 | 
					
						
							|  |  |  | 			// 		directly, skipping the events and their quirks...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							| 
									
										
										
										
											2015-06-26 15:57:47 +03:00
										 |  |  | 			// XXX does not work on IE yet...
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 			// XXX do we handle other types???
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:23:31 +03:00
										 |  |  | 			// 		...try and get the path of anything, including files, dirs, etc...
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 			// XXX seems not to work until we cycle any of the editable
 | 
					
						
							|  |  |  | 			// 		controls (filter/path), and then it still is on and 
 | 
					
						
							|  |  |  | 			// 		off...
 | 
					
						
							| 
									
										
										
										
											2015-06-28 05:23:31 +03:00
										 |  |  | 			// XXX does not work with ':not([contenteditable])' and kills
 | 
					
						
							|  |  |  | 			// 		copy/paste on editable fields without...
 | 
					
						
							|  |  |  | 			// XXX do we bother with these??
 | 
					
						
							|  |  |  | 			.on('paste', ':not([contenteditable])', function(){ | 
					
						
							| 
									
										
										
										
											2015-06-26 15:57:47 +03:00
										 |  |  | 				event.preventDefault() | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 				that.paste() | 
					
						
							| 
									
										
										
										
											2015-06-26 15:57:47 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-06-28 05:23:31 +03:00
										 |  |  | 			// XXX does not work...
 | 
					
						
							| 
									
										
										
										
											2015-06-27 02:34:52 +03:00
										 |  |  | 			.on('cut copy', function(){ | 
					
						
							|  |  |  | 				event.preventDefault() | 
					
						
							|  |  |  | 				that.copy() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			*/ | 
					
						
							| 
									
										
										
										
											2015-06-26 03:07:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 		// attach to parent...
 | 
					
						
							|  |  |  | 		if(parent != null){ | 
					
						
							|  |  |  | 			parent.append(dom) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-17 20:48:57 +03:00
										 |  |  | 		// load the initial state...
 | 
					
						
							| 
									
										
										
										
											2017-01-20 20:37:11 +03:00
										 |  |  | 		// NOTE: path can be a number so simply or-ing here is a bad idea...
 | 
					
						
							|  |  |  | 		var path = options.path != null ? options.path : that.path | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 		var selected = options.selected | 
					
						
							| 
									
										
										
										
											2017-01-20 20:37:11 +03:00
										 |  |  | 		typeof(path) == typeof(123) ? | 
					
						
							|  |  |  | 			// select item number...
 | 
					
						
							|  |  |  | 			that | 
					
						
							|  |  |  | 				.update() | 
					
						
							|  |  |  | 				.then(function(){  | 
					
						
							|  |  |  | 					that.select(path) }) | 
					
						
							|  |  |  | 			// select path...
 | 
					
						
							|  |  |  | 			: that | 
					
						
							|  |  |  | 				.update(path || '/') | 
					
						
							|  |  |  | 				// Select the default path...
 | 
					
						
							|  |  |  | 				.then(function(){  | 
					
						
							| 
									
										
										
										
											2017-02-05 08:22:39 +03:00
										 |  |  | 					// explicit config selection...
 | 
					
						
							|  |  |  | 					// NOTE: this takes precedence over the path syntax...
 | 
					
						
							|  |  |  | 					// XXX not sure if we need this...
 | 
					
						
							|  |  |  | 					// 		...currently this is used only when path is 
 | 
					
						
							|  |  |  | 					// 		a list and we need to also select an item...
 | 
					
						
							|  |  |  | 					selected ? that.select(selected)  | 
					
						
							|  |  |  | 						// we have a manually selected item but that was 
 | 
					
						
							|  |  |  | 						// not aligned...
 | 
					
						
							|  |  |  | 						: that.selected ? that.select() | 
					
						
							|  |  |  | 						: null }) | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var Browser =  | 
					
						
							| 
									
										
										
										
											2015-06-20 14:50:54 +03:00
										 |  |  | module.Browser =  | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | object.makeConstructor('Browser',  | 
					
						
							|  |  |  | 		BrowserClassPrototype,  | 
					
						
							|  |  |  | 		BrowserPrototype) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 21:54:28 +03:00
										 |  |  | // inherit from widget...
 | 
					
						
							|  |  |  | Browser.prototype.__proto__ = widget.Widget.prototype | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | var ListerPrototype = Object.create(Browser.prototype) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | ListerPrototype.options = { | 
					
						
							|  |  |  | 	pathPrefix: '',  | 
					
						
							|  |  |  | 	fullPathEdit: false, | 
					
						
							|  |  |  | 	traversable: false, | 
					
						
							|  |  |  | 	flat: true, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX not sure if we need these...
 | 
					
						
							|  |  |  | 	skipDisabledItems: false, | 
					
						
							|  |  |  | 	// NOTE: to disable this set it to false or null
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	isItemDisabled: '^- ', | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | } | 
					
						
							|  |  |  | // XXX should we inherit or copy options???
 | 
					
						
							|  |  |  | // 		...inheriting might pose problems with deleting values reverting
 | 
					
						
							|  |  |  | // 		them to default instead of nulling them and mutable options might
 | 
					
						
							|  |  |  | // 		get overwritten...
 | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | ListerPrototype.options.__proto__ = Browser.prototype.options | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var Lister =  | 
					
						
							|  |  |  | module.Lister =  | 
					
						
							|  |  |  | object.makeConstructor('Lister',  | 
					
						
							|  |  |  | 		BrowserClassPrototype,  | 
					
						
							|  |  |  | 		ListerPrototype) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This is a shorthand for: new List(<elem>, { data: <list> })
 | 
					
						
							|  |  |  | var makeLister =  | 
					
						
							|  |  |  | module.makeLister = function(elem, lister, options){ | 
					
						
							|  |  |  | 	var opts = {} | 
					
						
							|  |  |  | 	for(var k in options){ | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 		opts[k] = options[k] | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	opts.list = lister | 
					
						
							|  |  |  | 	return Lister(elem, opts) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-25 05:45:27 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | // Flat list...
 | 
					
						
							| 
									
										
										
										
											2015-06-22 17:22:01 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:26:56 +03:00
										 |  |  | // This expects a data option set with one of the following formats:
 | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | // 	{
 | 
					
						
							|  |  |  | // 		<option-text>: <callback>,
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // or:
 | 
					
						
							|  |  |  | // 	[
 | 
					
						
							|  |  |  | // 		<option-text>,
 | 
					
						
							|  |  |  | // 		...
 | 
					
						
							|  |  |  | // 	]
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // If <option-test> starts with a '- ' then it will be added disabled,
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | // to control the pattern use the .isItemDisabled option, and to 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | // disable this feature set it to false|null.
 | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | // 	
 | 
					
						
							|  |  |  | // NOTE: this essentially a different default configuration of Browser...
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:26:56 +03:00
										 |  |  | // NOTE: this is essentially a wrapper around make.List(...)
 | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | var ListPrototype = Object.create(Browser.prototype) | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | ListPrototype.options = { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-09 00:04:09 +03:00
										 |  |  | 	pathPrefix: '',  | 
					
						
							| 
									
										
										
										
											2015-07-14 02:02:37 +03:00
										 |  |  | 	fullPathEdit: false, | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | 	traversable: false, | 
					
						
							|  |  |  | 	flat: true, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 	// XXX not sure if we need these...
 | 
					
						
							|  |  |  | 	skipDisabledItems: false, | 
					
						
							|  |  |  | 	// NOTE: to disable this set it to false or null
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	isItemDisabled: '^- ', | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | 	list: function(path, make){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 		var data = this.options.data | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 		var res = [] | 
					
						
							| 
									
										
										
										
											2016-01-15 05:37:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 		// this is here to get the modified titles...
 | 
					
						
							|  |  |  | 		var _make = function(txt){ | 
					
						
							|  |  |  | 			res.push(txt) | 
					
						
							|  |  |  | 			return make.apply(make, arguments) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		_make.__proto__ = make | 
					
						
							| 
									
										
										
										
											2015-06-24 18:21:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:26:56 +03:00
										 |  |  | 		// build the list...
 | 
					
						
							|  |  |  | 		_make | 
					
						
							|  |  |  | 			.List(data, { | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 				isItemDisabled: this.options.isItemDisabled, | 
					
						
							| 
									
										
										
										
											2017-01-21 18:26:56 +03:00
										 |  |  | 				skipDisabledItems: this.options.skipDisabledItems, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-21 18:15:11 +03:00
										 |  |  | 		return res | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | ListPrototype.options.__proto__ = Browser.prototype.options | 
					
						
							| 
									
										
										
										
											2015-06-22 18:09:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var List =  | 
					
						
							|  |  |  | module.List =  | 
					
						
							|  |  |  | object.makeConstructor('List',  | 
					
						
							|  |  |  | 		BrowserClassPrototype,  | 
					
						
							|  |  |  | 		ListPrototype) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This is a shorthand for: new List(<elem>, { data: <list> })
 | 
					
						
							| 
									
										
										
										
											2015-06-22 17:22:01 +03:00
										 |  |  | var makeList =  | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | module.makeList = makeBrowserMaker(List) | 
					
						
							| 
									
										
										
										
											2015-06-22 17:22:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 07:26:39 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Make an list/Array editor...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // For options format see: Items.EditableList(..)
 | 
					
						
							|  |  |  | var makeListEditor =  | 
					
						
							|  |  |  | module.makeListEditor = | 
					
						
							|  |  |  | function(list, options){ | 
					
						
							|  |  |  | 	return makeLister(null,  | 
					
						
							|  |  |  | 		function(path, make){ | 
					
						
							|  |  |  | 			make.EditableList(list, options) },  | 
					
						
							|  |  |  | 		options) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // This is similar to List(..) but will parse paths in keys...
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-09-05 17:46:29 +03:00
										 |  |  | // Path grammar:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	PATH ::= [/]<dirs>				- simple traversable path
 | 
					
						
							|  |  |  | // 			| [/]<dirs>/<item>		- path with last item non-traversable
 | 
					
						
							|  |  |  | // 			| [/]<dirs>/*			- path to lister
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	<dirs> ::= <item> 
 | 
					
						
							|  |  |  | // 			| <dirs>/<item>/
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	<item> ::= <name>				- explicit path element 
 | 
					
						
							|  |  |  | // 			| <item>|<name>			- multiple path elements (a-la simlink)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	<name> ::= [^\|\\\/]*
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	NOTE: <dirs> always ends with '/' or '\' and produces a set of 
 | 
					
						
							|  |  |  | // 		traversable items.
 | 
					
						
							|  |  |  | // 	NOTE: the last item is non-traversable iff:
 | 
					
						
							|  |  |  | // 		- it does not end with '/' or '\'
 | 
					
						
							|  |  |  | // 		- there is no other path defined where it is traversable
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // Format:
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | // 	{
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // 		// basic 'file' path...
 | 
					
						
							|  |  |  | // 		// NOTE: this path is non-traversable by default, but if a 
 | 
					
						
							|  |  |  | // 		//		sub-path handler is defined (e.g. 'dir/file/x') then this
 | 
					
						
							|  |  |  | // 		//		will be set traversable...
 | 
					
						
							|  |  |  | // 		'dir/file': function(evt, path){ .. },
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// file object at the tree root...
 | 
					
						
							|  |  |  | // 		// NOTE: the leading '/' is optional...
 | 
					
						
							|  |  |  | // 		'file': function(evt, path){ .. },
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		// a directory handler is defined by path ending with '/', 
 | 
					
						
							|  |  |  | // 		// set traversable...
 | 
					
						
							|  |  |  | // 		'dir/dir/': function(evt, path){ .. },
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | // 		// add a file object to two dirs...
 | 
					
						
							|  |  |  | // 		'dir|other/other file': function(evt, path){ .. },
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | //		// path lister...
 | 
					
						
							|  |  |  | //		'dynamic/*': function(path, make){ .. }
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | // 	}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // The above definition will be interpreted into the following tree:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	/
 | 
					
						
							|  |  |  | // 		dir/
 | 
					
						
							|  |  |  | // 			file
 | 
					
						
							|  |  |  | // 			dir/
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | // 			other file
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // 		file
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | // 		other/
 | 
					
						
							|  |  |  | // 			other file
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // 		dynamic/
 | 
					
						
							|  |  |  | // 			..
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Here the contents of the '/dynamic/' path are generated by the matching 
 | 
					
						
							|  |  |  | // lister for that pattern path...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | // NOTE: in the A|B|C pattern, ALL of the alternatives will be created.
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // NOTE: there may be multiple matching patterns/listers or a given path
 | 
					
						
							|  |  |  | // 		the one used is the longest match.
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | // NOTE: if path is receded with '- ' ('- a|b/c') then the basename of 
 | 
					
						
							|  |  |  | // 		that path will be disabled, to control the pattern use
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | // 		.isItemDisabled and to disable this feature set it to false.
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Handler format:
 | 
					
						
							|  |  |  | // 	function(evt, path){ .. }
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // 		This function will be called on the 'open' event for the defined 
 | 
					
						
							|  |  |  | // 		item.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Lister format:
 | 
					
						
							|  |  |  | // 	function(path, make){ .. } -> list
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		This function will get called on .update(..) of the matching path.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		make(text, traversable) is a list item constructor.
 | 
					
						
							|  |  |  | //		for more docs see: Browser.list(..)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:57:05 +03:00
										 |  |  | // NOTE: listers take precedence over explicit path definitions, thus 
 | 
					
						
							|  |  |  | // 		if a custom lister pattern intersects with a normal path the path
 | 
					
						
							|  |  |  | // 		will be ignored and the lister called.
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | // NOTE: currently only trailing '*' are supported.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX add support for '*' and '**' glob patterns...
 | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | var PathListPrototype = Object.create(Browser.prototype) | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | PathListPrototype.options = { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 12:41:44 +03:00
										 |  |  | 	fullPathEdit: true, | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 	traversable: true, | 
					
						
							|  |  |  | 	flat: false, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 	// XXX not sure if we need these...
 | 
					
						
							|  |  |  | 	skipDisabledItems: false, | 
					
						
							|  |  |  | 	// NOTE: to disable this set it to false or null
 | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 	isItemDisabled: '^- ', | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 	list: function(path, make){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var data = this.options.data | 
					
						
							|  |  |  | 		var keys = data.constructor == Array ? data : Object.keys(data) | 
					
						
							| 
									
										
										
										
											2017-02-02 03:25:58 +03:00
										 |  |  | 		var pattern = this.options.isItemDisabled  | 
					
						
							|  |  |  | 			&& RegExp(this.options.isItemDisabled) | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(pattern && this.options.skipDisabledItems){ | 
					
						
							|  |  |  | 			keys = keys.filter(function(k){ return !pattern.test(k) }) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var visited = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 		// match path elements accounting for patterns...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Supported patterns:
 | 
					
						
							|  |  |  | 		// 	A		- matches A exactly
 | 
					
						
							|  |  |  | 		// 	A|B		- matches either A or B
 | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 		// 	shortcut marker
 | 
					
						
							|  |  |  | 		// 			- see .options.itemShortcutMarker
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: only the second argument is checked for '|' patterns...
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 		var match = function(a, path){ | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 			var marker = that.options.itemShortcutMarker  | 
					
						
							|  |  |  | 			marker = marker && RegExp(marker, 'g') | 
					
						
							|  |  |  | 			path = marker ? e.replace(marker, '$1') : path | 
					
						
							| 
									
										
										
										
											2015-09-05 17:46:29 +03:00
										 |  |  | 			// NOTE: might be good to make this recursive when expanding
 | 
					
						
							|  |  |  | 			// 		pattern support...
 | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 			return a | 
					
						
							|  |  |  | 					.split('|') | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 					.map(function(e){  | 
					
						
							|  |  |  | 						return marker ? e.replace(marker, '$1') : e }) | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 					.filter(function(e){  | 
					
						
							| 
									
										
										
										
											2017-01-28 01:09:05 +03:00
										 |  |  | 						return e == path }) | 
					
						
							|  |  |  | 					.length > 0 } | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 		// get the '*' listers...
 | 
					
						
							|  |  |  | 		var lister = keys | 
					
						
							| 
									
										
										
										
											2015-12-14 00:00:17 +03:00
										 |  |  | 			.filter(function(k){  | 
					
						
							|  |  |  | 				return k.trim().split(/[\\\/]+/g).pop() == '*' }) | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 			.filter(function(k){ | 
					
						
							| 
									
										
										
										
											2015-09-05 02:52:51 +03:00
										 |  |  | 				k = k.split(/[\\\/]+/) | 
					
						
							|  |  |  | 					// remove the trailing '*'...
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 					.slice(0, -1) | 
					
						
							| 
									
										
										
										
											2015-09-05 02:52:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// do the match...
 | 
					
						
							|  |  |  | 				return k.length <= path.length  | 
					
						
							|  |  |  | 					&& k.filter(function(e, i){  | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 							return e != '*' && !match(e, path[i]) | 
					
						
							| 
									
										
										
										
											2015-09-05 02:52:51 +03:00
										 |  |  | 						}).length == 0 }) | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 			.sort(function(a, b){ return a.length - b.length}) | 
					
						
							|  |  |  | 			.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// use the custom lister (defined by trailing '*')...
 | 
					
						
							|  |  |  | 		if(data !== keys && lister){ | 
					
						
							| 
									
										
										
										
											2015-11-28 18:15:12 +03:00
										 |  |  | 			return data[lister].call(this, this.options.pathPrefix + path.join('/'), make) | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// list via provided paths...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return keys | 
					
						
							|  |  |  | 				.map(function(k){ | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 					var disable = null | 
					
						
							|  |  |  | 					if(pattern){ | 
					
						
							|  |  |  | 						var n = k.replace(pattern, '') | 
					
						
							|  |  |  | 						disable = n != k | 
					
						
							|  |  |  | 						k = n | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 					var kp = k.split(/[\\\/]+/g) | 
					
						
							|  |  |  | 					kp[0] == '' && kp.shift() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// see if we have a star...
 | 
					
						
							|  |  |  | 					var star = kp.slice(-1)[0] == '*' | 
					
						
							|  |  |  | 					star && kp.pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// get and check current path, continue if relevant...
 | 
					
						
							|  |  |  | 					var p = kp.splice(0, path.length) | 
					
						
							|  |  |  | 					if(kp.length == 0  | 
					
						
							|  |  |  | 							|| p.length < path.length | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 							|| p.filter(function(e, i){ return !match(e, path[i]) }).length > 0){ | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 						return false | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 					// get current path element if one exists and we did not create it already...
 | 
					
						
							|  |  |  | 					cur = kp.shift() | 
					
						
							|  |  |  | 					if(cur == undefined){ | 
					
						
							|  |  |  | 						return false | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 					cur.split('|') | 
					
						
							|  |  |  | 						// skip empty path items...
 | 
					
						
							|  |  |  | 						// NOTE: this avoids creating empty items in cases
 | 
					
						
							|  |  |  | 						// 		of paths ending with '/' or containing '//'
 | 
					
						
							|  |  |  | 						.filter(function(e){ return e.trim() != '' }) | 
					
						
							|  |  |  | 						.forEach(function(cur){ | 
					
						
							|  |  |  | 							if(visited.indexOf(cur) >= 0){ | 
					
						
							|  |  |  | 								// set element to traversable if we visit it again...
 | 
					
						
							|  |  |  | 								if(kp.length > 0){ | 
					
						
							|  |  |  | 									that.filter(cur, false) | 
					
						
							|  |  |  | 										.removeClass('not-traversable') | 
					
						
							|  |  |  | 										//.removeClass('disabled')
 | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 								return false | 
					
						
							| 
									
										
										
										
											2015-09-05 16:07:08 +03:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2015-12-11 07:32:46 +03:00
										 |  |  | 							visited.push(cur) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// build the element....
 | 
					
						
							|  |  |  | 							var e = make(cur, | 
					
						
							|  |  |  | 								star || kp.length > 0,  | 
					
						
							|  |  |  | 								// XXX this might still disable a dir...
 | 
					
						
							|  |  |  | 								!star && kp.length == 0 && disable) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// setup handlers...
 | 
					
						
							|  |  |  | 							if(!star && data !== keys && kp.length == 0 && data[k] != null){ | 
					
						
							|  |  |  | 								e.on('open', function(){  | 
					
						
							|  |  |  | 									return that.options.data[k].apply(this, arguments) | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-31 20:13:29 +03:00
										 |  |  | 					return cur | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.filter(function(e){ return e !== false }) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-05-27 23:04:15 +03:00
										 |  |  | PathListPrototype.options.__proto__ = Browser.prototype.options | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var PathList =  | 
					
						
							|  |  |  | module.PathList =  | 
					
						
							|  |  |  | object.makeConstructor('PathList',  | 
					
						
							|  |  |  | 		BrowserClassPrototype,  | 
					
						
							|  |  |  | 		PathListPrototype) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var makePathList =  | 
					
						
							| 
									
										
										
										
											2015-12-10 00:24:43 +03:00
										 |  |  | module.makePathList = makeBrowserMaker(PathList) | 
					
						
							| 
									
										
										
										
											2015-08-29 21:41:46 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-29 03:42:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 05:02:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-21 16:45:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |