@@ -302,12 +302,18 @@ CKEDITOR.plugins.add('scayt', {
302302
303303 var contentDomHandler = function ( ) {
304304 if ( inline_mode ) {
305- editor . on ( 'blur' , scaytDestroy ) ;
306- editor . on ( 'focus' , contentDomReady ) ;
307305
308- // We need to check if editor has focus(created) right now.
309- // If editor is active - make attempt to create scayt
310- if ( editor . focusManager . hasFocus ) {
306+ if ( ! editor . config . scayt_inlineModeImmediateMarkup ) {
307+ editor . on ( 'blur' , scaytDestroy ) ;
308+ editor . on ( 'focus' , contentDomReady ) ;
309+
310+ // We need to check if editor has focus(created) right now.
311+ // If editor is active - make attempt to create scayt
312+ if ( editor . focusManager . hasFocus ) {
313+ contentDomReady ( ) ;
314+ }
315+
316+ } else {
311317 contentDomReady ( ) ;
312318 }
313319
@@ -322,6 +328,7 @@ CKEDITOR.plugins.add('scayt', {
322328
323329 editor . on ( 'beforeCommandExec' , function ( ev ) {
324330 var scaytInstance = editor . scayt ,
331+ selectedLangElement = null ,
325332 forceBookmark = false ,
326333 removeMarkupInsideSelection = true ;
327334
@@ -333,36 +340,33 @@ CKEDITOR.plugins.add('scayt', {
333340 }
334341 } else if ( ev . data . name === 'bold' || ev . data . name === 'italic' || ev . data . name === 'underline' ||
335342 ev . data . name === 'strike' || ev . data . name === 'subscript' || ev . data . name === 'superscript' ||
336- ev . data . name === 'enter' || ev . data . name === 'cut' ) {
343+ ev . data . name === 'enter' || ev . data . name === 'cut' || ev . data . name === 'language' ) {
337344 if ( scaytInstance ) {
338345 if ( ev . data . name === 'cut' ) {
339346 removeMarkupInsideSelection = false ;
340347 // We need to force bookmark before we remove our markup.
341348 // Otherwise we will get issues with cutting text via context menu.
342349 forceBookmark = true ;
343350 }
344- scaytInstance . removeMarkupInSelectionNode ( {
345- removeInside : removeMarkupInsideSelection ,
346- forceBookmark : forceBookmark
347- } ) ;
348-
349- setTimeout ( function ( ) {
350- scaytInstance . fire ( 'startSpellCheck, startGrammarCheck' ) ;
351- } , 0 ) ;
352- }
353- }
354351
355- // We need to remove all SCAYT markup from 'lang' node before it will be deleted.
356- // We need to remove SCAYT markup from selected text before creating 'lang' node as well.
357- if ( ev . data . name === 'language' ) {
358- var selectedLangElement = editor . plugins . language . getCurrentLangElement ( editor ) ;
359-
360- if ( scaytInstance ) {
361- scaytInstance . removeMarkupInSelectionNode ( { selectionNode : selectedLangElement && selectedLangElement . $ } ) ;
352+ // We need to remove all SCAYT markup from 'lang' node before it will be deleted.
353+ // We need to remove SCAYT markup from selected text before creating 'lang' node as well.
354+ if ( ev . data . name === 'language' ) {
355+ selectedLangElement = editor . plugins . language . getCurrentLangElement ( editor ) ;
356+ selectedLangElement = selectedLangElement && selectedLangElement . $ ;
357+ // We need to force bookmark before we remove our markup.
358+ // Otherwise we will get issues with cutting text via language plugin menu.
359+ forceBookmark = true ;
360+ }
362361
363- setTimeout ( function ( ) {
364- scaytInstance . fire ( 'startSpellCheck, startGrammarCheck' ) ;
365- } , 0 ) ;
362+ editor . fire ( 'reloadMarkupScayt' , {
363+ removeOptions : {
364+ removeInside : removeMarkupInsideSelection ,
365+ forceBookmark : forceBookmark ,
366+ selectionNode : selectedLangElement
367+ } ,
368+ timeout : 0
369+ } ) ;
366370 }
367371 }
368372 } ) ;
@@ -435,36 +439,35 @@ CKEDITOR.plugins.add('scayt', {
435439 }
436440 } , this , null , 50 ) ;
437441
438- function reloadMarkupScayt ( ) {
439- var scaytInstance = editor . scayt ;
442+ editor . on ( 'reloadMarkupScayt' , function ( ev ) {
443+ var scaytInstance = editor . scayt ,
444+ removeOptions = ev . data && ev . data . removeOptions ,
445+ timeout = ev . data && ev . data . timeout ;
440446
441447 if ( scaytInstance ) {
442- scaytInstance . removeMarkupInSelectionNode ( ) ;
443- scaytInstance . fire ( 'startSpellCheck, startGrammarCheck' ) ;
448+ scaytInstance . removeMarkupInSelectionNode ( removeOptions ) ;
449+ if ( typeof timeout === 'number' ) {
450+ setTimeout ( function ( ) {
451+ scaytInstance . fire ( 'startSpellCheck, startGrammarCheck' ) ;
452+ } , timeout ) ;
453+ } else {
454+ scaytInstance . fire ( 'startSpellCheck, startGrammarCheck' ) ;
455+ }
444456 }
445- }
457+ } ) ;
446458
447459 // Reload spell-checking for current word after insertion completed.
448460 editor . on ( 'insertElement' , function ( ) {
449-
450461 // IE bug: we need wait here to make sure that focus is returned to editor, and we can store the selection before we proceed with markup
451- if ( CKEDITOR . env . ie ) {
452- setTimeout ( function ( ) {
453- reloadMarkupScayt ( ) ;
454- } , 50 ) ;
455- } else {
456- reloadMarkupScayt ( ) ;
457- }
458-
459-
462+ editor . fire ( 'reloadMarkupScayt' , { removeOptions : { forceBookmark : true } } ) ;
460463 } , this , null , 50 ) ;
461464
462465 editor . on ( 'insertHtml' , function ( ) {
463- reloadMarkupScayt ( ) ;
466+ editor . fire ( 'reloadMarkupScayt' ) ;
464467 } , this , null , 50 ) ;
465468
466469 editor . on ( 'insertText' , function ( ) {
467- reloadMarkupScayt ( ) ;
470+ editor . fire ( 'reloadMarkupScayt' ) ;
468471 } , this , null , 50 ) ;
469472
470473 // The event is listening to open necessary dialog tab
@@ -499,6 +502,9 @@ CKEDITOR.plugins.add('scayt', {
499502 if ( typeof editor . config . grayt_autoStartup !== 'boolean' || inlineMode || editor . plugins . divarea ) {
500503 editor . config . grayt_autoStartup = false ;
501504 }
505+ if ( typeof editor . config . scayt_inlineModeImmediateMarkup !== 'boolean' ) {
506+ editor . config . scayt_inlineModeImmediateMarkup = false ;
507+ }
502508 plugin . state . grayt [ editor . name ] = editor . config . grayt_autoStartup ;
503509
504510 if ( ! editor . config . scayt_contextCommands ) {
@@ -675,22 +681,12 @@ CKEDITOR.plugins.add('scayt', {
675681 var dataFilterRules = {
676682 elements : {
677683 span : function ( element ) {
678- var scaytState = plugin . state . scayt [ editor . name ] ,
679- graytState = plugin . state . grayt [ editor . name ] ;
680-
681- if ( plugin && element . classes && (
682- ( scaytState && CKEDITOR . tools . search ( element . classes , plugin . options . misspelled_word_class ) ) ||
683- ( graytState && CKEDITOR . tools . search ( element . classes , plugin . options . problem_grammar_class ) )
684- ) ) {
685-
686- if ( element . classes && element . parent . type === CKEDITOR . NODE_DOCUMENT_FRAGMENT ) {
687- delete element . attributes [ 'style' ] ;
688- delete element . name ;
689- } else {
690- delete element . classes [ CKEDITOR . tools . indexOf ( element . classes , plugin . options . misspelled_word_class ) ] ;
691- delete element . classes [ CKEDITOR . tools . indexOf ( element . classes , plugin . options . problem_grammar_class ) ] ;
692- }
693684
685+ var scaytState = element . hasClass ( plugin . options . misspelled_word_class ) && element . attributes [ plugin . options . data_attribute_name ] ,
686+ graytState = element . hasClass ( plugin . options . problem_grammar_class ) && element . attributes [ plugin . options . problem_grammar_data_attribute ] ;
687+
688+ if ( plugin && ( scaytState || graytState ) ) {
689+ delete element . name ;
694690 }
695691
696692 return element ;
@@ -705,15 +701,11 @@ CKEDITOR.plugins.add('scayt', {
705701 var htmlFilterRules = {
706702 elements : {
707703 span : function ( element ) {
708- var scaytState = plugin . state . scayt [ editor . name ] && element . hasClass ( plugin . options . misspelled_word_class ) && element . attributes [ plugin . options . data_attribute_name ] ,
709- graytState = plugin . state . grayt [ editor . name ] && element . hasClass ( plugin . options . problem_grammar_class ) && element . attributes [ plugin . options . problem_grammar_data_attribute ] ;
710704
711- if ( plugin && ( scaytState || graytState ) ) {
705+ var scaytState = element . hasClass ( plugin . options . misspelled_word_class ) && element . attributes [ plugin . options . data_attribute_name ] ,
706+ graytState = element . hasClass ( plugin . options . problem_grammar_class ) && element . attributes [ plugin . options . problem_grammar_data_attribute ] ;
712707
713- element . removeClass ( plugin . options . misspelled_word_class ) ;
714- element . removeClass ( plugin . options . problem_grammar_class ) ;
715- delete element . attributes [ plugin . options . data_attribute_name ] ;
716- delete element . attributes [ plugin . options . problem_grammar_data_attribute ] ;
708+ if ( plugin && ( scaytState || graytState ) ) {
717709 delete element . name ;
718710 }
719711
@@ -1032,8 +1024,11 @@ CKEDITOR.plugins.add('scayt', {
10321024
10331025 eventObject [ replaceKeyName ] = suggestion ;
10341026 scaytInstance . replaceSelectionNode ( eventObject ) ;
1035- // we need to remove markup from selection node here in case that there are still our markup - grayt or scayt
1036- scaytInstance . removeMarkupInSelectionNode ( ) ;
1027+
1028+ // we need to remove grammar markup from selection node if we just performed replace action for misspelling
1029+ if ( updateEventName === 'startGrammarCheck' ) {
1030+ scaytInstance . removeMarkupInSelectionNode ( { grammarOnly : true } ) ;
1031+ }
10371032 // for grayt problem replacement we need to fire 'startSpellCheck'
10381033 // for scayt misspelling replacement we need to fire 'startGrammarCheck'
10391034 scaytInstance . fire ( updateEventName ) ;
@@ -1124,7 +1119,7 @@ CKEDITOR.plugins.scayt = {
11241119
11251120 // Fix bug with getting wrong uid after re-creating SCAYT instance.
11261121 // And as result - restoring options for wrong instance
1127- if ( ! container . id ) {
1122+ if ( ! container . id && _editor . element . getAttribute ( 'id' ) ) {
11281123 container . id = _editor . element . getAttribute ( 'id' ) ;
11291124 }
11301125
@@ -1184,10 +1179,14 @@ CKEDITOR.plugins.scayt = {
11841179 timestamp ,
11851180 scaytUrl ;
11861181
1182+ // no need to process load requests from same editor as it can cause bugs with
1183+ // loading ckscayt app due to subsequent calls of some events
1184+ // need to be before 'if' statement, because of timing issue in CKEDITOR.scriptLoader
1185+ // when callback executing is delayed for a few milliseconds, and scayt can be created twise
1186+ // on one instance
1187+ if ( this . loadingHelper [ editor . name ] ) return ;
1188+
11871189 if ( typeof window . SCAYT === 'undefined' || typeof window . SCAYT . CKSCAYT !== 'function' ) {
1188- // no need to process load requests from same editor as it can cause bugs with
1189- // loading ckscayt app due to subsequent calls of some events
1190- if ( this . loadingHelper [ editor . name ] ) return ;
11911190
11921191 // add onLoad callbacks for editors while SCAYT is loading
11931192 this . loadingHelper [ editor . name ] = callback ;
@@ -1196,7 +1195,10 @@ CKEDITOR.plugins.scayt = {
11961195 //creating unique timestamp for SCAYT URL
11971196 date = new Date ( ) ;
11981197 timestamp = date . getTime ( ) ;
1199- scaytUrl = editor . config . scayt_srcUrl + '?' + timestamp ;
1198+ scaytUrl = editor . config . scayt_srcUrl ;
1199+
1200+ //if there already implemented timstamp for scayr_srcURL use it, if not use our timestamp
1201+ scaytUrl = scaytUrl + ( scaytUrl . indexOf ( '?' ) >= 0 ? '' : '?' + timestamp ) ;
12001202
12011203 if ( ! this . loadingHelper . ckscaytLoading ) {
12021204 CKEDITOR . scriptLoader . load ( scaytUrl , function ( success ) {
@@ -1232,15 +1234,33 @@ CKEDITOR.plugins.scayt = {
12321234} ;
12331235
12341236CKEDITOR . on ( 'dialogDefinition' , function ( dialogDefinitionEvent ) {
1237+ var dialogName = dialogDefinitionEvent . data . name ,
1238+ dialogDefinition = dialogDefinitionEvent . data . definition ,
1239+ dialog = dialogDefinition . dialog ;
12351240
1236- if ( dialogDefinitionEvent . data . name === 'scaytDialog' ) {
1237-
1238- var dialogDefinition = dialogDefinitionEvent . data . definition ;
1239-
1240- dialogDefinition . dialog . on ( 'cancel' , function ( cancelEvent ) {
1241+ if ( dialogName === 'scaytDialog' ) {
1242+ dialog . on ( 'cancel' , function ( cancelEvent ) {
12411243 return false ;
12421244 } , this , null , - 1 ) ;
12431245 }
1246+
1247+ if ( dialogName === 'link' ) {
1248+ dialog . on ( 'ok' , function ( okEvent ) {
1249+ var editor = okEvent . sender && okEvent . sender . getParentEditor ( ) ;
1250+
1251+ if ( editor ) {
1252+ setTimeout ( function ( ) {
1253+ editor . fire ( 'reloadMarkupScayt' , {
1254+ removeOptions : {
1255+ removeInside : true ,
1256+ forceBookmark : true
1257+ } ,
1258+ timeout : 0
1259+ } ) ;
1260+ } , 0 ) ;
1261+ }
1262+ } ) ;
1263+ }
12441264} ) ;
12451265
12461266CKEDITOR . on ( 'scaytReady' , function ( ) {
@@ -1287,7 +1307,7 @@ CKEDITOR.on('scaytReady', function() {
12871307 } ) ;
12881308 }
12891309
1290- if ( CKEDITOR . config . scayt_handleUndoRedo === true ) {
1310+ if ( CKEDITOR . config . scayt_handleUndoRedo === true ) {
12911311 var undoImagePrototype = CKEDITOR . plugins . undo . Image . prototype ;
12921312
12931313 // add backword compatibility for CKEDITOR 4.2. method equals was repleced on other method
@@ -1336,6 +1356,17 @@ CKEDITOR.on('scaytReady', function() {
13361356 * @member CKEDITOR.config
13371357 */
13381358
1359+ /**
1360+ * The parameter turns on/off SCAYT initiation when Inline CKEditor is not focused. SCAYT markup is taken place (SCAYT instance is not destroyed)
1361+ * in both Inline CKEditor's states, focused and unfocused.
1362+ *
1363+ * config.scayt_inlineModeImmediateMarkup = true;
1364+ *
1365+ * @cfg {Boolean} [scayt_inlineModeImmediateMarkup=false]
1366+ * @member CKEDITOR.config
1367+ */
1368+
1369+
13391370/**
13401371 * The parameter defines the number of SCAYT suggestions to show in the main context menu.
13411372 * Possible values are:
0 commit comments