|
8 | 8 | import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; |
9 | 9 |
|
10 | 10 | import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; |
11 | | - |
12 | | -import TreeWalker from '../../../../src/model/treewalker'; |
13 | | -import Position from '../../../../src/model/position'; |
14 | 11 | import Range from '../../../../src/model/range'; |
15 | 12 | import LivePosition from '../../../../src/model/liveposition'; |
16 | 13 |
|
@@ -45,51 +42,45 @@ class Link extends Plugin { |
45 | 42 | } |
46 | 43 | } |
47 | 44 |
|
48 | | -const urlRegex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/; |
49 | | - |
50 | 45 | class AutoLinker extends Plugin { |
51 | 46 | init() { |
52 | | - this.editor.model.document.on( 'change', ( event, type, changes, batch ) => { |
53 | | - if ( type != 'insert' ) { |
54 | | - return; |
55 | | - } |
| 47 | + this.editor.model.document.on( 'change', () => { |
| 48 | + const changes = this.editor.model.document.differ.getChanges(); |
56 | 49 |
|
57 | | - for ( const value of changes.range.getItems( { singleCharacters: true } ) ) { |
58 | | - const walker = new TreeWalker( { |
59 | | - direction: 'backward', |
60 | | - startPosition: Position.createAfter( value ) |
61 | | - } ); |
| 50 | + for ( const entry of changes ) { |
| 51 | + if ( entry.type != 'insert' || entry.name != '$text' || !entry.position.textNode ) { |
| 52 | + continue; |
| 53 | + } |
62 | 54 |
|
63 | | - const currentValue = walker.next().value; |
64 | | - const text = currentValue.item.data; |
| 55 | + const textNode = entry.position.textNode; |
| 56 | + const text = textNode.data; |
65 | 57 |
|
66 | 58 | if ( !text ) { |
67 | 59 | return; |
68 | 60 | } |
69 | 61 |
|
70 | | - const matchedUrl = urlRegex.exec( text ); |
71 | | - |
72 | | - if ( !matchedUrl ) { |
73 | | - return; |
| 62 | + const regexp = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g; |
| 63 | + let match; |
| 64 | + |
| 65 | + while ( ( match = regexp.exec( text ) ) !== null ) { |
| 66 | + const index = match.index; |
| 67 | + const url = match[ 0 ]; |
| 68 | + const length = url.length; |
| 69 | + |
| 70 | + if ( entry.position.offset + entry.length == index + length ) { |
| 71 | + const livePos = LivePosition.createFromParentAndOffset( textNode.parent, index ); |
| 72 | + this.editor.model.enqueueChange( writer => { |
| 73 | + const urlRange = Range.createFromPositionAndShift( livePos, length ); |
| 74 | + writer.setAttribute( 'link', url, urlRange ); |
| 75 | + } ); |
| 76 | + return; |
| 77 | + } |
74 | 78 | } |
75 | | - |
76 | | - const url = matchedUrl[ 0 ]; |
77 | | - const offset = _getLastPathPart( currentValue.nextPosition.path ) + matchedUrl.index; |
78 | | - const livePos = LivePosition.createFromParentAndOffset( currentValue.item.parent, offset ); |
79 | | - |
80 | | - this.editor.model.enqueueChange( batch, writer => { |
81 | | - const urlRange = Range.createFromPositionAndShift( livePos, url.length ); |
82 | | - writer.setAttribute( 'link', url, urlRange ); |
83 | | - } ); |
84 | 79 | } |
85 | 80 | } ); |
86 | 81 | } |
87 | 82 | } |
88 | 83 |
|
89 | | -function _getLastPathPart( path ) { |
90 | | - return path[ path.length - 1 ]; |
91 | | -} |
92 | | - |
93 | 84 | ClassicEditor.create( document.querySelector( '#editor' ), { |
94 | 85 | plugins: [ Enter, Typing, Paragraph, Undo, Link, AutoLinker ], |
95 | 86 | toolbar: [ 'undo', 'redo' ] |
|
0 commit comments