国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Squire編輯器源碼解讀

raise_yang / 3418人閱讀

摘要:編輯器構造函數的模型。編輯器構造函數編輯器的參數操作函數編輯器的原型方法操作函數自定義事件機制光標以及選區的方法

編輯器簡單介紹
Squire is an HTML5 rich text editor, which provides powerful cross-browser normalisation, whilst being supremely lightweight and flexible. It is built for the present and the future, and as such does not support truly ancient browsers. It should work fine back to around Opera 12, Firefox 3.5, Safari 5, Chrome 9 and IE9.
各文件的功能

Editor.js:用構造函數定義了編輯器,并且在原型上增加屬性,以實現更多的編輯器操作

function Squire ( root, config ) {}

var proto = Squire.prototype;

clean.js:定義了編輯支持的各種元素,包括tag、屬性、style。

對標簽,屬性,樣式多統一化處理

去除白名單外的標簽,屬性和樣式

clipboard.js:定義了復制、剪切、粘貼、拖拽操作的drop。所有的編輯器定義的粘貼操作都類似,基本步驟如下:

先從系統剪貼板獲取數據;

根據不同瀏覽器以及數據類型,將數據插入到對應的位置

阻止默認事件

Constants.js:定義了編輯器的全局配置,以及一些縮寫變量。通常包含以下內容:

給生澀變量取別名

var ELEMENT_NODE = 1;  
var TEXT_NODE = 3;
var ZWS = "u200B";

縮寫,比如當前文檔對象所在的window對象:var win = doc.defaultView, 也就是var win = node.ownerDocument.defaultView

瀏覽器的判定以及判斷是否支持一些屬性:var canObserveMutations = typeof MutationObserver !== "undefined";

exports.js:定義了將要暴露的接口

Squire.onPaste = onPaste;
// Node.js exports
Squire.isInline = isInline;
Squire.isBlock = isBlock;
Squire.isContainer = isContainer;
Squire.getBlockWalker = getBlockWalker;

intro.js:代碼拼湊的頭部`

( function ( doc, undefined ) {
"use strict";`

outro.js:代碼拼湊的尾部。用Shell命令依次合并intro.js-->其他js文件-->outro.js

if ( typeof exports === "object" ) {
    module.exports = Squire;
} else if ( typeof define === "function" && define.amd ) {
    define( function () {
        return Squire;
    });
} else {
    win.Squire = Squire;
    if ( top !== win &&
            doc.documentElement.getAttribute( "data-squireinit" ) === "true" ) {
        win.editor = new Squire( doc );
        if ( win.onEditorLoad ) {
            win.onEditorLoad( win.editor );
            win.onEditorLoad = null;
        }
    }
}
}( document ) );

KeyHandlers.js:重新定義了上下左右導航、刪除、backspace、tab、回車,以及組合按鍵等操作。以獲取在編輯器一致的變現,并且在某些操作中增加鉤子函數,比如beforeDelete;afterDelete

對于會對產生變化的操作,先需壓入undolist->根據range.collapsed進行操作->更新選區、dom結構樹路徑

去除白名單外的標簽,屬性和樣式

space按鍵操作的代碼解讀:

space: function ( self, _, range ) {
    var node, parent;
    self._recordUndoState( range );
    addLinks( range.startContainer, self._root, self );
    self._getRangeAndRemoveBookmark( range );

    // If the cursor is at the end of a link (foo|) then move it
    // outside of the link (foo|) so that the space is not part of
    // the link text.
    node = range.endContainer;
    parent = node.parentNode;
    

asdfsdfasasdf

if ( range.collapsed && range.endOffset === getLength( node ) ) { if ( node.nodeName === "A" ) { range.setStartAfter( node ); } else if ( parent.nodeName === "A" && !node.nextSibling ) { range.setStartAfter( parent ); } } // Delete the selection if not collapsed if ( !range.collapsed ) { deleteContentsOfRange( range, self._root ); self._ensureBottomLine(); self.setSelection( range ); self._updatePath( range, true ); } self.setSelection( range ); },

Range.js:關于光標、選區以及范圍的操作。

定義一些輔助函數,以實現節點的定位

var getNodeBefore = function ( node, offset ) {
var children = node.childNodes;
// 
while ( offset && node.nodeType === ELEMENT_NODE ) {
    node = children[ offset - 1 ];
    children = node.childNodes;
    offset = children.length;
}
return node;
};

Range的增刪改查操作

// Returns the first block at least partially contained by the range,
// or null if no block is contained by the range.
var getStartBlockOfRange = function ( range, root ) {
    var container = range.startContainer,
        block;

    // If inline, get the containing block.
    if ( isInline( container ) ) {
        block = getPreviousBlock( container, root );
    } else if ( container !== root && isBlock( container ) ) {
        block = container;
    } else {
        block = getNodeBefore( container, range.startOffset );
        block = getNextBlock( block, root );
    }
    // Check the block actually intersects the range
    return block && isNodeContainedInRange( range, block, true ) ? block : null;
};

Node.js:關于節點的基礎定義,以及基本操作。

從各種角度,定義節點類型,如:inline&&block、葉子節點&&非葉子節點

定義查找指定節點的方法以及節點間的關系:

function getNearest ( node, root, tag, attributes ) {
    while ( node && node !== root ) {
        if ( hasTagAttributes( node, tag, attributes ) ) {
            return node;
        }
        node = node.parentNode;
    }
    return null;
}

定義節點以及之間的操作方法,如:split、merge等操作:

function _mergeInlines ( node, fakeRange ) {
    var children = node.childNodes,
        l = children.length,
        frags = [],
        child, prev, len;
    while ( l-- ) {
        child = children[l];
        prev = l && children[ l - 1 ];
        if ( l && isInline( child ) && areAlike( child, prev ) &&
                !leafNodeNames[ child.nodeName ] ) {
            if ( fakeRange.startContainer === child ) {
                fakeRange.startContainer = prev;
                fakeRange.startOffset += getLength( prev );
            }
            if ( fakeRange.endContainer === child ) {
                fakeRange.endContainer = prev;
                fakeRange.endOffset += getLength( prev );
            }
            if ( fakeRange.startContainer === node ) {
                if ( fakeRange.startOffset > l ) {
                    fakeRange.startOffset -= 1;
                }
                else if ( fakeRange.startOffset === l ) {
                    fakeRange.startContainer = prev;
                    fakeRange.startOffset = getLength( prev );
                }
            }
            if ( fakeRange.endContainer === node ) {
                if ( fakeRange.endOffset > l ) {
                    fakeRange.endOffset -= 1;
                }
                else if ( fakeRange.endOffset === l ) {
                    fakeRange.endContainer = prev;
                    fakeRange.endOffset = getLength( prev );
                }
            }
            detach( child );
            if ( child.nodeType === TEXT_NODE ) {
                prev.appendData( child.data );
            }
            else {
                frags.push( empty( child ) );
            }
        }
        else if ( child.nodeType === ELEMENT_NODE ) {
            len = frags.length;
            while ( len-- ) {
                child.appendChild( frags.pop() );
            }
            _mergeInlines( child, fakeRange );
        }
    }
}

TreeWakler.js:定義節點的遍歷模型,定義最基本的節點查找方法。

TreeWalker.prototype.previousNode = function () {
    var current = this.currentNode,
        root = this.root,
        nodeType = this.nodeType,
        filter = this.filter,
        node;
    while ( true ) {
        if ( current === root ) {
            return null;
        }
        node = current.previousSibling;
        if ( node ) {
            while ( current = node.lastChild ) {
                node = current;
            }
        } else {
            node = current.parentNode;
        }
        if ( !node ) {
            return null;
        }
        if ( ( typeToBitArray[ node.nodeType ] & nodeType ) &&
                filter( node ) ) {
            this.currentNode = node;
            return node;
        }
        current = node;
    }
};

Editor.js:編輯器構造函數的模型function Squire ( root, config ) { }

編輯器構造函數

編輯器的參數操作函數

編輯器的原型方法(操作函數、自定義事件機制、光標以及選區的方法)

proto.getSelection = function () {
    var sel = getWindowSelection( this );
    var root = this._root;
    var selection, startContainer, endContainer, node;
    // If not focused, always rely on cached selection; another function may
    // have set it but the DOM is not modified until focus again
    if ( this._isFocused && sel && sel.rangeCount ) {
        selection  = sel.getRangeAt( 0 ).cloneRange();
        startContainer = selection.startContainer;
        endContainer = selection.endContainer;
        // FF can return the selection as being inside an . WTF?
        if ( startContainer && isLeaf( startContainer ) ) {
            selection.setStartBefore( startContainer );
        }
        if ( endContainer && isLeaf( endContainer ) ) {
            selection.setEndBefore( endContainer );
        }
    }
    if ( selection &&
            isOrContains( root, selection.commonAncestorContainer ) ) {
        this._lastSelection = selection;
    } else {
        selection = this._lastSelection;
        node = selection.commonAncestorContainer;
        // Check the editor is in the live document; if not, the range has
        // probably been rewritten by the browser and is bogus
        if ( !isOrContains( node.ownerDocument, node ) ) {
            selection = null;
        }
    }
    if ( !selection ) {
        selection = this._createRange( root.firstChild, 0 );
    }
    return selection;
};

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/96582.html

相關文章

  • Laravel php artisan optimize 源碼解讀

    摘要:確定的代碼位于的中這樣一看,其實就是將文件刪除,而這個是會自動生成的一個數組文件,這里指定了每個和的位置和命名空間的全路徑等,在啟動項目的時候,可以直接讀取使用。所以這個命令可以拆為兩步層面優化加載速度刪除很清晰。 原文:https://www.codecasts.com/blo... 在部署 Laravel 項目的時候,我們經常會使用到一個提升性能的命令: php artisan o...

    brianway 評論0 收藏0
  • 源碼解讀:php artisan serve

    摘要:原文來自在學習的時候,可能很多人接觸的第一個的命令就是,這樣我們就可以跑起第一個的應用。本文來嘗試解讀一下這個命令行的源碼。 原文來自:https://www.codecasts.com/blo... 在學習 Laravel 的時候,可能很多人接觸的第一個 artisan 的命令就是:php artisan serve,這樣我們就可以跑起第一個 Laravel 的應用。本文來嘗試解讀一...

    Loong_T 評論0 收藏0
  • 源碼解讀:Laravel php artisan route:cache

    摘要:然而,本文的討論重點,還是背后的源碼,是怎么做到這一步的。從哪開始看源碼位于你還是可以使用編輯器搜,就可以看到源碼了。第三步序列化所有路由注冊映射關系,還是在的方法中上面的方法位于中的中。所以到這里,的源碼解讀就完成了。 學 Laravel 和 Vuejs 你真應該來 codecasts.com ! Laravel ?route:cache 可以直接緩存路由文件,這樣其實可以在一定程度...

    wangzy2019 評論0 收藏0
  • vue源碼解讀-目錄結構

    摘要:目錄結構構建相關的文件,一般情況下我們不需要動鉤子別名配置 目錄結構 ├── scripts ------------------------------- 構建相關的文件,一般情況下我們不需要動│ ├── git-hooks ------------------------- git鉤子│ ├── alias.js -------------------------- 別名配...

    philadelphia 評論0 收藏0
  • Laravel 源碼解讀:php artisan make:auth

    摘要:添加路由在方法中,通過下面幾行代碼添加路由注意這個參數,就是將這個文件的內容附加在原來路由文件的后面,并不會將原來的路由清零。 學 Laravel 和 Vuejs,你真應該來 codecasts.com ,有免費高質量視頻! 在 Laravel 5.2 的時候,官方給我們提供了 make:auth 命令,這個命令使得我們在執行一條命令的情況下實現用戶注冊和登錄,忘記密碼,找回密碼的過程...

    xorpay 評論0 收藏0

發表評論

0條評論

raise_yang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<