\r
function onSelectionChange( evt )\r
{\r
- var elements = evt.data.path.elements,\r
- listNode, listItem,\r
- editor = evt.editor;\r
+ var editor = evt.editor;\r
\r
- for ( var i = 0 ; i < elements.length ; i++ )\r
- {\r
- if ( elements[i].getName() == 'li' )\r
- {\r
- listItem = elements[i];\r
- continue;\r
- }\r
- if ( listNodeNames[ elements[i].getName() ] )\r
- {\r
- listNode = elements[i];\r
- break;\r
- }\r
- }\r
+ var elementPath = evt.data.path,\r
+ list = elementPath && elementPath.contains( listNodeNames );\r
\r
- if ( listNode )\r
- {\r
- if ( this.name == 'outdent' )\r
+ if ( list )\r
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );\r
- else\r
- {\r
- while ( listItem && ( listItem = listItem.getPrevious( CKEDITOR.dom.walker.whitespaces( true ) ) ) )\r
- {\r
- if ( listItem.getName && listItem.getName() == 'li' )\r
- return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );\r
- }\r
- return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );\r
- }\r
- }\r
\r
if ( !this.useIndentClasses && this.name == 'indent' )\r
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );\r
iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;\r
var block;\r
while ( ( block = iterator.getNextParagraph() ) )\r
- {\r
+ indentElement.call( this, editor, block );\r
+ }\r
\r
+ function indentElement( editor, element )\r
+ {\r
if ( this.useIndentClasses )\r
{\r
// Transform current class name to indent step index.\r
- var indentClass = block.$.className.match( this.classNameRegex ),\r
+ var indentClass = element.$.className.match( this.classNameRegex ),\r
indentStep = 0;\r
if ( indentClass )\r
{\r
indentStep--;\r
else\r
indentStep++;\r
+\r
+ if ( indentStep < 0 )\r
+ return false;\r
+\r
indentStep = Math.min( indentStep, editor.config.indentClasses.length );\r
indentStep = Math.max( indentStep, 0 );\r
- var className = CKEDITOR.tools.ltrim( block.$.className.replace( this.classNameRegex, '' ) );\r
+ var className = CKEDITOR.tools.ltrim( element.$.className.replace( this.classNameRegex, '' ) );\r
if ( indentStep < 1 )\r
- block.$.className = className;\r
+ element.$.className = className;\r
else\r
- block.$.className = CKEDITOR.tools.ltrim( className + ' ' + editor.config.indentClasses[ indentStep - 1 ] );\r
+ element.addClass( editor.config.indentClasses[ indentStep - 1 ] );\r
}\r
else\r
{\r
- var currentOffset = parseInt( block.getStyle( this.indentCssProperty ), 10 );\r
+ var currentOffset = parseInt( element.getStyle( this.indentCssProperty ), 10 );\r
if ( isNaN( currentOffset ) )\r
currentOffset = 0;\r
currentOffset += ( this.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;\r
+\r
+ if ( currentOffset < 0 )\r
+ return false;\r
+\r
currentOffset = Math.max( currentOffset, 0 );\r
currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;\r
- block.setStyle( this.indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );\r
- if ( block.getAttribute( 'style' ) === '' )\r
- block.removeAttribute( 'style' );\r
+ element.setStyle( this.indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );\r
+ if ( element.getAttribute( 'style' ) === '' )\r
+ element.removeAttribute( 'style' );\r
}\r
+\r
+ return true;\r
}\r
- }\r
\r
function indentCommand( editor, name )\r
{\r
this.startDisabled = name == 'outdent';\r
}\r
\r
+ function isListItem( node )\r
+ {\r
+ return node.type = CKEDITOR.NODE_ELEMENT && node.is( 'li' );\r
+ }\r
+\r
indentCommand.prototype = {\r
exec : function( editor )\r
{\r
var selection = editor.getSelection(),\r
range = selection && selection.getRanges()[0];\r
\r
- if ( !selection || !range )\r
- return;\r
-\r
- var bookmarks = selection.createBookmarks( true ),\r
- nearestListBlock = range.getCommonAncestor();\r
+ var startContainer = range.startContainer,\r
+ endContainer = range.endContainer,\r
+ rangeRoot = range.getCommonAncestor(),\r
+ nearestListBlock = rangeRoot;\r
\r
while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&\r
listNodeNames[ nearestListBlock.getName() ] ) )\r
nearestListBlock = nearestListBlock.getParent();\r
\r
- if ( nearestListBlock )\r
+ // Avoid selection anchors under list root.\r
+ // <ul>[<li>...</li>]</ul> => <ul><li>[...]</li></ul>\r
+ if ( nearestListBlock && startContainer.type == CKEDITOR.NODE_ELEMENT\r
+ && startContainer.getName() in listNodeNames )\r
+ {\r
+ var walker = new CKEDITOR.dom.walker( range );\r
+ walker.evaluator = isListItem;\r
+ range.startContainer = walker.next();\r
+ }\r
+\r
+ if ( nearestListBlock && endContainer.type == CKEDITOR.NODE_ELEMENT\r
+ && endContainer.getName() in listNodeNames )\r
+ {\r
+ walker = new CKEDITOR.dom.walker( range );\r
+ walker.evaluator = isListItem;\r
+ range.endContainer = walker.previous();\r
+ }\r
+\r
+ var bookmarks = selection.createBookmarks( true );\r
+\r
+ if ( nearestListBlock )\r
+ {\r
+ var firstListItem = nearestListBlock.getFirst( function( node )\r
+ {\r
+ return node.type == CKEDITOR.NODE_ELEMENT && node.is( 'li' );\r
+ }),\r
+ rangeStart = range.startContainer,\r
+ indentWholeList = firstListItem.equals( rangeStart ) || firstListItem.contains( rangeStart );\r
+\r
+ // Indent the entire list if cursor is inside the first list item. (#3893)\r
+ if ( !( indentWholeList && indentElement.call( this, editor, nearestListBlock ) ) )\r
indentList.call( this, editor, range, nearestListBlock );\r
+ }\r
else\r
indentBlock.call( this, editor, range );\r
\r
// Register the state changing handlers.\r
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, indent ) );\r
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, outdent ) );\r
+\r
+ // [IE6/7] Raw lists are using margin instead of padding for visual indentation in wysiwyg mode. (#3893)\r
+ if ( CKEDITOR.env.ie6Compat || CKEDITOR.env.ie7Compat )\r
+ {\r
+ editor.addCss(\r
+ "ul,ol" +\r
+ "{" +\r
+ " margin-left: 0px;" +\r
+ " padding-left: 40px;" +\r
+ "}" );\r
+ }\r
},\r
\r
requires : [ 'domiterator', 'list' ]\r