PageRenderTime 73ms CodeModel.GetById 29ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/BlogEngine/BlogEngine.NET/editors/tiny_mce_3_4_3_1/plugins/lists/editor_plugin_src.js

#
JavaScript | 688 lines | 591 code | 65 blank | 32 comment | 181 complexity | f9be125e4533524cc0fb64f7ffc0a1b1 MD5 | raw file
  1/**
  2 * editor_plugin_src.js
  3 *
  4 * Copyright 2011, Moxiecode Systems AB
  5 * Released under LGPL License.
  6 *
  7 * License: http://tinymce.moxiecode.com/license
  8 * Contributing: http://tinymce.moxiecode.com/contributing
  9 */
 10
 11(function() {
 12	var each = tinymce.each, Event = tinymce.dom.Event, bookmark;
 13
 14	// Skips text nodes that only contain whitespace since they aren't semantically important.
 15	function skipWhitespaceNodes(e, next) {
 16		while (e && (e.nodeType === 8 || (e.nodeType === 3 && /^[ \t\n\r]*$/.test(e.nodeValue)))) {
 17			e = next(e);
 18		}
 19		return e;
 20	}
 21	
 22	function skipWhitespaceNodesBackwards(e) {
 23		return skipWhitespaceNodes(e, function(e) { return e.previousSibling; });
 24	}
 25	
 26	function skipWhitespaceNodesForwards(e) {
 27		return skipWhitespaceNodes(e, function(e) { return e.nextSibling; });
 28	}
 29	
 30	function hasParentInList(ed, e, list) {
 31		return ed.dom.getParent(e, function(p) {
 32			return tinymce.inArray(list, p) !== -1;
 33		});
 34	}
 35	
 36	function isList(e) {
 37		return e && (e.tagName === 'OL' || e.tagName === 'UL');
 38	}
 39	
 40	function splitNestedLists(element, dom) {
 41		var tmp, nested, wrapItem;
 42		tmp = skipWhitespaceNodesBackwards(element.lastChild);
 43		while (isList(tmp)) {
 44			nested = tmp;
 45			tmp = skipWhitespaceNodesBackwards(nested.previousSibling);
 46		}
 47		if (nested) {
 48			wrapItem = dom.create('li', { style: 'list-style-type: none;'});
 49			dom.split(element, nested);
 50			dom.insertAfter(wrapItem, nested);
 51			wrapItem.appendChild(nested);
 52			wrapItem.appendChild(nested);
 53			element = wrapItem.previousSibling;
 54		}
 55		return element;
 56	}
 57	
 58	function attemptMergeWithAdjacent(e, allowDifferentListStyles, mergeParagraphs) {
 59		e = attemptMergeWithPrevious(e, allowDifferentListStyles, mergeParagraphs);
 60		return attemptMergeWithNext(e, allowDifferentListStyles, mergeParagraphs);
 61	}
 62	
 63	function attemptMergeWithPrevious(e, allowDifferentListStyles, mergeParagraphs) {
 64		var prev = skipWhitespaceNodesBackwards(e.previousSibling);
 65		if (prev) {
 66			return attemptMerge(prev, e, allowDifferentListStyles ? prev : false, mergeParagraphs);
 67		} else {
 68			return e;
 69		}
 70	}
 71	
 72	function attemptMergeWithNext(e, allowDifferentListStyles, mergeParagraphs) {
 73		var next = skipWhitespaceNodesForwards(e.nextSibling);
 74		if (next) {
 75			return attemptMerge(e, next, allowDifferentListStyles ? next : false, mergeParagraphs);
 76		} else {
 77			return e;
 78		}
 79	}
 80	
 81	function attemptMerge(e1, e2, differentStylesMasterElement, mergeParagraphs) {
 82		if (canMerge(e1, e2, !!differentStylesMasterElement, mergeParagraphs)) {
 83			return merge(e1, e2, differentStylesMasterElement);
 84		} else if (e1 && e1.tagName === 'LI' && isList(e2)) {
 85			// Fix invalidly nested lists.
 86			e1.appendChild(e2);
 87		}
 88		return e2;
 89	}
 90	
 91	function canMerge(e1, e2, allowDifferentListStyles, mergeParagraphs) {
 92		if (!e1 || !e2) {
 93			return false;
 94		} else if (e1.tagName === 'LI' && e2.tagName === 'LI') {
 95			return e2.style.listStyleType === 'none' || containsOnlyAList(e2);
 96		} else if (isList(e1)) {
 97			return (e1.tagName === e2.tagName && (allowDifferentListStyles || e1.style.listStyleType === e2.style.listStyleType)) || isListForIndent(e2);
 98		} else if (mergeParagraphs && e1.tagName === 'P' && e2.tagName === 'P') {
 99			return true;
100		} else {
101			return false;
102		}
103	}
104	
105	function isListForIndent(e) {
106		var firstLI = skipWhitespaceNodesForwards(e.firstChild), lastLI = skipWhitespaceNodesBackwards(e.lastChild);
107		return firstLI && lastLI && isList(e) && firstLI === lastLI && (isList(firstLI) || firstLI.style.listStyleType === 'none'  || containsOnlyAList(firstLI));
108	}
109	
110	function containsOnlyAList(e) {
111		var firstChild = skipWhitespaceNodesForwards(e.firstChild), lastChild = skipWhitespaceNodesBackwards(e.lastChild);
112		return firstChild && lastChild && firstChild === lastChild && isList(firstChild);
113	}
114	
115	function merge(e1, e2, masterElement) {
116		var lastOriginal = skipWhitespaceNodesBackwards(e1.lastChild), firstNew = skipWhitespaceNodesForwards(e2.firstChild);
117		if (e1.tagName === 'P') {
118			e1.appendChild(e1.ownerDocument.createElement('br'));
119		}
120		while (e2.firstChild) {
121			e1.appendChild(e2.firstChild);
122		}
123		if (masterElement) {
124			e1.style.listStyleType = masterElement.style.listStyleType;
125		}
126		e2.parentNode.removeChild(e2);
127		attemptMerge(lastOriginal, firstNew, false);
128		return e1;
129	}
130	
131	function findItemToOperateOn(e, dom) {
132		var item;
133		if (!dom.is(e, 'li,ol,ul')) {
134			item = dom.getParent(e, 'li');
135			if (item) {
136				e = item;
137			}
138		}
139		return e;
140	}
141	
142	tinymce.create('tinymce.plugins.Lists', {
143		init: function(ed, url) {
144			var enterDownInEmptyList = false;
145
146			function isTriggerKey(e) {
147				return e.keyCode === 9 && (ed.queryCommandState('InsertUnorderedList') || ed.queryCommandState('InsertOrderedList'));
148			};
149
150			function isEnterInEmptyListItem(ed, e) {
151				var sel = ed.selection, n;
152				if (e.keyCode === 13) {
153					n = sel.getStart();
154
155					// Get start will return BR if the LI only contains a BR
156					if (n.tagName == 'BR' && n.parentNode.tagName == 'LI')
157						n = n.parentNode;
158
159					// Check for empty LI or a LI with just one BR since Gecko and WebKit uses BR elements to place the caret
160					enterDownInEmptyList = sel.isCollapsed() && n && n.tagName === 'LI' && (n.childNodes.length === 0 || (n.firstChild.nodeName == 'BR' && n.childNodes.length === 1));
161					return enterDownInEmptyList;
162				}
163			};
164
165			function cancelKeys(ed, e) {
166				if (isTriggerKey(e) || isEnterInEmptyListItem(ed, e)) {
167					return Event.cancel(e);
168				}
169			};
170
171			function imageJoiningListItem(ed, e) {
172				if (!tinymce.isGecko)
173					return;
174
175				var n = ed.selection.getStart();
176				if (e.keyCode != 8 || n.tagName !== 'IMG') 
177					return;
178
179				function lastLI(node) {
180					var child = node.firstChild;
181					var li = null;
182					do {
183						if (!child)
184							break;
185
186						if (child.tagName === 'LI')
187							li = child;
188					} while (child = child.nextSibling);
189
190					return li;
191				}
192
193				function addChildren(parentNode, destination) {
194					while (parentNode.childNodes.length > 0)
195						destination.appendChild(parentNode.childNodes[0]);
196				}
197
198				var ul;
199				if (n.parentNode.previousSibling.tagName === 'UL' || n.parentNode.previousSibling.tagName === 'OL')
200					ul = n.parentNode.previousSibling;
201				else if (n.parentNode.previousSibling.previousSibling.tagName === 'UL' || n.parentNode.previousSibling.previousSibling.tagName === 'OL')
202					ul = n.parentNode.previousSibling.previousSibling;
203				else
204					return;
205
206				var li = lastLI(ul);
207
208				// move the caret to the end of the list item
209				var rng = ed.dom.createRng();
210				rng.setStart(li, 1);
211				rng.setEnd(li, 1);
212				ed.selection.setRng(rng);
213				ed.selection.collapse(true);
214
215				// save a bookmark at the end of the list item
216				var bookmark = ed.selection.getBookmark();
217
218				// copy the image an its text to the list item
219				var clone = n.parentNode.cloneNode(true);
220				if (clone.tagName === 'P' || clone.tagName === 'DIV')
221					addChildren(clone, li);
222				else
223					li.appendChild(clone);
224					
225				// remove the old copy of the image
226				n.parentNode.parentNode.removeChild(n.parentNode);
227
228				// move the caret where we saved the bookmark
229				ed.selection.moveToBookmark(bookmark);
230			}
231
232			this.ed = ed;
233			ed.addCommand('Indent', this.indent, this);
234			ed.addCommand('Outdent', this.outdent, this);
235			ed.addCommand('InsertUnorderedList', function() {
236				this.applyList('UL', 'OL');
237			}, this);
238			ed.addCommand('InsertOrderedList', function() {
239				this.applyList('OL', 'UL');
240			}, this);
241			
242			ed.onInit.add(function() {
243				ed.editorCommands.addCommands({
244					'outdent': function() {
245						var sel = ed.selection, dom = ed.dom;
246						function hasStyleIndent(n) {
247							n = dom.getParent(n, dom.isBlock);
248							return n && (parseInt(ed.dom.getStyle(n, 'margin-left') || 0, 10) + parseInt(ed.dom.getStyle(n, 'padding-left') || 0, 10)) > 0;
249						}
250						return hasStyleIndent(sel.getStart()) || hasStyleIndent(sel.getEnd()) || ed.queryCommandState('InsertOrderedList') || ed.queryCommandState('InsertUnorderedList');
251					}
252				}, 'state');
253			});
254			
255			ed.onKeyUp.add(function(ed, e) {
256				var n, rng;
257				if (isTriggerKey(e)) {
258					ed.execCommand(e.shiftKey ? 'Outdent' : 'Indent', true, null);
259					return Event.cancel(e);
260				} else if (enterDownInEmptyList && isEnterInEmptyListItem(ed, e)) {
261					if (ed.queryCommandState('InsertOrderedList')) {
262						ed.execCommand('InsertOrderedList');
263					} else {
264						ed.execCommand('InsertUnorderedList');
265					}
266					n = ed.selection.getStart();
267					if (n && n.tagName === 'LI') {
268						// Fix the caret position on IE since it jumps back up to the previous list item.
269						n = ed.dom.getParent(n, 'ol,ul').nextSibling;
270						if (n && n.tagName === 'P') {
271							if (!n.firstChild) {
272								n.appendChild(ed.getDoc().createTextNode(''));
273							}
274							rng = ed.dom.createRng();
275							rng.setStart(n.firstChild, 1);
276							rng.setEnd(n.firstChild, 1);
277							ed.selection.setRng(rng);
278						}
279					}
280					return Event.cancel(e);
281				}
282			});
283			ed.onKeyPress.add(cancelKeys);
284			ed.onKeyDown.add(cancelKeys);
285			ed.onKeyDown.add(imageJoiningListItem);
286		},
287		
288		applyList: function(targetListType, oppositeListType) {
289			var t = this, ed = t.ed, dom = ed.dom, applied = [], hasSameType = false, hasOppositeType = false, hasNonList = false, actions,
290				selectedBlocks = ed.selection.getSelectedBlocks();
291			
292			function cleanupBr(e) {
293				if (e && e.tagName === 'BR') {
294					dom.remove(e);
295				}
296			}
297			
298			function makeList(element) {
299				var list = dom.create(targetListType), li;
300				function adjustIndentForNewList(element) {
301					// If there's a margin-left, outdent one level to account for the extra list margin.
302					if (element.style.marginLeft || element.style.paddingLeft) {
303						t.adjustPaddingFunction(false)(element);
304					}
305				}
306				
307				if (element.tagName === 'LI') {
308					// No change required.
309				} else if (element.tagName === 'P' || element.tagName === 'DIV' || element.tagName === 'BODY') {
310					processBrs(element, function(startSection, br, previousBR) {
311						doWrapList(startSection, br, element.tagName === 'BODY' ? null : startSection.parentNode);
312						li = startSection.parentNode;
313						adjustIndentForNewList(li);
314						cleanupBr(br);
315					});
316					if (element.tagName === 'P' || selectedBlocks.length > 1) {
317						dom.split(li.parentNode.parentNode, li.parentNode);
318					}
319					attemptMergeWithAdjacent(li.parentNode, true);
320					return;
321				} else {
322					// Put the list around the element.
323					li = dom.create('li');
324					dom.insertAfter(li, element);
325					li.appendChild(element);
326					adjustIndentForNewList(element);
327					element = li;
328				}
329				dom.insertAfter(list, element);
330				list.appendChild(element);
331				attemptMergeWithAdjacent(list, true);
332				applied.push(element);
333			}
334			
335			function doWrapList(start, end, template) {
336				var li, n = start, tmp, i;
337				while (!dom.isBlock(start.parentNode) && start.parentNode !== dom.getRoot()) {
338					start = dom.split(start.parentNode, start.previousSibling);
339					start = start.nextSibling;
340					n = start;
341				}
342				if (template) {
343					li = template.cloneNode(true);
344					start.parentNode.insertBefore(li, start);
345					while (li.firstChild) dom.remove(li.firstChild);
346					li = dom.rename(li, 'li');
347				} else {
348					li = dom.create('li');
349					start.parentNode.insertBefore(li, start);
350				}
351				while (n && n != end) {
352					tmp = n.nextSibling;
353					li.appendChild(n);
354					n = tmp;
355				}
356				if (li.childNodes.length === 0) {
357					li.innerHTML = '<br _mce_bogus="1" />';
358				}
359				makeList(li);
360			}
361			
362			function processBrs(element, callback) {
363				var startSection, previousBR, END_TO_START = 3, START_TO_END = 1,
364					breakElements = 'br,ul,ol,p,div,h1,h2,h3,h4,h5,h6,table,blockquote,address,pre,form,center,dl';
365				function isAnyPartSelected(start, end) {
366					var r = dom.createRng(), sel;
367					bookmark.keep = true;
368					ed.selection.moveToBookmark(bookmark);
369					bookmark.keep = false;
370					sel = ed.selection.getRng(true);
371					if (!end) {
372						end = start.parentNode.lastChild;
373					}
374					r.setStartBefore(start);
375					r.setEndAfter(end);
376					return !(r.compareBoundaryPoints(END_TO_START, sel) > 0 || r.compareBoundaryPoints(START_TO_END, sel) <= 0);
377				}
378				function nextLeaf(br) {
379					if (br.nextSibling)
380						return br.nextSibling;
381					if (!dom.isBlock(br.parentNode) && br.parentNode !== dom.getRoot())
382						return nextLeaf(br.parentNode);
383				}
384				// Split on BRs within the range and process those.
385				startSection = element.firstChild;
386				// First mark the BRs that have any part of the previous section selected.
387				var trailingContentSelected = false;
388				each(dom.select(breakElements, element), function(br) {
389					var b;
390					if (br.hasAttribute && br.hasAttribute('_mce_bogus')) {
391						return true; // Skip the bogus Brs that are put in to appease Firefox and Safari.
392					}
393					if (isAnyPartSelected(startSection, br)) {
394						dom.addClass(br, '_mce_tagged_br');
395						startSection = nextLeaf(br);
396					}
397				});
398				trailingContentSelected = (startSection && isAnyPartSelected(startSection, undefined));
399				startSection = element.firstChild;
400				each(dom.select(breakElements, element), function(br) {
401					// Got a section from start to br.
402					var tmp = nextLeaf(br);
403					if (br.hasAttribute && br.hasAttribute('_mce_bogus')) {
404						return true; // Skip the bogus Brs that are put in to appease Firefox and Safari.
405					}
406					if (dom.hasClass(br, '_mce_tagged_br')) {
407						callback(startSection, br, previousBR);
408						previousBR = null;
409					} else {
410						previousBR = br;
411					}
412					startSection = tmp;
413				});
414				if (trailingContentSelected) {
415					callback(startSection, undefined, previousBR);
416				}
417			}
418			
419			function wrapList(element) {
420				processBrs(element, function(startSection, br, previousBR) {
421					// Need to indent this part
422					doWrapList(startSection, br);
423					cleanupBr(br);
424					cleanupBr(previousBR);
425				});
426			}
427			
428			function changeList(element) {
429				if (tinymce.inArray(applied, element) !== -1) {
430					return;
431				}
432				if (element.parentNode.tagName === oppositeListType) {
433					dom.split(element.parentNode, element);
434					makeList(element);
435					attemptMergeWithNext(element.parentNode, false);
436				}
437				applied.push(element);
438			}
439			
440			function convertListItemToParagraph(element) {
441				var child, nextChild, mergedElement, splitLast;
442				if (tinymce.inArray(applied, element) !== -1) {
443					return;
444				}
445				element = splitNestedLists(element, dom);
446				while (dom.is(element.parentNode, 'ol,ul,li')) {
447					dom.split(element.parentNode, element);
448				}
449				// Push the original element we have from the selection, not the renamed one.
450				applied.push(element);
451				element = dom.rename(element, 'p');
452				mergedElement = attemptMergeWithAdjacent(element, false, ed.settings.force_br_newlines);
453				if (mergedElement === element) {
454					// Now split out any block elements that can't be contained within a P.
455					// Manually iterate to ensure we handle modifications correctly (doesn't work with tinymce.each)
456					child = element.firstChild;
457					while (child) {
458						if (dom.isBlock(child)) {
459							child = dom.split(child.parentNode, child);
460							splitLast = true;
461							nextChild = child.nextSibling && child.nextSibling.firstChild; 
462						} else {
463							nextChild = child.nextSibling;
464							if (splitLast && child.tagName === 'BR') {
465								dom.remove(child);
466							}
467							splitLast = false;
468						}
469						child = nextChild;
470					}
471				}
472			}
473			
474			each(selectedBlocks, function(e) {
475				e = findItemToOperateOn(e, dom);
476				if (e.tagName === oppositeListType || (e.tagName === 'LI' && e.parentNode.tagName === oppositeListType)) {
477					hasOppositeType = true;
478				} else if (e.tagName === targetListType || (e.tagName === 'LI' && e.parentNode.tagName === targetListType)) {
479					hasSameType = true;
480				} else {
481					hasNonList = true;
482				}
483			});
484
485			if (hasNonList || hasOppositeType || selectedBlocks.length === 0) {
486				actions = {
487					'LI': changeList,
488					'H1': makeList,
489					'H2': makeList,
490					'H3': makeList,
491					'H4': makeList,
492					'H5': makeList,
493					'H6': makeList,
494					'P': makeList,
495					'BODY': makeList,
496					'DIV': selectedBlocks.length > 1 ? makeList : wrapList,
497					defaultAction: wrapList
498				};
499			} else {
500				actions = {
501					defaultAction: convertListItemToParagraph
502				};
503			}
504			this.process(actions);
505		},
506		
507		indent: function() {
508			var ed = this.ed, dom = ed.dom, indented = [];
509			
510			function createWrapItem(element) {
511				var wrapItem = dom.create('li', { style: 'list-style-type: none;'});
512				dom.insertAfter(wrapItem, element);
513				return wrapItem;
514			}
515			
516			function createWrapList(element) {
517				var wrapItem = createWrapItem(element),
518					list = dom.getParent(element, 'ol,ul'),
519					listType = list.tagName,
520					listStyle = dom.getStyle(list, 'list-style-type'),
521					attrs = {},
522					wrapList;
523				if (listStyle !== '') {
524					attrs.style = 'list-style-type: ' + listStyle + ';';
525				}
526				wrapList = dom.create(listType, attrs);
527				wrapItem.appendChild(wrapList);
528				return wrapList;
529			}
530			
531			function indentLI(element) {
532				if (!hasParentInList(ed, element, indented)) {
533					element = splitNestedLists(element, dom);
534					var wrapList = createWrapList(element);
535					wrapList.appendChild(element);
536					attemptMergeWithAdjacent(wrapList.parentNode, false);
537					attemptMergeWithAdjacent(wrapList, false);
538					indented.push(element);
539				}
540			}
541			
542			this.process({
543				'LI': indentLI,
544				defaultAction: this.adjustPaddingFunction(true)
545			});
546			
547		},
548		
549		outdent: function() {
550			var t = this, ed = t.ed, dom = ed.dom, outdented = [];
551			
552			function outdentLI(element) {
553				var listElement, targetParent, align;
554				if (!hasParentInList(ed, element, outdented)) {
555					if (dom.getStyle(element, 'margin-left') !== '' || dom.getStyle(element, 'padding-left') !== '') {
556						return t.adjustPaddingFunction(false)(element);
557					}
558					align = dom.getStyle(element, 'text-align', true);
559					if (align === 'center' || align === 'right') {
560						dom.setStyle(element, 'text-align', 'left');
561						return;
562					}
563					element = splitNestedLists(element, dom);
564					listElement = element.parentNode;
565					targetParent = element.parentNode.parentNode;
566					if (targetParent.tagName === 'P') {
567						dom.split(targetParent, element.parentNode);
568					} else {
569						dom.split(listElement, element);
570						if (targetParent.tagName === 'LI') {
571							// Nested list, need to split the LI and go back out to the OL/UL element.
572							dom.split(targetParent, element);
573						} else if (!dom.is(targetParent, 'ol,ul')) {
574							dom.rename(element, 'p');
575						}
576					}
577					outdented.push(element);
578				}
579			}
580			
581			this.process({
582				'LI': outdentLI,
583				defaultAction: this.adjustPaddingFunction(false)
584			});
585			
586			each(outdented, attemptMergeWithAdjacent);
587		},
588		
589		process: function(actions) {
590			var t = this, sel = t.ed.selection, dom = t.ed.dom, selectedBlocks, r;
591			function processElement(element) {
592				dom.removeClass(element, '_mce_act_on');
593				if (!element || element.nodeType !== 1) {
594					return;
595				}
596				element = findItemToOperateOn(element, dom);
597				var action = actions[element.tagName];
598				if (!action) {
599					action = actions.defaultAction;
600				}
601				action(element);
602			}
603			function recurse(element) {
604				t.splitSafeEach(element.childNodes, processElement);
605			}
606			function brAtEdgeOfSelection(container, offset) {
607				return offset >= 0 && container.hasChildNodes() && offset < container.childNodes.length &&
608						container.childNodes[offset].tagName === 'BR';
609			}
610			selectedBlocks = sel.getSelectedBlocks();
611			if (selectedBlocks.length === 0) {
612				selectedBlocks = [ dom.getRoot() ];
613			}
614
615			r = sel.getRng(true);
616			if (!r.collapsed) {
617				if (brAtEdgeOfSelection(r.endContainer, r.endOffset - 1)) {
618					r.setEnd(r.endContainer, r.endOffset - 1);
619					sel.setRng(r);
620				}
621				if (brAtEdgeOfSelection(r.startContainer, r.startOffset)) {
622					r.setStart(r.startContainer, r.startOffset + 1);
623					sel.setRng(r);
624				}
625			}
626			bookmark = sel.getBookmark();
627			actions.OL = actions.UL = recurse;
628			t.splitSafeEach(selectedBlocks, processElement);
629			sel.moveToBookmark(bookmark);
630			bookmark = null;
631			// Avoids table or image handles being left behind in Firefox.
632			t.ed.execCommand('mceRepaint');
633		},
634		
635		splitSafeEach: function(elements, f) {
636			if (tinymce.isGecko && (/Firefox\/[12]\.[0-9]/.test(navigator.userAgent) ||
637					/Firefox\/3\.[0-4]/.test(navigator.userAgent))) {
638				this.classBasedEach(elements, f);
639			} else {
640				each(elements, f);
641			}
642		},
643		
644		classBasedEach: function(elements, f) {
645			var dom = this.ed.dom, nodes, element;
646			// Mark nodes
647			each(elements, function(element) {
648				dom.addClass(element, '_mce_act_on');
649			});
650			nodes = dom.select('._mce_act_on');
651			while (nodes.length > 0) {
652				element = nodes.shift();
653				dom.removeClass(element, '_mce_act_on');
654				f(element);
655				nodes = dom.select('._mce_act_on');
656			}
657		},
658		
659		adjustPaddingFunction: function(isIndent) {
660			var indentAmount, indentUnits, ed = this.ed;
661			indentAmount = ed.settings.indentation;
662			indentUnits = /[a-z%]+/i.exec(indentAmount);
663			indentAmount = parseInt(indentAmount, 10);
664			return function(element) {
665				var currentIndent, newIndentAmount;
666				currentIndent = parseInt(ed.dom.getStyle(element, 'margin-left') || 0, 10) + parseInt(ed.dom.getStyle(element, 'padding-left') || 0, 10);
667				if (isIndent) {
668					newIndentAmount = currentIndent + indentAmount;
669				} else {
670					newIndentAmount = currentIndent - indentAmount;
671				}
672				ed.dom.setStyle(element, 'padding-left', '');
673				ed.dom.setStyle(element, 'margin-left', newIndentAmount > 0 ? newIndentAmount + indentUnits : '');
674			};
675		},
676		
677		getInfo: function() {
678			return {
679				longname : 'Lists',
680				author : 'Moxiecode Systems AB',
681				authorurl : 'http://tinymce.moxiecode.com',
682				infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/lists',
683				version : tinymce.majorVersion + "." + tinymce.minorVersion
684			};
685		}
686	});
687	tinymce.PluginManager.add("lists", tinymce.plugins.Lists);
688}());