Skip to content

Commit a77c85f

Browse files
committed
Merge branch 't/9481'
2 parents eb4eaf4 + 67dfcdf commit a77c85f

File tree

1 file changed

+156
-66
lines changed

1 file changed

+156
-66
lines changed

plugins/magicline/plugin.js

Lines changed: 156 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
holdDistance: 0 | triggerOffset * ( config.magicline_holdDistance || 0.5 ),
3737
boxColor: config.magicline_color || '#ff0000',
3838
rtl: config.contentsLangDirection == 'rtl',
39-
triggers: config.magicline_everywhere ? CKEDITOR.dtd.$block : { table:1,hr:1,div:1,ul:1,ol:1,dl:1,form:1,blockquote:1 }
39+
triggers: config.magicline_everywhere ? dtd.$block : { table:1,hr:1,div:1,ul:1,ol:1,dl:1,form:1,blockquote:1 }
4040
},
4141
scrollTimeout, hideTimeout, checkMouseTimeoutPending, checkMouseTimeout, checkMouseTimer;
4242

@@ -72,11 +72,6 @@
7272
&& !isFlowBreaker( node ); // -> Node can be neither floated nor positioned nor aligned.
7373
};
7474

75-
// %REMOVE_START%
76-
// Editor commands for accessing difficult focus spaces.
77-
editor.addCommand( 'accessSpaceBefore', accessSpaceCommand( that ) );
78-
editor.addCommand( 'accessSpaceAfter', accessSpaceCommand( that, true ) );
79-
// %REMOVE_END%
8075
editor.on( 'contentDom', addListeners, this );
8176

8277
function addListeners() {
@@ -99,7 +94,7 @@
9994

10095
// Enabling the box inside of inline editable is pointless.
10196
// There's no need to access spaces inside paragraphs, links, spans, etc.
102-
if ( editable.is( CKEDITOR.dtd.$inline ) )
97+
if ( editable.is( dtd.$inline ) )
10398
return;
10499

105100
// Handle in-line editing by setting appropriate position.
@@ -274,6 +269,15 @@
274269
that.debug.showHidden( that.hiddenMode ); // %REMOVE_LINE%
275270
});
276271

272+
// Editor commands for accessing difficult focus spaces.
273+
editor.addCommand( 'accessPreviousSpace', accessFocusSpaceCmd( that ) );
274+
editor.addCommand( 'accessNextSpace', accessFocusSpaceCmd( that, true ) );
275+
276+
editor.setKeystroke( [
277+
[ config.magicline_keystrokePrevious, 'accessPreviousSpace' ],
278+
[ config.magicline_keystrokeNext, 'accessNextSpace' ]
279+
] );
280+
277281
// This method handles mousemove mouse for box toggling.
278282
// It uses mouse position to determine underlying element, then
279283
// it tries to use different trigger type in order to place the box
@@ -332,8 +336,15 @@
332336
}
333337
}
334338

335-
// Constant values, types and so on.
336-
var EDGE_TOP = 128,
339+
// Some shorthands for common methods to save bytes
340+
var extend = CKEDITOR.tools.extend,
341+
newElement = CKEDITOR.dom.element,
342+
newElementFromHtml = newElement.createFromHtml,
343+
env = CKEDITOR.env,
344+
dtd = CKEDITOR.dtd,
345+
346+
// Constant values, types and so on.
347+
EDGE_TOP = 128,
337348
EDGE_BOTTOM = 64,
338349
EDGE_MIDDLE = 32,
339350
TYPE_EDGE = 16,
@@ -342,8 +353,9 @@
342353
LOOK_BOTTOM = 2,
343354
LOOK_NORMAL = 1,
344355
WHITE_SPACE = '\u00A0',
345-
DTD_LISTITEM = CKEDITOR.dtd.$listItem,
346-
DTD_TABLECONTENT = CKEDITOR.dtd.$tableContent,
356+
DTD_LISTITEM = dtd.$listItem,
357+
DTD_TABLECONTENT = dtd.$tableContent,
358+
DTD_NONACCESSIBLE = extend( {}, dtd.$nonEditable, dtd.$empty ),
347359

348360
// Minimum time that must elapse between two update*Size calls.
349361
// It prevents constant getComuptedStyle calls and improves performance.
@@ -352,42 +364,7 @@
352364
// Shared CSS stuff for box elements
353365
CSS_COMMON = 'width:0px;height:0px;padding:0px;margin:0px;display:block;' + 'z-index:9999;color:#fff;position:absolute;font-size: 0px;line-height:0px;',
354366
CSS_TRIANGLE = CSS_COMMON + 'border-color:transparent;display:block;border-style:solid;',
355-
TRIANGLE_HTML = '<span>' + WHITE_SPACE + '</span>',
356-
357-
// Some shorthands for common methods to save bytes
358-
extend = CKEDITOR.tools.extend,
359-
newElement = CKEDITOR.dom.element,
360-
newElementFromHtml = newElement.createFromHtml,
361-
env = CKEDITOR.env;
362-
363-
// %REMOVE_START%
364-
// Access focus space on demand by looking for closest parent trigger
365-
// or using current element under the caret as reference.
366-
function accessSpaceCommand( that, insertAfter ) {
367-
return {
368-
canUndo: true,
369-
modes: { wysiwyg:1 },
370-
exec: function( editor ) {
371-
var selection = editor.getSelection(),
372-
selected = selection.getStartElement(),
373-
range = selection.getRanges()[ 0 ],
374-
target = getAscendantTrigger( that, selected ) || selected;
375-
376-
if ( !isHtml( target ) )
377-
return;
378-
379-
accessFocusSpace( that, function( accessNode ) {
380-
if ( target.equals( that.editable ) )
381-
range.insertNode( accessNode );
382-
else
383-
accessNode[ insertAfter ? 'insertAfter' : 'insertBefore' ]( target );
384-
});
385-
386-
that.line.detach();
387-
}
388-
};
389-
}
390-
// %REMOVE_END%
367+
TRIANGLE_HTML = '<span>' + WHITE_SPACE + '</span>';
391368

392369
function areSiblings( that, upper, lower ) {
393370
return isHtml( upper ) && isHtml( lower ) && lower.equals( upper.getNext( function( node ) {
@@ -731,7 +708,7 @@
731708

732709
that.editor.focus();
733710

734-
if( !env.ie && that.enterMode != CKEDITOR.ENTER_BR )
711+
if ( !env.ie && that.enterMode != CKEDITOR.ENTER_BR )
735712
that.hotNode.scrollIntoView();
736713

737714
event.data.preventDefault( true );
@@ -782,6 +759,125 @@
782759
editor.fire( 'saveSnapshot' );
783760
}
784761

762+
// Access focus space on demand by taking an element under the caret as a reference.
763+
// The space is accessed provided the element under the caret is trigger AND:
764+
//
765+
// 1. First/last-child of its parent:
766+
// +----------------------- Parent element -+
767+
// | +------------------------------ DIV -+ | <-- Access before
768+
// | | Foo^ | |
769+
// | | | |
770+
// | +------------------------------------+ | <-- Access after
771+
// +----------------------------------------+
772+
//
773+
// OR
774+
//
775+
// 2. It has a direct sibling element, which is also a trigger:
776+
// +-------------------------------- DIV#1 -+
777+
// | Foo^ |
778+
// | |
779+
// +----------------------------------------+
780+
// <-- Access here
781+
// +-------------------------------- DIV#2 -+
782+
// | Bar |
783+
// | |
784+
// +----------------------------------------+
785+
//
786+
// OR
787+
//
788+
// 3. It has a direct sibling, which is a trigger and has a valid neighbour trigger,
789+
// but belongs to dtd.$.empty/nonEditable:
790+
// +------------------------------------ P -+
791+
// | Foo^ |
792+
// | |
793+
// +----------------------------------------+
794+
// +----------------------------------- HR -+
795+
// <-- Access here
796+
// +-------------------------------- DIV#2 -+
797+
// | Bar |
798+
// | |
799+
// +----------------------------------------+
800+
//
801+
function accessFocusSpaceCmd( that, insertAfter ) {
802+
return {
803+
canUndo: true,
804+
modes: { wysiwyg: 1 },
805+
exec: ( function() {
806+
// Inserts line (accessNode) at the position by taking target node as a reference.
807+
function doAccess( target ) {
808+
accessFocusSpace( that, function( accessNode ) {
809+
accessNode[ insertAfter ? 'insertAfter' : 'insertBefore' ]( target );
810+
});
811+
812+
if( !env.ie && that.enterMode != CKEDITOR.ENTER_BR )
813+
that.hotNode.scrollIntoView();
814+
815+
// Detach the line if was visible (previously triggered by mouse).
816+
that.line.detach();
817+
}
818+
819+
return function( editor ) {
820+
var selected = editor.getSelection().getStartElement();
821+
822+
// That holds element from mouse. Replace it with the
823+
// element under the caret.
824+
that.element = selected;
825+
826+
// (3.) Handle the following cases where selected neighbour
827+
// is a trigger inaccessible for the caret AND:
828+
// - Is first/last-child
829+
// OR
830+
// - Has a sibling, which is also a trigger.
831+
var neighbor = getNonEmptyNeighbour( that, selected, !insertAfter ),
832+
neighborSibling;
833+
834+
// Check for a neighbour that belongs to triggers.
835+
// Consider only non-accessible elements (they cannot have any children)
836+
// since they cannot be given a caret inside, to run the command
837+
// the regular way (1. & 2.).
838+
if ( isHtml( neighbor ) && neighbor.is( that.triggers ) && neighbor.is( DTD_NONACCESSIBLE ) &&
839+
(
840+
// Check whether neighbor is first/last-child.
841+
!getNonEmptyNeighbour( that, neighbor, !insertAfter )
842+
||
843+
// Check for a sibling of a neighbour that also is a trigger.
844+
(
845+
( neighborSibling = getNonEmptyNeighbour( that, neighbor, !insertAfter ) ) &&
846+
isHtml( neighborSibling ) &&
847+
neighborSibling.is( that.triggers )
848+
)
849+
)
850+
) {
851+
doAccess( neighbor );
852+
return;
853+
}
854+
855+
// Look for possible target element DOWN "selected" DOM branch (towards editable)
856+
// that belong to that.triggers
857+
var target = getAscendantTrigger( that, selected );
858+
859+
// No HTML target -> no access.
860+
if ( !isHtml( target ) )
861+
return;
862+
863+
// (1.) Target is first/last child -> access.
864+
if ( !getNonEmptyNeighbour( that, target, !insertAfter ) ) {
865+
doAccess( target );
866+
return;
867+
}
868+
869+
var sibling = getNonEmptyNeighbour( that, target, !insertAfter );
870+
871+
// (2.) Target has a sibling that belongs to that.triggers -> access.
872+
if ( sibling && isHtml( sibling ) && sibling.is( that.triggers ) ) {
873+
doAccess( target );
874+
return;
875+
}
876+
};
877+
})()
878+
};
879+
}
880+
785881
function isLine( that, node ) {
786882
if ( !( node && node.type == CKEDITOR.NODE_ELEMENT && node.$ ) )
787883
return false;
@@ -1545,35 +1641,29 @@
15451641
* @see CKEDITOR.config#magicline_triggerOffset
15461642
*/
15471643

1548-
// %REMOVE_START%
1549-
15501644
/**
1551-
* Defines default keystroke that access the space before an element that
1552-
* holds start of the current selection or just simply holds the caret.
1645+
* Defines default keystroke that access the closest unreachable focus space **before**
1646+
* the caret (start of the selection). If there's no any focus space, selection remains.
15531647
*
1554-
* // Changes keystroke to CTRL + SHIFT + ,
1555-
* CKEDITOR.config.magicline_keystrokeBefore = CKEDITOR.CTRL + CKEDITOR.SHIFT + 188;
1648+
* // Changes keystroke to CTRL + ,
1649+
* CKEDITOR.config.magicline_keystrokePrevious = CKEDITOR.CTRL + 188;
15561650
*
1557-
* @ignore
1558-
* @cfg {Number} [magicline_keystrokeBefore=CKEDITOR.CTRL + CKEDITOR.SHIFT + 219 (CTRL + SHIFT + [)]
1651+
* @cfg {Number} [magicline_keystrokePrevious=CKEDITOR.CTRL + CKEDITOR.ALT + 219 (CTRL + ALT + [)]
15591652
* @member CKEDITOR.config
15601653
*/
1561-
// CKEDITOR.config.magicline_keystrokeBefore = CKEDITOR.CTRL + CKEDITOR.SHIFT + 219; // CTRL + SHIFT + [
1654+
CKEDITOR.config.magicline_keystrokePrevious = CKEDITOR.CTRL + CKEDITOR.ALT + 219; // CTRL + ALT + [
15621655

15631656
/**
1564-
* Defines default keystroke that access the space after an element that
1565-
* holds start of the current selection or just simply holds the caret.
1657+
* Defines default keystroke that access the closest unreachable focus space **after**
1658+
* the caret (start of the selection). If there's no any focus space, selection remains.
15661659
*
1567-
* // Changes keystroke to CTRL + SHIFT + .
1568-
* CKEDITOR.config.magicline_keystrokeBefore = CKEDITOR.CTRL + CKEDITOR.SHIFT + 190;
1660+
* // Changes keystroke to CTRL + .
1661+
* CKEDITOR.config.magicline_keystrokeNext = CKEDITOR.CTRL + 190;
15691662
*
1570-
* @ignore
1571-
* @cfg {Number} [magicline_keystrokeBefore=CKEDITOR.CTRL + CKEDITOR.SHIFT + 221 (CTRK + SHIFT + ])]
1663+
* @cfg {Number} [magicline_keystrokeNext=CKEDITOR.CTRL + CKEDITOR.ALT + 221 (CTRL + ALT + ])]
15721664
* @member CKEDITOR.config
15731665
*/
1574-
// CKEDITOR.config.magicline_keystrokeAfter = CKEDITOR.CTRL + CKEDITOR.SHIFT + 221; // CTRL + SHIFT + ]
1575-
1576-
// %REMOVE_END%
1666+
CKEDITOR.config.magicline_keystrokeNext = CKEDITOR.CTRL + CKEDITOR.ALT + 221; // CTRL + ALT + ]
15771667

15781668
/**
15791669
* Defines box color. The color may be adjusted to enhance readability.

0 commit comments

Comments
 (0)