PageSourceSearch

https://www.railfuturescotland.org.uk/lib/tiki-js.js

js railfuturescotland.org.uk collected 2026-10-02 14:26:05 UTC 58,422 bytes, 1,969 lines download raw bytes

1//$Id: tiki-js.js 42057 2012-06-23 18:36:05Z jonnybradley $
2
3var feature_no_cookie = 'n';
4
5// simple translation function for tiki 6
6function tr(str) {
7	if (typeof lang[str] == 'string') {
8		return lang[str];
9	} else {
10		return str;
11	}
12}
13
14var lang = {};	// object to hold JS string translations
15				// default strings empty, override in lang/xx/language.js
16				// which will be included automatically
17
18// end translation
19
20function browser() {
21	var b = navigator.appName;
22	if (b == "Netscape") { this.b = "ns"; }
23	else { this.b = b; }
24	this.version = navigator.appVersion;
25	this.v = parseInt(this.version, 10);
26	this.ns = (this.b=="ns" && this.v>=5);
27	this.op = (navigator.userAgent.indexOf('Opera')>-1);
28	this.safari = (navigator.userAgent.indexOf('Safari')>-1);
29	this.op7 = (navigator.userAgent.indexOf('Opera')>-1 && this.v>=7);
30	this.ie56 = (this.version.indexOf('MSIE 5')>-1||this.version.indexOf('MSIE 6')>-1);
31	/* ie567 added by Enmore */
32	this.ie567 = (this.version.indexOf('MSIE 5')>-1||this.version.indexOf('MSIE 6')>-1||this.version.indexOf('MSIE 7')>-1);
33	this.iewin = (this.ie56 && navigator.userAgent.indexOf('Windows')>-1);
34	/* iewin7 added by Enmore */	
35	this.iewin7 = (this.ie567 && navigator.userAgent.indexOf('Windows')>-1);
36	this.iemac = (this.ie56 && navigator.userAgent.indexOf('Mac')>-1);
37	this.moz = (navigator.userAgent.indexOf('Mozilla')>-1);
38	this.moz13 = (navigator.userAgent.indexOf('Mozilla')>-1 && navigator.userAgent.indexOf('1.3')>-1);
39	this.oldmoz = (navigator.userAgent.indexOf('Mozilla')>-1 && navigator.userAgent.indexOf('1.4')>-1 || navigator.userAgent.indexOf('Mozilla')>-1 && navigator.userAgent.indexOf('1.5')>-1 || navigator.userAgent.indexOf('Mozilla')>-1 && navigator.userAgent.indexOf('1.6')>-1);
40	this.ns6 = (navigator.userAgent.indexOf('Netscape6')>-1);
41	this.docom = (this.ie56||this.ns||this.iewin||this.op||this.iemac||this.safari||this.moz||this.oldmoz||this.ns6);
42}
43
44/* toggle CSS (tableless) layout columns */
45function toggleCols(id,zeromargin,maincol) {
46	var showit = 'show_' + escape(id);
47	if (!zeromargin) { zeromargin = ''; }
48	if (!id) { id = ''; }
49	if (!maincol) { maincol = 'col1'; }
50	var $id = $('#' + id), $maincol = $('#' + maincol);
51	if (! $id.is(':visible')) {
52		showCol(id, zeromargin, maincol);
53		setSessionVar(showit,'y');
54	} else {
55		hideCol(id, zeromargin, maincol);
56		setSessionVar(showit,'n');
57	}
58}
59
60function showCol(id, zeromargin, maincol) {
61	var $id = $('#' + id), $maincol = $('#' + maincol);
62
63	$id.show();
64	if (zeromargin == 'left') {
65		$maincol.css('margin-left', '');
66		if (! $maincol.css('margin-left')) {
67			$maincol.css('margin-left', $id.width());
68		}
69	} else {
70		$maincol.css('margin-right', '');
71		if (! $maincol.css('margin-right')) {
72			$maincol.css('margin-right', $id.width());
73		}
74	}
75}
76
77function hideCol(id, zeromargin, maincol) {
78	var $id = $('#' + id), $maincol = $('#' + maincol);
79
80	$id.hide();
81	if (zeromargin == 'left') {
82		$maincol.css('margin-left', 0);
83	} else {
84		$maincol.css('margin-right', 0);
85	}
86}
87
88function toggle_dynamic_var(name) {
89	var name1 = 'dyn_'+name+'_display';
90	var name2 = 'dyn_'+name+'_edit';
91	if (document.getElementById(name1).style.display == "none") {
92		document.getElementById(name2).style.display = "none";
93		document.getElementById(name1).style.display = "inline";
94	} else {
95		document.getElementById(name1).style.display = "none";
96		document.getElementById(name2).style.display = "inline";
97
98	}
99
100}
101
102function chgArtType() {
103	var articleType = document.getElementById('articletype').value;
104	var typeProperties = articleTypes[articleType];
105
106	var propertyList = ['show_topline','y',
107	                    'show_subtitle','y',
108	                    'show_linkto','y',
109	                    'show_author','y',
110	                    'use_ratings','y',
111	                    'heading_only','n',
112	                    'show_image_caption','y',
113	                    'show_pre_publ','y',
114	                    'show_post_expire','y',
115	                    'show_image','y',
116	                    'show_expdate','y'
117	                    ];
118	if (typeof articleCustomAttributes != 'undefined') {
119		propertyList = propertyList.concat(articleCustomAttributes);
120	}
121	var l = propertyList.length, property, value, display;
122	for (var i=0; i<l; i++) {
123		property = propertyList[i++];
124		value = propertyList[i];
125
126		if (typeProperties[property] == value || (!typeProperties[property] && value == "n")) {
127			display = "";
128		} else {
129			display = "none";
130		}
131
132		if (document.getElementById(property)) {
133			document.getElementById(property).style.display = display;
134		} else {
135			var j = 1;
136			while (document.getElementById(property+'_'+j)) {
137				document.getElementById(property+'_'+j).style.display = display;
138				j++;
139			}
140		}
141	}
142}
143
144function chgMailinType() {
145	if (document.getElementById('mailin_type').value != 'article-put') {
146		document.getElementById('article_topic').style.display = "none";
147		document.getElementById('article_type').style.display = "none";
148	} else {
149		document.getElementById('article_topic').style.display = "";
150		document.getElementById('article_type').style.display = "";
151	}
152}
153
154function toggleSpan(id) {
155	if (document.getElementById(id).style.display == "inline") {
156		document.getElementById(id).style.display = "none";
157	} else {
158		document.getElementById(id).style.display = "inline";
159	}
160}
161
162function toggleBlock(id) {
163	if (document.getElementById(id).style.display == "none") {
164		document.getElementById(id).style.display = "block";
165	} else {
166		document.getElementById(id).style.display = "none";
167	}
168}
169
170function toggleTrTd(id) {
171	if (document.getElementById(id).style.display == "none") {
172		document.getElementById(id).style.display = "";
173	} else {
174		document.getElementById(id).style.display = "none";
175	}
176}
177
178function changeText(el, newText) {
179	// Safari work around
180	if (el.innerText) {
181		el.innerText = newText;
182	} else if (el.firstChild && el.firstChild.nodeValue) {
183		el.firstChild.nodeValue = newText;
184	}
185}
186
187function toggleToc() {
188	var toc = document.getElementById('toc').getElementsByTagName('ul')[0];
189
190	if (toc && toc.style.display == 'none') {
191		toc.style.display = 'block';
192	} else {
193		toc.style.display = 'none';
194	}
195}
196
197function chgTrkFld(f,o) {
198	var opt = 0;
199	document.getElementById('z').style.display = "none";
200	document.getElementById('zDescription').style.display = "";
201	document.getElementById('zStaticText').style.display = "none";
202	document.getElementById('zStaticTextToolbars').style.display = "none";
203
204	for (var i = 0; i < f.length; i++) {
205		var c = f.charAt(i);
206		if (document.getElementById(c)) {
207			var ichoiceParent = document.getElementById('itemChoicesRow');
208			var ichoice = document.getElementById(c + 'itemChoices');
209			if (c == o) {
210				document.getElementById(c).style.display = "";
211				document.getElementById('z').style.display = "block";
212				if (c == 'S') {
213					document.getElementById('zDescription').style.display = "none";
214					document.getElementById('zStaticText').style.display = "";
215					document.getElementById('zStaticTextToolbars').style.display = "";
216				}
217				if (ichoice) {
218					ichoice.style.display = "";
219					ichoiceParent.style.display = "";
220				} else {
221					ichoiceParent.style.display = "none";
222				}
223			} else {
224				document.getElementById(c).style.display = "none";
225				if (ichoice) {
226					ichoice.style.display = "none";
227				}
228			}
229		}
230	}
231}
232
233function chgTrkLingual(item) {
234	document.getElementById("multilabelRow").style.display = ( item == 't' || item == 'a' ) ? '' : 'none';
235}
236
237function multitoggle(f,o) {
238	for (var i = 0; i < f.length; i++) {
239		if (document.getElementById('fid'+f[i])) {
240			if (f[i] == o) {
241				document.getElementById('fid'+f[i]).style.display = "block";
242			} else {
243				document.getElementById('fid'+f[i]).style.display = "none";
244			}
245		}
246	}
247}
248
249function setMenuCon(foo) {
250	var it = foo.split(",");
251	document.getElementById('menu_url').value = it[0];
252	document.getElementById('menu_name').value = it[1];
253	if (it[2]) {
254		document.getElementById('menu_section').value = it[2];
255	} else {
256		document.getElementById('menu_section').value = '';
257	}
258	if (it[3]) {
259		document.getElementById('menu_perm').value = it[3];
260	} else {
261		document.getElementById('menu_perm').value = '';
262	}
263}
264
265function genPass(w1) {
266	var vo = "aeiouAEU", co, s, l, p, i, letter;
267
268	co = "bcdfgjklmnprstvwxzBCDFGHJKMNPQRSTVWXYZ0123456789_$%#";
269	s = Math.round(Math.random());
270	l = 8;
271	p = '';
272
273	for (i = 0; i < l; i++) {
274		if (s) {
275			letter = vo.charAt(Math.round(Math.random() * (vo.length - 1)));
276
277			s = 0;
278		} else {
279			letter = co.charAt(Math.round(Math.random() * (co.length - 1)));
280
281			s = 1;
282		}
283
284		p = p + letter;
285	}
286
287	document.getElementById(w1).value = p;
288}
289
290function setUserModule(foo1) {
291	document.getElementById('usermoduledata').value = foo1;
292}
293
294function replaceLimon(vec) {
295	document.getElementById(vec[0]).value = document.getElementById(vec[0]).value.replace(vec[1], vec[2]);
296}
297
298function setSelectionRange(textarea, selectionStart, selectionEnd) {
299	var $textareaEditor = syntaxHighlighter.get($(textarea));
300	if ($textareaEditor) {
301		syntaxHighlighter.setSelection($textareaEditor, selectionStart, selectionEnd);
302		return;
303	}
304
305	$(textarea).selection(selectionStart, selectionEnd);
306}
307
308function getTASelection( textarea ) {
309	var $textareaEditor = syntaxHighlighter.get($(textarea));
310	if ($textareaEditor) {
311		return $textareaEditor.getSelection();
312	}
313	
314	var ta_id = $(textarea).attr("id"), r, cked, output;
315	if ($('#cke_contents_' + ta_id).length !== 0) {
316		// get selection from ckeditor
317		cked = typeof CKEDITOR !== 'undefined' ? CKEDITOR.instances[ta_id] : null;
318		if (cked) {
319			var sel = cked.getSelection();
320			if (sel && sel.getType() === CKEDITOR.SELECTION_TEXT) {	// why so fiddly?
321				if (CKEDITOR.env.ie) {
322					output = sel.document.$.selection.createRange().text;
323				} else {
324					output = sel.getNative().toString();
325				}
326				return output;
327			}
328		}
329	} else {
330		if (typeof $(textarea).attr("selectionStartSaved") != 'undefined' && $(textarea).attr("selectionStartSaved")) { // forgetful firefox/IE now
331			return textarea.value.substring($(textarea).attr("selectionStartSaved"), $(textarea).attr("selectionEndSaved"));
332		} else if (typeof textarea.selectionStart != 'undefined') {
333			return textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
334		} else { // IE
335			r = document.selection.createRange();
336			return r.text;
337		}
338	}
339}
340
341var ieFirstTimeInsertKludge = null;
342
343function storeTASelection( area_id ) {
344	if ($('#cke_contents_' + area_id).length === 0) {
345		var $el = $("#" + area_id);
346		var sel = $el.selection();
347		$el.attr("selectionStartSaved", sel.start)
348				.attr("selectionEndSaved", sel.end)
349				.attr("scrollTopSaved", $el.attr("scrollTop"));
350	}
351	if (ieFirstTimeInsertKludge === null) {
352		ieFirstTimeInsertKludge = true;
353	}
354}
355
356function setCaretToPos (textarea, pos) {
357	setSelectionRange(textarea, pos, pos);
358}
359
360function getCaretPos (textarea) {
361	var $textareaEditor = syntaxHighlighter.get($(textarea));
362	if ($textareaEditor) {
363		var endPoint = $textareaEditor.cursorCoords();
364		return (endPoint.x ? endPoint.x : 0);
365	}
366	
367	if (typeof textarea.selectionEnd != 'undefined') {
368		return textarea.selectionEnd;
369	} else if ( document.selection ) {
370
371		textarea.focus();
372		var range = document.selection.createRange();
373		if (range === null) {
374			return 0;
375		}
376		var re = textarea.createTextRange();
377		var rc = re.duplicate();
378		re.moveToBookmark(range.getBookmark());
379		rc.setEndPoint('EndToStart', re);
380		return rc.text.length ? rc.text.length : 0;
381
382	} else {
383		return 0;
384	}
385}
386
387function insertAt(elementId, replaceString, blockLevel, perLine, replaceSelection) {
388	
389	// inserts given text at selection or cursor position
390	var $textarea = $('#' + elementId);
391	var $textareaEditor = syntaxHighlighter.get($textarea);
392	var toBeReplaced = /text|page|area_id/g; //substrings in replaceString to be replaced by the selection if a selection was done
393	var hiddenParents = $textarea.parents('fieldset:hidden:last');
394	if (hiddenParents.length) { hiddenParents.show(); }
395	
396	if ($textareaEditor) {
397	 	syntaxHighlighter.insertAt($textareaEditor, replaceString, perLine, blockLevel, replaceSelection);
398		return;
399	 // get ckeditor handling out of the way - can only be simple text insert for now
400	} else if ($('#cke_contents_' + elementId).length !== 0) {
401		// get selection from ckeditor
402		var cked = typeof CKEDITOR !== 'undefined' ? CKEDITOR.instances[elementId] : null;
403		if (cked) {
404			var isPlugin = replaceString.match(/^\s?\{/m);		// do match in two halves due to multiline problems
405			if (isPlugin) {
406				isPlugin = replaceString.match(/\}\s?$/m);		// not so simple {plugin} match
407			}
408			isPlugin = isPlugin && isPlugin.length > 0;
409
410			var sel = cked.getSelection(), rng;
411			if (sel) { // not from IE sometimes?
412				rng = sel.getRanges();
413				if (rng.length) {
414					rng = rng[0];
415				}
416			}
417			var plugin_el;
418			if (isPlugin && rng && !rng.collapsed) {
419				var com = cked.getSelection().getStartElement();
420				if (typeof com !== 'undefined' && com && com.$) {
421					while (!$(com.$).hasClass("tiki_plugin") && com.$.nextSibling && com.$ !== rng.endContainer.$) {	// loop through selection if multiple elements
422						com = new CKEDITOR.dom.element(com.$.nextSibling);
423						if ($(com.$).hasClass("tiki_plugin") || $(com.$).find(".tiki_plugin").length === 0) {	// found it or parent (hmm)
424							break;
425						}
426					}
427					if (!$(com.$).hasClass("tiki_plugin")) { // not found it yet?
428						plugin_el = $(com.$).find(".tiki_plugin"); // using jQuery
429						if (plugin_el.length == 1) { // found descendant plugin
430							com = new CKEDITOR.dom.element(plugin_el[0]);
431						} else {
432							plugin_el = $(com.$).parents(".tiki_plugin"); // try parents
433							if (plugin_el.length == 1) { // found p plugin
434								com = new CKEDITOR.dom.element(plugin_el[0]);
435							} else { // still not found it? sometimes Fx seems to get the editor body as the selection...
436								var plugin_type = replaceString.match(/^\s?\{([\w]+)/);
437								if (plugin_type.length > 1) { plugin_type = plugin_type[1].toLowerCase(); }
438								
439								plugin_el = $(com.$).find("[plugin=" + plugin_type + "].tiki_plugin"); // find all of them
440								if (plugin_el.length == 1) { // good guess!
441									com = new CKEDITOR.dom.element(plugin_el[0]);
442								} else {
443									// Does not seem to be a problem at least with the image plugin, commenting out for release but keeping it here in case problem reappears
444									//if (!confirm(tr("Development notice: Could not find plugin being edited, sorry. Choose cancel to debug."))) {
445									//	debugger;
446									//}
447								}
448							}
449						}
450					}
451				}
452				if ($(com.$).hasClass("tiki_plugin")) {
453					$(com.$).replaceWith($("<pre class='tiki_plugin'>" + replaceString + "</pre>"));
454					cked.reParse();
455					return;
456				}
457			}
458			//if (sel.getType() === CKEDITOR.SELECTION_TEXT) {
459				// fall through to insertText as if all else failed
460			//}
461		}
462		// catch all other issues and do the insert wherever ckeditor thinks best,
463		// sadly as the first element sometimes FIXME
464		cked.insertText( replaceString );
465		if (typeof cked.reParse === "function" && (isPlugin || replaceString.match(/^\s?\(\(.*?\)\)\s?$/))) {	// also ((wiki links))
466			cked.reParse();
467		}
468		return;
469	}
470	
471	if (!$textarea.length && elementId === "fgal_picker") {	// ckeditor file browser
472		$(".cke_dialog_contents").find("input:first").val(replaceString.replace("&amp;", "&"));
473		return;
474	} else if ($textarea.is(":input") && elementId === "fgal_picker_id") {
475		$textarea.val(replaceString);
476		return;
477	}
478
479	$textarea.focus();
480	
481	var val = $textarea.val();
482	var selection = $textarea.selection();
483	var scrollTop=$textarea[0].scrollTop;
484	
485	if (selection.start === 0 && selection.end === 0 &&
486					typeof $textarea.attr("selectionStartSaved") != 'undefined') {	// get saved textarea selection
487		if ($textarea.attr("selectionStartSaved")) {	// forgetful firefox/IE
488			selection.start = $textarea.attr("selectionStartSaved");
489			selection.end = $textarea.attr("selectionEndSaved");
490			if ($textarea.attr("scrollTopSaved")) {
491				scrollTop = $textarea.attr("scrollTopSaved");
492				$textarea.attr("scrollTopSaved", "");
493			}
494			$textarea.attr("selectionStartSaved", "").attr("selectionEndSaved", "");
495		} else {
496			selection.start = getCaretPos($textarea[0]);
497			selection.end = selection.start;
498		}
499	}
500
501	// deal with IE's two char line ends
502	var lines, startoff = 0, endoff = 0;
503	if ($textarea[0].createTextRange && $textarea[0].value !== val) {
504		val = $textarea[0].value;	// use raw value of the textarea
505		if (val.substring(selection.start, selection.start + 1) === "\n") {
506			selection.start++;
507		}
508		lines = val.substring(0, selection.start).match(/\r\n/g);
509		if (lines) {
510			startoff -= lines.length;	// remove one char per line for IE
511		}
512	}
513	var selectionStart = selection.start;
514	var selectionEnd = selection.end;
515
516	if ( blockLevel ) {
517		// Block level operations apply to entire lines
518
519		// +1 and -1 to handle end of line caret position correctly
520		selectionStart = val.lastIndexOf( "\n", selectionStart - 1 ) + 1;
521		var blockEnd = val.indexOf( "\r", selectionEnd ); // check for IE first
522		if (blockEnd < 0) {
523			selectionEnd = val.indexOf( "\n", selectionEnd );
524		} else {
525			selectionEnd = blockEnd;
526		}
527		if (selectionEnd < 0) {
528			selectionEnd = val.length;
529		}
530	}
531
532	var newString = '';
533	if ((selectionStart != selectionEnd) && !$textareaEditor) { // has there been a selection
534		if ( perLine ) {
535			lines = val.substring(selectionStart, selectionEnd).split("\n");
536			for( var k = 0; lines.length > k; ++k ) {
537				if ( lines[k].length !== 0 ) {
538					newString += replaceString.replace(toBeReplaced, lines[k]);
539				}
540				if ( k != lines.length - 1 ) {
541					newString += "\n";
542				}
543			}
544		} else {
545			if (replaceSelection) {
546				newString = replaceString;
547			} else if (replaceString.match(toBeReplaced)) {
548				newString = replaceString.replace(toBeReplaced, val.substring(selectionStart, selectionEnd));
549			} else {
550				newString = replaceString + '\n' + val.substring(selectionStart, selectionEnd);
551			}
552		}
553		
554		$textarea.val(val.substring(0, selectionStart)
555						+ newString
556						+ val.substring(selectionEnd)
557					);
558		lines = newString.match(/\r\n/g);
559		if (lines) {
560			endoff   -= lines.length;	// lines within the replacement for IE
561		}
562		setSelectionRange($textarea[0], selectionStart + startoff, selectionStart + startoff + newString.length + endoff);
563		
564	} else { // insert at caret
565		$textarea.val(val.substring(0, selectionStart)
566						+ replaceString
567						+ val.substring(selectionEnd)
568					);
569		lines = replaceString.match(/\r\n/g);
570		if (lines) {
571			endoff   -= lines.length;	// lines within the replacement for IE
572		}
573		setCaretToPos($textarea[0], selectionStart + startoff + replaceString.length + endoff);
574
575	}
576	$textarea.attr("scrollTop", scrollTop);
577	if ($.browser.msie && ieFirstTimeInsertKludge) {
578		setTimeout(function(){		// not only does IE reset the scrollTop and selection the first time a dialog is used
579			if (newString.length) {	// but somehow all the ints have been converted into strings...
580				setSelectionRange($textarea[0], parseInt(selectionStart,10) + parseInt(startoff,10),
581						parseInt(selectionStart,10) + parseInt(startoff,10) + newString.length + parseInt(endoff,10));
582			}
583			$textarea.attr("scrollTop", scrollTop);
584		}, 1000);
585		ieFirstTimeInsertKludge = false;
586	}
587
588	if (hiddenParents.length) { hiddenParents.hide(); }
589	if (typeof auto_save_id != "undefined" && auto_save_id.length > 0 && typeof auto_save == 'function') {
590		auto_save( elementId, auto_save_id[0]);
591	}
592}
593
594function setUserModuleFromCombo(id, textarea) {
595	document.getElementById(textarea).value = document.getElementById(textarea).value
596				+ document.getElementById(id).options[document.getElementById(id).selectedIndex].value;
597}
598
599
600function toggle(foo) {
601	var display = $("#"+foo).css('display');
602	if (display == "none") {
603		show(foo, true, "menu");
604	} else {
605		if (display == "block") {
606			hide(foo, true, "menu");
607		} else {
608			show(foo, true, "menu");
609		}
610	}
611}
612
613function flip_thumbnail_status(id) {
614	var elem = document.getElementById(id);
615	if ( elem.className == 'thumbnailcontener' ) {
616		elem.className += ' thumbnailcontenerchecked';
617	} else {
618		elem.className = 'thumbnailcontener';
619	}
620}
621
622function flip_class(itemid, class1, class2) {
623	var elem = document.getElementById(itemid);
624	if (elem && typeof elem != 'undefined') {
625		elem.className = elem.className == class1 ? class2 : class1;
626		setCookie('flip_class_' + itemid, elem.className);
627	}
628}
629
630function tikitabs( focus, tabElement) {
631	var container;
632	if (typeof tabElement === "undefined") {
633		container = $(".tabset:first");
634	} else {
635		container = $(tabElement).parents(".tabset:first");
636	}
637
638	if (focus > $("> .tabs .tabmark", container).length) {
639		focus = 1;	// limit to number of tabs - somehow getting set to 222 sometimes
640	}
641
642	$("> .tabs .tabmark:not(.tab" + focus + ":first)", container).removeClass("tabactive");		// may need .addClass("tabinactive");
643	$("> .tabs .tabmark.tab" + focus + ":first", container).addClass("tabactive");				// and .removeClass("tabinactive");
644	$("> .tabcontent:not(.content" + focus + ":first)", container).hide();
645	$("> .tabcontent.content" + focus + ":first", container).show();
646	setCookie( $(".tabs:first", container).data("name"), focus, "tabs", "session");
647
648}
649
650/* foo: name of the menu
651 * def: menu type (e:extended, c:collapsed, f:fixed)
652 * the menu is collapsed function of its cookie: if no cookie is set, the def is used
653 */
654function setfolderstate(foo, def, img, status) {
655	if (!status) {
656		status = getCookie(foo, "menu", "o");
657	}
658	if (!img) {
659		if (document.getElementsByName('icn' + foo)[0].src.search(/[\\\/]/)) {
660			img = document.getElementsByName('icn' + foo)[0].src.replace(/.*[\\\/]([^\\\/]*)$/, "$1");
661		} else {
662			img = 'folder.png';
663		}
664	}
665	var src = img; // default
666	if (status == 'c') {
667		hide(foo, false, "menu");
668	} else {
669		show(foo, false, "menu");
670	}
671	if (status == 'c' && def != 'd') { /* need to change the open icon to a close one*/
672		src = src.replace(/^o/, '');
673	} else if (status != 'c' && def == 'd' && src.indexOf('o') !== 0) { /* need to change the close icon to an open one */
674		src = 'o' + img;
675	}
676	document.getElementsByName('icn' + foo)[0].src = document.getElementsByName('icn' + foo)[0].src.replace(/[^\\\/]*$/, src);
677}
678
679function setheadingstate(foo) {
680	var status = getCookie(foo, "showhide_headings");
681	if (status == "o") {
682		show(foo);
683		collapseSign("flipper" + foo);
684	} else /* if (status == "c") */ {
685		if (!document.getElementById(foo).style.display == "none") {
686			hide(foo);
687			expandSign("flipper" + foo);
688		}
689	}
690}
691
692function setsectionstate(foo, def, img, status) {
693	var src;
694	if (!status) {
695		status = getCookie(foo, "menu", "o");
696	}
697	if (status == "o") {
698		show(foo);
699		if (img) { src = "o" + img; }
700	} else if (status != "c" && def != 'd') {
701		show(foo);
702		if (img) { src = "o" + img; }
703	} else /* if (status == "c") */ {
704		hide(foo);
705		if (img) { src = img; }
706	}
707	if (img && document.getElementsByName('icn' + foo).length) {
708		document.getElementsByName('icn' + foo)[0].src = document.getElementsByName('icn' + foo)[0].src.replace(/[^\\\/]*$/, src);
709	}
710}
711
712function icntoggle(foo, img) {
713	if (!img) {
714		if ($("#icn" + foo).attr("src").search(/[\\\/]/)) {
715			img = $("#icn" + foo).attr("src").replace(/.*[\\\/]([^\\\/]*)$/, "$1");
716		} else {
717			img = 'folder.png';
718		}
719	}
720	if ($("#" + foo + ":hidden").length) {
721		show(foo, true, "menu");
722		$("#icn" + foo).attr("src", $("#icn" + foo).attr("src").replace(/[^\\\/]*$/, 'o' + img));
723
724	} else {
725		hide(foo, true, "menu");
726		img = img.replace(/(^|\/|\\)o(.*)$/, '$1$2');
727		$("#icn" + foo).attr("src", $("#icn" + foo).attr("src").replace(/[^\\\/]*$/, img));
728	}
729}
730
731//Initialize a cross-browser XMLHttpRequest object.
732//The object return has to be sent using send(). More parameters can be
733//given.
734//callback - The function that will be called when the response arrives
735//First parameter will be the status
736//(HTTP Response Code [200,403, 404, ...])
737//method - GET or POST
738//url - The URL to open
739function getHttpRequest( method, url, async )
740{
741	if ( async === undefined ) {
742		async = false;
743	}
744	var request;
745
746	if ( window.XMLHttpRequest ) {
747		request = new XMLHttpRequest();
748	} else if ( window.ActiveXObject )
749	{
750		try
751		{
752			request = new ActiveXObject( "Microsoft.XMLHTTP" );
753		}
754		catch( ex )
755		{
756			request = new ActiveXObject("MSXML2.XMLHTTP");
757		}
758	}
759	else {
760		return false;
761	}
762	if ( !request ) {
763		return false;
764	}
765	request.open( method, url, async );
766
767	return request;
768}
769
770//name - name of the cookie
771//value - value of the cookie
772// [expires] - expiration date of the cookie (defaults to end of current session)
773// [path] - path for which the cookie is valid (defaults to path of calling document)
774// [domain] - domain for which the cookie is valid (defaults to domain of calling document)
775// [secure] - Boolean value indicating if the cookie transmission requires a secure transmission
776//* an argument defaults when it is assigned null as a placeholder
777//* a null placeholder is not required for trailing omitted arguments
778function setSessionVar(name,value) {
779	var request = getHttpRequest( "GET", "tiki-cookie-jar.php?" + name + "=" + escape(value));
780	request.send('');
781	tiki_cookie_jar[name] = value;
782}
783
784function setCookie(name, value, section, expires, path, domain, secure) {
785	if (getCookie(name, section) == value) {
786		return true;
787	}
788	if (!expires) {
789		expires = new Date();
790		expires.setFullYear(expires.getFullYear() + 1);
791	}
792	if (expires === "session") {
793		expires = "";
794	}
795	if (feature_no_cookie == 'y') {
796		var request = getHttpRequest( "GET", "tiki-cookie-jar.php?" + name + "=" + escape( value ) );
797		try {
798			request.send('');
799			// alert("XMLHTTP/set"+request.readyState+request.responseText);
800			tiki_cookie_jar[name] = value;
801			return true;
802		}
803		catch( ex )	{
804			setCookieBrowser(name, value, section, expires, path, domain, secure);
805			return false;
806		}
807	}
808	else {
809		setCookieBrowser(name, value, section, expires, path, domain, secure);
810		return true;
811	}
812}
813function setCookieBrowser(name, value, section, expires, path, domain, secure) {
814	if (section) {
815		var valSection = getCookie(section);
816		var name2 = "@" + name + ":";
817		if (valSection) {
818			if (new RegExp(name2).test(valSection)) {
819				valSection  = valSection.replace(new RegExp(name2 + "[^@;]*"), name2 + value);
820			} else {
821				valSection = valSection + name2 + value;
822			}
823			setCookieBrowser(section, valSection, null, expires, path, domain, secure);
824		}
825		else {
826			valSection = name2+value;
827			setCookieBrowser(section, valSection, null, expires, path, domain, secure);
828		}
829
830	}
831	else {
832		var curCookie = name + "=" + escape(value) + ((expires) ? "; expires=" + expires.toGMTString() : "")
833		+ ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : "");
834		document.cookie = curCookie;
835	}
836}
837
838//name - name of the desired cookie
839//section - name of group of cookies or null
840// * return string containing value of specified cookie or null if cookie does not exist
841function getCookie(name, section, defval) {
842	if ( feature_no_cookie == 'y' && (window.XMLHttpRequest || window.ActiveXObject) && typeof tiki_cookie_jar != "undefined" && tiki_cookie_jar.length > 0) {
843		if (typeof tiki_cookie_jar[name] == "undefined") {
844			return defval;
845		}
846		return tiki_cookie_jar[name];
847	}
848	else {
849		return getCookieBrowser(name, section, defval);
850	}
851}
852function getCookieBrowser(name, section, defval) {
853	if (typeof defval === "undefined") { defval = null; }
854	if (section) {
855		var valSection = getCookieBrowser(section);
856		if (valSection) {
857			var name2 = "@"+name+":";
858			var val = valSection.match(new RegExp(name2 + "([^@;]*)"));
859			if (val) {
860				return unescape(val[1]);
861			} else {
862				return defval;
863			}
864		} else {
865			return defval;
866		}
867	} else {
868		var dc = document.cookie;
869
870		var prefix = name + "=";
871		var begin = dc.indexOf("; " + prefix);
872
873		if (begin == -1) {
874			begin = dc.indexOf(prefix);
875
876			if (begin !== 0) {
877				return defval;
878			}
879		} else { begin += 2; }
880
881		var end = document.cookie.indexOf(";", begin);
882
883		if (end == -1) {
884			end = dc.length;
885		}
886		return unescape(dc.substring(begin + prefix.length, end));
887	}
888}
889
890//name - name of the cookie
891//[path] - path of the cookie (must be same as path used to create cookie)
892// [domain] - domain of the cookie (must be same as domain used to create cookie)
893// * path and domain default if assigned null or omitted if no explicit argument proceeds
894function deleteCookie(name, section, expires, path, domain, secure) {
895	if (section) {
896		var valSection = getCookieBrowser(section);
897		var name2 = "@" + name + ":";
898		if (valSection) {
899			if (new RegExp(name2).test(valSection)) {
900				valSection  = valSection.replace(new RegExp(name2 + "[^@;]*"), "");
901				setCookieBrowser(section, valSection, null, expires, path, domain, secure);
902			}
903		}
904	}
905	else {
906
907//		if ( !setCookie( name, '', 0, path, domain ) ) {
908//		if (getCookie(name)) {
909		document.cookie = name + "="
910		+ ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
911//		}
912	}
913}
914
915//date - any instance of the Date object
916//* hand all instances of the Date object to this function for "repairs"
917function fixDate(date) {
918	var base = new Date(0);
919
920	var skew = base.getTime();
921
922	if (skew > 0) {
923		date.setTime(date.getTime() - skew);
924	}
925}
926
927
928//Expand/collapse lists
929
930function flipWithSign(foo) {
931	if (document.getElementById(foo).style.display == "none") {
932		show(foo, true, "showhide_headings");
933		collapseSign("flipper" + foo);
934	} else {
935		hide(foo, true, "showhide_headings");
936		expandSign("flipper" + foo);
937	}
938}
939
940//set the state of a flipped entry after page reload
941function setFlipWithSign(foo) {
942	if (getCookie(foo, "showhide_headings", "o") == "o") {
943		collapseSign("flipper" + foo);
944
945		show(foo);
946	} else {
947		expandSign("flipper" + foo);
948
949		hide(foo);
950	}
951}
952
953function expandSign(foo) {
954	if (document.getElementById(foo)) {
955		document.getElementById(foo).firstChild.nodeValue = "[+]";
956	}
957}
958
959function collapseSign(foo) {
960	if (document.getElementById(foo)) {
961		document.getElementById(foo).firstChild.nodeValue = "[-]";
962	}
963} // flipWithSign()
964
965// Set client timezone
966// moved to lib/setup/javascript.php
967
968//function added for use in navigation dropdown
969//example :
970//<select name="anything" onchange="go(this);">
971//<option value="http://tiki.org">tiki.org</option>
972//</select>
973function go(o) {
974	if (o.options[o.selectedIndex].value !== "") {
975		location.replace(o.options[o.selectedIndex].value);
976
977		o.options[o.selectedIndex] = 1;
978	}
979
980	return false;
981}
982
983
984//function: targetBlank
985//desc: opens a new window, XHTML-compliant replacement of the "TARGET" tag
986//added by: Ralf Lueders ([email protected])
987//date: Sep 7, 2003
988//params: url: the url for the new window
989//mode='nw': new, full-featured browser window
990//mode='popup': new windows, no features & buttons
991
992function targetBlank(url,mode) {
993	var features = 'menubar=yes,toolbar=yes,location=yes,directories=yes,fullscreen=no,titlebar=yes,hotkeys=yes,status=yes,scrollbars=yes,resizable=yes';
994	switch (mode) {
995	// new full-equipped browser window
996	case 'nw':
997		break;
998		// new popup-window
999	case 'popup':
1000		features = 'menubar=no,toolbar=no,location=no,directories=no,fullscreen=no,titlebar=no,hotkeys=no,status=no,scrollbars=yes,resizable=yes';
1001		break;
1002	default:
1003		break;
1004	}
1005	window.open(url,'_blank',features);
1006}
1007
1008//function: confirmTheLink
1009//desc: pop up a dialog box to confirm the action
1010//added by: Franck Martin
1011//date: Oct 12, 2003
1012//params: theLink: The link where it is called from
1013//params: theMsg: The message to display
1014function confirmTheLink(theLink, theMsg)
1015{
1016    // Confirmation is not required if browser is Opera (crappy js implementation)
1017	if (typeof(window.opera) != 'undefined') {
1018		return true;
1019	}
1020
1021	var is_confirmed = confirm(theMsg);
1022	// if (is_confirmed) {
1023	// theLink.href += '&amp;is_js_confirmed=1';
1024	// }
1025
1026	return is_confirmed;
1027}
1028
1029/** \brief: insert img tag in textarea
1030 * 
1031 */
1032function insertImgFile(elementId, fileId, oldfileId,type,page,attach_comment) {
1033	var textarea = $('#' + elementId)[0];
1034	var fileup   = $('input[name=' + fileId + ']')[0];
1035	var oldfile  = $('input[name=' + oldfileId + ']')[0];
1036	var prefixEl = $('input[name=prefix]')[0];
1037	var prefix   = "img/wiki_up/";
1038
1039	if (!textarea || ! fileup) {
1040		return;
1041	}
1042	if ( prefixEl) { prefix= prefixEl.value; }
1043
1044	var filename = fileup.value, dirs, str;
1045	var oldfilename = oldfile.value;
1046
1047    if (filename == oldfilename || filename === "" ) { // insert only if name really changed
1048		return;
1049	}
1050	oldfile.value = filename;
1051
1052	if (filename.indexOf("/")>=0) { // unix
1053		dirs = filename.split("/");
1054		filename = dirs[dirs.length-1];
1055	}
1056	if (filename.indexOf("\\")>=0) { // dos
1057		dirs = filename.split("\\");
1058		filename = dirs[dirs.length-1];
1059	}
1060	if (filename.indexOf(":")>=0) { // mac
1061		dirs = filename.split(":");
1062		filename = dirs[dirs.length-1];
1063	}
1064	// @todo - here's a hack: we know its ending up in img/wiki_up.
1065	// replace with dyn. variable once in a while to respect the tikidomain
1066	if (type == "file") {
1067		str = "{file name=\""+filename + "\"";
1068		var desc = $('#' + attach_comment).val();
1069		if (desc) {
1070			str = str + " desc=\"" + desc + "\"";
1071		}
1072		str = str + "}";
1073	} else {
1074		str = "{img src=\"img/wiki_up/" + filename + "\" }\n";
1075	}
1076	insertAt(elementId, str);
1077}
1078
1079/* add new upload image form in page edition */
1080var img_form_count = 2, needToConfirm = false;
1081function addImgForm() {
1082	var new_text = document.createElement('span');
1083	new_text.setAttribute('id','picfile' + img_form_count);
1084	new_text.innerHTML = '<input name=\'picfile' + img_form_count + '\' type=\'file\' onchange=\'javascript:insertImgFile("editwiki","picfile' + img_form_count + '","hasAlreadyInserted","img")\'/><br />';
1085	document.getElementById('new_img_form').appendChild(new_text);
1086	needToConfirm = true;
1087	img_form_count ++;
1088}
1089
1090/*
1091 * opens wiki 3d browser
1092 */
1093function wiki3d_open (page, width, height) {
1094	window.open('tiki-wiki3d.php?page='+page,'wiki3d','width='+width+',height='+height+',scrolling=no');
1095}
1096
1097/* some little email protection */
1098function protectEmail(nom, domain, sep) {
1099	return '<a class="wiki" href="mailto:'+nom+'@'+domain+'">'+nom+sep+domain+'</a>';
1100}
1101
1102browser();
1103
1104//This was added to allow wiki3d to change url on tiki's window
1105window.name = 'tiki';
1106
1107var fgals_window = null;
1108
1109function openFgalsWindow(filegal_manager_url, reload) {
1110	if (fgals_window && typeof fgals_window.document != "undefined" && typeof fgals_window.document != "unknown" && !fgals_window.closed) {
1111		if (reload) {
1112			fgals_window.location.replace(filegal_manager_url);
1113		}
1114		fgals_window.focus();
1115	} else {
1116		fgals_window=window.open(filegal_manager_url,'_blank','menubar=1,scrollbars=1,resizable=1,height=500,width=800,left
1116=50,top=50');
1117	}
1118	$(window).unload(function(){	// tidy
1119		fgals_window.close();
1120	});
1121}
1122
1123/* Count the number of words (spearated with space) */
1124function wordCount(maxSize, source, cpt, message) {
1125	var formcontent = source.value;
1126	var str = formcontent.replace(/^\s+|\s+$/g, '') ;
1127	formcontent = str.split(/[^\S]+/);
1128	if (maxSize > 0 && formcontent.length > maxSize) {
1129		alert(message);
1130		source.value = source.value.substr(0, source.value.length-1);
1131	} else {
1132		document.getElementById(cpt).value = formcontent.length;
1133	}
1134}
1135function charCount(maxSize, source, cpt, message) {
1136	var formcontent = source.value;
1137	if (maxSize > 0 && formcontent.length > maxSize) {
1138		alert(message);
1139		source.value = source.value.substr(0, maxSize);
1140	} else {
1141		document.getElementById(cpt).value = formcontent.length;
1142	}
1143}
1144
1145// apparently this function is not used anymore, should we remove it? - sampaioprimo
1146function show_plugin_form( type, index, pageName, pluginArgs, bodyContent )
1147{
1148	var target = document.getElementById( type + index );
1149	var content = target.innerHTML;
1150
1151	var form = build_plugin_form( type, index, pageName, pluginArgs, bodyContent );
1152
1153	target.innerHTML = '';
1154	target.appendChild( form );
1155}
1156
1157/* wikiplugin editor */
1158function popup_plugin_form(area_id, type, index, pageName, pluginArgs, bodyContent, edit_icon )
1159{
1160	if ($.ui) {
1161		return popupPluginForm( area_id, type, index, pageName, pluginArgs, bodyContent, edit_icon );
1162	}
1163	var container = document.createElement( 'div' );
1164	container.className = 'plugin-form-float';
1165	var textarea = $('#' + area_id)[0];
1166
1167	var minimize = document.createElement( 'a' );
1168	var icon = document.createElement( 'img' );
1169	minimize.appendChild( icon );
1170	minimize.href = 'javascript:void(0)';
1171	container.appendChild( minimize );
1172	icon.src = 'img/icons/cross.png';
1173	icon.style.position = 'absolute';
1174	icon.style.top = '5px';
1175	icon.style.right = '5px';
1176	icon.style.border = 'none';
1177
1178	if (!index) { index = 0; }
1179	if (!pageName) { pageName = ''; }
1180	if (!pluginArgs) { pluginArgs = {}; }
1181	if (!bodyContent) { 
1182		if (document.getTASelection) {
1183			bodyContent = document.getTASelection(textarea);
1184		} else if (window.getTASelection) {
1185			bodyContent = window.getTASelection(textarea);
1186		} else if (document.selection) {
1187			bodyContent = document.selection.createRange().text;
1188		} else {
1189			bodyContent = '';
1190		}
1191	}
1192
1193	var form = build_plugin_form(
1194			type,
1195			index,
1196			pageName,
1197			pluginArgs,
1198			bodyContent
1199	);
1200
1201	form.onsubmit = function()
1202	{
1203		var meta = tiki_plugins[type];
1204		var params = [];
1205		var edit = edit_icon;
1206
1207		for(var i=0; i<form.elements.length; i++){
1208			var element = form.elements[i].name;
1209
1210			var matches = element.match(/params\[(.*)\]/);
1211
1212			if (matches === null) {
1213				// it's not a parameter, skip
1214				continue;
1215			}
1216			var param = matches[1];
1217
1218			var val = form.elements[i].value;
1219
1220			if ( val !== '' ) {
1221				params.push( param + '="' + val + '"' );
1222			}
1223		}
1224
1225		var blob;
1226		if (typeof form.content != 'undefined' && form.content.length > 0) {
1227			blob = '{' + type.toUpperCase() + '(' + params.join(' ') + ')}' + form.content.value + '{' + type.toUpperCase() + '}';
1228		} else {
1229			blob = '{' + type.toLowerCase() + ' ' + params.join(' ') + '}';
1230		}
1231
1232		if (edit) {
1233			return true;
1234		} else {
1235			insertAt( area_id, blob );
1236			document.body.removeChild( container );
1237		}
1238		return false;
1239	};
1240
1241	minimize.onclick = function() {
1242		var edit = edit_icon;
1243		if (edit) {
1244			edit.style.display = 'inline';
1245		}
1246		document.body.removeChild( container );
1247	};
1248
1249	document.body.appendChild( container );
1250	if (edit_icon) {
1251		edit_icon.style.display = 'none';
1252	}
1253	container.appendChild( form );
1254	
1255	handlePluginFieldsHierarchy(type);
1256}
1257
1258function build_plugin_form( type, index, pageName, pluginArgs, bodyContent, selectedMod )
1259{
1260	var form = document.createElement( 'form' );
1261	form.method = 'post';
1262	form.action = 'tiki-wikiplugin_edit.php';
1263	form.className  = 'wikiplugin_edit';
1264
1265	var hiddenPage = document.createElement( 'input' );
1266	hiddenPage.type = 'hidden';
1267	hiddenPage.name = 'page';
1268	hiddenPage.value = pageName;
1269	form.appendChild( hiddenPage );
1270
1271	var hiddenType = document.createElement( 'input' );
1272	hiddenType.type = 'hidden';
1273	hiddenType.name = 'type';
1274	hiddenType.value = type;
1275	form.appendChild( hiddenType );
1276
1277	var hiddenIndex = document.createElement( 'input' );
1278	hiddenIndex.type = 'hidden';
1279	hiddenIndex.name = 'index';
1280	hiddenIndex.value = index;
1281	form.appendChild( hiddenIndex );
1282	
1283	//
1284	var savedArgs = document.createElement( 'input' );
1285	savedArgs.type = 'hidden';
1286	savedArgs.name = 'args';
1287	savedArgs.value = $.toJSON(pluginArgs);
1288	form.appendChild( savedArgs );
1289	
1290	//Convert to JSON and then back to an object to break
1291	//link between meta local variable and tiki_plugins[type] global variable.
1292	//Otherwise each change to meta.params using the extend below was being appended to the global
1293	//Probably a much easier way to do this
1294	var infostring = $.toJSON(tiki_plugins[type]);
1295	var meta = $.parseJSON(infostring);
1296	
1297	//For PluginModule, add selected module parameters to the plugin edit form
1298	if (type == 'module') {
1299		//isolate the module parameter object so it will be shown first in the form
1300		var onlymod = {"params":{"module": meta.params.module}};
1301		//user has not changed the module selection since opening the form
1302		if (typeof selectedMod == 'undefined') {
1303			//pick up the parameters of the saved module parameter
1304			if (typeof pluginArgs.module != 'undefined') {
1305				//this orders the module parameter first, module related parameters second, other PluginModule parameters besides module last
1306				meta.params = $.extend(onlymod.params, tiki_module_params[pluginArgs.module].params, meta.params);
1307				//Use the module description
1308				meta.params.module.description = tiki_module_params[pluginArgs.module].description;
1309			//otherwise pick up the parameters of the first module option since that will be selected automatically
1310			} else {
1311				meta.params = $.extend(onlymod.params, tiki_module_params[meta.params.module.options[0].value].params, meta.params);
1312				meta.params.module.description = tiki_module_params[meta.params.module.options[0].value].description;
1313			}
1314		//user has selected another module while the form was open - pick up parameters for the selected module
1315		} else {
1316			meta.params = $.extend(onlymod.params, tiki_module_params[selectedMod].params, meta.params);
1317			meta.params.module.description = tiki_module_params[selectedMod].description;
1318		}
1319	}
1320
1321	var header = document.createElement( 'h3' );
1322	header.innerHTML = meta.name;
1323	form.appendChild( header );
1324
1325	var desc = document.createElement( 'div' );
1326	desc.innerHTML = meta.description;
1327	if (meta.documentation) {
1328		desc.innerHTML += ' <a href="http://doc.tiki.org/' + meta.documentation + '" target="tikihelp" class="tikihelp" tabIndex="-1">' +
1329				'<img src="img/icons/help.png" alt="Help" width="16" height="16" class="icon" title="Help" class="icon">' +
1330			'</a>';
1331
1332	}
1333	form.appendChild( desc );
1334
1335	var table = document.createElement( 'table' ), param;
1336	table.className = 'normal';
1337	table.id = 'plugin_params';
1338	form.appendChild( table );
1339
1340	for (param in meta.params) {
1341		if (meta.params[param].advanced) {
1342			var br = document.createElement( 'br' );
1343			form.appendChild( br );
1344
1345			var span_advanced_button = document.createElement( 'span' );
1346			span_advanced_button.className = 'button';
1347			form.appendChild( span_advanced_button );
1348
1349			var advanced_button = document.createElement( 'a' );
1350			advanced_button.innerHTML = tr('Advanced options');
1351			advanced_button.onclick = function() { flip('plugin_params_advanced');};
1352			span_advanced_button.appendChild(advanced_button);
1353
1354			var table_advanced = document.createElement( 'table' );
1355			table_advanced.className = 'normal';
1356			table_advanced.style.display = 'none';
1357			table_advanced.id = 'plugin_params_advanced';
1358			form.appendChild( table_advanced );
1359
1360			break;
1361		}
1362	}
1363
1364	var potentiallyExtraPluginArgs = pluginArgs, extraArg;
1365
1366	var rowNumber = 0;
1367	var rowNumberAdvanced = 0;
1368	for( param in meta.params )
1369	{
1370		if ( typeof(meta.params[param]) != 'object' || meta.params[param].name == 'array' ) {
1371			continue;
1372		}
1373
1374		var row;
1375		if (meta.params[param].advanced && !meta.params[param].required && typeof pluginArgs[param] === "undefined") {
1376			row = table_advanced.insertRow( rowNumberAdvanced++ );
1377		} else {
1378			row = table.insertRow( rowNumber++ );
1379		}
1380		var value = pluginArgs.length < 1?'': pluginArgs[param];// for param like sort
1381		//for use with PluginModule to identify saved module parameter value
1382		var nsavedArgs = $.parseJSON($(form).find('input[name="args"][type="hidden"]').val());
1383		//last two parameters (selectedMod and savedArgs are only needed for PluginModule
1384		build_plugin_form_row(row, param, meta.params[param].name, meta.params[param].required, value, meta.params[param].description, meta.params[param], selectedMod, nsavedArgs);
1385
1386		delete potentiallyExtraPluginArgs[param];
1387	}
1388
1389	for( extraArg in potentiallyExtraPluginArgs) {
1390		if (extraArg === '') {
1391			// TODO HACK: See bug 2499 http://dev.tiki.org/tiki-view_tracker_item.php?itemId=2499
1392			continue;
1393		}
1394
1395		row = table.insertRow( rowNumber++ );
1396		build_plugin_form_row(row, extraArg, extraArg, 'extra', pluginArgs[extraArg], extraArg);
1397	}
1398
1399	var bodyRow = table.insertRow(rowNumber++);
1400	var bodyCell = bodyRow.insertCell(0);
1401	var bodyField = document.createElement( 'textarea' );
1402	bodyField.cols = '70';
1403	bodyField.rows = '12';
1404	var bodyDesc = document.createElement( 'div' );
1405
1406	if ( meta.body ) {
1407		bodyDesc.innerHTML = meta.body;
1408	} else {
1409		bodyRow.style.display = 'none';
1410	}
1411	bodyField.name = 'content';
1412	bodyField.value = bodyContent;
1413
1414	bodyRow.className = 'formcolor';
1415
1416	bodyCell.appendChild( bodyDesc );
1417	bodyCell.appendChild( bodyField );
1418	bodyCell.colSpan = '2';
1419
1420	var submitRow = table.insertRow(rowNumber++);
1421	var submitCell = submitRow.insertCell(0);
1422	var submit = document.createElement( 'input' );
1423
1424	submit.type = 'submit';
1425	submitCell.colSpan = 2;
1426	submitCell.appendChild( submit );
1427	submitCell.className = 'submit';
1428
1429	return form;
1430}
1431
1432//last two parameters (selectedMod and savedArgs are only needed for PluginModule
1433function build_plugin_form_row(row, name, label_name, requiredOrSpecial, value, description, paramDef, selectedMod, savedArgs)
1434{
1435
1436	var label = row.insertCell( 0 );
1437	var field = row.insertCell( 1 );
1438	row.className = 'formcolor';
1439	row.id = 'param_' + name;
1440
1441	label.innerHTML = label_name;
1442	label.style.width = '130px';
1443	switch ( requiredOrSpecial ) {
1444	case (true):  // required flag
1445		label.style.fontWeight = 'bold';
1446	break;
1447	case ('extra') :
1448		label.style.fontStyle = 'italic';
1449	}
1450
1451	var input, icon;
1452	if (paramDef && paramDef.options) {
1453		input = document.createElement('select');
1454		input.name = 'params[' + name + ']';
1455		for (var o = 0; o < paramDef.options.length; o++) {
1456			var opt = document.createElement('option');
1457			opt.value = paramDef.options[o].value;
1458			var opt_text = document.createTextNode(paramDef.options[o].text);
1459			opt.appendChild(opt_text);
1460			//either not PluginModule or user has not changed module selection, so use saved value
1461			if (typeof selectedMod == 'undefined') {
1462				if (value && opt.value == value) {
1463					opt.selected = true;
1464				}
1465			} else {
1466				//user changed module selection in PluginModule
1467				if (selectedMod == opt.value) {
1468					opt.selected = true;
1469				} else if (savedArgs.module == opt.value) {
1470					//use later to display saved module parameter value
1471					var savedtext = opt.innerHTML;
1472					opt.style.fontWeight = 'bold';
1473					opt.innerHTML = opt.innerHTML + '  -- ' + tr('saved value');
1474				}
1475			}
1476			input.appendChild(opt);
1477		}
1478	} else {
1479		input = document.createElement('input');
1480		input.type = 'text';
1481		input.name = 'params[' + name + ']';
1482		if (value) {
1483			input.value = value;
1484		}
1485	}
1486
1487	field.appendChild( input );
1488	if (paramDef && paramDef.type == 'image') {
1489		icon = document.createElement( 'img' );
1490		icon.src = 'img/icons/image.png';
1491		input.id = paramDef.area ? paramDef.area : 'fgal_picker';
1492		icon.onclick = function() {openFgalsWindowArea(paramDef.area ? paramDef.area :'fgal_picker');};
1493		field.appendChild( icon );
1494	} else if (paramDef && paramDef.type == 'fileId') {
1495		var help = document.createElement( 'span' );
1496		input.id = paramDef.area ? paramDef.area : 'fgal_picker';
1497		help.onclick = function() {openFgalsWindowArea(paramDef.area ? paramDef.area :'fgal_picker');};
1498		help.innerHTML = " <a href='#'>" + tr('Pick a file.') + "</a>";
1499		field.appendChild( help );
1500	}
1501
1502	if (description) {
1503		var desc = document.createElement( 'div' );
1504		desc.style.fontSize = 'x-small';
1505		desc.innerHTML = description;
1506		field.appendChild( desc );
1507	}
1508	//in PluginModule, show saved nodule parameter value if user has changed selection
1509	//since the form changes to match the newly selected module, it's useful to show the
1510	//saved module parameter so the user can go back to it
1511	if (typeof savedtext != 'undefined') {
1512		var saved = document.createElement('div');
1513		saved.style.fontSize = 'x-small';
1514		saved.style.fontStyle = 'italic';
1515		saved.style.fontWeight = 'bold';
1516		saved.innerHTML = tr('Saved value:') + ' ' + savedtext;
1517		field.appendChild( saved );
1518	}
1519
1520	if (paramDef && paramDef.filter) {
1521		if (paramDef.filter == "pagename") {
1522			$(input).tiki("autocomplete", "pagename");
1523		} else if (paramDef.filter == "groupname") {
1524			$(input).tiki("autocomplete", "groupname", {multiple: true, multipleSeparator: "|"});
1525		} else if (paramDef.filter == "username") {
1526			$(input).tiki("autocomplete", "username", {multiple: true, multipleSeparator: "|"});
1527		} else if (paramDef.filter == "date") {
1528			$(input).tiki("datepicker");
1529		}
1530	}
1531
1532}
1533
1534function openFgalsWindowArea(area) {
1535	openFgalsWindow('tiki-list_file_gallery.php?filegals_manager='+area+'&galleryId='+jqueryTiki.home_file_gallery, true);	// reload
1536}
1537
1538
1539//Password strength
1540//Based from code by:
1541//Matthew R. Miller - 2007
1542//www.codeandcoffee.com
1543//originally released as "free software license"
1544
1545/*
1546 * Password Strength Algorithm:
1547 * 
1548 * Password Length: 5 Points: Less than 4 characters 10 Points: 5 to 7
1549 * characters 25 Points: 8 or more
1550 * 
1551 * Letters: 0 Points: No letters 10 Points: Letters are all lower case 20
1552 * Points: Letters are upper case and lower case
1553 * 
1554 * Numbers: 0 Points: No numbers 10 Points: 1 number 20 Points: 3 or more
1555 * numbers
1556 * 
1557 * Characters: 0 Points: No characters 10 Points: 1 character 25 Points: More
1558 * than 1 character
1559 * 
1560 * Bonus: 2 Points: Letters and numbers 3 Points: Letters, numbers, and
1561 * characters 5 Points: Mixed case letters, numbers, and characters
1562 * 
1563 * Password Text Range: >= 90: Very Secure >= 80: Secure >= 70: Very Strong >=
1564 * 60: Strong >= 50: Average >= 25: Weak >= 0: Very Weak
1565 * 
1566 */
1567
1568
1569//Settings
1570// -- Toggle to true or false, if you want to change what is checked in the password
1571var m_strUpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1572var m_strLowerCase = "abcdefghijklmnopqrstuvwxyz";
1573var m_strNumber = "0123456789";
1574var m_strCharacters = "!@#$%^&*?_~";
1575
1576//Check password
1577function checkPassword(strPassword)
1578{
1579	// Reset combination count
1580	var nScore = 0;
1581
1582	// Password length
1583	// -- Less than 4 characters
1584	if (strPassword.length < 5)
1585	{
1586		nScore += 5;
1587	}
1588	// -- 5 to 7 characters
1589	else if (strPassword.length > 4 && strPassword.length < 8)
1590	{
1591		nScore += 10;
1592	}
1593	// -- 8 or more
1594	else if (strPassword.length > 7)
1595	{
1596		nScore += 25;
1597	}
1598
1599	// Letters
1600	var nUpperCount = countContain(strPassword, m_strUpperCase);
1601	var nLowerCount = countContain(strPassword, m_strLowerCase);
1602	var nLowerUpperCount = nUpperCount + nLowerCount;
1603	// -- Letters are all lower case
1604	if (nUpperCount === 0 && nLowerCount !== 0)
1605	{
1606		nScore += 10;
1607	}
1608	// -- Letters are upper case and lower case
1609	else if (nUpperCount !== 0 && nLowerCount !== 0)
1610	{
1611		nScore += 20;
1612	}
1613
1614	// Numbers
1615	var nNumberCount = countContain(strPassword, m_strNumber);
1616	// -- 1 number
1617	if (nNumberCount == 1)
1618	{
1619		nScore += 10;
1620	}
1621	// -- 3 or more numbers
1622	if (nNumberCount >= 3)
1623	{
1624		nScore += 20;
1625	}
1626
1627	// Characters
1628	var nCharacterCount = countContain(strPassword, m_strCharacters);
1629	// -- 1 character
1630	if (nCharacterCount == 1)
1631	{
1632		nScore += 10;
1633	}
1634	// -- More than 1 character
1635	if (nCharacterCount > 1)
1636	{
1637		nScore += 25;
1638	}
1639
1640	// Bonus
1641	// -- Letters and numbers
1642	if (nNumberCount !== 0 && nLowerUpperCount !== 0)
1643	{
1644		nScore += 2;
1645	}
1646	// -- Letters, numbers, and characters
1647	if (nNumberCount !== 0 && nLowerUpperCount !== 0 && nCharacterCount !== 0)
1648	{
1649		nScore += 3;
1650	}
1651	// -- Mixed case letters, numbers, and characters
1652	if (nNumberCount !== 0 && nUpperCount !== 0 && nLowerCount !== 0 && nCharacterCount !== 0)
1653	{
1654		nScore += 5;
1655	}
1656
1657
1658	return nScore;
1659}
1660
1661//Runs password through check and then updates GUI
1662function runPassword(strPassword, strFieldID)
1663{
1664	// Check password
1665	var nScore = checkPassword(strPassword);
1666
1667	// Get controls
1668	var ctlBar = document.getElementById(strFieldID + "_bar");
1669	var ctlText = document.getElementById(strFieldID + "_text");
1670	if (!ctlBar || !ctlText) {
1671		return;
1672	}
1673	// Set new width
1674	ctlBar.style.width = nScore + "%";
1675
1676	// Color and text
1677	// -- Very Secure
1678	if (nScore >= 90)
1679	{
1680		var strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Very Secure' />";
1681		var strText = tr("Very Secure");
1682		var strColor = "#0ca908";
1683	}
1684	// -- Secure
1685	else if (nScore >= 80)
1686	{
1687		strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Secure' />";
1688		strText = tr("Secure");
1689		strColor = "#0ca908";
1690	}
1691	// -- Very Strong
1692	else if (nScore >= 70)
1693	{
1694		strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Very Strong' />";
1695		strText = tr("Very Strong");
1696		strColor = "#0ca908";
1697	}
1698	// -- Strong
1699	else if (nScore >= 60)
1700	{
1701		strIcon = "<img src='img/icons/accept.png' style='vertical-align:middle' alt='Strong' />";
1702		strText = tr("Strong");
1703		strColor = "#0ca908";
1704	}
1705	// -- Average
1706	else if (nScore >= 40)
1707	{
1708		strIcon = " ";
1709		strText = tr("Average");
1710		strColor = "#e3cb00";
1711	}
1712	// -- Weak
1713	else if (nScore >= 25)
1714	{
1715		strIcon = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Weak' />";
1716		strText = tr("Weak");
1717		strColor = "#ff0000";
1718	}
1719	// -- Very Weak
1720	else
1721	{
1722		strIcon = "<img src='img/icons/exclamation.png' style='vertical-align:middle' alt='Very weak' />";
1723		strText = tr("Very Weak");
1724		strColor = "#ff0000";
1725	}
1726	ctlBar.style.backgroundColor = strColor;
1727	ctlText.innerHTML = "<span>"  + strIcon + " " + tr("Strength") + ": " + strText + "</span>";
1728}
1729
1730//Checks a string for a list of characters
1731function countContain(strPassword, strCheck)
1732{
1733	// Declare variables
1734	var nCount = 0, i;
1735
1736	for (i = 0; i < strPassword.length; i++)
1737	{
1738		if (strCheck.indexOf(strPassword.charAt(i)) > -1)
1739		{
1740			nCount++;
1741		}
1742	}
1743
1744	return nCount;
1745}
1746
1747function checkPasswordsMatch(in1, in2, el) {
1748	if ($(in1).val().length && $(in1).val() == $(in2).val()) {
1749		$(el).html("<img src='img/icons/accept.png' style='vertical-align:middle' alt='Secure' /><em>" + tr("Passwords match") + "</em>");
1750		return true;
1751	} else {
1752		$(el).html("");
1753		return false;
1754	}
1755}
1756
1757/**
1758 * Adds an Option to the quickpoll section.
1759 */
1760function pollsAddOption()
1761{
1762	var newOption = $( '<input />').attr('type', 'text').attr('name', 'options[]');
1763	$('#tikiPollsOptions').append($('<div></div>').append(newOption));
1764}
1765
1766/**
1767 * toggles the quickpoll section
1768 */
1769function pollsToggleQuickOptions()
1770{
1771	$( '#tikiPollsQuickOptions' ).toggle();
1772}
1773
1774/**
1775 * toggles div for droplist with Disabled option
1776 */
1777
1778function hidedisabled(divid,value) {
1779	if (value=='disabled') {
1780		document.getElementById(divid).style.display = 'none';
1781	} else {
1782		document.getElementById(divid).style.display = 'block';
1783	}
1784}
1785
1786/* for filegals */
1787
1788function adjustThumbnails() {
1789	var i,j,h = 0;
1790	var t = document.getElementById("thumbnails").childNodes;
1791	for ( i = 0; i < t.length; i++ ) {
1792		if ( t[i].className == "thumbnailcontener" ) {
1793			var t2 = t[i].childNodes;
1794			for ( j = 0; j < t2.length; j++ ) {
1795				if ( t2[j].className == "thumbnail" ) {
1796					t2[j].style.height = "100%";
1797					t2[j].style.overflow = "visible";
1798				}
1799			}
1800			if ( t[i].offsetHeight >= h ) {
1801				h = t[i].offsetHeight;
1802				t[i].style.height = h+"px";
1803			} else if ( t[i].offsetHeight < h ) {
1804				t[i].style.height = h+"px";
1805			}
1806		}
1807	}
1808	for ( i = 0; i < t.length; i++ ) {
1809		if ( t[i].className == "thumbnailcontener" ) {
1810			if ( t[i].offsetHeight <= h ) {
1811				t[i].style.height = h+"px";
1812			} else {
1813				break;
1814			}
1815		}
1816	}
1817}
1818
1819function open_webdav(url) {
1820	// Works only in IE
1821	if (typeof ActiveXObject != 'undefined') {
1822		var EditDocumentButton = new ActiveXObject("SharePoint.OpenDocuments.1");
1823		EditDocumentButton.EditDocument(url); 
1824	} else {
1825		prompt(tr('URL to open this file with WebDAV'), url);
1826	}
1827}
1828
1829function ccsValueToInteger(str) {
1830	var v = str.replace(/[^\d]*$/, "");
1831	if (v) {
1832		v = parseInt(v, 10);
1833	}
1834	if (isNaN(v)) {
1835		return 0;
1836	} else {
1837		return v;
1838	}
1839}
1840
1841// function to allow multiselection in checkboxes
1842// must be called like this :
1843//
1844// <input type="checkbox" onclick="checkbox_list_check_all(form_name,[checkbox_name_1,checkbox_name2 ...],true|false);">
1845function checkbox_list_check_all(form,list,checking) {
1846  for (var checkbox in list) {
1847    document.forms[form].elements[list[checkbox]].checked=checking;
1848  }
1849}
1850
1851if (!window.syntaxHighlighter) {
1852	window.syntaxHighlighter = {
1853		get: function() {return null;}
1854	};
1855}
1856
1857/**
1858* Wrapper for javascript encodeURI
1859*/
1860function tiki_encodeURI(rawstr)
1861{
1862	return encodeURI(rawstr);
1863}
1864
1865/**
1866* Wrapper for javascript decodeURI
1867*/
1868function tiki_decodeURI(encstr)
1869{
1870	return decodeURI(encstr.replace(/\+/g, " "));
1871}
1872
1873/**
1874* Wrapper for javascript encodeURIComponent
1875*/
1876function tiki_encodeURIComponent(rawstr)
1877{
1878	var str = encodeURIComponent(rawstr);
1879    return str;
1880}
1881
1882/**
1883* Wrapper for javascript decodeURIComponent
1884*/
1885function tiki_decodeURIComponent(encstr)
1886{
1887    var str = decodeURIComponent(encstr.replace(/\+/g, " "));
1888    return str;
1889}
1890
1891//Date helpers for to and from unix times
1892Date.prototype.toUnix = function() {
1893	return Math.round(this.getTime() / 1000.0);
1894};
1895
1896var UnixDate = function(unixDate) {
1897	return new Date(unixDate * 1000);
1898};
1899
1900Date.parseUnix = function(date) {
1901	date = new Date(Date.parse(date));
1902	return date.toUnix();
1903};
1904
1905/**
1906 * Tracker rating field adjust after voing using ajax
1907 * (when rendered in search results)
1908 *
1909 * @param data	array containing result
1910 *			'my_rate',
1911 *			'numvotes',
1912 *			'voteavg',
1913 *			'request_rate',
1914 *			'value',
1915 *			'mode',
1916 *			'labels',
1917 *			'rating_options'
1918 */
1919
1920function adjustRating(element, data) {
1921
1922	var $sibs, $help;
1923
1924	if ($(element).text() == "x") {	// unvote
1925		$sibs = $("span > a", $(element).parent())
1926		$help = $(element).prev().prev();
1927	} else {
1928		$sibs = $(element).siblings().andSelf();
1929		$help = $(element).parent().next();
1930	}
1931
1932	for (var i=0; i < $sibs.length; i++) {
1933		var v = $($sibs[i]).attr("onclick");	// get value from onclick script
1934		if (v) {
1935			v = v.match(/,(\d+)\)/);
1936			if (v && v.length === 2) {
1937				v = v[1];
1938				if (v <= data[0].voteavg && data[0].numvotes > 0) {
1939					$("img", $sibs[i]).attr("src", "img/icons/star.png");
1940				} else {
1941					$("img", $sibs[i]).attr("src", "img/icons/star_grey.png");
1942				}
1943			}
1944		}
1945	}
1946	var t = tr("Number of votes:") + " " + data[0].numvotes + ", " + tr("Average:") + " " + data[0].voteavg;
1947	if (data[0].result) {
1948		t = t + ", " + tr("Your rating:") + " " + data[0].my_rate;
1949	} else {
1950		t = t + ", " + tr("Vote not accepted");
1951	}
1952	$help.text("(" + data[0].numvotes + ")")
1953			.next().attr("title", t);
1954
1955}
1956
1957function sendVote(element, itemId, fieldId, vote) {
1958	$(element).parent().modal(" ");
1959	$.getJSON(
1960		$.service(
1961			'tracker',
1962			'vote',
1963			{i:itemId,f:fieldId,v:vote}
1964		), function(data){
1965			$(element).parent().modal();
1966			adjustRating(element, data);
1967		}
1968	);
1969}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.