Ticket #1272: webkitFix.patch

File webkitFix.patch, 5.4 KB (added by Jude Allred, 10 years ago)

A 90% fix for this bug

  • Website/ckeditor/_source/plugins/styles/plugin.js

    # HG changeset patch
    # User Jude Allred <jude@fogcreek.com>
    # Date 1292452510 18000
    # Node ID 615452d7c8d0ae41f649397178d94199b8d7c21e
    # Parent  1bb2347734e13ebbd9500c24139c96a56fe48e58
    temp commit
    
    diff -r 1bb2347734e1 -r 615452d7c8d0 Website/ckeditor/_source/plugins/styles/plugin.js
    a b  
    362362                        // Create the element to be inserted in the DOM.
    363363                        var collapsedElement = getElement( this, document );
    364364
     365                        //Handle Webkit's collapsed selection quirks
     366                        if(CKEDITOR.env.webkit) {
     367                                webkitFix.fixApplyStyle(collapsedElement, range);
     368                        }
     369
    365370                        // Insert the empty element into the DOM at the range position.
    366371                        range.insertNode( collapsedElement );
    367372
     
    586591
    587592        function removeInlineStyle( range )
    588593        {
     594                if(CKEDITOR.env.webkit) {
     595                        webkitFix.fixRemoveStyle(range, this);
     596                }
    589597                /*
    590598                 * Make sure our range has included all "collpased" parent inline nodes so
    591599                 * that our operation logic can be simpler.
     
    13711379                else
    13721380                        selection.selectBookmarks( bookmarks );
    13731381        }
     1382
     1383        // Webkit requires textual content within a selection in order to apply styles to it (#3708)
     1384        // webkitFix provides fixApplyStyle and fixRemoveStyle which (mostly) mitigate
     1385        // webkit's difficulties with styling collapsed selections.  BugzID: 1904972
     1386        var webkitFix = (function() {
     1387
     1388                var chBogus = '\ufeff'; //Zero-width non-breaking space.
     1389
     1390                function isControlCode(evt) {
     1391                        var keyCode = evt.data.getKey();
     1392
     1393                        return (
     1394                                evt.data.$.ctrlKey ||
     1395                                evt.data.$.altKey  ||
     1396                                $.inArray(keyCode, [
     1397                                        16, // Shift
     1398                                        17, // Ctrl
     1399                                        18, // Alt
     1400                                        20 // Caps Lock
     1401                                ]) !== -1
     1402                        );
     1403                }
     1404
     1405                //injectBogusNode fixes adding and removing styles from collapsed selections by injecting a bogus character into
     1406                //the current selection so that it is no longer collapsed.  A callback to createFxnCleanup is provided to allow
     1407                //the bogus-character cleanup code to be customized based on whether the style is being applied or removed.
     1408                //createInjectBogusNode is used to instantiate versions of the injectBogusNode function that are tailored to
     1409                //specific style add or remove tasks.
     1410                function createInjectBogusNode(fxnCleanUp) {
     1411                        return function(el, range) {
     1412                                function onInputRemoveBogus(evt) {
     1413                                        // Skip control keys
     1414                                        if (isControlCode(evt)) {
     1415                                                return;
     1416                                        }
     1417
     1418                                        //Valid input- kill the handlers.
     1419                                        doc.removeListener('keydown', onInputRemoveBogus);
     1420                                        doc.removeListener('mouseup', onInputRemoveBogus);
     1421
     1422                                        //The rest of this work must be done inside a timeout,
     1423                                        //since its state should reflect whatever happens after this event finishes.
     1424                                        setTimeout(function() { fxnCleanUp(el, range, elBogus) }, 1);
     1425                                }
     1426
     1427                                var doc = range.document;
     1428                                var elBogus = doc.createText(chBogus);
     1429
     1430                                el.append(elBogus);
     1431                                doc.on('keydown', onInputRemoveBogus);
     1432                                doc.on('mouseup', onInputRemoveBogus);
     1433                        };
     1434                }
     1435
     1436                function safeMoveRange(range, elBogus) {
     1437                        try {
     1438                                range.moveToPosition(elBogus, CKEDITOR.POSITION_AFTER_END);
     1439                        } catch (e) { }
     1440                }
     1441
     1442                //fixRemove operates on a text range and an editing context.  If the bogusnode trick is necessary,
     1443                //we'll invoke injectBogusNode, otherwise we'll just let the editor proceed.
     1444                var fixRemove = (function() {
     1445                        var injectBogusNode = createInjectBogusNode(function(el, range, elBogus) {
     1446                                if (elBogus.getText() === chBogus) {
     1447                                        safeMoveRange(range, elBogus);
     1448                                        elBogus.remove();
     1449                                        if (!editor.ck.getSelection().getRanges().length) {
     1450                                                range.select();
     1451                                        }
     1452                                }
     1453                        });
     1454
     1455                        return function(range, context) {
     1456                                if (range.collapsed) {
     1457                                        //Webkit can't handle style changes to collapsed ranges.
     1458                                        //Let's insert a dummy node into the range and instead apply the style to that.
     1459                                        var el = getElement(context, range.document);
     1460                                        injectBogusNode(el, range);
     1461                                        range.insertNode(el);
     1462                                }
     1463                        }
     1464                } ());
     1465
     1466                //fixApply operates on an element and a selection range, and is assuming that
     1467                //the range is already collapsed.  It can call directly to injectBogusNode.
     1468                var fixApply = createInjectBogusNode(function(el, range, elBogus) {
     1469                        var elBogus = el.getFirst();
     1470                        if (!elBogus) {
     1471                                return;
     1472                        }
     1473
     1474                        // If there're characters inside the text node aside from bogus,
     1475                        // we saved the day! Bogus is no longer needed and can be removed.
     1476                        if (elBogus.getText().length !== 1) {
     1477                                // The bogus text has been merged with newly inputted char, 
     1478                                // split it out, move selection after it, then remove it.
     1479                                elBogus = elBogus.split(1).getPrevious();
     1480                                safeMoveRange(range, elBogus);
     1481                                elBogus.remove();
     1482                                range.select();
     1483                        }
     1484                        // We've felt a keypress, but the bogus element hasn't expanded.
     1485                        // This means that the selection has moved or we aborted the style. Kill bogus.
     1486                        else {
     1487                                elBogus.remove();
     1488                                if (!editor.ck.getSelection().getRanges().length) {
     1489                                        //If we just removed from within our range, we've lost focus.
     1490                                        //Reselect our range.
     1491                                        range.select();
     1492                                }
     1493                        }
     1494                });
     1495
     1496                return {
     1497                        fixApplyStyle: fixApply,
     1498                        fixRemoveStyle: fixRemove
     1499                };
     1500        } ());
    13741501})();
    13751502
    13761503CKEDITOR.styleCommand = function( style )
© 2003 – 2019 CKSource – Frederico Knabben. All rights reserved. | Terms of use | Privacy policy