/*
	Javascript
	source code fully copyright by flemishdreams.com
	terms of usage:
	free to use on non-commercial sites; in that case a searchbot-readable link to flemishdreams,com would be appreciated; don't remove this copyright notice; don't email for support; code provided 'as is'
	code last modified on March 5 2008
*/

// ____ global variables _____________________________________________________________________________________

var imgdir = 'img/';
var debug_flag = false;

var tags = new Array();
var tag_cursor = 0;
var tags_ncols = 5;
var clipboard_nrows = 6;
var clipboard_ncols = 70;
var insertbox_ncols = 20;
var screen_width = 600;
var tags_limit = 0;
	switch (site_version) {
		case 1:		{ var tags_limitn = 15;	break; };
		default:	{ var tags_limitn = 50;	break; };
	};
//var thesmatch_nocase = false;
var tag_treated = -1;
var tag_added = -1;
var tag_duplicateflag = false;
var tag_insert = -1;
var tags_mode = 0; // 0 = replace; 1 = delete; 2 = insert; 3 = edit; 4 = thesaurus
var help_mode = -1;
var separator_mode = 3; // 0 = comma; 1 = semicolon; 2 = space; 3 = new line; 4 = comma-space; 5 = semicolon-space; 6 = comma-space-new line
var quote_mode = 0; // 0 = as is; 1 = to single quote; 2 = to double quote; 3 = spaces as is; 4 = spaces to hyphens; 5 = spaces to underscores; 6 = remove spaces
var autoimport = true;
var stack = new Array(); var stackindex = new Array(); var stackptr = 0; var current_rollback = 0; var dontstack = false;
var priority = new Array();
var thesaurus = new Array();
var thesaurus_lc = new Array();
var thesaurus_uc = new Array();
var standardthesaurusflag = false;
var alltagsinthesaurus = false;
var template = new Array();
var incompat = new Array();
var incompat_forbid = true;
var overn = true; var overt = true; // used in inter-tag blocks style
var tag_duplicate = 0;

// ____ building _____________________________________________________________________________________

function build_fdtags () {
	build_banner();
	build_buttonstable();
	build_tagstable(null,-1,true);
	build_clipboardtable(tinyhelp_clipboard);
	/*	build_prioritytable();
	build_thesaurustable();
	build_templatetable();*/
	push_stack(999);
	if (confirm("Click 'OK' if you want to preload the standard thesaurus for spell check.\n"+
				"Click 'Cancel' if you have your own custom thesaurus or you don't need spell check.\n"+
				"You can always load the standard thesaurus later. "+
				"In doubt? Click 'OK'.")) {
				build_thesaurustable();
				thesaurus_import(0);
				closeWindow('thesaurustable');
		};
	build_helptable(null,-1);
};

function build_banner () {
	switch (site_version) {
		case 1:		{ var t = 'ftbanner_600x50_csp.jpg';	break; };
		default:	{ var t = 'ftbanner_600x50.jpg';		break; };
	};
	document.getElementById('banner').innerHTML =
		table_begin(screen_width.toString()+"px") + tdc_begin(img(imgdir+t)) + td_end() + table_end();
};

function build_clipboardtable (msg, type) {
	var s = build_tabletop('ordbackground','c_clipboard.png','Clipboard','id_clipboardmessage') +
	build_button('right','import_tags()',								'c_arrowup.png',	'Import from clipboard and add to tags') + 
	build_button('right','export_tags()',								'c_arrowdown.png',	'Export tags to clipboard using selected separator (see Options window)') +
	build_button('right','clear_clipboard()',							'c_newclip.png',	'Clear clipboard') + 
	build_button('right','focusClipboard(&#39;id_clipboard&#39;)',		'c_fulclip.png',	'Select full clipboard') + 
	build_button('right','header_msg(&#39;id_clipboardmessage&#39;,shorthelp_clipboard)',
																		'c_help.png',		'Show help') + 
	build_tablemiddle('Clipboard') +
	build_textarea('changed_clipboard(this)','id_clipboard');
	build_tablebottom(s,'clipboardtable');
	header_msg('id_clipboardmessage',msg,type);
};

function build_thesaurustable (msg, type, rollbackbusy) {
	if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (3);
	var s = build_tabletop('outbackground','c_thes.png','Thesaurus','id_thesaurusmessage') +
	build_button('right','thesaurus_import(0)',							'c_thes.png',		'Use standard thesaurus (current thesaurus deleted)') + 
	build_button('right','thesaurus_import()',							'c_arrowup.png',	'Import from clipboard and add to thesaurus') + 
	//build_button('right','thesaurus_export(thesaurus_uc)',				'c_arrowdown.png',	'Export upper case thesaurus to clipboard using selected separator (see Options window)') + // can be omitted in production version when no uppercase thesaurus needed
	//build_button('right','thesaurus_export(thesaurus_lc)',				'c_arrowdown.png',	'Export lower case thesaurus to clipboard using selected separator (see Options window)') + // can be omitted in production version when no uppercase thesaurus needed
	//build_button('right','thesaurus_export()',							'c_arrowdown.png',	'Export thesaurus to clipboard in Javascript mode') + 
	build_button('right','thesaurus_export(thesaurus)',					'c_arrowdown.png',	'Export thesaurus to clipboard using selected separator (see Options window)') + 
	build_button('right','clear_thesaurus()',							'c_new.png',		'Clear thesaurus') + 
	build_button('right','focusClipboard(&#39;id_thesaurus&#39;)',		'c_fulclip.png',	'Select full clipboard') + 
	build_button('right','header_msg(&#39;id_thesaurusmessage&#39;,shorthelp_thesaurus)',
																		'c_help.png',		'Show help') + 
	build_button('right','closeWindow(&#39;thesaurustable&#39;)',		'c_close.png',	'Close window') +
	build_tablemiddle('Thesaurus','id_thesauruscontent') +
	build_textarea('changed_thesaurus(this)','id_thesaurus');
	build_tablebottom(s,'thesaurustable');
	build_thesauruscontent(msg,type,true);
};
function build_thesauruscontent (msg, type, rollbackbusy) {
	if (isOpen('thesaurustable')) {
		if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (3);
		var n = thesaurus.length; var tk = new String(""); var style = new String("");
		if (n>0) {
			thesaurus.sort();
			tk = thesaurus[0];
			if (n>1) tk = tk + ' ... ' + thesaurus[n-1];
			tk = tk + ' (' + n.toString() + ')';
			style = 'token_td';
		}
		else tk = 'Import thesaurus from the clipboard below or <br>import standard thesaurus (<i>star button</i>) please.'
		document.getElementById('id_thesauruscontent').innerHTML =
			table_begin(null,3,5,'ordbackground') +
			tdc_begin(tk,'center',null,null,style,null,null,0,extra_txt(null,'cursor: default;',null,'clicked_thesaurus()')) +
			td_end() + table_end();
			header_msg('id_thesaurusmessage',msg,type,rollbackbusy);
};	};

function build_prioritytable (msg, type, rollbackbusy) {
	if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (2);
	var s = build_tabletop('outbackground','c_prio.png','Priorities','id_prioritymessage') +
	build_button('right','import_example_priority()',				'c_prio.png',		'Import example priority templates') +
	build_button('right','import_priority()',						'c_arrowup.png',	'Import from clipboard and add to existing priority templates') + 
	build_button('right','priority_export()',						'c_arrowdown.png',	'Export priority templates to clipboard using selected separator (see Options window)');
	/*if (priority.length>0) s = s + 
	build_button('right','priorityadd_thesaurus()',					'c_thes.png',		'Add all priority templates to thesaurus','msoverthb_priority()','msoutthb_priority()');*/
	s = s +
	build_button('right','clear_priority()',						'c_new.png',		'Clear priority templates') +
	build_button('right','focusClipboard(&#39;id_priority&#39;)',	'c_fulclip.png',	'Select full clipboard') +
	build_button('right','header_msg(&#39;id_prioritymessage&#39;,shorthelp_priority)',
																	'c_help.png',		'Show help') +
	build_button('right','closeWindow(&#39;prioritytable&#39;)',	'c_close.png',	'Close window') +
	build_tablemiddle('Priority','id_prioritycontent') +
	build_textarea('changed_priority(this)','id_priority');
	build_tablebottom(s,'prioritytable');
	build_prioritycontent(msg,type,true);
};
function build_prioritycontent (msg, type, rollbackbusy) {
	if (isOpen('prioritytable')) {
		if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (2);
		var s = new String("");
		s =	table_begin(null,3,5,'ordbackground');
		if (priority.length>0) {
			var size = 0; var col = 0;
			for (var i=0; i<priority.length; i++) {
				size = priority[i];
				s = s + tdc_begin(priority[i+1],null,null,null,'token_td',null,null,0,
					extra_txt	(null,'cursor: pointer;','Click to prioritize tags with this template','clicked_priority(this)',
								'p'+i.toString(),null,'mouseover_priority(this)','mouseout_priority(this)')) + td_end();
				i = i + size;
				col++;
				if (col>=tags_ncols) { col = 0; s = s + table_newrow(); }
				else if (i<(priority.length-1)) s = s + td_empty();
			};
		}
		else {
			var tmp = new String("Import priority templates from the clipboard below ");
			/*if (examples)*/ tmp = tmp + "or <br>import example (<i>priority button</i>) ";
			s = s + tdc_begin(tmp+'please.',null,null,null,null,null,null,0) + td_end();
		};
		s = s + table_end();
		document.getElementById('id_prioritycontent').innerHTML = s;
		header_msg('id_prioritymessage',msg,type);
};	};

function build_templatetable (msg, type, rollbackbusy) {
	if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (1);
	var s = build_tabletop('outbackground','c_templ.png','Templates','id_templatemessage') +
	build_button('right','import_example_template()',				'c_templ.png',		'Import example templates') +
	build_button('right','import_template()',						'c_arrowup.png',	'Import from clipboard and add to existing templates') +
	build_button('right','template_export()',						'c_arrowdown.png',	'Export templates to clipboard using selected separator (see Options window)');
	/*if (template.length>0) s = s + 
	build_button('right','templateadd_thesaurus()',					'c_thes.png',		'Add all templates to thesaurus','msoverthb_template()','msoutthb_template()');*/
	s = s +
	build_button('right','clear_template()',						'c_new.png',		'Clear templates') + 
	build_button('right','focusClipboard(&#39;id_template&#39;)',	'c_fulclip.png',	'Select full clipboard') +
	build_button('right','header_msg(&#39;id_templatemessage&#39;,shorthelp_template)',
																	'c_help.png',		'Show help') + 
	build_button('right','closeWindow(&#39;templatetable&#39;)',	'c_close.png',		'Close window') +
	build_tablemiddle('Template','id_templatecontent') +
	build_textarea('changed_template(this)','id_template');
	build_tablebottom(s,'templatetable');
	build_templatecontent(msg,type,true);
};
function build_templatecontent (msg, type, rollbackbusy) {
	if (isOpen('templatetable')) {
		if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (1);
		var s = new String("");
		s =	table_begin(null,3,5,'ordbackground');
		if (template.length>0) {
			var size = 0; var col = 0;
			for (var i=0; i<template.length; i++) {
				size = template[i];
				s = s + tdc_begin(template[i+1],null,null,null,'token_td',null,null,0,
					extra_txt	(null,'cursor: pointer;','Click to add template to tags','clicked_template(this)',
								't'+i.toString(),null,'mouseover_template(this)','mouseout_template(this)')) + td_end();
				i = i + size;
				col++;
				if (col>=tags_ncols) { col = 0; s = s + table_newrow(); }
				else if (i<(template.length-1)) s = s + td_empty();
			};
		}
		else {
			var tmp = new String("Import templates from the clipboard below ");
			/*if (examples)*/ tmp = tmp + "or <br>import example (<i>template button</i>) ";
			s = s + tdc_begin(tmp+'please.',null,null,null,null,null,null,0) + td_end();
		};
		s = s + table_end();
		document.getElementById('id_templatecontent').innerHTML = s;
		header_msg('id_templatemessage',msg,type);
};	};

function build_tabletop (background, icon, title, idmsg) {
	return	(table_begin(screen_width.toString()+"px") + tdc_begin() +
	table_begin("100%",null,null,background) + tdc_begin() +
	table_begin("100%",2,2) +
	tdc_begin(img(imgdir+icon),null,'top') + td_end() +
	tdc_begin('<strong>'+title+'</strong>',null,'top',null,"title",null,null,0) + td_end() + td_empty() +
	tdc_begin(null,'center','top','100%') + div_begin(idmsg) + div_end() + td_end() +
	tdc_begin(null,'right','top',null,null,null,null,0) +
	table_begin());
};
function build_tablemiddle (title, idcontent) {
	var s = table_newrow() + td_empty(null,null,extra_txt(null,"font-size: 3px;")) + table_end() + td_end() + table_end() + td_end();
	/*var s =	table_newrow() + tdc_begin(js('	scroll(0,0)','Top of window'),'right',null,null,null,9) + td_end() +
			table_end() + td_end() + table_end() + td_end();*/
	if (idcontent!=null) s = s + table_newrow() + tdc_begin(null,'center') + div_begin(idcontent) + div_end() + td_end() + table_newrow() + td_empty();
	s = s + table_newrow();
	return s;
};
function build_tablebottom (s, idtable, nolastspace) {
	if (nolastspace==null) var sn = table_newrow() + td_empty()
	else var sn = new String("");
	document.getElementById(idtable).innerHTML = s + sn	+ table_end() + td_end() + table_newrow() + td_empty() + table_end();
};
function build_textarea (action, id) {
	return	tdc_begin(null,'center',null,"100%") +
			make_textarea(clipboard_nrows,clipboard_ncols,action,null,null,null,extra_txt(null,null,null,null,id)) + td_end();
};
function build_button (align, action, icon, tooltip, mousover, mouseout) {
	return (
		tdc_begin(null,align,'top') + 
		make_button('',action,null,imgdir+icon,tooltip,null,null,
			extra_txt(null,null,null,null,null,null,mousover,mouseout)) +
		td_end()); };
function build_buttontext (title, action, tooltip, mode, refmode, width, mousover,mouseout) {
	return (
		tdc_begin() +
		make_button(title,action,null,null,tooltip,null,null,
			extra_txt(null,butstyle((refmode==mode),width),null,null,null,null,mousover,mouseout)) +
		td_end()); };
function butstyle (active, width) {
	if (active)	return "width: "+width.toString()+"px; font-weight: bold; color: #00f;"
	else		return "width: "+width.toString()+"px;"
};
function header_msg (id, msg, type) {
	if (type==null) var t = 'c_info.png'
	else {
		if (type==0) var t = 'c_info.png'
		else if (type<0) var t = ''
		else var t = 'c_warn.png';
	};
	if (t.length>0) t = tdc_begin(img(imgdir+t)) + td_end()
	else t = td_empty();
	if (msg==null) var s = '&nbsp;'
	else if (msg.length<1) var s = '&nbsp;'
	else var s = msg;
	document.getElementById(id).innerHTML = table_begin() + t + td_empty() + tdc_begin(s) + td_end() + table_end();
};

function build_toolstable (msg, type) {
	var s = build_tabletop('ordbackground','c_tools.png','Options','id_toolsmessage') + tdc_begin(null,'right') + table_begin() +
	build_button('right','header_msg(&#39;id_toolsmessage&#39;,shorthelp_tools)','c_help.png','Show help') +
	build_button('right','closeWindow(&#39;toolstable&#39;)','c_close.png','Close window') + table_end() + td_end() +
	build_tablemiddle() + tdc_begin() +
//
	table_begin("100%",4);
// column 1
	s = s +	tdc_begin(null,'center') + table_begin(null,6) + 
			tdc_begin(null,null,'top') + table_begin() + tdc_begin(null,null,'top') +
			table_begin(null,null,3,'outbackground') + tdc_begin('<u>Separators</u>') + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("0",'separator_box','separator_clicked(this)',(separator_mode==0)) + '(,) single comma' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("1",'separator_box','separator_clicked(this)',(separator_mode==1)) + '(;) single semicolon' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("2",'separator_box','separator_clicked(this)',(separator_mode==2)) + '( ) single space' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("3",'separator_box','separator_clicked(this)',(separator_mode==3)) + 'new line' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("4",'separator_box','separator_clicked(this)',(separator_mode==4)) + '(, ) comma + space' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("5",'separator_box','separator_clicked(this)',(separator_mode==5)) + '(; ) semicolon + space' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("6",'separator_box','separator_clicked(this)',(separator_mode==6)) + 'comma + new line' + td_end() + 
			table_end() + td_end() + table_newrow() + td_empty() + table_newrow() +
			tdc_begin(null,null,'top') + table_begin(null,null,3,'outbackground') + 
			tdc_begin('Auto import on any<br>clipboard change') + make_checkbox(null,'clicked_autoimport(this)',autoimport) + td_end() + table_newrow() +
			tdc_begin("Don't allow incompatible<br>tags") + make_checkbox(null,'clicked_incompat(this)',incompat_forbid) + td_end() + 
			table_end() + td_end() +
			table_end() + td_end();
// column 2
	s = s +	tdc_begin(null,'center','top') +
			table_begin(null,null,3,'outbackground') + tdc_begin('<u>Quotes</u>') + td_end() + table_newrow() +
			tdc_begin() + table_begin(null,null,4) +
			tdc_begin() + table_begin(null,null,3,'ordbackground') +
			tdc_begin('<i>Keep quotes</i>') + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("0",'quote_box','quote_clicked(this)',(quote_mode==0)) + 'leave quotes as is' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("1",'quote_box','quote_clicked(this)',(quote_mode==1)) + "(') convert to single quotes" + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("2",'quote_box','quote_clicked(this)',(quote_mode==2)) + '(") convert to double quotes' + td_end() + 
			table_end() + td_end() + table_newrow() +
			tdc_begin() + table_begin(null,null,3,'ordbackground') +
			tdc_begin('<i>Remove quotes</i>') + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("3",'quote_box','quote_clicked(this)',(quote_mode==3)) + 'leave spaces as is' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("4",'quote_box','quote_clicked(this)',(quote_mode==4)) + 'spaces to hyphens (-)' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("5",'quote_box','quote_clicked(this)',(quote_mode==5)) + 'spaces to underscores (_)' + td_end() + table_newrow() +
			tdc_begin() + make_radiobutton("6",'quote_box','quote_clicked(this)',(quote_mode==6)) + 'remove spaces' + td_end() +
			table_end() + td_end() +
			table_end() + td_end() +
			table_end() + td_end();
// column 3
	s = s +	tdc_begin(null,'right','top') + table_begin() + tdc_begin(null,null,'top') +
			table_begin(null,null,3,'outbackground') + tdc_begin('<u>Layout</u>') + td_end() + table_newrow() +
			tdc_begin('Columns in tags') + td_end() + td_empty() +
			tdc_begin() + make_input(tags_ncols.toString(),2,'colsbox_changed(this)') + td_end() +
			table_newrow() + 
			tdc_begin('Rows in clipboard') + td_end() + td_empty() +
			tdc_begin() + make_input(clipboard_nrows.toString(),2,'rowstxt_changed(this)') + td_end() +
			table_newrow() + 
			tdc_begin('Columns in clipboard') + td_end() + td_empty() +
			tdc_begin() + make_input(clipboard_ncols.toString(),2,'colstxt_changed(this)') + td_end() +
			table_newrow() + 
			tdc_begin('Screen width (pixels)') + td_end() + td_empty() +
			tdc_begin() + make_input(screen_width.toString(),2,'screenwidth_changed(this)') + td_end() +
			table_end() + td_end() + table_newrow() + td_empty() + table_newrow() + tdc_begin() +
			table_begin(null,null,3,'outbackground') +
			tdc_begin('<u>Limits indication</u>') + td_end() + table_newrow() +
			tdc_begin('Tags > ') + make_input(tags_limitn.toString(),3,'tagslimitn_changed(this)') + td_end() + table_newrow() +
			tdc_begin('Characters > ') + make_input(tags_limit.toString(),3,'tagslimit_changed(this)') + td_end() + table_newrow() +
			tdc_begin('<i>(0 = not applicable)</i') + td_end() +
			table_end() + td_end() +
			table_end() + td_end() + table_end() + td_end() + table_end() + td_end();
//
	build_tablebottom(s,'toolstable',0);
	header_msg('id_toolsmessage',msg,type);
};

function build_buttonstable () {
	var s =	table_begin(screen_width.toString()+"px") + tdc_begin() +
	table_begin("100%") + tdc_begin(null,null,null,null,null,null,null,0) + table_begin(null,null,1) +
	build_button(null,'unredo(true)',			'c_undo.png',	'Undo') +
	build_button(null,'unredo(false)',			'c_redo.png',	'Redo') +
	build_button(null,'case_tags(0)',			'c_upcase.png',	'All upper case') +
	build_button(null,'case_tags()',			'c_locase.png',	'All lower case') +
	build_button(null,'sort_tags()',			'c_alpha.png',	'Rank alphabetically') +
	td_empty() +
	build_button(null,'openclose_priority()',	'c_prio.png',	'Priority template window') +
	build_button(null,'openclose_thesaurus()',	'c_thes.png',	'Thesaurus window') +
	build_button(null,'openclose_template()',	'c_templ.png',	'Templates window') +
	td_empty() +
	build_button(null,'openclose_tools()',		'c_tools.png',	'Options window') +
	table_end() + td_end() + td_empty() + td_end();
	if (screen_width<585) s = s + table_newrow(); s = s +
	tdc_begin(null,'right',null,null,null,null,null,0) + table_begin() +
	build_buttontext('Reorder',		'editmode_tags(0)',	'Reorder tags by clicking on them',	0,tags_mode,65) +
	build_buttontext('Delete',		'editmode_tags(1)',	'Delete tag by clicking on it',		1,tags_mode,55) +
	build_buttontext('Insert',		'editmode_tags(2)',	'Insert tag where you click',		2,tags_mode,50) +
	build_buttontext('Edit',		'editmode_tags(3)',	'Edit tag by clicking on it',		3,tags_mode,50) +
	build_buttontext('Thesaurus',	'editmode_tags(4)',	'Check tags against thesaurus',		4,tags_mode,80) +
	table_end() + td_end() +
	build_button('right','help_mode=0;build_helptable(null,-1)','c_help.png','Show help on this program') +
	table_end() + td_end() + table_end();
	document.getElementById('buttonstable').innerHTML = s;
};

function build_tagstable (msg, type, rollbackbusy) {
// tag_cursor		cursor position		0..tags.length (at tags.length, the cursor points after the tags
// tag_insert		insert position		will build the insert box at that position - not used if < 0 - if >=0, the cursor will be set there after building the table	only used in insert and edit mode	reset after building the table
// tag_duplicateflag	goes with tag_insert	flag that affects the tooltip on that tag	only usde with tag_insert	reset after building the table
// tag_treated		only display			the tag will show green	reset after building the table		
	if ((rollbackbusy==null) || (!rollbackbusy)) push_stack (0);
	var s = new String(""); var style = new String(""); var tooltip = new String(""); var inserteditbox_present = false; var incompat_msg = false;
// stats
	var n = tags.length; var word = new String("");
	if (n>0) for (var i=0; i<tags.length; i++) { word = tags[i]; n = n + word.length; };
	if ((tags_limit>0) && (n>=tags_limit))				var n1 = '<font color="red">' + n.toString() + '</font>'
	else												var n1 = n.toString();
	if ((tags_limitn>0) && (tags.length>tags_limitn))	var n2 = '<font color="red">' + tags.length.toString() + '</font>'
	else												var n2 = tags.length.toString();
// incompatibilities
	if (incompatibles() && incompat_forbid) { incompat_msg = true; var tmp = tags_mode; tags_mode = 1; if (tags_mode!=tmp) build_buttonstable(); };
// headers
	switch (tags_mode) {
		case 1:		{ style = 'delbackground';	break; };
		case 2: 	{ style = 'insbackground';	break; };
		case 3: 	{ style = 'insbackground';	break; };
		case 4: 	{ style = 'thesbackground';	break; };
		default:	{ style = 'ordbackground';	break; };
	};
	s =	table_begin(screen_width.toString()+"px") + tdc_begin(null,'center',null,'100%') +
		table_begin("100%",2,null,'outbackground') + tdc_begin() +
		table_begin("100%",2) + tdc_begin('<strong>Tags</strong><br>&nbsp;'+n2+'&nbsp;/&nbsp;'+n1,null,'top',null,"title",null,null,0) + td_end() + td_empty() +
		tdc_begin(null,'center','top','100%') + div_begin('id_tagsmessage') + div_end() + td_end() +
		tdc_begin(null,'right','top') + table_begin() +
			build_button('right','export_tags()',			'c_arrowdown.png',	'Export tags to clipboard using selected separator (see Options window)');
		if (tags_mode==4) alltagsinthesaurus = true;
		if ((tags_mode==4) && (tags.length>0)) s = s + 
			build_button('right','tagsadd_thesaurus()',		'c_thes.png',		'Add all tags to thesaurus',
																				'msoverthb_tags()',	'msoutthb_tags()');
	s = s +	build_button('right','clear_tags()',			'c_new.png',		'Delete all tags') + 
			build_button('right','header_msg(&#39;id_tagsmessage&#39;,shorthelp_tags)',
															'c_help.png',		'Show help') + 
			table_end() + td_end() + table_end() + td_end() + table_newrow() +
			tdc_begin(null,'center') + table_begin(null,3,5,style);
// loop over tags
	if (tags.length>0) {
		var col = 0; var nchars = 0; var notfound = 0; overt = true; overn = true; var showtag = true;
		var tag_function = new String(""); var tag_cursortype = new String(""); var inthesaurus = false;
		for (i=0; i<=tags.length; i++) {
			if (i<tags.length) {
				word = tags[i];
				nchars = nchars + word.length + 1;
				tag_function = 'clicked_tags(this)'; tag_cursortype = 'cursor: pointer;';
			};
			inthesaurus = isInList(word,thesaurus);
			switch (tags_mode) {
				case 0: { // reorder
					if (i==tag_cursor)	s = s + build_block(i,nchars,'Clicked tag will come on this cursor position','curbl_td')
					else				s = s +	build_block(i,nchars,'Click to move cursor here');
					if (i==tag_treated)	{ 
						if (tag_duplicateflag)	{ style = 'tokend_td';	tooltip = 'Already there; click to place |' + word + '| right behind cursor position'; }
						else					{ style = 'tokenm_td';	tooltip = 'Just moved; click to place |' + word + '| right behind cursor position'; };
					}
					else {
						if ((thesaurus.length>0) && (!inthesaurus))	style = 'tokene_td'
						else										style = 'token_td';
						tooltip = 'Click to place |' + word + '| right behind cursor position';
					};
					// if ((i==tag_cursor) || (i==(tag_cursor-1))) {
					if (i==tag_cursor) {
						tag_function = ''; tag_cursortype = 'cursor: crosshair';
						if (i==tag_treated)	tooltip = '|' + word + '| already on cursor position; just moved'
						else				tooltip = '|' + word + '| already on cursor position';
					};
					if ((i==(tags.length-1)) && (tag_cursor>=tags.length)) {
						tag_function = ''; tag_cursortype = 'cursor: crosshair';
						tooltip = '|' + word + '| already at last position';
					};
					break; };
				case 1: { // delete
					if (i==tag_cursor)	s = s + build_block(i,nchars,'Cursor','curbl_td')
					else				s = s +	build_block(i,nchars,'Click to move cursor here');
					if (incompat[i] && incompat_forbid)
										{ style = 'tokeni_td'; tooltip = 'Click to delete incompatible |' + word + '|'; }
					else {
						if ((i==tag_treated) && (tag_duplicateflag))
										{ style = 'tokend_td'; tooltip = 'Already there; click to delete |' + word + '|'; }
						else {
							if ((thesaurus.length>0) && (!inthesaurus))	style = 'tokene_td'
							else										style = 'token_td';
							tooltip = 'Click to delete |' + word + '|';
						};
					};
					break; };
				case 2: { // insert
					if (i==tag_cursor)	s = s + build_block(i,nchars,'Cursor; click to insert tag here','curbl_td','cursor: pointer;')
					else				s = s +	build_block(i,nchars,'Click to insert tag here',null,'cursor: pointer;');
					if (i==tag_treated)	{
						if (tag_duplicateflag)	{ style = 'tokend_td';	tooltip = 'Already there'; }
						else					{ style = 'tokenm_td';	tooltip = 'Just inserted'; };
					}
					else {
						if ((i==tag_treated) && (tag_duplicateflag))
										{ style = 'tokend_td'; tooltip = 'Already there; click to delete |' + word + '|'; }
						else {
							if ((thesaurus.length>0) && (!inthesaurus))	style = 'tokene_td'
							else										style = 'token_td';
							tooltip = '';
						};
					};
					if (i==tag_insert) {
						s = s +	build_editbox('') + tdc_begin('&nbsp;&nbsp;',null,null,null,"sepbl_td",null,null,0) + td_end();
						inserteditbox_present = true;
					};
					tag_cursortype = 'cursor: crosshair';
					break; };
				case 3: { // edit
					if (showtag) {
						if (i==tag_cursor)	s = s + build_block(i,nchars,'Cursor','curbl_td')
						else				s = s +	build_block(i,nchars,'Click to move cursor here');
					};
					if (i==tag_treated)	{
						if (tag_duplicateflag)	{ style = 'tokend_td';	tooltip = 'Already here; click again to edit |' + word + '|'; }
						else					{ style = 'tokenm_td';	tooltip = 'Just edited; click again to edit |' + word + '|'; };
					} else {
						if ((thesaurus.length>0) && (!inthesaurus))	style = 'tokene_td'
						else										style = 'token_td';
						tooltip = 'Click here to edit |' + word + '|';
					};
					if (i==tag_insert) {
						s = s +	build_editbox(word) + tdc_begin('&nbsp;&nbsp;',null,null,null,"sepbl_td",null,null,0) + td_end();
						inserteditbox_present = true;
						showtag = false;
					} else showtag = true;
					break; };
				case 4: { // thesaurus
					if (i==tag_cursor)	s = s + build_block(i,nchars,'Cursor','curbl_td')
					else				s = s +	build_block(i,nchars,'Click to move cursor here');
					if (i<tags.length) {
						if (thesaurus.length>0) {
							if (inthesaurus)
								{	style = 'token_td';	tooltip = '|' + word + '| is in thesaurus';
									tag_function = ''; tag_cursortype = 'cursor: crosshair'; }
							else if (isInList(word.toLowerCase(),thesaurus_lc))
								{	style = 'tokenu_td';	tooltip = '|' + word + '| should contain upper case letters; click to add this version.';
									alltagsinthesaurus = false; }
							else if (isInList(word.toLowerCase(),thesaurus))
								{	style = 'tokenu_td';	tooltip = '|' + word + '| should contain lower case letters; click to add this version.';
									alltagsinthesaurus = false; }
							else
								{	style = 'tokene_td';	tooltip = 'Click to add |' + word + '| to thesaurus';
									alltagsinthesaurus = false; };
						}
						else {
							style = 'token_td';
							tooltip = 'Click to add |' + word + '| to empty thesaurus';
							alltagsinthesaurus = false;
						};
						if ((i==tag_treated) && (tag_duplicateflag)) tooltip = tooltip + '; already there';
					};
					break; };
			};
			if ((showtag) && (i<tags.length))
				s = s +	tdc_begin(word,null,null,null,style,null,null,0,
						extra_txt(null,tag_cursortype,tooltip,tag_function,i.toString(),
						null,'msoverthb_tags()','msoutthb_tags()')) + td_end();
			col++;
			if ((col>=tags_ncols) && (i<tags.length)) { col = 0; s = s + table_newrow(); };
		}; // loop end
	}
	else { // there are no tags
		s = s +	tdc_begin('Import tags from clipboard below please.',null,null,null,null,null,null,0) + td_end();
	};
// footer
	s =	s +	table_end() + td_end() + table_newrow() +
			td_empty(null,null,extra_txt(null,"font-size: 1px;")) + table_end() + td_end() +
			table_newrow() + td_empty() +table_end();
	document.getElementById('tagstable').innerHTML = s;
// clean up pointers
	if (tag_insert >= 0) { tag_cursor = tag_insert; tag_insert = -1; };
	tag_duplicateflag = false; tag_treated = -1;
// fill up divs: message and edit box
	if (incompat_msg)	header_msg('id_tagsmessage','Delete incompatible tags first please.',1)
	else				header_msg('id_tagsmessage',msg,type);
	if (inserteditbox_present) {
		document.getElementById('id_insertbox').select(); // doesnt work
		document.getElementById('id_insertbox').focus();
};	};
function build_block (i, nchars, tooltip, style, cursortype) {
// to implement maxima - only if style is null; if not, style is used
	if (cursortype!=null)	var varcursortype = cursortype
	else					var varcursortype = 'cursor: crosshair;';
	if (tooltip!=null)		var vartooltip = tooltip
	else					var vartooltip = new String("");
	if (style!=null)		var varstyle = style
	else {
		if (((tags_limit>0) && (nchars>=tags_limit)) || ((tags_limitn>0) && (i>=tags_limitn))) {
			var varstyle = "sepblover_td";
			if ((nchars>=tags_limit)	&& (overt)) {
				varstyle = "sepblover1st_td";
				if (vartooltip.length>0) vartooltip = vartooltip + ' - ';
				vartooltip = vartooltip + 'Maximum characters (' + tags_limit.toString() + ') reached';
				overt = false;
			};
			if ((i>=tags_limitn)		&& (overn)) {
				varstyle = "sepblover1st_td";
				if (vartooltip.length>0) vartooltip = vartooltip + ' - ';
				vartooltip = vartooltip + 'Maximum tags (' + tags_limitn.toString() + ') reached';
				overn = false;
		};	}
		else var varstyle = "sepbl_td";
	};
	return	tdc_begin('&nbsp;&nbsp;',null,null,null,varstyle,null,null,0,
				extra_txt(null,varcursortype,vartooltip,'clicked_block(this)','b'+i.toString())) + td_end();
};
function build_editbox (word) {
	if (word.length>0)	var func = 'changed_edit(this,' + tag_insert.toString() + ')'
	else				var func = 'changed_insert(this,' + tag_insert.toString() + ')';
	return	tdc_begin(null,null,null,null,null,3,null,0) +
			make_input(word,insertbox_ncols,func,null,extra_txt('insertbox',null,null,null,'id_insertbox')) +
			td_end();
};

// ____ tags events _____________________________________________________________________________________

function sort_tags () { // alphabetize
	if (tags.length<1) header_msg('id_tagsmessage','No tags.',0)
	else {
		tags.sort();
		tag_cursor = 0; tag_treated = -1; tag_insert = -1;
		build_tagstable('Tags sorted alphabetically.');
};	};
function case_tags (upcase_flag) { // all upper- or lowercase
	if (tags.length<1) header_msg('id_tagsmessage','No tags.',0)
	else {
		for (var i=0; i<tags.length; i++)
			if (upcase_flag==null)	tags[i] = tags[i].toLowerCase()
			else					tags[i] = tags[i].toUpperCase();
		var s = RemoveDuplicatesFromUnsortedList(tags);
		if (s.length>0) { s = ' Duplicates removed: ' + s + '.'; tag_treated = -1; tag_insert = -1; tag_cursor = tags.length};
		if (upcase_flag==null)	s = 'All tags lowercase.' + s
		else					s = 'All tags uppercase.' + s;
		build_tagstable(s);
};	};
function clear_tags () {
	if (tags.length<1) header_msg('id_tagsmessage','No tags.',0)
	else {
		tags.length = 0; tag_cursor = 0; tag_treated = -1; tag_insert = -1;
		build_tagstable('All tags deleted.');
};	};
function msoverthb_tagsbut ()	{ if (tags_mode!=4) thesaurus_warning_tags('id_tagsmessage',1); };
function msoutthb_tagsbut ()	{ if (tags_mode!=4) thesaurus_warning_tags('id_tagsmessage',0); };
function msoverthb_tags ()		{ if (tags_mode==4) thesaurus_warning_tags('id_tagsmessage',1); };
function msoutthb_tags ()		{ if (tags_mode==4) thesaurus_warning_tags('id_tagsmessage',0); };
function editmode_tags (mode) {
	var i = parseInt_(mode);
	if (i!=tags_mode) {
		tags_mode = i;
		build_buttonstable();
		tag_insert = -1;
		tag_treated = -1;
		build_tagstable(tagsmode_msg(true,true),null,true);
		if ((tags_mode==4) && (!isOpen('thesaurustable')) && (tags.length>0)) openclose_thesaurus();
		push_stack(999);
};	};
function clicked_block (ctrl) {
	switch (tags_mode) {
		case 2:		{ tag_insert = parseInt_(ctrl.id.substring(1)); tag_duplicateflag = false; build_tagstable(null,-1);	break; };
		default:	{ tag_cursor = parseInt_(ctrl.id.substring(1)); build_tagstable(tagsmode_msg());															break; };
};	};
function clicked_tags (ctrl) {
	var word = new String("");
	var p = parseInt_(ctrl.id);
		switch (tags_mode) {
			case 0: { // reorder
				if (p!=tag_cursor) {
					var temp = new Array(); var n = 0;
					tag_treated = tag_cursor;
					for (var i=0; i<tags.length; i++) {
						if (i==tag_cursor) { temp[n] = tags[p]; n++; };
						if (i!=p) { temp[n] = tags[i]; n++; };
					};
					if (tag_cursor>=tags.length) { temp[n] = tags[p]; n++; };
					for (i=0; i<n; i++) tags[i] = temp[i];
					if (p>tag_cursor) tag_cursor++
					else tag_treated--;
					build_tagstable(tagsmode_msg());	
				};
				break; };
			case 1: { // delete
				word = tags[p];
				if (p<(tags.length-1)) for (var i=p; i<(tags.length-1); i++) tags[i] = tags[i+1];
				tags.length--
				build_tagstable('Tag <i>' + word + '</i> deleted.');
				break; };
			case 2: { // insert
				break; };
			case 3: { // edit
				tag_insert = p; tag_duplicateflag = false; build_tagstable(null,-1);
				break; };
			case 4: { // add to thesaurus
				word = tags[p];
				var list = new Array(""); list[0] = word; standardthesaurusflag = false;
				var npv = thesaurus.length;
				var tmx = thesaurus_addarray(list);
				if (thesaurus.length>npv) {
					build_tagstable(tmx,null,true);
					rebuild_thesaurus(tmx);
				} else {
					header_msg('id_tagsmessage',tmx,null);
					header_msg('id_thesaurusmessage',tmx,null);
				};	
				break; };
};	};
function changed_insert (ctrl, position) {
	var list = new Array("");
	StringToListwithUniques(ctrl.value,list); if (list.length < 1) return;
	tag_cursor = position;
	var duplist = ListInTags(list);
	if (tag_added>1)		var tmx = tag_added.toString() + ' tags inserted. '
	else if (tag_added=1)	var tmx = 'One tag inserted. '
	else 					var tmx = 'No tags inserted. ';
	if (tag_duplicate>=0) {
		tmx = tmx + 'Tag(s) already there: <i>' + duplist.substring(1) + '</i>.';
		tag_treated = tag_duplicate;
		tag_duplicateflag = true;
	};
	build_tagstable(tmx);
};
function changed_edit (ctrl, position) {
	var list = new Array("");
	StringToListwithUniques(ctrl.value,list); if (list.length < 1) return;
	tag_cursor = position;
	var word = tags[tag_cursor];
	if (list.length==1)	var nword = list[0]
	else				var nword = new String("");
	if (tag_cursor<(tags.length-1)) for (var i=(tag_cursor+1); i<tags.length; i++) tags[i-1] = tags[i];
	tags.length = tags.length -1;
	var duplist = ListInTags(list);
	if (tag_added>1)		var tmx = 'Tag <i>' + word + '</i> edited in ' + tag_added.toString() + ' new tags. '
	else if (tag_added=1) {
		if (nword.length>0)	var tmx = 'Tag <i>' + word + '</i> edited in <i>' + nword + '</i>. '
		else				var tmx = 'Tag <i>' + word + '</i> edited in one new tag. '
	}
	else 					var tmx = 'No tags edited. ';
	if (tag_duplicate>=0) {
		tmx = tmx + 'Tag(s) already there: <i>' + duplist.substring(1) + '</i>.';
		tag_treated = tag_duplicate;
		tag_duplicateflag = true;
	};
	build_tagstable(tmx);
};
function tagsadd_thesaurus () {
	if (alltagsinthesaurus) {
		if (standardthesaurusflag)	var tst = 'standard'
		else						var tst = 'custom';
		header_msg('id_tagsmessage','All tags already in '+tst+' thesaurus.',null);
	}
	else {
		var npv = thesaurus.length;
		standardthesaurusflag = false;
		var tmx = thesaurus_addarray(tags);
		if (thesaurus.length>npv) {
			build_tagstable(tmx,null,true);
			rebuild_thesaurus(tmx);
		} else {
			header_msg('id_tagsmessage',tmx,null);
			header_msg('id_thesaurusmessage',tmx,null);
};	};	};

// ____ clipboard events _____________________________________________________________________________________

function clear_clipboard () {
	setClipboard('id_clipboard','');
	header_msg('id_clipboardmessage','Clipboard cleared.');
};
function changed_clipboard (ctrl) {
	if (ctrl.value.length>0) {
		if (autoimport) import_tags()
		else header_msg('id_clipboardmessage',shorthelp_autoimport);
};	};
function import_tags () {
	var list = new Array("");
	StringToList(document.getElementById('id_clipboard').value,list);
	if (list.length>0) {
		var duplist = ListInTags(list);
		if (tag_added>1)		var tmx = tag_added.toString() + ' tags imported from clipboard. '
		else if (tag_added=1)	var tmx = 'One tag imported from clipboard. '
		else 					var tmx = 'No tags imported from clipboard. ';
		if (tag_duplicate>=0) {
			tmx = tmx + 'Tag(s) already there: <i>' + duplist.substring(1) + '</i>.';
			tag_treated = tag_duplicate;
			tag_duplicateflag = true;
		};
		build_tagstable(tmx);
	} else header_msg('id_clipboardmessage','Clipboard empty.');
	focusClipboard('id_clipboard');
};
function ListInTags (list) {
	var dups = new String("");
	if (list.length>0) {
		RemoveDuplicatesFromUnsortedList(list);
		var temp = new Array(""); var n = 0; var word = new String(""); var k = 0; var notfound = false;
		var p = tag_cursor; if (p<0) p = 0; if (p>tags.length) p = tags.length;
		tag_treated = -1; tag_duplicateflag = false; tag_insert = -1; tag_duplicate = -1; tag_added = 0;
		if (p>0) for (k=0; k<p; k++) { temp[n] = tags[k]; n++; }; // copy preceding
		for (var i=0; i<list.length; i++) {
			word = list[i]; notfound = true;
			if (tags.length>0) for (k=0; k<tags.length; k++) if (tags[k]==word) {
				if (tag_duplicate<0) tag_duplicate = k;
				dups = dups + ' ' + word; notfound = false; break;
			};
			if (notfound) {
				if (tag_treated<0) tag_treated = n;
				tag_added++;
				temp[n] = word; n++;
				tag_cursor = n;
			};	};
			if (tag_duplicate>=p) tag_duplicate = tag_duplicate + tag_added;
		if (p<tags.length) for (k=p; k<tags.length; k++) { temp[n] = tags[k]; n++; }; // copy following
		tags = temp;
	};
	return dups;
};
function export_tags () {
	var t = tags.join(getSeparator());
	setClipboard('id_clipboard',t);
	if (t.length>0) header_msg('id_clipboardmessage',"Tags exported to the clipboard.<br>Press <i>CTRL-C</i> to copy the clipboard to the system clipboard, then to the IPTC keywords section of your image. Don't forget to save that image.")
	else header_msg('id_clipboardmessage','No tags to export.');
};

// ____ template events _____________________________________________________________________________________

function openclose_template () {
	if (!isOpen('templatetable')) { build_templatetable(shorthelp_template,null,true); push_stack(999); }
	else closeWindow('templatetable');
};
function clear_template () {
	var n = countTemplates(template); template.length = 0;
	if (n>0) build_templatetable(n.toString()+' templates cleared.')
	else build_templatetable('No templates.');
	setClipboard('id_template','');
};
function changed_template (ctrl) {
	if (ctrl.value.length>0) {
		if (autoimport) import_template()
		else header_msg('id_templatemessage',shorthelp_autoimport);
};	};
function import_template () {
	build_templatetable(templatelist_import(document.getElementById('id_template').value,template));
	focusClipboard('id_template');
};
function import_example_template () {
	build_templatetable(templatelist_import(get_example_template(),template));
	focusClipboard('id_template');
};
function template_export () {
	header_msg('id_templatemessage',templatelist_export(template,'id_template'));
};
function mouseout_template ()		{ /*header_msg('id_templatemessage',null,-1);*/ };
function mouseover_template (ctrl)	{ header_msg('id_templatemessage',mouseover_templatetag(ctrl,template),-1); };
//function templateadd_thesaurus ()	{ header_msg('id_templatemessage',all_templates_to_thesaurus(template)); };
function msoverthb_template ()		{ thesaurus_warning('id_templatemessage',1); };
function msoutthb_template ()		{ thesaurus_warning('id_templatemessage',0); };
function clicked_template (ctrl) {
	var t = new String("");
	if (template.length>0) {
		var pt = parseInt_(ctrl.id.substring(1));
		var nt = template[pt]; pt++;
		if (nt>0) {
			var list = new Array("");
			for (var i=0; i<nt; i++) { list[i] = template[pt]; pt++; }
			var duplist = ListInTags(list);
			if (tag_added>1)		var tmx = tag_added.toString() + ' tags added from template. '
			else if (tag_added=1)	var tmx = 'One tag added from template. '
			else 					var tmx = 'No tags added from template. ';
			if (tag_duplicate>=0) {
				tmx = tmx + 'Tag(s) already there: <i>' + duplist.substring(1) + '</i>.';
				tag_treated = tag_duplicate;
				tag_duplicateflag = true;
			};
			build_tagstable(tmx);
};	};	};

// ____ priority events _____________________________________________________________________________________

function openclose_priority () {
	if (!isOpen('prioritytable')) { build_prioritytable(shorthelp_priority,null,true); push_stack(999); }
	else closeWindow('prioritytable');
};
function clear_priority () {
	var n = countTemplates(priority); priority.length = 0;
	if (n>0) build_prioritytable(n.toString()+' priority templates cleared.')
	else build_prioritytable('No priority templates.',null,true);
	setClipboard('id_priority','');
};
function changed_priority (ctrl) {
	if (ctrl.value.length>0) {
		if (autoimport) import_priority()
		else header_msg('id_prioritymessage',shorthelp_autoimport);
};	};
function import_priority () {
	build_prioritytable(templatelist_import(document.getElementById('id_priority').value,priority));
	focusClipboard('id_priority');
};
function import_example_priority () {
	build_prioritytable(templatelist_import(get_example_priority(),priority));
	focusClipboard('id_priority');
};
function priority_export () {
	header_msg('id_prioritymessage',templatelist_export(priority,'id_priority'));
};
function mouseout_priority ()		{ /*header_msg('id_prioritymessage',null,-1);*/ };
function mouseover_priority (ctrl)	{ header_msg('id_prioritymessage',mouseover_templatetag(ctrl,priority),-1); };
//function priorityadd_thesaurus ()	{ header_msg('id_prioritymessage',all_templates_to_thesaurus(priority)); };
function msoverthb_priority ()		{ thesaurus_warning('id_prioritymessage',1); };
function msoutthb_priority ()		{ thesaurus_warning('id_prioritymessage',0); };
function clicked_priority (ctrl) {
	if (tags.length>0) {
		if (priority.length>0) {
			var pt = parseInt_(ctrl.id.substring(1));
			var nt = priority[pt]; pt++;
			if (nt>0) {
				tagscopy = new Array(); tagsnew = new Array(); var n = 0; var word = new String("");
				var j = 0; var pts = new String(""); var nmx = -1;
				for (var i=0; i<tags.length; i++) tagscopy[i] = tags[i];
				if (tag_cursor>0) for (i=0; i<tag_cursor; i++) { tagsnew[n] = tagscopy[i]; n++; tagscopy[i] = ''; };
				for (i=pt; i<(pt+nt); i++) {
					word = priority[i];
					for (j=0; j<tagscopy.length; j++)
						if (word==tagscopy[j]) {
							pts = pts + word + '</u> ';
							tagsnew[n] = word; n++; nmx = n;
							tagscopy[j] = '';
						};
				};
				for (i=0; i<tagscopy.length; i++) if (tagscopy[i].length>0) { tagsnew[n] = tagscopy[i]; n++; };
				for (i=0; i<tagsnew.length; i++) tags[i] = tagsnew[i];
				tags.length = tagsnew.length;
				if (nmx>0) tag_cursor = nmx;
				if (pts.length>0) {	var mx = 'Prioritized: <i><u>' + pts + '</i>.';
									var my = 'Tags were prioritized from the priority template.<br>'+mx; }
				else {				var mx = 'No tags were prioritized.';
									var my = 'Tags to prioritize not present or already at cursor.<br>'+mx; };
				header_msg('id_prioritymessage',mx);
				build_tagstable(my);
			}
			else header_msg('id_prioritymessage','Template is empty. Nothing to prioritize.',0);
		}
		else header_msg('id_prioritymessage','No templates. Nothing to prioritize.',0);
	}
	else header_msg('id_prioritymessage','No tags to prioritize.',0);
};

// ____ thesaurus events _____________________________________________________________________________________

function openclose_thesaurus () {
	if (!isOpen('thesaurustable')) { build_thesaurustable(shorthelp_thesaurus,null,true); push_stack(999); }
	else closeWindow('thesaurustable');
};
function clear_thesaurus () {
	var n = thesaurus.length;
	thesaurus.length = 0; thesaurus_lc.length = 0;
	standardthesaurusflag = false;
	if (n>0) {
		build_thesaurustable(n.toString()+' thesaurus items removed.');
		if (tags_mode==4) build_tagstable('Thesaurus was emptied.');
	}
	else build_thesaurustable('Thesaurus empty.',null,true);
	setClipboard('id_thesaurus','');
};
function changed_thesaurus (ctrl) {
	if (ctrl.value.length>0) {
		if (autoimport) {
			if (thesaurus.length>25000)
				header_msg('id_thesaurusmessage','Large thesaurus ('+thesaurus.length.toString()+
					' tags) might lead to delays importing thesaurus clipboard.<br>'+
					'When your browser warns for busy script, just continue and be patient.'+
					'<br>Click on <i>green arrow up button</i> in this window to import.',1);
			else if (ctrl.value.length>200000)
				header_msg('id_thesaurusmessage','Large thesaurus clipboard ('+ctrl.value.length.toString()+
					' characters) might lead to delays importing thesaurus.<br>'+
					'When your browser warns for busy script, just continue and be patient.'+
					'<br>Click on <i>green arrow up button</i> in this window to import.',1);
			else thesaurus_import()
		}
		else header_msg('id_thesaurusmessage',shorthelp_autoimport);
};	};
function thesaurus_import (standardflag) {
	var list = new Array("");
	if (standardflag==null)	{
		var n = document.getElementById('id_thesaurus').value.length; 
		if (n>200000) {
			if(!confirm(	'Large thesaurus clipboard ('+n.toString()+' characters) might lead to delays importing thesaurus.\n'+
							'When your browser warns for busy script, just continue and be patient.')) return;
		};
		StringToList(document.getElementById('id_thesaurus').value,list);
		standardthesaurusflag = false;
	}
	else {
		header_msg(	'id_thesaurusmessage','Large standard thesaurus might lead to delays importing thesaurus.<br>'+
					'When your browser warns for busy script, just continue and be patient.',1);
		if (confirm('Large standard thesaurus might lead to delays importing thesaurus.\n'+
					'When your browser warns for busy script, just continue and be patient.')) {
			thesaurus.length = 0; thesaurus_lc.length = 0;
			StringToList(get_fixed_thesaurus(),list);
			standardthesaurusflag = true;
		}
		else return
	};
	var npv = thesaurus.length;
	if (standardthesaurusflag)	var tmx = 'Standard thesaurus present.<br>'
	else						var tmx = 'Custom thesaurus present.<br>';
	tmx = tmx + thesaurus_addarray(list);
	if (tags_mode==4) {
		if (thesaurus.length>npv) build_tagstable(tmx,null,true)
		else header_msg('id_tagsmessage',tmx,null);
	};
	if (thesaurus.length>npv) rebuild_thesaurus(tmx)
	else header_msg('id_thesaurusmessage',tmx,null);
	focusClipboard('id_thesaurus');
};
function thesaurus_export (list) {
	if (list==null) {
		var t = new String();
		if (thesaurus.length>0) {
			var n = 0; t = '(\n"'; var nmax = 20;
			for (var i=0;i<thesaurus.length;i++) {
				t = t + thesaurus[i] + ',';
				if (i>=(thesaurus.length-1))	t = t + '"\n)'
				else if (n>=(nmax-1))			{ t = t + '"+\n"'; n = 0; }
				else							n++;
	};	};	}
	else var t = list.join(getSeparator());
	setClipboard('id_thesaurus',t);
	if (t.length>0) {
		if (standardthesaurusflag)	var tmt = 'Standard'
		else						var tmt = 'Custom';
		header_msg('id_thesaurusmessage',tmt+" thesaurus exported to the clipboard.<br>Press <i>CTRL-C</i> to copy the clipboard to the system clipboard, then to a thesaurus file on your disk. Don't forget to save that file for later retrieval and re-use.")
	}
	else header_msg('id_thesaurusmessage','No thesaurus items to export.');
};
function clicked_thesaurus () {
	var n = thesaurus.length; if (n>0) {
		if (n==1) var tmx = 'Thesaurus contains one tag (<i>' + thesaurus[0] + '</i>). '
		else {
			var l = 0; var lmin = 10000; var lmax = 0; var tmax = new String(""); var totll = 0.0;
			for (var i=0; i<n; i++) {
				l = thesaurus[i].length;
				totll = totll + l;
				if (l<lmin) lmin = l;
				if (l>lmax) { lmax = l; tmax = thesaurus[i]; };
			};
			var tmx = 'Thesaurus contains ' + n.toString() + ' tags.' +
					'<br>Shortest tag is ' + lmin.toString() + ' characters, longest tag (<i>' + tmax + '</i>) is ' + lmax.toString() +
					' characters. Mean tag length = ' + Math.round(totll/n) + ' characters. ';
		};
	} else var tmx = 'Thesaurus empty. ';
	n = thesaurus_lc.length; if (n>0) {
		if (n==1) tmx = tmx + '<br>Case thesaurus contains one tag (<i>' + thesaurus_lc[0] + '</i>).'
		else {
			lmin = 10000; lmax = 0; tmax = ''; totll = 0.0;
			for (i=0; i<n; i++) {
				l = thesaurus_lc[i].length;
				totll = totll + l;
				if (l<lmin) lmin = l;
				if (l>lmax) { lmax = l; tmax = thesaurus_lc[i]; };
			};
			tmx = tmx + '<br>Case thesaurus contains ' + n.toString() + ' tags.' +
					'<br>Shortest tag is ' + lmin.toString() + ' characters, longest tag (<i>' + tmax + '</i>) is ' + lmax.toString() +
					' characters. Mean tag length = ' + Math.round(totll/n) + ' characters.';
		};
	} else var tmx = tmx + 'Case thesaurus empty.';
	header_msg('id_thesaurusmessage',tmx);
};
function thesaurus_addarray (a) {
	var npv = thesaurus.length; var npv_lc = thesaurus_lc.length;
	var tkn = new String(""); // report first word from a that is not added
	if (a.length>0) {
		var notthere = false;
		for (var i=0; i<a.length; i++)
			if (isInList(a[i],thesaurus)) tkn = a[i]
			else { notthere = true; break; };
		if (notthere) {
			var temp = new Array();
			temp.length = 0; var nlc = 0;
			var temp_uc = new Array(); // can be omitted in production version when no uppercase thesaurus needed
			//for (i=0; i<a.length; i++) if (anyUpperCase(a[i])) { temp[nlc] = a[i].toLowerCase(); nlc++; };
			for (i=0; i<a.length; i++) if (anyUpperCase(a[i])) { temp_uc[nlc] = a[i]; temp[nlc] = a[i].toLowerCase(); nlc++; }; // can be exchanged in production version when no uppercase thesaurus needed
			var temp_lc = thesaurus_lc.concat(temp);
			thesaurus_lc = temp_lc;
			temp_lc = thesaurus_uc.concat(temp_uc); // can be omitted in production version when no uppercase thesaurus needed
			thesaurus_uc = temp_lc; // can be omitted in production version when no uppercase thesaurus needed
			SortRemoveDuplicates(thesaurus_lc);
			temp.length = 0; temp = a.concat(thesaurus); temp.sort();
			var word = new String(""); var cword = new String(""); var n = 0;
			for (i=0; i<temp.length; i++) {
				word = temp[i];
				if (word!=cword) { cword = word; thesaurus[n] = word; n++;
			};	};
			thesaurus.length = n;
	};	};
	n = thesaurus.length; var nad = n - npv; var na = a.length; n = na - nad;
	if (nad>1) { // more added
							var tmx	= 'Thesaurus updated with ' + nad.toString() + ' tags. '
		if (n>1)			tmx		= tmx + n.toString() + ' tags were already there. '
		else if (n==1)		tmx		= tmx + 'Tag <i>' + tkn + '</i> was already there. ';
	}
	else if (nad==1) { // one added
		if (na==1)			var tmx	= 'Tag <i>' + a[0] + '</i> added to the thesaurus. '
		else {
			if (n>1)		var tmx	= 'One tag was added to the thesaurus. ' + n.toString() + ' tags were already there. '
			else			var tmx	= 'Tag <i>' + tkn + '</i> added to the thesaurus. ';
		};
	}
	else { // nothing added
		if (na>1)			var tmx	= 'All ' + na.toString() + ' tags are already in the thesaurus. '
		else if (na==1)		var tmx	= 'Tag <i>' + a[0] + '</i> is already in the thesaurus. '
		else				var tmx	= 'Nothing to add to the thesaurus. ';
	};
	if (thesaurus.length>0) {
		n = thesaurus_lc.length; nad = n - npv_lc;
		if (nad>1) { // more added
								tmx		= tmx + 'Case thesaurus updated with ' + nad.toString() + ' tags. '
		}
		else if (nad==1) { // one added
								tmx		= tmx + 'Case thesaurus updated with one tag. '
		};
		n = thesaurus.length;
		if (n>1)				tmx		= tmx + n.toString() + ' tags now in the thesaurus. '
		else if (n==1)			tmx		= tmx + 'One tag (<i>' + thesaurus[0] + '</i>) now in the thesaurus. '
		else					tmx		= tmx + 'Thesaurus now empty. ';
		n = thesaurus_lc.length;
		if (n>1)				tmx		= tmx + n.toString() + ' tags now in the case thesaurus.'
		else if (n==1)			tmx		= tmx + 'One tag (<i>' + thesaurus_lc[0] + '</i>) now in the case thesaurus.'
		else					tmx		= tmx + 'Case thesaurus now empty.';
	};
	return tmx;
};
function thesaurus_warning (id, type) {
	var n = thesaurus.length;
	if (type>0) {
		 if (n>25000)		header_msg(id,'Very large thesaurus: long delays possible updating or matching.',1)
		 else if (n>3000)	header_msg(id,'Large thesaurus: some delays possible updating or matching.',1);
	} else {
		 if (n>3000)		header_msg(id,'&nbsp;',-1);
};	};
function thesaurus_warning_tags (id, type) {
	if (tags.length>0) {
		if (standardthesaurusflag)	var tst = 'standard thesaurus'
		else						var tst = 'custom thesaurus';
		if (alltagsinthesaurus)		header_msg(id,'All tags already in '+tst+'.')
		else {
			var n = thesaurus.length;
			if (type>0) {
				 if (n>25000)		header_msg(id,'Very large '+tst+': long delays possible updating or matching.',1)
				 else if (n>3000)	header_msg(id,'Large '+tst+': some delays possible updating or matching.',1);
			} else {
				 if (n>3000)		header_msg(id,'&nbsp;',-1);
};	};	};	};

// ____ tools events _____________________________________________________________________________________

function openclose_tools () {
	if (!isOpen('toolstable')) { build_toolstable(shorthelp_tools,null,true); push_stack(999); }
	else closeWindow('toolstable');
};
function quote_clicked(ctrl)		{ quote_mode		= parseInt_(ctrl.value); };
function separator_clicked(ctrl)	{ separator_mode	= parseInt_(ctrl.value); };
function clicked_autoimport(ctrl)	{ autoimport		= ctrl.checked; };
function clicked_incompat(ctrl)		{ incompat_forbid	= ctrl.checked; build_tagstable(null,-1,true); };
//function clicked_nocase(ctrl)		{ thesmatch_nocase	= ctrl.checked; };
function colsbox_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n<1) n = 1; if (n>12) n = 12;
	if (n!=tags_ncols) { tags_ncols = n; changed_tables('Tags columns changed'); };
};
function screenwidth_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n<300) n = 300; if (n>2048) n = 2048;
	if (n!=screen_width) { screen_width = n; changed_tables('Screen width changed'); };
};
function rowstxt_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n<1) n = 1; if (n>200) n = 200;
	if (n!=clipboard_nrows) { clipboard_nrows = n; changed_tables('Clipboard rows changed'); };
};
function colstxt_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n<20) n = 20; if (n>200) n = 200;
	if (n!=clipboard_ncols) { clipboard_ncols = n; changed_tables('Clipboard columns changed'); };
};
function tagslimit_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n!=tags_limit) {
		tags_limit = n;
		if (n<1) build_tagstable('Number of characters exceeded not shown by red block.',null,true)
		else build_tagstable('Number of '+n.toString()+' characters exceeded shown by red block.',null,true);
		push_stack(999);
};	};
function tagslimitn_changed (ctrl) {
	var n = parseInt_(ctrl.value);
	if (n!=tags_limitn) {
		tags_limitn = n;
		if (n<1) build_tagstable('Number of tags exceeded not shown by red block.',null,true)
		else build_tagstable('Number of '+n.toString()+' tags exceeded shown by red block.',null,true);
		push_stack(999);
};	};
function changed_tables (mx) {
	var t = new String("");
	push_stack(999);
	dontstack = true;
	rebuild_help (mx);
	rebuild_banner (mx);
	rebuild_tools (mx);
	rebuild_buttons (mx);
	rebuild_tags (mx);
	rebuild_clipboard (mx);
	rebuild_template (mx);
	rebuild_priority (mx);
	rebuild_thesaurus (mx);
	dontstack = false;
};
function rebuild_help (msg, type, rollbackbusy) {
	if (isOpen('helptable')) build_helptable(msg,type);
};
function rebuild_banner (msg, type, rollbackbusy) {
	if (isOpen('banner')) build_banner(msg,type,rollbackbusy);
};
function rebuild_tools (msg, type, rollbackbusy) {
	if (isOpen('toolstable')) build_toolstable(msg,type,rollbackbusy);
};
function rebuild_buttons (msg, type, rollbackbusy) {
	if (isOpen('buttonstable')) build_buttonstable(msg,type,rollbackbusy);
};
function rebuild_tags (msg, type, rollbackbusy) {
	if (isOpen('tagstable')) build_tagstable(msg,type,rollbackbusy);
};
function rebuild_clipboard (msg, type, rollbackbusy) {
	if (isOpen('clipboardtable')) {
		var t = document.getElementById('id_clipboard').value; build_clipboardtable(msg,type,rollbackbusy);
		document.getElementById('id_clipboard').value = t;
};	};
function rebuild_thesaurus (msg, type, rollbackbusy) {
	if (isOpen('thesaurustable')) {
		var t = document.getElementById('id_thesaurus').value; build_thesaurustable(msg,type,rollbackbusy);
		document.getElementById('id_thesaurus').value = t;
};	};
function rebuild_priority (msg, type, rollbackbusy) {
	if (isOpen('prioritytable')) {
		var t = document.getElementById('id_priority').value; build_prioritytable(msg,type,rollbackbusy);
		document.getElementById('id_priority').value = t;
};	};
function rebuild_template (msg, type, rollbackbusy) {
	if (isOpen('templatetable')) {
		var t = document.getElementById('id_template').value; build_templatetable(msg,type,rollbackbusy);
		document.getElementById('id_template').value = t;
};	};

// ____ stuff _____________________________________________________________________________________

function StringToListwithUniques (str, list) {
// input: str; output in list (array) and in function result (string, duplicates)
	StringToList(str,list);
	return RemoveDuplicatesFromUnsortedList(list);
};

function templatelist_export (a, id) {
// input in a (array), id: id of clipboard; output function result is diagnostic text
	var t = new String(""); var size = 0; var j = 0; var nn = 0; var nt = 0;
	var list = new Array("");
	if (a.length>0) for (var i=0; i<a.length; i++) {
		size = a[i];
		if (size>0) {
			nn++;
			list.length = 0; nt = 0;
			for (j=(i+1); j<=(i+size); j++) { list[nt] = a[j]; nt++; };
			t = t + list.join(getSeparator(0));
		};
		t = t + '\n';
		i = i + size;
	};
	setClipboard(id,t);
	if (nn>0) {
		if (nn==1) var tmx = 'One template'
		else var tmx = nn.toString() + ' templates';
		return tmx + " exported to the clipboard.<br>Press <i>CTRL-C</i> to copy the clipboard to the system clipboard, then to a file on your disk. Don't forget to save that file for later retrieval and re-use."
	}
	else return 'No templates to export.';
};

function templatelist_import (t, a) {
// input: t; updated a (array) and function result is diagnostic string
	var npv = countTemplates(a); var nad = 0; var tad = new String(""); var nud = 0; var tud = new String("");
	var nn = a.length; var tn = t + '\n'; var tnl = new String(""); var j = 0; var list = new Array("");
	for (var i=0; i<tn.length; i++) 
		if (tn.charAt(i)=='\n') {
			StringToListwithUniques (tnl,list);
			if (list.length>0) {
				a[nn] = list.length; nn++; nad++; tad = tad + ' ' + list[0];
				for (j=0; j<list.length; j++) { a[nn] = list[j]; nn++; };
			};
			tnl = '';
		}
		else tnl = tnl + tn.charAt(i);
// sort a according to template name, remove duplicate templates
	if (a.length>0) { // make array of non-duplicate template names
		var tempfirst = new Array("");
		var size = 0; var ntf = 0; var word = new String("");
		for (i=0; i<a.length; i++) {
			size = a[i];
			word = a[i+1];
			if (word.length>0) {
				if (ntf>0) { for (j=0; j<ntf; j++) if (tempfirst[j]==word) { tud = tud + ' ' + word; nud++; word = ''; a[i+1] = ''; break }; };
				if (word.length>0) { tempfirst[ntf] = word; ntf++; };
			};
			i = i + size;
		};
//
		if (tempfirst.length>0) {
			tempfirst.sort();
			var tempnew = new Array ("");
			var ntn = 0; var k = 0;
			for (i=0; i<tempfirst.length; i++) {
				word = tempfirst[i];
				if (word.length>0) {
					for (j=0; j<a.length; j++) {
						size = a[j];
						if (word==a[j+1]) {
							tempnew[ntn] = size; ntn++;
							if (size>0) for (k=(j+1); k<=(j+size); k++) { tempnew[ntn] = a[k]; ntn++; };
						};
						j = j + size;
			};	};	};
			a.length = 0;
			if (tempnew.length>0) for (i=0; i<tempnew.length; i++) a[i] = tempnew[i];
		} else a.length = 0;
	};
// report
	nn = countTemplates(a);
	if (nn<1)			var tmx = 'No templates. '
	else if (nn==1)		var tmx = 'One template (<i>' + a[1] + '</i>). '
	else				var tmx = nn.toString() + ' templates. ';
	nn = nn - npv;
	if (nn<1)			tmx = tmx + 'No templates added. '
	else if (nn==1)		tmx = tmx + 'One template added. '
	else				tmx = tmx + ' ' + nn.toString() + ' templates added. ';
	if (nad>1)			tmx = tmx + ' ' + nad.toString() + ' templates were on the clipboard:<i>' + tad + '</i>). '
	else if (nad==1)	tmx = tmx + 'One template was on the clipboard:<i>' + tad + '</i>. '
	else				tmx = tmx + 'Clipboard was empty. ';
	if (nud>1)			tmx = tmx + '<br>' + nud.toString() + ' duplicates not added:<i>' + tud + '</i>.'
	if (nud==1)			tmx = tmx + '<br>Duplicate not added:<i>' + tud + '</i>.';
	return tmx;
};

/*function all_templates_to_thesaurus (a) {
	var list = new Array();
	if (a.length>0) {
		var n = 0; var k = 0; var size = 0;
		for (var i=0; i<a.length; i++) {
			size = a[i];
			if (size>0)	for (k=(i+1); k<=(i+size); k++) { list[n] = a[k]; n++; };
			i = i + size;
	};	};
	var npv = thesaurus.length;
	var tmx = thesaurus_addarray(list);
	if (tags_mode==4) {
		if (thesaurus.length>npv) build_tagstable(tmx,null,true)
		else header_msg('id_tagsmessage',tmx,null);
	};
	return tmx;
};*/

function getSeparator (nonewline) {
	switch (separator_mode) {
		case 0:		{ return ",";	break; };
		case 1:		{ return ";";	break; };
		case 2:		{ return " ";	break; };
		case 3:		{	if (nonewline!=null) return ", "
						else return "\n"; break; };
		case 4:		{ return ", ";	break; };
		case 5:		{ return "; ";	break; };
		case 6:		{	if (nonewline!=null) return ", "
						else return ", \n"; break; };
		default:	{ return "|";	break; };
	};
};

function closeWindow (id) { document.getElementById(id).innerHTML = ''; push_stack(999); };

function focusClipboard (id) {
	var thisID = document.getElementById(id);
	thisID.select();
	thisID.focus();
};
function setClipboard (id, t) {
	document.getElementById(id).value = t;
	focusClipboard(id);
};
function isOpen (id) {
	return (document.getElementById(id).innerHTML.length>0);
};
function countTemplates (a) {
	var n = 0; var size = 0;
	if (a.length>0) for (var i=0; i<a.length; i++) { size = a[i]; if (a[i+1].length>0) n++; i = i + size; };
	return n;
};
function mouseover_templatetag (ctrl, a) {
	var pt = parseInt_(ctrl.id.substring(1));
	var nt = a[pt]; pt++;
	if (nt>10)	{ var e = '&nbsp;...&nbsp;(<i>'+(nt-10).toString()+'&nbsp;more</i>)'; nt = 10 }
	else		var e = '';
	var pta = new String("<u>");
	if (nt>0) for (i=pt; i<(pt+nt); i++) pta = pta + a[i] + '</u> ';
	return pta+e;
};

function incompatibles () {
	if (tags.length<1) { incompat[0] = false; return false; };
	for (var i=0; i<tags.length; i++) incompat[i] = false;
	var a = new Array('nude','nudes','nudo','naked','sexy','sexier','sexiest','sex','erotic','erotical','erotically');
	var athere = false; for (i=0; i<a.length; i++) if (isInUnsortedList(a[i],tags)>=0) { athere = true; break; };
	if (!athere) return false;
	var b = new Array('teen','teens','teenager','teenagers','underage','minor','minors','kid','kids','child','children','baby','babies','toddler','toddlers');
	var bthere = false; for (i=0; i<b.length; i++) if (isInUnsortedList(b[i],tags)>=0) { bthere = true; break; };
	if (!bthere) return false;
	var p = 0;
	for (i=0; i<a.length; i++) { p = isInUnsortedList(a[i],tags); if (p>=0) incompat[p] = true; };
	for (i=0; i<b.length; i++) { p = isInUnsortedList(b[i],tags); if (p>=0) incompat[p] = true; };
	return true;
};

// ____ do-redo _____________________________________________________________________________________

function push_stack (type) {
// type 0 = tags, 1 = templates, 2 = priority templates, 3 = thesaurus
	if (dontstack) return;
	var n = stack.length;
	stackptr = current_rollback;
	stackindex[stackptr] = n;
		//var ttt = '<br>'; for (var k=0; k<stackindex.length; k++) ttt = ttt + stackindex[k] + ' ';
		var ttt = '';
		debug('toSTACK '+current_rollback.toString()+' stackpointer='+n.toString()+' type='+type.toString()+ttt);
	stackptr++;	current_rollback = stackptr;
	stack[n] = type; n++;
	stack[n] = tags_ncols; n++;
	stack[n] = clipboard_nrows; n++;
	stack[n] = clipboard_ncols; n++;
	stack[n] = screen_width; n++;
	stack[n] = tag_cursor; n++;
	stack[n] = tags_mode; n++;
	stack[n] = tag_treated; n++;
	stack[n] = tag_insert; n++;
	stack[n] = tag_duplicateflag; n++;
	//stack[n] = thesmatch_nocase; n++;
	stack[n] = tags_limit; n++;
	stack[n] = tags_limitn; n++;
	stack[n] = isOpen('helptable'); n++;
	stack[n] = isOpen('toolstable'); n++;
	stack[n] = isOpen('templatetable'); n++;
	stack[n] = isOpen('prioritytable'); n++;
	stack[n] = isOpen('thesaurustable'); n++;
	switch (type) {
		case 0: { // tags
			stack[n] = tags.length; n++;
			if (tags.length>0) for (var i=0; i<tags.length; i++) { stack[n] = tags[i]; n++; };
			break;
		};
		case 1: { // template
			stack[n] = template.length; n++;
			if (template.length>0) for (var i=0; i<template.length; i++) { stack[n] = template[i]; n++; };
			break;
		};
		case 2: { // priority template
			stack[n] = priority.length; n++;
			if (priority.length>0) for (var i=0; i<priority.length; i++) { stack[n] = priority[i]; n++; };
			break;
		};
		case 3: { // thesaurus
			stack[n] = thesaurus.length; n++;
			if (thesaurus.length>0) for (var i=0; i<thesaurus.length; i++) { stack[n] = thesaurus[i]; n++; };
			stack[n] = thesaurus.length; n++;
			if (thesaurus_lc.length>0) for (i=0; i<thesaurus_lc.length; i++) { stack[n] = thesaurus_lc[i]; n++; };
			break;
		};
	};
	stack.length = n;
	stackindex[stackptr] = n; // safety, shouldn't be necessary
	stack[n] = -1; // safety, shouldn't be necessary
};

function unredo (undoflag) {
// type 0 = tags, 1 = templates, 2 = priority templates, 3 = thesaurus
	if (undoflag) {
		if (current_rollback<1) { current_rollback = 0; header_msg('id_tagsmessage',"No more undo's possible."); return; }
		else current_rollback--;
	}
	else {
		current_rollback++;
		if (current_rollback>=stackptr) { current_rollback = stackptr; header_msg('id_tagsmessage',"No more redo's possible."); return; };
	};
	dontstack = true;
	var n = stackindex[current_rollback];
	var msg = 'Rollback at level '+current_rollback.toString()+'.';
	var type = stack[n]; n++;
		//var ttt = '<br>'; for (var k=0; k<stackindex.length; k++) ttt = ttt + stackindex[k] + ' ';
		var ttt = '';
		debug('DO/UNDO '+current_rollback.toString()+'/'+stackptr.toString()+' stackpointer='+(n-1).toString()+' type='+type.toString()+ttt);
	if (type<0) { alert ('Bad stack'); };  // safety, shouldn't be necessary
//
	var rb_banner = false;		var rb_help = false;		var rb_buttons = false;		var rb_tags = false;		var rb_tools = false; 
	var rb_template = false;	var rb_priority = false;	var rb_thesaurus = false;	var rb_clipboard = false;
	var p = 0;
	p = tags_ncols;			tags_ncols = stack[n];		n++; if (p!=tags_ncols)				{ rb_tags = true; rb_template = true; rb_priority = true; rb_tools = true; };
	p = clipboard_nrows;	clipboard_nrows = stack[n];	n++; if (p!=clipboard_nrows)		{ rb_clipboard = true; rb_template = true; rb_priority = true; rb_thesaurus = true; rb_tools = true; };
	p = clipboard_ncols;	clipboard_ncols = stack[n];	n++; if (p!=clipboard_ncols)		{ rb_clipboard = true; rb_template = true; rb_priority = true; rb_thesaurus = true; rb_tools = true; };
	p = screen_width;		screen_width = stack[n];	n++; if (p!=screen_width)			{ rb_banner = true; rb_buttons = true; rb_tags = true; rb_clipboard = true; rb_template = true; rb_priority = true; rb_thesaurus = true; rb_tools = true; };
	p = tag_cursor;			tag_cursor = stack[n];		n++; if (p!=tag_cursor)				{ rb_tags = true; rb_tools = true; };
	p = tags_mode;			tags_mode = stack[n];		n++; if (p!=tags_mode)				{ rb_buttons = true; rb_tags = true; rb_tools = true; };
	p = tag_treated;		tag_treated = stack[n];		n++; if (p!=tag_treated)			{ rb_tags = true; rb_tools = true; };
	p = tag_insert;			tag_insert = stack[n];		n++; if (p!=tag_insert)				{ rb_tags = true; rb_tools = true; };
	p = tag_duplicateflag;	tag_duplicateflag = stack[n];	n++; if (p!=tag_duplicateflag)	{ rb_tags = true; rb_tools = true; };
	//p = thesmatch_nocase;	thesmatch_nocase = stack[n];n++; if (p!=thesmatch_nocase)	{ rb_tags = true; rb_tools = true; };
	p = tags_limit;			tags_limit = stack[n];		n++; if (p!=tags_limit)				{ rb_tags = true; rb_tools = true; };
	p = tags_limitn;		tags_limitn = stack[n];		n++; if (p!=tags_limitn)			{ rb_tags = true; rb_tools = true; };
	var help_open		= (stack[n]); n++;
	var tools_open		= (stack[n]); n++;
	var template_open	= (stack[n]); n++;
	var priority_open	= (stack[n]); n++;
	var thesaurus_open	= (stack[n]); n++;
	switch (type) {
		case 0: { // tags
			var l = stack[n]; n++; tags.length = 0;
			if (l>0) for (var i=0; i<l; i++) { tags[i] = stack[n]; n++; };
			rb_tags = true;
			break;
		};
		case 1: { // template
			var l = stack[n]; n++; template.length = 0;
			if (l>0) for (var i=0; i<l; i++) { template[i] = stack[n]; n++; };
			rb_template = true;
			break;
		};
		case 2: { // priority template
			var l = stack[n]; n++; priority.length = 0;
			if (l>0) for (var i=0; i<l; i++) { priority[i] = stack[n]; n++; };
			rb_priority = true;
			break;
		};
		case 3: { // thesaurus
			var l = stack[n]; n++; thesaurus.length = 0;
			if (l>0) for (var i=0; i<l; i++) { thesaurus[i] = stack[n]; n++; };
			l = stack[n]; n++; thesaurus_lc.length = 0;
			if (l>0) for (i=0; i<l; i++) { thesaurus_lc[i] = stack[n]; n++; };
			rb_thesaurus = true;
			break;
		};
	};
	if (help_open) build_helptable(msg,null,true)
	else closeWindow('helptable');
	if (tools_open) build_toolstable(msg,null,true)
	else closeWindow('toolstable');
	if (template_open) build_templatetable(msg,null,true)
	else closeWindow('templatetable');
	if (priority_open) build_prioritytable(msg,null,true)
	else closeWindow('prioritytable');
	if (thesaurus_open) build_thesaurustable(msg,null,true)
	else closeWindow('thesaurustable');
	if (rb_help)		rebuild_help(msg,null,true);
	if (rb_banner)		rebuild_banner(msg,null,true);
	if (rb_buttons)		rebuild_buttons(msg,null,true);
	if (rb_tags)		rebuild_tags(msg,null,true);
	if (rb_clipboard)	rebuild_clipboard(msg,null,true);
	if (rb_template)	rebuild_template(msg,null,true);
	if (rb_priority)	rebuild_priority(msg,null,true);
	if (rb_thesaurus)	rebuild_thesaurus(msg,null,true);
	if (rb_tools)		rebuild_tools(msg,null,true);
	dontstack = false;
};
function debug (tx) {
	if (debug_flag) document.getElementById('debug').innerHTML =
		table_begin(screen_width.toString()+"px") + tdc_begin(tx) + td_end() + table_end();
};

// ____ help _____________________________________________________________________________________

function set_advanced (simple) {
	if (isOpen('tagstable'))		rebuild_tags(tagsmode_msg(0,0),null,true)
	else							build_tagstable(tagsmode_msg(0,0),null,true);
	if (isOpen('clipboardtable'))	rebuild_clipboard(tinyhelp_clipboard,null,true)
	else							build_clipboardtable(tinyhelp_clipboard,null,true);
	if (simple==null) {
		if (isOpen('templatetable'))	rebuild_template(tinyhelp_template,null,true)
		else							build_templatetable(tinyhelp_template,null,true);
		if (isOpen('prioritytable'))	rebuild_priority(tinyhelp_priority,null,true)
		else							build_prioritytable(tinyhelp_priority,null,true);
		if (isOpen('thesaurustable'))	rebuild_thesaurus(tinyhelp_thesaurus,null,true)
		else							build_thesaurustable(tinyhelp_thesaurus,null,true);
		if (isOpen('toolstable'))		rebuild_tools(tinyhelp_tools,null,true)
		else							build_toolstable(tinyhelp_tools,null,true);
		push_stack(999);
	} else {
		closeWindow('templatetable');
		closeWindow('prioritytable');
		closeWindow('thesaurustable');
		closeWindow('toolstable');
		closeWindow('helptable');
};	};
function set_beginner (simple) {
	if (isOpen('tagstable'))		rebuild_tags(shorthelp_tags,null,true)
	else							build_tagstable(shorthelp_tags,null,true);
	if (isOpen('clipboardtable'))	rebuild_clipboard(shorthelp_clipboard,null,true)
	else							build_clipboardtable(shorthelp_clipboard,null,true);
	if (simple==null) {
		if (isOpen('helptable'))		{ help_mode = 7; rebuild_help(null,-1,true); }
		else							{ help_mode = 7; build_helptable(null,-1,true); };
		if (isOpen('templatetable'))	rebuild_template(shorthelp_template,null,true)
		else							build_templatetable(shorthelp_template,null,true);
		if (isOpen('prioritytable'))	rebuild_priority(shorthelp_priority,null,true)
		else							build_prioritytable(shorthelp_priority,null,true);
		if (isOpen('thesaurustable'))	rebuild_thesaurus(shorthelp_thesaurus,null,true)
		else							build_thesaurustable(shorthelp_thesaurus,null,true);
		if (isOpen('toolstable'))		rebuild_tools(shorthelp_tools,null,true)
		else							build_toolstable(shorthelp_tools,null,true);
		push_stack(999);
	} else {
		closeWindow('templatetable');
		closeWindow('prioritytable');
		closeWindow('thesaurustable');
		closeWindow('toolstable');
		closeWindow('helptable');
};	};
function build_helptable(msg, type) {
	var s = build_tabletop('ordbackground','c_info.png','Help','id_helpmessage') +
	build_button('right','help_mode=0;build_helptable(null,-1)','c_help.png','Show help on this program') +
	build_button('right','closeWindow(&#39;helptable&#39;)','c_close.png','Close window') +
	build_tablemiddle('Help','id_helpcontent') +
	table_end() + td_end();
	build_tablebottom(s,'helptable');
	build_helpcontent(msg,type);
	push_stack(999);
	scroll(0,0)
};
function build_helpcontent (msg, type) {
	if (isOpen('helptable')) {
		if (help_mode>=0) {
			var s = tdc_begin(null,'center',null,"100%") +
			table_begin(null,3,3,'outbackground') + tdc_begin() + table_begin() +
			build_buttontext('Intro',				'editmode_help(0)',	'Introduction',						0,help_mode,45) +
			build_buttontext('Workflow',			'editmode_help(1)',	'Workflow examples',				1,help_mode,70) +
			build_buttontext('Tags',				'editmode_help(2)',	'About the main tags window',		2,help_mode,45);
			if (screen_width<580) s = s + td_end() + table_newrow() + tdc_begin(); s = s +
			build_buttontext('Templates',			'editmode_help(3)',	'About the templates',				3,help_mode,80) +
			build_buttontext('Priority',			'editmode_help(4)',	'About the priority templates',		4,help_mode,60) +
			build_buttontext('Thesaurus',			'editmode_help(5)',	'About the thesaurus',				5,help_mode,80) +
			build_buttontext('Options',				'editmode_help(6)',	'About the options window',			6,help_mode,60) +
			build_buttontext('About',				'editmode_help(7)',	'About this program; feedback',		7,help_mode,50) +
			table_end() + td_end() + table_end() + td_end() + table_newrow() + td_empty() + table_newrow() + tdc_begin() +
			table_begin(null,3,3) + tdc_begin() + table_begin(null,3,5,'helpbackground');
			switch (help_mode) {
				case 0:	{ s = s + tdc_begin(longhelp_intro);			break; };
				case 1:	{ s = s + tdc_begin(longhelp_workflow)	;		break; };
				case 2:	{ s = s + tdc_begin(longhelp_tags);				break; };
				case 3:	{ s = s + tdc_begin(longhelp_template);			break; };
				case 4:	{ s = s + tdc_begin(longhelp_priority);			break; };
				case 5:	{ s = s + tdc_begin(longhelp_thesaurus);		break; };
				case 6:	{ s = s + tdc_begin(longhelp_tools);			break; };
				case 7:	{ s = s + tdc_begin(longhelp_about);			break; };
			}
			s = s +	td_end() + table_end();
		}
		else var s = tdc_begin() + opening_help;
		s = s + td_end() + table_end();
		document.getElementById('id_helpcontent').innerHTML = s;
		header_msg('id_helpmessage',msg,type);
};	};
function editmode_help (mode) {
	var i = parseInt_(mode);
	if (i!=help_mode) {
		help_mode = i;
		build_helpcontent(null,-1);
		push_stack(999);
};	};
function tables_restore () {
	build_banner();
	build_buttonstable();
	build_tagstable(null,-1,true);
	build_clipboardtable(null,-1,true);
};
function tables_delete () {
	closeWindow('tagstable');
	closeWindow('clipboardtable');
	closeWindow('buttonstable');
	closeWindow('templatetable');
	closeWindow('prioritytable');
	closeWindow('thesaurustable');
	closeWindow('toolstable');
};
function template_only()	{ tables_delete(); build_templatetable	('Just try the templates...',null,true); };
function thesaurus_only()	{ tables_delete(); build_thesaurustable	('Just try the thesaurus...',null,true); };
function priority_only()	{ tables_delete(); build_prioritytable	('Just try the priority templates...',null,true); };
function tools_only()		{ tables_delete(); build_toolstable		('Just try the options...',null,true); };
function build_quicklinks () {
	return js('set_beginner()','Full help') + ' all windows | ' + js('set_beginner(0)','Beginner') + ' | ' + js('set_advanced()','Advanced') + ' | ' + js('set_advanced(0)','Simple') + ' || ' + js('scroll(0,0)','Top') + ' | ' + js('scroll(0,32000)','Bottom');
};
function demo_template () {
	tables_delete();
	build_buttonstable() ;
	build_tagstable(null,-1,true);
	build_clipboardtable(null,-1,true);
	build_templatetable(null,-1,true);
};
function demo_priority () {
	tables_delete();
	build_buttonstable() ;
	build_tagstable(null,-1,true);
	build_clipboardtable(null,-1,true);
	build_prioritytable(null,-1,true);
};
function demo_thesaurus () {
	tables_delete();
	build_buttonstable() ;
	build_tagstable(null,-1,true);
	build_clipboardtable(null,-1,true);
	build_thesaurustable(null,-1,true);
};
function demo_simple () {
	tables_delete();
	build_buttonstable() ;
	build_tagstable(null,-1,true);
	build_clipboardtable(null,-1,true);
};
