wmp.editor.baseModuleBlock = new Class({
	Extends: wmp.editor.baseModule,
	type: "block",
	moveUp: function() {
		this.editor.moveBlockUp(this);
	},
	moveDown: function() {
		this.editor.moveBlockDown(this);
	}
});

wmp.editor.modules.div = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "div",
	title: "Div",
	nodeName: "div",
	defaultContent: "",
	legalChilds: ["inline","block"],
	splittable: true,
	arbitraryClasses: true,
	specificity: -5
});

wmp.editor.modules.unknown = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "unknown",
	title: "Unbekanntes Element",
	nodeName: "div",
	nodeClass: "unknown",
	defaultContent: "",
	legalChilds: ["text", "br"],
	handleKeypress: function(event) {
		if (!event.shift && event.key == "enter") {
			event.stop();
			this.editor.createModule("p");
			return false;
		}
		return true;
	},
	exportXml: function() {
		return this.node.get("text");
	},
	xml2html: function(node, editor) {
		var code = wmp.xml.outerXml(node);//wmp.xml.xmlizeSource
		var n = editor.c("div").addClass("unknown").inject(node, "before").set("text", code);
		return n;
	},
	convertElement: function(node, editor) {
		var code = wmp.xml.xmlizeSource(wmp.xml.outerXml(node));
		var n = editor.c("div").addClass("unknown").inject(node, "before").set("text", code);
		$(node).dispose();
		return n;
	}
});



wmp.editor.modules.xmlcomment = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "xmlcomment",
	title: "Kommentar",
	nodeName: "div",
	nodeClass: "xmlcomment",
	defaultContent: "",
	legalChilds: ["text", "br"],
	exportXml: function() {
		return "<!--" + this.node.get("text") + "-->";
	},
	xml2html: function(node, editor) {
		var n = editor.c("div");
		n.className="xmlcomment";
		n.set("text",node.textContent);
		return n;
	},
});


wmp.editor.modules.p = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "p",
	title: "Absatz",
	nodeName: "p",
	canBeEmpty: true,
	defaultContent: "",
	legalChilds: ["inline"],
	shortcut: "p",
	splittable: true,
	fixme: function() {
		this.nodes.content = this.node;
		this.fixMoveOutIllegal();
		this.fixInline();
		this.fixSetDefaultContent();
		this.fixFFDoubleClickBug();
		this.fixAppendWhitespace();
	},
	handleKeypress: function(event) {
		if (!event.shift && event.key == "enter") {
			event.stop();
			this.splitAndConvertToP();
			/*
			if (atbr) {
				event.stop();
				this.splitAndConvertToP();
				console.log("br am start->insertp", el);
			}
			else {
				event.stop();
				var br=this.editor.c("br");
				br.inject(el, 'before');
				var text = this.editor.ct(" ");
				el.parentNode.insertBefore(text, el);
				//this.editor.selectNode(text);
				wmp.selection.selectNode(text);
			}
			*/
			return false;
		}
		return true;
	}
});

wmp.editor.modules.h = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "h",
	title: "Überschrift",
	nodeName: "h1",
	nodeNames: ["h1", "h2", "h3", "h4", "h5", "h6", "h7"],
	legalChilds: ["inline"],
	illlegalChilds: ["strong"],
	shortcut: "h",
	splittable: true,
	canBeEmpty: true,
	fixme: function() {
		this.nodeName = $(this.node).get('tag');
		if (["h6","h7"].contains(this.nodeName)) {
			this.changeType("h5");
			this.nodeName = "h5";
		}
		this.nodes.content = this.node;
		this.fixInline();
		this.fixMoveOutIllegal();
		this.fixSetDefaultContent();
		this.fixFFDoubleClickBug();
	},	
	guiactivateme: function() {
		this.guicreatemenu();
		this.inputs.type = new wmp.gui.select({
			options: {"h1":"1. Ordnung", "h2":"2. Ordnung", "h3":"3. Ordnung", "h4":"4. Ordnung"},
			selectedValues: [this.node.get('tag')],
			onchange: this.changeType.bind(this)
		});
		this.menu.addInput({
			title: "Überschrift",
			input: this.inputs.type,
			help: ""
		});
	},
	
	changeType: function(type) 	{
		this.rename(type || this.inputs.type.getValue());
	},
	
	handleKeypress: function(event) {
		if (!event.shift && event.key == "enter") {
			event.stop();
			this.splitAndConvertToP();
			return false;
		}
		return true;
	}
});



wmp.editor.modules.wmpblock = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "wmpblock",
	title: "Block",
	nodeName: "div",
	legalChilds: ["block"],
	illlegalChilds: ["wmpblock", "figure"],
	nodeClass: "block",
	defaultContent: "<p></p>",
	classes: {
		"Position": {
			title: "Position",
			names: {"right": "rechts", "left":"links", "center": "normal"},
			preset: "center"
		},
		"Stile": {
			title: "Stile",
			//select: "multiple",
			names: {"shaded": "Hintergrundfarbe", "warning":"Warnung","info":"Information/Tipp", "error":"Fehler", "todo":"Baustelle/Todo"},
			preset: "info"
		}
	},
	fixme: function() {
		this.nodes.content = this.node;
		this.fixCapsuleInline(this.node);
		this.fixMoveOutIllegal();
		return this.removeIfEmpty();
	},
	focus: function() {
		this.fix();
		this.editor.selectNode(this.node.getChildren()[0], "start");
	},
	guiactivateme: function() {
		this.guicreatemenu();
		this.menu.addItem({title:this.title + " nach oben", func:this.moveUp.bind(this), icon: "editor/16x16/go-up.png);"});
		this.menu.addItem({title:this.title + " nach unten", func:this.moveDown.bind(this), icon: "editor/16x16/go-down.png"});
		this.menu.addItem({title:this.title + " löschen", func:this.removeButNotTheContent.bind(this), icon: "editor/16x16/edit-delete.png"});
		this.menu.addItem({title:this.title + " spalten", func:this.splitAndInsert.bind(this), icon: "editor/16x16/edit-delete.png"});
	}
});


wmp.editor.modules.list = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "list",
	title: "Liste",
	nodeName: "ul",
	nodeNames: ["ul", "ol", "nl"],
	legalChilds: ["li"],
	defaultContent: "<li></li>",
	splittable: true,
	
	guiactivateme: function() {
		this.guicreatemenu();
		this.inputs.type = new wmp.gui.select({
			options: {"ol":"nummerierte Liste", "ul":"ungeordnete Liste"},
			selectedValues: [this.node.get('tag')],
			onchange: this.changeType.bind(this)
		});
		this.menu.addInput({
			title: "Typ",
			input: this.inputs.type,
			help: ""
		});
	},
	fixme: function() {
		this.fixCapsuleInline(this.node, "li");
		this.fixMoveOutIllegal(this.node);
		this.fixSetDefaultContent();
		//this.movable = new Tree(this.node);
	},
	focus: function() {
		this.fix();
		var li = this.node.getElement("li");
		this.editor.selectNode(li, "end");
	},
	changeType: function() {
		this.rename(this.inputs.type.getValue());
	},
	exportXml: function() {
		var xml =  "<" + this.node.get('tag') + ">";
		xml += this.exportXmlChildren();
		xml += "</" + this.node.get('tag') + ">";
		return xml;
	}
});

wmp.editor.modules.li = new Class({
	Extends: wmp.editor.baseModule,
	name: "li",
	type: "flow",
	title: "Listenpunkt",
	legalChilds: ["inline", "list"],
	nodeName: "li",
	defaultContent: "Listenpunkt",
	canBeEmpty: true,
	
	fixme: function() {
		this.nodes.content = this.node;
		this.fixRemoveIllegal();
		this.fixInline();
		if (!wmp.xml.hasVisibleContent(this.node, "<ul.+</ul>|<ol.+</ol>")){
			this.logfix("fixme-li", this.node);
			this.editor.c("br").inject(this.node, 'top');
		}
		this.fixAppendWhitespace();
	},
	
	guiactivateme: function() {
		this.guicreatemenu();
		this.menu.addItem({title:"Unterpunkt Hinzufügen",icon: '/editor/16x16/list-add.png', func:this.addSubLi.bind(this)});
	},
	
	addSubLi: function() {
		var ul = $(this.node).getElement("ul");
		if (!ul) {
			ul = this.editor.c("ul");
			ul.innerHTML = "<li></li>";
			this.node.appendChild(ul);
			var ulmod = this.editor.getModule(ul);
			ulmod.select();
		}
		else {
			var li = this.editor.c("li");
			li.innerHTML = "Unterpunkt";
			ul.appendChild(li);
		}
	}
});


wmp.editor.modules.blockcode = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "blockcode",
	title: "Codeblock",
	nodeName: "blockcode",
	html5: true,
	legalChilds: ["text", "br"],
	allowedAttributes: ["language", "title", "sample"],
	canBeEmpty: true,
	tree: {
		title: {'class':"blockcode-title", 'editable': true, 'default':'kein Titel'},
		sample: {'class':"sample", "text":"Dieses Beispiel ausprobieren"},
		language: {'class':"blockcode-lang"},
		content: {"name":"pre", 'editable': true, "spellcheck":false}
	},
	languages:{"html":"HTML","javascript":"Javascript","css":"CSS","xml":"XML","html+php":"PHP","python":"Python","pycon":"Python Consolenlog","ruby":"Ruby","actionscript":"ActionScript","perl":"Perl","sql":"SQL","java":"Java","sh":"Shellcode","asp":"ASP","text":"Text","apacheconf":"Apache Konfiguration"},
	fixme: function() {
		this.importXml();
		this.build();
		//this.nodes.title.setStyle("opacity",this.values.title=="" ? ".5":"1");
		
		this.values.sample = this.values.sample && this.values.sample!="false";
		this.nodes.sample.setStyle("visibility",this.values.sample ? "visible":"hidden");
		
		this.nodes.language.set({"html":this.languages[this.values.language]});
		
		this.fiximportTextToElement(this.node, this.nodes.content);
		this.fixRemoveIllegal(); //todo: make newlines
		this.fixNl2br(this.nodes.content);
		this.fixSetDefaultContent();
	},
	importXml: function(node) {
		if (this.imported)
			return;
		this.imported=true;
		var pre = this.node.getElement("pre");
		this.tree.content.node = this.node.getElement("pre");
		this.tree.sample.node = this.node.getElement(".sample");
		this.tree.title.node = this.node.getElement(".blockcode-title");
		this.tree.language.node = this.node.getElement(".blockcode-lang");
		this.build(true);
		this.values = {
			language: this.node.getAttribute("language") || "html",
			title: this.node.getAttribute("title") || "",
			sample: this.node.getAttribute("sample") || ""
		}
		this.nodes.title.innerHTML = this.values.title;
	},
	exportXml: function() {
		var xml = '<blockcode language="' + this.values.language + '"';
		if (this.values.title.trim())
			xml += ' title="' + this.xmlEscape(this.values.title.trim()) + '"';
		if (this.values.sample)
			xml += ' sample="true"';
		xml += '>';
		xml += this.nodes.content.innerHTML.replace(new RegExp("<br[^>]*>", "gi"), "\n");
		xml += "</blockcode>";
		return xml;
	},
	manipulators: {
		"language": {
			title: "Sprache",
			onchange: "gui_changed",
			type: "select",
			options: "languages",
			help: ""
		},
		"title": {
			title: "Titel",
			onchange: "gui_changed"
		},
		"sample": {
			title: "Beispiel",
			type: "checkbox",
			onchange: "gui_changed",
			text: "Code ist ein Beispiel und kann ausprobiert werden"
		}
	},
	
	gui_changed: function() {
		this.values.language = this.inputs.language.getValue();
		this.values.title = this.inputs.title.getValue();
		this.nodes.title.innerHTML = this.values.title;
		if (this.inputs.sample) {
			this.values.sample = this.inputs.sample.getValue();
			this.node.setAttribute("sample",	this.values.sample);
		}
		this.node.setAttribute("title",		this.values.title);
		this.node.setAttribute("language",	this.values.language);
		this.fixme();
	},
	
	xml2html: function(node, editor) {
		var n = editor.c("blockcode");
		wmp.xml.copyAttributes(node, n);
		var pre = editor.c("pre").inject(n);
		pre.set("html",wmp.xml.innerXml(node));
		return n;
	},
	
	convertElement: function(node, editor) {
		/*if ($(node).get('tag') == "pre") {
			return wmp.xml.renameNode(node, "p");
		}*/
		if (node.get('tag') == "script") {
			console.log("convert", $(node).get('tag'), node);
			var node = wmp.xml.renameNode(node, "div");
			node.className = "blockcode";
			return node;
		}
	},
	
	handleKeypress: function(event) {
		if (event.key == "space")
			return false;
		
		//insert tabs instead of jumping around
		if (event.code == 9) {
			if (event.shift)
				return true;
			if (Browser.Engine.trident) {
				//TODO: pasteHTML with \t does not work in IE
			}
			else {
				event.stop();
				wmp.selection.pasteHTML("	", this.editor.doc, true);
				return false;
			}
		}
		//insert <br/> in IE&Saf
		if ((Browser.Engine.trident || Browser.Engine.webkit) && event.key == "enter") {
			event.stop();
			wmp.selection.pasteHTML("<br/>", this.editor.doc, true);
			return false;
		}
		return true;
	}
});

wmp.editor.modules.blockcodesimple = new Class({
	Extends: wmp.editor.modules.blockcode,
	manipulators: {	"sample": null }
});

wmp.editor.modules.figure = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "figure",
	title: "Abbildung",
	nodeName: "figure",
	html5: true,
	legalChilds: ["inline"],	
	canBeEmpty: true,
	sampleImage: "/editor/sample-image/",
	imagepath: "image/ajax/",
	uploadpath: "", //todo
	defaultContent: "",
	classes: {
		"position": {
			title: "Ausrichtung",
			names: {"normalleft": "normal linksbündig", "right": "rechts", "left":"links", "center": "zentriert"},
			preset: "normalleft"
		},
		"size": {
			title: "Größe",
			names: {"maxwidth": "maximale Größe", "big": "groß", "normal": "normal", "small": "klein", "icon": "Icon", "tiny": "winzig"},
			preset: "normal"
		}
	},
	tree: {
		img: {'name':'img', 'styles':{'width':'auto','height':'auto'}},
		content: {"name":"legend", 'editable': true}
	},
	sizes: {"maxwidth": "scale/580x2500/", "big": "scale/400x400/", "normal": "scale/250x250/", "small": "scale/100x100/", "icon": "icon/"/*"50x50"*/, "tiny": "scale/25x25/"},
	handleKeypress: wmp.editor.baseModule.getStatic("appendPOnEnter"),
	manipulators: {
		"images": {
			title: "Bilder",
			type: "imagechooser",
			onchange: "setimage_chooser"			
		},
		"upload": {
			title: "Bild hochladen",
			type: "upload",
			onchange: "setimage_upload",
			fieldname: "image",
			target: "image/create-ajax/"
		},
		"url": {
			title: "Bildadresse",
			onchange: "setimage_url",
			closed: true
		},
		"alt": {
			title: "Alternativtext",
			closed: true
		},
		"title": {
			title: "Titel",
			closed: true
		}
	},
	fixme: function() {
		this.importXml();
		this.build();
		this.fiximportTextToElement(this.node, this.nodes.content);
		this.fixMoveOutIllegal();
		this.fixInline();
		this.fixSetDefaultContent();
	},
	
	getImageMode: function(src) {
		if (src.test("(/static/)|(/media/)", "i"))
			return "static";
		else if (src.test("^http:", "i") && !src.test("webmasterpro\\.de"))
			return "static";
		return "dynamic";
	},
	
	loadImages: function() {
		if (this.editor.imagesloaded)
			return this.addImages(this.editor.imagesloaded);
		new Request.JSON({'url': this.imagepath, onComplete: this.addImages.bind(this)}).send();
	},
	
	addImages: function(json) {
		this.editor.imagesloaded = json || {};
		if (this.inputs.images)
			this.inputs.images.setOptions(this.editor.imagesloaded);
	},
	guiactivateme: function() {
		this.loadImages();
	},
	getproperty: function(pid) {
		return this.values[pid] || this.nodes.img.getAttribute(pid,2) || '';
	},
	setproperty: function(pid) {
		this.nodes.img.setProperty(pid, this.inputs[pid].getValue());
	},
	importXml: function() {
		if (this.imported)
			return;
		this.imported=true;
		this.nodes.img=this.tree.img.node=this.node.getElement("img");
		
		if (this.nodes.img)
			this.values.url = this.nodes.img.getAttribute("src",2);
		this.values.url = this.values.url || this.sampleImage;
		
		this.values.url = wmp.url.toRel(this.values.url);
		this.values.mode = this.getImageMode(this.values.url);
		for (var s in this.sizes) {
			if (this.node.hasClass(s))
				this.values.size = s;
			if (this.values.url.test(this.sizes[s])) {
				if (!this.values.size)
					this.values.size = s;
				this.values.url = this.values.url.replace(new RegExp(("/" + this.sizes[s]).escapeRegExp(), "g"), "");
				break;
			}
		}
		if (!this.values.size)
			this.values.size = "normal";
		this.node.addClass(this.values.size);
		this.setby = "init";
			
		this.build(true);
		this.setimage();
		this.fixStripAttributes(this.node);
		this.fixStripAttributes(this.nodes.img, ["src","alt","title"]);
		this.fixStripAttributes(this.nodes.content);
	},
	exportXml: function() {
		//todo: alt, title
		var xml =  "<figure";
		if (this.node.className.length>2)
			xml += ' class="' + this.node.className.replace(new RegExp("normalleft|figure", "g"), "").trim() + '"';
		xml += ">";
		xml += '<img src="' + this.values.url + '" title="' + this.getproperty("title") + '" alt="' + this.getproperty("alt") + '"/>';
		//if (wmp.xml.hasVisibleContent(this.nodes.content))
		xml += "<legend>" + this.exportXmlChildren(this.nodes.content) + "</legend>";
		xml += "</figure>";
		this.xml = xml;
		return this.xml;
	},
	onSetStyles: function() {
		this.values.size = this.inputs["classsize"].getSelectedValues()[0];
		this.setby = "style";
		this.setimage();
	},
	setimage: function() {
		if (this.getImageMode(this.values.url) == "dynamic") {
			var s = this.sizes[this.values.size];
			if (this.values.url.lastIndexOf('/') == this.values.url.length-1)
				var fullurl = this.values.url + s;
			else
				var fullurl = this.values.url + "/" + s;
			fullurl = wmp.url.toRel(fullurl);
		}
		else
			var fullurl = this.values.url;
		this.nodes.img.setAttribute("src", fullurl);
		if (this.setby != "manual" && this.inputs && this.inputs.url)
			this.inputs.url.setValue(this.values.url);
	},
	setimage_url: function() {
		this.setby = "manual";
		this.values.url = this.inputs.url.getValue();
		this.setimage();
	},
	setimage_chooser: function() {
		this.setby = "chooser";
		this.values.url = this.inputs.images.getValue()
		this.setimage();
	},
	setimage_upload: function() {
		this.setby = "chooser";
		this.values.url = 'image/' + this.inputs.upload.getValue();
		this.values.name = this.inputs.upload.getValue();
		this.editor.imagesloaded[this.values.url] = this.values.name
		this.inputs.images.setOptions(this.editor.imagesloaded);
		this.inputs.images.setValue(this.values.url);
		this.setimage();
	}/*,
	xml2html: function(node, editor) {
		return node;
	}*/
});

wmp.editor.modules.blockquote = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "blockquote",
	title: "Zitatblock",
	nodeName: "blockquote",
	legalChilds: ["block"],
	illlegalChilds: [],
	nodeClass: "",
	defaultContent: "<p></p>",
	fixme: function() {
		this.nodes.content = this.node;
		this.fixCapsuleInline(this.node);
		this.fixMoveOutIllegal(this.node);
	},
	focus: function() {
		this.fix();
		var p = $(this.node).getElement("p");
		if (p)
			this.editor.selectNode(p,"start");
	},
	handleKeypress: function(event) {
		if (!event.shift && !event.contorl && event.key == "enter") {
			var focus = this.editor.modules.focused[0];
			if (focus && focus.name=="p" && focus.node.parentNode==this.node && !wmp.xml.hasRealContent(focus.node)) {
				//console.log("blockquote: enter pressed in empty p -> split blockquote");
				this.splitAndInsert("p");
				event.stop();
				return false;
			}
		}
		return true;
	},
	guiactivateme: wmp.editor.modules.wmpblock.prototype.guiactivateme
});



wmp.editor.modules.table = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "table",
	title: "Tabelle",
	nodeName: "table",
	legalChilds: ["tr", "thead", "tbody", "caption"],
	defaultColNum: "2",
	defaultContent: "<thead><tr><td>Spalte1</td><td>Spalte2</td></tr></thead><tr><td>&nbsp;</td><td>&nbsp;</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td></tr>",
	fixme: function() {
		this.node.className = this.nodeClass;
		return this.removeIfEmpty();
	},
	
	fixSetDefaultContent: function() {
		if (!this.node.getElement("td") && !this.node.getElement("th")) {
			var thead = this.node.getElement("thead") || this.editor.c("thead").inject(this.node, 'top');
			var tr = this.editor.c("tr");
			var x=0;
			while (x++<this.defaultColNum) {
				var tdmod = this.editor.createModuleOnly("td");
				var td = tdmod.node;
				this.editor.getModule(td).fix();
				tr.appendChild(td);
			}
			tr.inject(thead, 'top');
			var tbody = this.node.getElement("tbody") || this.editor.c("tbody").inject(thead, 'after');
			var trmod = this.editor.getModule(tr);
			trmod.addRow();
			trmod.addRow();
			trmod.addRow();
			//todo: select fails in ie & opera
			//todo: this.remove();
		}
	},
	
	removeIfEmpty: function() {
		if (!this.node.getElement("tr")) {
			this.remove();
			return true;
		}
	},
	focus: function() {
		if (this.fix())
			return;
		var td = this.node.getElement("td");
		this.editor.getModule(td).focus();
	},
	
	exportXml: function() {
		var xml =  "<table>";
		var thead = this.node.getElement("thead");
		if (thead) {
			xml += "<thead>";
			var trs = thead.getElements("tr");
			var tr,x=0;
			while (tr = trs[x++])
				xml += this.editor.getModule(tr).exportXml();
			xml += "</thead>";
		}
		var tbody = this.node.getElement("tbody");
		if (tbody) {
			xml += "<tbody>";
			var trs = tbody.getElements("tr");
			var tr,x=0;
			while (tr = trs[x++])
				xml += this.editor.getModule(tr).exportXml();
			xml += "</tbody>";
		}
		xml += "</table>";
		return xml;
	},
	
	scanForErrors: function() {
		var x=0, c, m;
		var tds = this.node.getElements("td, th");
		while (c = tds[x++]) {
			if (m = this.editor.getModule(c))
				m.fix();
		}
	}
});

wmp.editor.modules.tr = new Class({
	Extends: wmp.editor.baseModule,
	name: "tr",
	type: "tr",
	title: "Zeile",
	nodeName: "tr",
	legalChilds: ["td"],
	nodeClass: "",
	defaultContent: "<td>Zelle</td>",
	fixme: function() {
		
	},
	
	focus: function() {
		this.fix();
		var td = this.node.getElement("td");
		this.editor.getModule(td).focus();
	},
	
	select: function() {
		var td = this.node.getElement("td");
		this.editor.getModule(td).select();
	},
	
	guiactivateme: function() {
		this.guicreatemenu();
		var thead = this.getTable().getElement("thead");
		if (!thead|| !thead.getElement("td"))
			this.menu.addItem({title:"Tabellenkopf hinzufügen", func:this.addHead.bind(this), icon: "editor/16x16/list-add.png"});
		this.menu.addItem({title:"Zeile hinzufügen", func:this.addRow.bind(this), icon: "editor/16x16/list-add.png"});
		this.menu.addItem({title:"Zeile löschen", func:this.removeRow.bind(this), icon: "editor/16x16/edit-delete.png"});
		this.menu.addItem({title:this.title + " nach oben", func:this.moveUp.bind(this), icon: "editor/16x16/go-up.png);"});
		this.menu.addItem({title:this.title + " nach unten", func:this.moveDown.bind(this), icon: "editor/16x16/go-down.png"});
	},
	
	removeRow: function() {
		var alt = this.node.getNext() ||  this.node.getPrevious() || this.getTable();
		var p = this.node.getParent();
		this.remove();
		if (p.get('tag') == "thead")
			p.dispose();
		this.editor.getModule(alt).focus();
	},
	addRow: function() {
		var tr = this.editor.c("tr");
		var c = this.node.getFirst();
		while (c) {
			var td = this.editor.c(c.get('tag'));
			this.editor.getModule(td).fix();
			tr.appendChild(td);
			var c = c.getNext();
		}
		
		var p = this.node.getParent();
		if (p.get('tag') == "thead")
			if (p.getNext() && p.getNext().get('tag')== "tbody")
				tr.inject(p.getNext(), 'top');
			else
				tr.inject(p, 'after');
		else
			tr.inject(this.node, 'after');
		var trmod = this.editor.getModule(tr);
		trmod.focus();
	},
	moveUp: function() {
		var alt = this.node.getPrevious();
		if (alt && alt.get('tag')=="tr") {
			var sel = wmp.selection.save(this.editor.doc);
			this.node.inject(alt, 'before');
			wmp.selection.restore(sel);
		}
	},
	moveDown: function() {
		var alt = this.node.getNext();
		if (alt && alt.get('tag')=="tr") {
			var sel = wmp.selection.save(this.editor.doc);
			this.node.inject(alt, 'after');
			wmp.selection.restore(sel);
		}
	},
	addHead: function() {
		var table = this.getTable();
		var thead = table.getElement("thead") || this.editor.c("thead").inject(table, 'top');
		var tr = this.editor.c("tr");
		var tr = this.editor.c("tr");
		var c = this.node.getFirst();
		while (c) {
			var td = this.editor.c(c.get('tag'));
			this.editor.getModule(td).fix();
			tr.appendChild(td);
			var c = c.getNext();
		}
		tr.inject(thead, 'top');
		this.editor.getModule(tr).focus();
	},
	getTable: function(node) {
		var p=node||this.node; 
		while (p=p.parentNode)
			if (p.nodeName.toLowerCase() == "table")
				return p;
	},
	handleKeypress: function(event) {
		var n,alt;
		if (event.code == 9 && event.shift) {
			if (n = this.node.getPrevious())
				alt = this.editor.getModule(n.getLast());
			else if ((n=this.node.getParent()) && (n=n.getPrevious()) && n.get('tag')=="thead" && (n=n.getLast()))
				alt = this.editor.getModule(n.getLast());
		}
		else if (event.code == 9){
			if (n = this.node.getNext())
				alt = this.editor.getModule(n.getFirst());
			else if ((n=this.node.getParent()) && (n=n.getNext()) && n.get('tag')=="tbody" && (n=n.getFirst()))
				alt = this.editor.getModule(n.getFirst());
		}
		if (alt) {
			alt.focus();
			event.stop();
			return false;
		}
		return true;
	},
	exportXml: function() {
		var xml = "<tr>";
		var ns = this.node.getChildren();
		var n,x=0;
		while (n = ns[x++])
			xml += this.editor.getModule(n).exportXml();
		xml += "</tr>";
		return xml;
	}
});
wmp.editor.modules.td = new Class({
	Extends: wmp.editor.baseModule,
	name: "td",
	type: "td",
	title: "Zelle",
	nodeName: "td",
	nodeNames: ["td","th"],
	legalChilds: ["inline", "block"],
	illlegalChilds: ["table", "wmpblock"],
	nodeClass: "",
	defaultContent: "",
	classes: {
		"style": {
			title: "Stil",
			names: {"":"Normal","th": "Kopfzelle ", "green":"grün", "orange":"orange", "red": "rot"},
			preset: ""
		}
	},
	onSetStyles: function() {
		var kind = this.inputs["classstyle"].getSelectedValues()[0];
		if (kind != "th")
			kind = "td";
		if (this.node.get('tag')!=kind) {
			this.rename(kind);
			this.setStyles();
		}
	},
	fixme: function() {
		this.nodes.content = this.node;
		this.fixMoveOutIllegal();
		this.fixInline();
		this.fixSetDefaultContent();
	},
	guiactivateme: function() {
		this.guicreatemenu();
		this.menu.addItem({title:"Spalte hinzufügen", func:this.addCol.bind(this), icon: "editor/16x16/list-add.png"});
		this.menu.addItem({title:"Spalte löschen", func:this.removeCol.bind(this), icon: "editor/16x16/edit-delete.png"});
		this.menu.addItem({title:"Spalte nach links", func:this.moveLeft.bind(this), icon: "editor/16x16/go-previous.png);"});
		this.menu.addItem({title:"Spalte nach rechts", func:this.moveRight.bind(this), icon: "editor/16x16/go-next.png"});
	},
	addCol: function() {
		var x=0, tr, colPos=this.getMyPos();
		var trs = this.getTable().getElements("tr");
		while (tr = trs[x++]) {
			var newtd = this.editor.c("td");
			this.editor.getModule(newtd).fix();
			tr.insertBefore(newtd, tr.getChildren()[colPos]);
		}
	},
	getMyPos: function() {
		var col = this.node, colPos=0;
		while (col = col.getPrevious())
			colPos++;
		return colPos;
	},
	moveLeft: function() {
		var sel = wmp.selection.save(this.editor.doc);
		var trs = this.getTable().getElements("tr");
		var x=0, tr, colPos=this.getMyPos();
		while (tr = trs[x++]) {
			var td = tr.getChildren()[colPos];
			var alt = td.getPrevious();
			if (alt)
				td.inject(alt, 'before');
		}
		wmp.selection.restore(sel);
	},
	moveRight: function() {
		var sel = wmp.selection.save(this.editor.doc);
		var trs = this.getTable().getElements("tr");
		var x=0, tr, colPos=this.getMyPos();
		while (tr = trs[x++]) {
			var td = tr.getChildren()[colPos];
			var alt = td.getNext();
			if (alt)
				td.inject(alt, 'after');
		}
		wmp.selection.restore(sel);
	},
	removeCol: function() {
		var td = this.node;
		var alt = td.getNext() || td.getPrevious() || this.getTable();
		var x=0, tr, colPos=this.getMyPos();
		var trs = this.getTable().getElements("tr");
		while (tr = trs[x++]) {
			tr.getChildren()[colPos].dispose();
		}
		this.editor.getModule(alt).focus();
	},
	getTable: wmp.editor.modules.tr.prototype.getTable,
	
	handleKeypress: function(event) {
		var n,alt;
		if (event.code == 9 && event.shift) {
			if (n = this.node.getPrevious())
				alt = this.editor.getModule(n);
		}
		else if (event.code == 9){
			if (n = this.node.getNext())
				alt = this.editor.getModule(n);
		}
		if (alt) {
			alt.focus();
			event.stop();
			return false;
		}
		return true;
	},
	exportXml: function() {
		var xml =  "<" + this.node.get('tag');
		if (this.node.className.length>2)
			xml += ' class="' + this.node.className + '"';
		xml += ">";
		xml += this.exportXmlChildren();
		xml += "</"+this.node.get('tag')+">";
		return xml;
	}
});

wmp.editor.modules.dl = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "dl",
	title: "Definitionsliste",
	nodeName: "dl",
	legalChilds: ["dd", "dt"],
	nodeClass: "",
	defaultContent: "<dt>Definitionstext</dt><dd>Definitionsname</dd>",
	fixme: function() {
		//this.fixCapsuleInline(this.node, "dd");
	},
	
	select: function() {
		
	}
});

wmp.editor.modules.dd = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "dd",
	title: "Definitionsname",
	nodeName: "dd",
	legalChilds: ["inline"],
	nodeClass: "",
	defaultContent: "Definitionsname"
});
wmp.editor.modules.dt = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "dt",
	title: "Definitionstext",
	nodeName: "dt",
	legalChilds: ["inline"],
	nodeClass: "",
	defaultContent: "Definitionstext"
});





wmp.editor.modules.body = new Class({
	Extends: wmp.editor.baseModule,
	name: "body",
	title: "Dokument",
	nodeName: "body",
	otherclasses: ["editor-content"],
	type: "body",
	allowedAttributes: ["id", "spellcheck"],
	defaultContent: "",
	legalChilds: ["block"],
	fixme: function() {
		this.nodes.content = this.node;
		this.fixCapsuleInline();
		this.fixRemoveIllegal();
		if (this.node.innerHTML.length<5) {
			this.editor.createModule("p")
		}
	},
	
	exportXml: function() {
		return this.exportXmlChildren().replace(new RegExp("^\\s*(<p>\\s*(<br\\s*/?>\\s*)*</p>|<p\\s*/>)*\\s*$", ""), "");
	}
});

wmp.editor.modules.body_comment = new Class({
	Extends: wmp.editor.modules.body,
	title: "Kommentar",
	defaultContent: "",
	nodeName: "body",
	otherclasses: ["comments","editor-content"],
	fixme: function() {
		this.nodes.content = this.node;
		this.fixCapsuleInline();
		this.fixRemoveIllegal();
		
		if (this.node.innerHTML.length<5) {
			this.logfix("body - fixNoContent");
			this.editor.createModule("p")
		}
		if (!this.notFirstRun) {
			var lastmod = this.editor.getModule(this.node.getLast());
			if(!lastmod || lastmod.name!="p") {
				this.logfix("body - firstRun - no p at bottom");
				var p = this.editor.createModuleOnly("p");
				this.node.appendChild(p.node);
				p.focus();
			}
			var lastmod = this.editor.getModule(this.node.getFirst());
			if(!lastmod || lastmod.name!="p") {
				this.logfix("body - firstRun - no p at top");
				var p = this.editor.createModuleOnly("p");
				this.node.insertBefore(p.node, this.node.firstChild);
				p.focus();
			}
			this.notFirstRun = true;
		}
	}
});

wmp.editor.modules.blockquote_forum = new Class({
	Extends: wmp.editor.modules.blockquote,
	name: "blockquote",
	title: "Zitatblock",
	nodeName: "blockquote",
	legalChilds: ["block"],
	illlegalChilds: [],
	nodeClass: "",
	allowedAttributes: ["cite", "author"],
	defaultContent: "<p></p>"
});
wmp.editor.modules.body_forum = new Class({
	Extends: wmp.editor.modules.body,
	title: "Foren-Beitrag",
	defaultContent: "",
	nodeName: "body",
	otherclasses: ["forum","editor-content"],
	fixme: function() {
		this.nodes.content = this.node;
		this.fixCapsuleInline();
		this.fixRemoveIllegal();
		
		if (this.node.innerHTML.length<5) {
			this.logfix("body - fixNoContent");
			this.editor.createModule("p")
		}
		if (!this.notFirstRun) {
			var lastmod = this.editor.getModule(this.node.getLast());
			if(!lastmod || lastmod.name!="p") {
				this.logfix("body - firstRun - no p at bottom");
				var p = this.editor.createModuleOnly("p");
				this.node.appendChild(p.node);
				p.focus();
			}
			this.notFirstRun = true;
		}
	}
});

wmp.editor.modules.body_inline = new Class({
	Extends: wmp.editor.modules.body,
	nodeName: "body",
	title: "Beschreibung",
	otherclasses: ["editor-content"],
	legalChilds: ["inline"],
	fixme: function() {
		this.nodes.content = this.node;
		this.fixInline();
		this.fixRemoveIllegal();
		if (!wmp.xml.hasVisibleContent(this.node)) {
			this.logfix("fixNoContent");
			this.node.innerHTML = "&nbsp;";
			this.focus();
		}
		var c=0, br, brs = this.node.getElements("br"), last = this.node.lastChild;
		while (br = brs[c++]) {
			if (!Browser.Engine.trident && br != last) {
				console.log("body_inline->remove br");
				br.dispose();
			}
		}
	},
	
	handleKeypress: function(event) {
		if (event.key == "enter") {
			event.stop();
		}
		return true;
	},
	
	exportXml: function() {
		return this.exportXmlChildren(this.node).replace(new RegExp("<br.?.?>", "g"), "").trim();
	}
});

wmp.editor.modules.body_gallery = new Class({
	Extends: wmp.editor.modules.body,
	nodeName: "body",
	title: "Beschreibung",
	otherclasses: ["comments","editor-content"],
	legalChilds: ["inline"],
	fixme: function() {
		this.nodes.content = this.node;
		this.fixInline();
		this.fixRemoveIllegal();
		if (!wmp.xml.hasVisibleContent(this.node)) {
			this.logfix("fixNoContent");
			this.node.innerHTML = "&nbsp;";
			this.focus();
		}
	},
	
	exportXml: function() {
		return this.exportXmlChildren(this.node).trim();
	}
});

wmp.editor.modules.downloads = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "downloads",
	title: "Downloads",
	nodeName: "downloads",
	html5: true,
	legalChilds: ["file"],	
	canBeEmpty: false,
	tree: {
		title: {'name':'h2', 'html':'Downloads'},
		text: {'name':'p', 'html':'Für diesen Artikel stehen zusätzliche Dateien zum Herunterladen bereit. Der Download ist nur für registrierte Benutzer möglich. Die <a href="/account/login/">kostenlose Registrierung</a> dauert nur wenige Sekunden.'},
		content: {"name":"div", 'editable': false}
	},
	handleKeypress: wmp.editor.baseModule.getStatic("appendPOnEnter"),
	manipulators: {
		"upload": {
			title: "Datei hochladen",
			type: "upload",
			onchange: "afterupload",
			fieldname: "file",
			target: "file/create-ajax/"
		},
		"name": {
			title: "Name der Datei"
		}
	},
	fixme: function() {
		this.importXml();
		this.build();
		this.fixRemoveIllegal();
	},
	importXml: function() {
		if (this.imported)
			return;
		this.imported=true;
		this.build(true);
		this.node.getChildren("a").each(
			function(n) {
				this.addFile(n.getAttribute("href",2), n.get("text"));
				n.destroy();
			}, this);
	},
	exportXml: function() {
		var xml =  "<downloads>";
		xml += this.exportXmlChildren(this.nodes.content);
		xml += "</downloads>";
		return xml;
	},
	afterupload: function() {
		var file = this.addFile('file/' + this.inputs.upload.getValue(), this.inputs.name.getValue());
		this.inputs.name.setValue("");
		file.select();
	},
	addFile: function(file, name) {
		//console.log("addFile", file, name);
		var n = this.editor.c("div").addClass("file").set('html', (name||"").trim() || "Datei ohne Titel"). inject(this.nodes.content);
		this.makeEditable(n);
		n.setAttribute("_href", file);
		return this.editor.getModule(n);
	},
	focus: function() {
		var mod = this.editor.getModule(this.nodes.content.getElement("div"));
		if (mod)
			mod.focus();
		else
			this.editor.selectNode(this.nodes.content, "end");
	}
});



wmp.editor.modules.file = new Class({
	Extends: wmp.editor.baseModuleBlock,
	name: "file",
	title: "Datei",
	nodeName: "div",
	nodeClass: "file",
	legalChilds: [],	
	canBeEmpty: true,
	manipulators: {
		"remove":  {
			type: "item",
			title: "Datei entfernen",
			action: "remove",
			icon: "editor/16x16/edit-delete.png"
		}
	},
	handleKeypress: wmp.editor.baseModule.getStatic("appendPOnEnter"),
	exportXml: function() {
		return xml = '<a href="'+this.node.getAttribute('_href', 2)+'">'+this.node.get('html')+'</a>';
	}
});


/* extenders */
wmp.editor.modules.extenders = {}

wmp.editor.modules.extenders.cssclasses = {
	manipulators: {
		"classes": {
			title: "CSS Klassen",
			type: "url",
			property: "classes"
		}
	},
	getproperty_classes: function() {
		this.values.classes =  this.node.getAttribute("class",2) || "";
		return this.values.classes;
	},
	setproperty_classes: function() {
		this.values.classes = this.inputs.classes.getValue();
		this.node.setAttribute("class", this.values.classes);
	}
}

wmp.editor.modules.extenders.clearer = {
	manipulators: {
		"clearer": {
			title: "Umfluß",
			type: "checkbox",
			property: "clearer",
			input: {
				text: "Nicht umfließen"
			}
		}
	},
	initialize: function() {
		if (this.node.hasClass("clearboth"))
			this.otherclasses.include("clearboth");
	},
	getproperty_clearer: function() {
		return this.node.hasClass("clearboth");
	},
	setproperty_clearer: function() {
		if (this.inputs.clearer.getValue())
			this.node.addClass("clearboth");
		else
			this.node.removeClass("clearboth");
	}
}
//wmp.editor.modules.h.prototype.extenders = new Hash();
//wmp.editor.modules.h.prototype.extenders.clearer = wmp.editor.modules.extenders.clearer;
wmp.editor.modules.div.prototype.extenders = {classes:wmp.editor.modules.extenders.cssclasses};

