Skip to content

Commit

Permalink
Merge branch 't/10828' into major
Browse files Browse the repository at this point in the history
  • Loading branch information
oleq committed Oct 29, 2013
2 parents 3c40e20 + 899e530 commit 3ec2376
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -35,6 +35,7 @@ Fixed Issues:
* [#10866](http://dev.ckeditor.com/ticket/10866): Fixed: Broken *Tab* key navigation in the Image2 dialog.
* [#10854](http://dev.ckeditor.com/ticket/10854): Fixed: Firefox prepends `<br>` to `<body>`, so it is stripped by the HTML data processor.
* [#10823](http://dev.ckeditor.com/ticket/10823): Fixed: Link plugin does not work with non-editable content.
* [#10828](http://dev.ckeditor.com/ticket/10828): Magicline integration with widgets system.

## CKEditor 4.3 Beta

Expand Down
100 changes: 80 additions & 20 deletions plugins/magicline/plugin.js
Expand Up @@ -17,26 +17,19 @@

// Activates the box inside of an editor.
function initPlugin( editor ) {

var enterBehaviors = {};
enterBehaviors[ CKEDITOR.ENTER_BR ] = 'br';
enterBehaviors[ CKEDITOR.ENTER_P ] = 'p';
enterBehaviors[ CKEDITOR.ENTER_DIV ] = 'div';

// Configurables
var config = editor.config,
triggerOffset = config.magicline_triggerOffset || 30,
enterMode = config.enterMode,
that = {
// Global stuff is being initialized here.
editor: editor,
enterBehavior: enterBehaviors[ enterMode ], // A tag which is to be inserted by the magicline.
enterMode: enterMode,
triggerOffset: triggerOffset,
holdDistance: 0 | triggerOffset * ( config.magicline_holdDistance || 0.5 ),
boxColor: config.magicline_color || '#ff0000',
rtl: config.contentsLangDirection == 'rtl',
tabuList: [ 'data-widget-wrapper' ].concat( config.magicline_tabuList || [] ),
tabuList: [ 'data-cke-hidden-sel' ].concat( config.magicline_tabuList || [] ),
triggers: config.magicline_everywhere ? DTD_BLOCK : { table:1,hr:1,div:1,ul:1,ol:1,dl:1,form:1,blockquote:1 }
},
scrollTimeout, checkMouseTimeoutPending, checkMouseTimeout, checkMouseTimer;
Expand Down Expand Up @@ -86,7 +79,8 @@
editable: editable,
inInlineMode: editable.isInline(),
doc: doc,
win: win
win: win,
hotNode: null
}, true );

// This is the boundary of the editor. For inline the boundary is editable itself.
Expand Down Expand Up @@ -278,15 +272,15 @@

// Revert magicline hot node on undo/redo.
editor.on( 'loadSnapshot', function( event ) {
var elements = editor.document.getElementsByTag( that.enterBehavior ),
var elements = doc.find( 'p,br,div' ),
element;

for ( var i = elements.count(); i--; ) {
if ( ( element = elements.getItem( i ) ).hasAttribute( 'data-cke-magicline-hot' ) ) {
if ( ( element = elements.getItem( i ) ).data( 'cke-magicline-hot' ) ) {
// Restore hotNode
that.hotNode = element;
// Restore last access direction
that.lastCmdDirection = element.getAttribute( 'data-cke-magicline-dir' ) === 'true' ? true : false;
that.lastCmdDirection = element.data( 'cke-magicline-dir' ) === 'true' ? true : false;
break;
}
}
Expand Down Expand Up @@ -359,6 +353,9 @@
env = CKEDITOR.env,
dtd = CKEDITOR.dtd,

// Global object associating enter modes with elements.
enterElements = {},

// Constant values, types and so on.
EDGE_TOP = 128,
EDGE_BOTTOM = 64,
Expand All @@ -383,6 +380,10 @@
CSS_TRIANGLE = CSS_COMMON + 'border-color:transparent;display:block;border-style:solid;',
TRIANGLE_HTML = '<span>' + WHITE_SPACE + '</span>';

enterElements[ CKEDITOR.ENTER_BR ] = 'br';
enterElements[ CKEDITOR.ENTER_P ] = 'p';
enterElements[ CKEDITOR.ENTER_DIV ] = 'div';

function areSiblings( that, upper, lower ) {
return isHtml( upper ) && isHtml( lower ) && lower.equals( upper.getNext( function( node ) {
return !( isEmptyTextNode( node ) || isComment( node ) || isFlowBreaker( node ) );
Expand Down Expand Up @@ -462,9 +463,25 @@
trigger;

if ( node && isHtml( node ) ) {
return ( trigger = node.getAscendant( that.triggers, true ) ) &&
!trigger.contains( that.editable ) &&
!trigger.equals( that.editable ) ? trigger : null;
trigger = node.getAscendant( that.triggers, true );

// If trigger is an element, neither editable nor editable's ascendant.
if ( trigger && !trigger.contains( that.editable ) && !trigger.equals( that.editable ) ) {
// Check for closest editable limit.
var limit = getClosestEditableLimit( trigger, true );

// Trigger in nested editable area.
if ( limit.getAttribute( 'contenteditable' ) == 'true' )
return trigger
// Trigger in non-editable area.
else if ( limit.is( that.triggers ) )
return limit;
else
return null;

return trigger;
} else
return null;
}

return null;
Expand Down Expand Up @@ -497,6 +514,29 @@
return val > lower && val < upper;
}

// Returns the closest ancestor that has contenteditable attribute.
// Such ancestor is the limit of (non-)editable DOM branch that element
// belongs to. This method omits editor editable.
function getClosestEditableLimit( element, includeSelf ) {
if ( element.data( 'cke-editable' ) )
return null;

if ( !includeSelf )
element = element.getParent();

while ( element ) {
if ( element.data( 'cke-editable' ) )
return null;

if ( element.hasAttribute( 'contenteditable' ) )
return element;

element = element.getParent();
}

return null;
}

// Access space line consists of a few elements (spans):
// \-> Line wrapper.
// \-> Line.
Expand Down Expand Up @@ -759,9 +799,19 @@

// In other cases a regular element is used.
else {
accessNode = new newElement( that.enterBehavior, that.doc );
// Use the enterMode of editable's limit or editor's
// enter mode if not in nested editable.
var limit = getClosestEditableLimit( that.element, true ),

if ( that.enterMode != CKEDITOR.ENTER_BR ) {
// This is an enter mode for the context. We cannot use
// editor.activeEnterMode because the focused nested editable will
// have a different enterMode as editor but magicline will be inserted
// directly into editor's editable.
enterMode = limit && limit.data( 'cke-enter-mode' ) || that.enterMode;

accessNode = new newElement( enterElements[ enterMode ], that.doc );

if ( !accessNode.is( 'br' ) ) {
var dummy = that.doc.createText( WHITE_SPACE );
dummy.appendTo( accessNode );
}
Expand Down Expand Up @@ -857,7 +907,8 @@
}

return function( editor ) {
var selected = editor.getSelection().getStartElement();
var selected = editor.getSelection().getStartElement(),
limit;

// (#9833) Go down to the closest non-inline element in DOM structure
// since inline elements don't participate in in magicline.
Expand All @@ -873,6 +924,11 @@
if ( !selected || selected.equals( that.editable ) || selected.contains( that.editable ) )
return;

// Executing the command directly in nested editable should
// access space before/after it.
if ( ( limit = getClosestEditableLimit( selected ) ) && limit.getAttribute( 'contenteditable' ) == 'false' )
selected = limit;

// That holds element from mouse. Replace it with the
// element under the caret.
that.element = selected;
Expand Down Expand Up @@ -969,7 +1025,7 @@
var isComment = CKEDITOR.dom.walker.nodeType( CKEDITOR.NODE_COMMENT );

function isPositioned( element ) {
return !!{ absolute:1,fixed:1,relative:1 }[ element.getComputedStyle( 'position' ) ];
return !!{ absolute:1,fixed:1 }[ element.getComputedStyle( 'position' ) ];
}

// Is text node?
Expand Down Expand Up @@ -1058,7 +1114,7 @@
// Edge node according to bottomTrigger.
edgeNode = editable[ bottomTrigger ? 'getLast' : 'getFirst' ]( function( node ) {
return !( isEmptyTextNode( node ) || isComment( node ) );
});
} );

// There's no edge node. Abort.
if ( !edgeNode ) {
Expand Down Expand Up @@ -1331,6 +1387,10 @@
return null;
}

// Stop searching if element is in non-editable branch of DOM.
if ( startElement.isReadOnly() )
return null;

trigger = verticalSearch( that,
function( current, startElement ) {
return !startElement.equals( current ); // stop when start element and the current one differ
Expand Down

0 comments on commit 3ec2376

Please sign in to comment.