| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // Hepers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var path2lst = function(path){  | 
					
						
							|  |  |  | 	return (path instanceof Array ?  path : path.split(/[\\\/]+/g)) | 
					
						
							|  |  |  | 		// handle '..' (lookahead) and trim path elements...
 | 
					
						
							|  |  |  | 		// NOTE: this will not touch the leading '.' or '..'
 | 
					
						
							|  |  |  | 		.map(function(p, i, l){ | 
					
						
							|  |  |  | 			return (i > 0 && (p.trim() == '..' || p.trim() == '.') | 
					
						
							|  |  |  | 					|| (l[i+1] || '').trim() == '..') ?  | 
					
						
							|  |  |  | 				null  | 
					
						
							|  |  |  | 				: p.trim() }) | 
					
						
							|  |  |  | 		// cleanup and clear '.'...
 | 
					
						
							|  |  |  | 		.filter(function(p){  | 
					
						
							|  |  |  | 			return p != null && p != '' })} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var normalizePath = function(path){ | 
					
						
							|  |  |  | 	return path2lst(path).join('/') } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var clearWikiWords = function(elem){ | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 	// clear existing...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 	elem.find('.wikiword').each(function(){ | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		$(this).attr('bracketed') == 'yes' ?  | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 			$(this).replaceWith(['['].concat(this.childNodes, [']'])) | 
					
						
							|  |  |  | 			: $(this).replaceWith(this.childNodes) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	return elem }  | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | var setWikiWords = function(text, show_brackets, skip){ | 
					
						
							|  |  |  | 	skip = skip || [] | 
					
						
							|  |  |  | 	skip = skip instanceof Array ? skip : [skip] | 
					
						
							|  |  |  | 	return text  | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 		// set new...
 | 
					
						
							|  |  |  | 		.replace( | 
					
						
							|  |  |  | 			Wiki.__wiki_link__, | 
					
						
							|  |  |  | 			function(l){ | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 				return skip.indexOf(l) < 0 ?  | 
					
						
							|  |  |  | 					('<a ' | 
					
						
							|  |  |  | 						+'class="wikiword" ' | 
					
						
							|  |  |  | 						+'href="#" ' | 
					
						
							|  |  |  | 						+'bracketed="'+ (show_brackets && l[0] == '[' ? 'yes' : 'no') +'" ' | 
					
						
							|  |  |  | 						+'onclick="go($(this).text())" ' | 
					
						
							|  |  |  | 						+'>' | 
					
						
							|  |  |  | 							+ (!!show_brackets && l[0] == '[' ? l.slice(1, -1) : l)  | 
					
						
							|  |  |  | 						+'</a>') | 
					
						
							|  |  |  | 					: l | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			})} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX should inline macros support named args???
 | 
					
						
							|  |  |  | var macro = { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 	__include_marker__: '__include_marker__', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	// Abstract macro syntax:
 | 
					
						
							|  |  |  | 	// 	Inline macro:
 | 
					
						
							|  |  |  | 	// 		@macro(arg ..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	HTML-like:
 | 
					
						
							|  |  |  | 	// 		<macro arg=value ../>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	HTML-like with body:
 | 
					
						
							|  |  |  | 	// 		<macro arg=value ..>
 | 
					
						
							|  |  |  | 	// 			..text..
 | 
					
						
							|  |  |  | 	// 		</macro>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	__macro__pattern__:  | 
					
						
							|  |  |  | 		/<([a-zA-Z-_:]+)(.|[\n\r])*?(>(.|[\n\r])*?<\/\1>|\/>)|@([a-zA-Z-_]+)\(([^)]*)\)/mg, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// default filters...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: these are added AFTER the user defined filters...
 | 
					
						
							|  |  |  | 	__filters__: [ | 
					
						
							|  |  |  | 		'wikiword', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Maacros...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// stage 1...
 | 
					
						
							|  |  |  | 	// XXX do not like how args are defined...
 | 
					
						
							|  |  |  | 	// 		...putting them in the same pot as the macro-handlers is 
 | 
					
						
							|  |  |  | 	// 		error-prone, need a bit more separation -- constructor?
 | 
					
						
							|  |  |  | 	// 			Macro( <doc>, <args>, <func> )
 | 
					
						
							|  |  |  | 	macro: { | 
					
						
							|  |  |  | 		// select filter to post-process text...
 | 
					
						
							|  |  |  | 		filter_args: ['name'], | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		filter: function(context, args, text, state){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			var filter = args[0] || args.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			filter[0] == '-' ? | 
					
						
							|  |  |  | 				// disabled -- keep at head of list...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 				state.filters.unshift(filter) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				// normal -- tail...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 				: state.filters.push(filter) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return '' | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// include page/slot...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: this will render the page in the caller's context.
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		// NOTE: included pages are rendered completely independently 
 | 
					
						
							|  |  |  | 		// 		from the including page.
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// XXX do we need to control the rendering of nested pages???
 | 
					
						
							|  |  |  | 		// 		...currently I do not think so...
 | 
					
						
							|  |  |  | 		// 		...if required this can be done via global and local 
 | 
					
						
							|  |  |  | 		// 		filters... (now filters are only local)
 | 
					
						
							|  |  |  | 		// XXX do we need to render just one slot??? (slot arg)
 | 
					
						
							|  |  |  | 		include_args: ['src'], | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		include: function(context, args, _, state){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			var path = args.src | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 			// XXX not sure if we need to render the source page relative
 | 
					
						
							|  |  |  | 			// 		to this or as-is...
 | 
					
						
							|  |  |  | 			state.include | 
					
						
							|  |  |  | 				//.push(this.parse(context, context.get(path).raw))
 | 
					
						
							|  |  |  | 				.push(context.get(path).text) | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return this.__include_marker__ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		/* | 
					
						
							|  |  |  | 		// NOTE: this is similar to include, the difference is that this
 | 
					
						
							|  |  |  | 		// 		includes the page source to the current context while 
 | 
					
						
							|  |  |  | 		// 		include works in an isolated context
 | 
					
						
							|  |  |  | 		// XXX currently this will not parse the target...
 | 
					
						
							|  |  |  | 		source_args: ['src'], | 
					
						
							|  |  |  | 		source: function(context, args, _, state){ | 
					
						
							|  |  |  | 			var path = args.src | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return context.get(path).raw | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		//*/
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		// fill/define slot (stage 1)...
 | 
					
						
							|  |  |  | 		slot_args: ['name'], | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		slot: function(context, args, text, state){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			var name = args.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			if(state.slots[name] == null){ | 
					
						
							|  |  |  | 				state.slots[name] = text | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				// return a slot macro parsable by stage 2...
 | 
					
						
							|  |  |  | 				return '<slot name="'+name+'">'+ text +'</slot>' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			} else if(name in state.slots){ | 
					
						
							|  |  |  | 				state.slots[name] = text | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				return '' | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// stage 2...
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 	post_macro: { | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		slot_args: ['name'], | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		slot: function(context, args, text, state){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			var name = args.name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			if(state.slots[name] == null){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				return text | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			} else if(name in state.slots){ | 
					
						
							|  |  |  | 				return state.slots[name] | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Filters...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 	// Signature:
 | 
					
						
							|  |  |  | 	// 	filter(text) -> html
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	filter: { | 
					
						
							|  |  |  | 		default: 'html', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		html: function(context, text){ return $('<div>').html(text).html() }, | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		json: 'text', | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		text: function(context, text){ return $('<div>').text(text).html() }, | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		wikiword: function(context, text){  | 
					
						
							|  |  |  | 			return setWikiWords(text, null, this.__include_marker__) }, | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	parseElem: function(text, stage){ | 
					
						
							|  |  |  | 		var res = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// @<name>(<args>)
 | 
					
						
							|  |  |  | 		if(text[0] == '@'){ | 
					
						
							|  |  |  | 			var d = text.match(/@([a-zA-Z-_:]*)\(([^)]*)\)/) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			res.text = '' | 
					
						
							|  |  |  | 			res.name = d[1] | 
					
						
							|  |  |  | 			var args = res.args = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var a = d[2].split(/\s+/g) | 
					
						
							|  |  |  | 			a.forEach(function(e, i){ | 
					
						
							|  |  |  | 				args[(stage[res.name + '_args'] || [])[i]] = e | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// html-like...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var elem = res.elem = $('<div>').html(text).children().eq(0) | 
					
						
							|  |  |  | 			res.name = elem.prop('tagName').toLowerCase() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var args = res.args = {} | 
					
						
							|  |  |  | 			var a = elem.prop('attributes') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for(var i=0; i<a.length; i++){ | 
					
						
							|  |  |  | 				args[a[i].name] = a[i].value | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			res.text = elem.html() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 	parse: function(context, text, state){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		state = state || { | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			filters: [], | 
					
						
							|  |  |  | 			slots: {}, | 
					
						
							|  |  |  | 			include: [], | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		var _parse = function(context, text, macro){ | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			return text.replace(that.__macro__pattern__, function(match){ | 
					
						
							|  |  |  | 				var m = that.parseElem(match, macro) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// found a macro...
 | 
					
						
							|  |  |  | 				return m.name in macro ?  | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 						macro[m.name].call(that, context, m.args, m.text, state) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 					// found a tag -> look inside...
 | 
					
						
							|  |  |  | 					: m.elem && m.text != ''?  | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 						m.elem.html(_parse(context, m.text, macro))[0].outerHTML | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 					// else nothing changed...
 | 
					
						
							|  |  |  | 					: match | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// macro stage 1...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		text = _parse(context, text, this.macro) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// macro stage 2...
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		text = _parse(context, text, this.post_macro) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX for some reason the next line parses WikiHome twice, once
 | 
					
						
							|  |  |  | 		// 		with -wikiword and oce without...
 | 
					
						
							|  |  |  | 		// 			$('body').html(Wiki.get('WikiHome/_view').text)
 | 
					
						
							|  |  |  | 		console.log('filters:', state.filters, text.slice(0, 60)) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// filter stage....
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		state.filters | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			.concat(this.__filters__) | 
					
						
							|  |  |  | 			// unique -- leave last occurance..
 | 
					
						
							|  |  |  | 			.filter(function(k, i, lst){  | 
					
						
							|  |  |  | 				return k[0] != '-' | 
					
						
							|  |  |  | 					// filter dupplicates... 
 | 
					
						
							|  |  |  | 					&& lst.slice(i+1).indexOf(k) == -1  | 
					
						
							|  |  |  | 						// filter disabled...
 | 
					
						
							|  |  |  | 					&& lst.slice(0, i).indexOf('-' + k) == -1 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			// unique -- leave first occurance..
 | 
					
						
							|  |  |  | 			//.filter(function(k, i, lst){ return lst.slice(0, i).indexOf(k) == -1 })
 | 
					
						
							|  |  |  | 			// apply the filters...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 			.forEach(function(f){ | 
					
						
							|  |  |  | 				var k = f | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				// get filter aliases...
 | 
					
						
							|  |  |  | 				var seen = [] | 
					
						
							|  |  |  | 				while(typeof(k) == typeof('str') && seen.indexOf(k) == -1){ | 
					
						
							|  |  |  | 					seen.push(k) | 
					
						
							|  |  |  | 					k = that.filter[k] | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 				// could not find the filter...
 | 
					
						
							|  |  |  | 				if(!k){ | 
					
						
							|  |  |  | 					console.warn('Unknown filter:', f) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// use the filter...
 | 
					
						
							|  |  |  | 				text = k.call(that, context, text)  | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		// merge includes...
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 		// XXX need to check for errors (includes too short/long)...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 		text = text.replace(RegExp(this.__include_marker__, 'g'), function(){ | 
					
						
							|  |  |  | 			return state.include.shift() | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 		return text | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-17 15:58:50 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | // XXX not sure about these...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:23:28 +03:00
										 |  |  | // XXX add docs...
 | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | var BaseData = { | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	// Macro acces to standard page attributes...
 | 
					
						
							|  |  |  | 	'System/title': function(){ return this.get('..').title }, | 
					
						
							|  |  |  | 	'System/path': function(){ return this.dir }, | 
					
						
							|  |  |  | 	'System/dir': function(){ return this.get('..').dir }, | 
					
						
							|  |  |  | 	'System/location': function(){ return this.dir }, | 
					
						
							|  |  |  | 	'System/resolved': function(){ return this.get('..').acquire() }, | 
					
						
							| 
									
										
										
										
											2016-07-10 04:30:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	// page data...
 | 
					
						
							|  |  |  | 	'System/raw': function(){ return this.get('..').raw }, | 
					
						
							|  |  |  | 	'System/text': function(){ return this.get('..').text }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 20:42:33 +03:00
										 |  |  | 	// XXX move this to Wiki.children + rename...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	'System/list': function(){ | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 		var p = this.dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return Object.keys(this.__wiki_data) | 
					
						
							|  |  |  | 			.map(function(k){ | 
					
						
							|  |  |  | 				if(k.indexOf(p) == 0){ | 
					
						
							|  |  |  | 					return path2lst(k.slice(p.length)).shift() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return null | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			.filter(function(e){ return e != null }) | 
					
						
							| 
									
										
										
										
											2016-07-10 03:29:53 +03:00
										 |  |  | 			.sort() | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			.map(function(e){ return '['+ e +']' }) | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 			.join('<br>') | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	'System/tree': function(){ | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 		var p = this.dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return Object.keys(this.__wiki_data) | 
					
						
							|  |  |  | 			.map(function(k){ | 
					
						
							|  |  |  | 				if(k.indexOf(p) == 0){ | 
					
						
							|  |  |  | 					return k | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return null | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			.filter(function(e){ return e != null }) | 
					
						
							| 
									
										
										
										
											2016-07-10 03:29:53 +03:00
										 |  |  | 			.sort() | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			.map(function(e){ return '['+ e +']' }) | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 			.join('<br>') | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	// list links to this page...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	'System/links': function(){ | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		var p = this.dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var res = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var wiki = this.__wiki_data | 
					
						
							|  |  |  | 		Object.keys(wiki).forEach(function(k){ | 
					
						
							|  |  |  | 			(wiki[k].links || []).forEach(function(l){ | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 				(l == p || that.get(path2lst(l).slice(0, -1)).acquire('./'+path2lst(l).pop()) == p) | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 					&& res.push([l, k]) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return res | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 			//.map(function(e){ return '['+ e[0] +'] <i>from page: ['+ e[1] +']</i>' })
 | 
					
						
							|  |  |  | 			.map(function(e){ return '['+ e[1] +'] <i>-> ['+ e[0] +']</i>' }) | 
					
						
							| 
									
										
										
										
											2016-07-10 03:29:53 +03:00
										 |  |  | 			.sort() | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 			.join('<br>') | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX this needs a redirect...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	'System/delete': function(){ | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 		var p = this.dir | 
					
						
							|  |  |  | 		delete this.__wiki_data[p] | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // data store...
 | 
					
						
							|  |  |  | // Format:
 | 
					
						
							|  |  |  | // 	{
 | 
					
						
							|  |  |  | // 		<path>: {
 | 
					
						
							|  |  |  | // 			text: <text>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 			links: [
 | 
					
						
							|  |  |  | // 				<offset>: <link>,
 | 
					
						
							|  |  |  | // 			],
 | 
					
						
							|  |  |  | // 		}
 | 
					
						
							|  |  |  | // 	}
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:23:28 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // XXX add .json support...
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | var data = { | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 	'Templates/EmptyPage': { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:22:00 +03:00
										 |  |  | 		text: 'Page [@include(./path)] is empty.' +'<br><br>' | 
					
						
							|  |  |  | 			+'Links to this page:' +'<br>' | 
					
						
							|  |  |  | 			+'@include(./links)' +'<br><br>' | 
					
						
							|  |  |  | 			+'---' +'<br>' | 
					
						
							|  |  |  | 			+'WikiHome', | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	'Templates/_view': { | 
					
						
							|  |  |  | 		text: '\n' | 
					
						
							|  |  |  | 			+'<div>/@include(../path) ([../_edit])</div>\n' | 
					
						
							|  |  |  | 			+'<hr>\n' | 
					
						
							|  |  |  | 			+'<h1>@include(../title)</h1>\n' | 
					
						
							|  |  |  | 			+'<br>\n' | 
					
						
							|  |  |  | 			+'<div>@include(../text)</div>\n' | 
					
						
							|  |  |  | 			+'\n', | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	'Templates/_edit': { | 
					
						
							|  |  |  | 		text: '\n' | 
					
						
							|  |  |  | 			+'<div>/@include(../path) ([../_view])</div>\n' | 
					
						
							|  |  |  | 			+'<hr>\n' | 
					
						
							|  |  |  | 			+'<h1 contenteditable>@include(../title)</h1>\n' | 
					
						
							|  |  |  | 			+'<br>\n' | 
					
						
							|  |  |  | 			+'<div class="raw" contenteditable>@include(../text)</div>\n' | 
					
						
							|  |  |  | 			+'<script>\n' | 
					
						
							|  |  |  | 			+'\t$(".raw").text($(".raw").html())\n' | 
					
						
							|  |  |  | 			+'</script>\n' | 
					
						
							|  |  |  | 			+'', | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | data.__proto__ = BaseData | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:23:28 +03:00
										 |  |  | // XXX add .json support...
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | var Wiki = { | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	__wiki_data: data, | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 	__home_page__: 'WikiHome', | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 	__default_page__: 'EmptyPage', | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 	// Special sub-paths to look in on each level...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	__acquesition_order__: [ | 
					
						
							|  |  |  | 		'Templates', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 	__post_acquesition_order__: [ | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	// XXX should this be read only???
 | 
					
						
							|  |  |  | 	__system__: 'System', | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 	//__redirect_template__: 'RedirectTemplate',
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 	__wiki_link__: RegExp('('+[ | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 		'(\\./|\\.\\./|[A-Z][a-z0-9]+[A-Z/])[a-zA-Z0-9/]*', | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 		'\\[[^\\]]+\\]', | 
					
						
							|  |  |  | 	].join('|') +')', 'g'), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 	// Resolve '.' and '..' relative to current page...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-07-10 04:30:52 +03:00
										 |  |  | 	// NOTE: '.' is relative to .path and not to .dir
 | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 	// NOTE: this is a method as it needs the context to resolve...
 | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 	resolveDotPath: function(path){ | 
					
						
							|  |  |  | 		path = normalizePath(path) | 
					
						
							|  |  |  | 		// '.' or './*'
 | 
					
						
							|  |  |  | 		return path == '.' || /^\.\//.test(path) ?  | 
					
						
							| 
									
										
										
										
											2016-07-10 04:30:52 +03:00
										 |  |  | 				//path.replace(/^\./, this.dir)
 | 
					
						
							|  |  |  | 				path.replace(/^\./, this.path) | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 			// '..' or '../*'
 | 
					
						
							|  |  |  | 			: path == '..' || /^\.\.\//.test(path) ?  | 
					
						
							| 
									
										
										
										
											2016-07-10 04:30:52 +03:00
										 |  |  | 				//path.replace(/^\.\./, 
 | 
					
						
							|  |  |  | 				//	normalizePath(path2lst(this.dir).slice(0, -1)))
 | 
					
						
							|  |  |  | 				path.replace(/^\.\./, this.dir) | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 			: path | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	// current location...
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 	get location(){ | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 		return this.__location || this.__home_page__ }, | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 	set location(value){ | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 		this.__location = this.resolveDotPath(value) }, | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	get data(){ | 
					
						
							|  |  |  | 		return this.__wiki_data[this.acquire()] }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:40:51 +03:00
										 |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	clone: function(){ | 
					
						
							|  |  |  | 		var o = Object.create(Wiki) | 
					
						
							|  |  |  | 		o.location = this.location | 
					
						
							|  |  |  | 		return o | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	// page path...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	<dir>/<title>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: changing this will move the page to the new path and change
 | 
					
						
							|  |  |  | 	// 		.location acordingly...
 | 
					
						
							|  |  |  | 	// NOTE: same applies to path parts below...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:22:00 +03:00
										 |  |  | 	// NOTE: changing path will update all the links to the moving page.
 | 
					
						
							|  |  |  | 	// NOTE: if a link can't be updated without a conflit then it is left
 | 
					
						
							|  |  |  | 	// 		unchanged, and a redirect page will be created.
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	get path(){  | 
					
						
							|  |  |  | 		return this.location }, | 
					
						
							| 
									
										
										
										
											2016-07-11 19:22:00 +03:00
										 |  |  | 	// XXX should lik updating be part of this???
 | 
					
						
							|  |  |  | 	// XXX use a template for the redirect page...
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 	set path(value){ | 
					
						
							| 
									
										
										
										
											2016-07-09 19:16:25 +03:00
										 |  |  | 		value = this.resolveDotPath(value) | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 		var l = this.location | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(value == l){ | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// old...
 | 
					
						
							|  |  |  | 		var otitle = this.title | 
					
						
							|  |  |  | 		var odir = this.dir | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		if(this.exists(l)){ | 
					
						
							|  |  |  | 			this.__wiki_data[value] = this.__wiki_data[l] | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 		this.location = value | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 		// new...
 | 
					
						
							|  |  |  | 		var ntitle = this.title | 
					
						
							|  |  |  | 		var ndir = this.dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var redirect = false | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 		// update links to this page...
 | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		this.pages(function(page){ | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 			// skip the old page...
 | 
					
						
							|  |  |  | 			if(page.location == l){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 			page.raw = page.raw.replace(page.__wiki_link__, function(lnk){ | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 				var from = lnk[0] == '[' ? lnk.slice(1, -1) : lnk | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// get path/title...
 | 
					
						
							|  |  |  | 				var p = path2lst(from) | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 				var t = p.pop() | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 				p = normalizePath(p) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 				var target = page.get(p).acquire('./'+t) | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 				// page target changed...
 | 
					
						
							|  |  |  | 				// NOTE: this can happen either when a link was an orphan
 | 
					
						
							|  |  |  | 				// 		or if the new page path shadowed the original 
 | 
					
						
							|  |  |  | 				// 		target...
 | 
					
						
							|  |  |  | 				// XXX should we report the exact condition here???
 | 
					
						
							|  |  |  | 				if(target == value){ | 
					
						
							|  |  |  | 					console.log('Link target changed:', lnk, '->', value) | 
					
						
							|  |  |  | 					return lnk | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// skip links that do not resolve to target...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 				} else if(page.get(p).acquire('./'+t) != l){ | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 					return lnk | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// format the new link...
 | 
					
						
							|  |  |  | 				var to = p == '' ? ntitle : p +'/'+ ntitle | 
					
						
							|  |  |  | 				to = lnk[0] == '[' ? '['+to+'}' : to | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// explicit link change -- replace...
 | 
					
						
							|  |  |  | 				if(from == l){ | 
					
						
							|  |  |  | 					//console.log(lnk, '->', to)
 | 
					
						
							|  |  |  | 					return to | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// path did not change -- change the title...
 | 
					
						
							|  |  |  | 				} else if(ndir == odir){ | 
					
						
							|  |  |  | 					// conflict: the new link will not resolve to the 
 | 
					
						
							|  |  |  | 					// 		target page...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 					if(page.get(p).acquire('./'+ntitle) != value){ | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 						console.log('ERR:', lnk, '->', to, | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 							'is shadowed by:', page.get(p).acquire('./'+ntitle)) | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 						// XXX should we add a note to the link???
 | 
					
						
							|  |  |  | 						redirect = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// replace title...
 | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						//console.log(lnk, '->', to)
 | 
					
						
							|  |  |  | 						return to | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// path changed -- keep link + add redirect page...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					redirect = true | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// no change...
 | 
					
						
							|  |  |  | 				return lnk | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 		// redirect...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// XXX should we use a template here???
 | 
					
						
							|  |  |  | 		// 		...might be a good idea to set a .redirect attr and either
 | 
					
						
							|  |  |  | 		// 		do an internal/transparent redirect or show a redirect 
 | 
					
						
							|  |  |  | 		// 		template
 | 
					
						
							|  |  |  | 		// 		...might also be good to add an option to fix the link from
 | 
					
						
							|  |  |  | 		// 		the redirect page...
 | 
					
						
							|  |  |  | 		if(redirect){ | 
					
						
							|  |  |  | 			console.log('CREATING REDIRECT PAGE:', l, '->', value, '') | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 			this.__wiki_data[l].raw = 'REDIRECT TO: ' + value | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 				+'<br>' | 
					
						
							|  |  |  | 				+'<br><i>NOTE: This page was created when renaming the target ' | 
					
						
							|  |  |  | 					+'page that resulted new link being broken (i.e. resolved ' | 
					
						
							|  |  |  | 					+'to a different page from the target)</i>' | 
					
						
							|  |  |  | 			this.__wiki_data[l].redirect = value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		// cleaup...
 | 
					
						
							| 
									
										
										
										
											2016-07-09 06:26:16 +03:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			delete this.__wiki_data[l] | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	// path parts: directory...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: see .path for details...
 | 
					
						
							|  |  |  | 	get dir(){ | 
					
						
							|  |  |  | 		return path2lst(this.location).slice(0, -1).join('/') }, | 
					
						
							|  |  |  | 	set dir(value){ | 
					
						
							|  |  |  | 		this.path = value +'/'+ this.title }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// path parts: title...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: see .path for details...
 | 
					
						
							|  |  |  | 	get title(){  | 
					
						
							|  |  |  | 		return path2lst(this.location).pop() }, | 
					
						
							|  |  |  | 	set title(value){ | 
					
						
							|  |  |  | 		this.path = this.dir +'/'+ value }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// page content...
 | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 	get raw(){ | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		var data = this.data | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 		return data instanceof Function ? data.call(this, this) | 
					
						
							|  |  |  | 			: typeof(data) == typeof('str') ? data | 
					
						
							|  |  |  | 			: data != null ? data.text | 
					
						
							|  |  |  | 			: '' | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 	set raw(value){ | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 		var l = this.location | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// prevent overwriting actions...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		if(this.data instanceof Function){ | 
					
						
							| 
									
										
										
										
											2016-07-09 21:40:48 +03:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 		this.__wiki_data[l] = this.__wiki_data[l] || {} | 
					
						
							|  |  |  | 		this.__wiki_data[l].text = value | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// cache links...
 | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		delete this.__wiki_data[l].links | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 		this.__wiki_data[l].links = this.links | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-20 02:32:17 +03:00
										 |  |  | 	get text(){ return macro.parse(this, this.raw) }, | 
					
						
							| 
									
										
										
										
											2016-07-19 23:13:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 	// NOTE: this is set by setting .text
 | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	get links(){ | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		var data = this.data || {} | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		var links = data.links = data.links | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 			|| (this.raw.match(this.__wiki_link__) || []) | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 				// unwrap explicit links...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				.map(function(e){ return e[0] == '[' ? e.slice(1, -1) : e }) | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 				// unique...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 				.filter(function(e, i, l){ return l.slice(0, i).indexOf(e) == -1 }) | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 		return links | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	// navigation...
 | 
					
						
							|  |  |  | 	get parent(){ | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 		return this.get('..') }, | 
					
						
							| 
									
										
										
										
											2016-07-19 03:10:16 +03:00
										 |  |  | 	// XXX list children/sub-pages...
 | 
					
						
							|  |  |  | 	get children(){ | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:40:51 +03:00
										 |  |  | 	// XXX add prpper insyantiation ( .clone() )...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 	get: function(path){ | 
					
						
							| 
									
										
										
										
											2016-07-19 02:40:51 +03:00
										 |  |  | 		//var o = Object.create(this)
 | 
					
						
							|  |  |  | 		var o = this.clone()  | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		o.location = path || this.path | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 		return o | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 	exists: function(path){ | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 		return normalizePath(path || this.path) in this.__wiki_data }, | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 	// get title from dir and then go up the tree...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:23:28 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should we also acquire each path part???
 | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 	acquire: function(path, no_default){ | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2016-07-11 18:41:23 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// handle paths and relative paths...
 | 
					
						
							|  |  |  | 		var p = this.get(path) | 
					
						
							|  |  |  | 		var title = p.title | 
					
						
							|  |  |  | 		path = path2lst(p.dir) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		var acquire_from = this.__acquesition_order__ || [] | 
					
						
							|  |  |  | 		var post_acquire_from = this.__post_acquesition_order__ || [] | 
					
						
							|  |  |  | 		var data = this.__wiki_data | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		var _get = function(path, title, lst){ | 
					
						
							|  |  |  | 			lst = (lst == null || lst.length == 0) ? [''] : lst | 
					
						
							|  |  |  | 			for(var i=0; i < lst.length; i++){ | 
					
						
							|  |  |  | 				var p = path.concat([lst[i], title]) | 
					
						
							|  |  |  | 				if(that.exists(p)){ | 
					
						
							|  |  |  | 					p = normalizePath(p) | 
					
						
							|  |  |  | 					return that.__wiki_data[p] && p | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		while(true){ | 
					
						
							|  |  |  | 			// get title from path...
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 			var p = _get(path, title) | 
					
						
							|  |  |  | 				// get title from special paths in path...
 | 
					
						
							|  |  |  | 				|| _get(path, title, acquire_from) | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 			if(p != null){ | 
					
						
							|  |  |  | 				return p | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(path.length == 0){ | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 				break | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			path.pop() | 
					
						
							| 
									
										
										
										
											2016-07-04 20:42:46 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-07-11 04:32:56 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		// default paths...
 | 
					
						
							|  |  |  | 		var p = _get(path, title, post_acquire_from) | 
					
						
							|  |  |  | 			// system path...
 | 
					
						
							|  |  |  | 			|| this.__system__  | 
					
						
							|  |  |  | 				&& _get([this.__system__], title) | 
					
						
							| 
									
										
										
										
											2016-07-07 22:21:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 17:57:28 +03:00
										 |  |  | 		// NOTE: this may be null...
 | 
					
						
							|  |  |  | 		return p  | 
					
						
							| 
									
										
										
										
											2016-07-11 19:22:00 +03:00
										 |  |  | 			|| ((!no_default && title != this.__default_page__) ?  | 
					
						
							|  |  |  | 				this.acquire('./'+this.__default_page__)  | 
					
						
							|  |  |  | 				: null) | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// serialization...
 | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 	// XXX
 | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 	json: function(path){ | 
					
						
							|  |  |  | 		return path == null ? JSON.parse(JSON.stringify(this.__wiki_data)) | 
					
						
							|  |  |  | 			: path == '.' ? { | 
					
						
							|  |  |  | 					path: this.location, | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 					text: this.raw, | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			: { | 
					
						
							|  |  |  | 				path: path, | 
					
						
							| 
									
										
										
										
											2016-07-12 03:22:06 +03:00
										 |  |  | 				text: (this.__wiki_data[path] || {}).raw, | 
					
						
							| 
									
										
										
										
											2016-07-05 16:58:04 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// XXX should we inherit from the default???
 | 
					
						
							|  |  |  | 	load: function(json){ | 
					
						
							|  |  |  | 		this.__wiki_data = json | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// iteration...
 | 
					
						
							|  |  |  | 	// XXX this is not page specific, might need refactoring...
 | 
					
						
							|  |  |  | 	pages: function(callback){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		Object.keys(this.__wiki_data).forEach(function(location){ | 
					
						
							|  |  |  | 			// XXX not sure if this is the right way to go...
 | 
					
						
							| 
									
										
										
										
											2016-07-19 02:40:51 +03:00
										 |  |  | 			//var o = Object.create(that)
 | 
					
						
							|  |  |  | 			var o = that.clone()  | 
					
						
							| 
									
										
										
										
											2016-07-08 01:40:59 +03:00
										 |  |  | 			o.location = location | 
					
						
							|  |  |  | 			callback.call(o, o) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return this | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-13 05:06:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-04 19:51:37 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ |