Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/extensions/VisualEditor/lib/ve/tests/dm/ve.dm.SurfaceFragment.test.js
Ðазад
/*! * VisualEditor DataModel SurfaceFragment tests. * * @copyright See AUTHORS.txt */ QUnit.module( 've.dm.SurfaceFragment' ); /* Tests */ QUnit.test( 'constructor', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ); surface.setLinearSelection( new ve.Range( 1 ) ); let fragment = new ve.dm.SurfaceFragment( surface ); // Default range and autoSelect assert.strictEqual( fragment.getSurface(), surface, 'surface reference is stored' ); assert.strictEqual( fragment.getDocument(), doc, 'document reference is stored' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 1 ), 'range is taken from surface' ); assert.strictEqual( fragment.willAutoSelect(), true, 'auto select by default' ); // AutoSelect fragment = new ve.dm.SurfaceFragment( surface, null, 'truthy' ); assert.strictEqual( fragment.willAutoSelect(), false, 'noAutoSelect values are boolean' ); } ); QUnit.test( 'update', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ); let fragment1 = surface.getLinearFragment( new ve.Range( 55, 61 ) ), fragment2 = surface.getLinearFragment( new ve.Range( 55, 61 ) ); const fragment3 = surface.getLinearFragment( new ve.Range( 55, 61 ) ); fragment1.wrapNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.equalRange( fragment2.getSelection().getRange(), new ve.Range( 55, 69 ), 'fragment range changes after wrapNodes' ); surface.undo(); assert.equalRange( fragment3.getSelection().getRange(), new ve.Range( 55, 61 ), 'fragment range restored after undo' ); fragment1 = surface.getLinearFragment( new ve.Range( 1 ) ); surface.breakpoint(); fragment1.insertContent( '01' ); surface.breakpoint(); fragment1 = fragment1.collapseToEnd(); fragment1.insertContent( '234' ); fragment2 = fragment1.clone(); surface.undo(); fragment1.insertContent( '5678' ); assert.equalRange( fragment2.getSelection().getRange(), new ve.Range( 3, 7 ), 'Range created during truncated undo point still translates correctly' ); } ); QUnit.test( 'getSelectedModels', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ); assert.deepEqual( surface.getLinearFragment( new ve.Range( 1, 3 ) ).getSelectedModels(), [], 'Empty' ); assert.deepEqual( surface.getLinearFragment( new ve.Range( 2, 3 ) ).getSelectedModels(), [ doc.data.store.value( ve.dm.example.boldHash ) ], 'Bold annotation' ); assert.deepEqual( surface.getLinearFragment( new ve.Range( 1, 3 ) ).getSelectedModels( true ), [ doc.getDocumentNode().children[ 0 ].children[ 0 ], doc.data.store.value( ve.dm.example.boldHash ) ], 'Bold annotation and text node' ); assert.deepEqual( surface.getLinearFragment( new ve.Range( 39, 41 ) ).getSelectedModels(), [ doc.getDocumentNode().children[ 2 ].children[ 1 ] ], 'Inline image node' ); } ); QUnit.test( 'getAnnotations', ( assert ) => { const doc = ve.dm.example.createExampleDocument( 'annotatedTable' ), tableRange = new ve.Range( 0, 52 ), surface = new ve.dm.Surface( doc ); let tableSelection = new ve.dm.TableSelection( tableRange, 0, 0, 1, 0 ); assert.deepEqual( surface.getFragment( tableSelection ).getAnnotations().getHashes(), [ ve.dm.example.boldHash, ve.dm.example.strongHash ], 'Comparable annotations: [B] ∩ [Strong] = [B,Strong] ' ); tableSelection = new ve.dm.TableSelection( tableRange, 0, 0, 2, 0 ); assert.deepEqual( surface.getFragment( tableSelection ).getAnnotations().getHashes(), [], 'Non-comparable annotations: [B] ∩ [Strong] ∩ [I] = [] ' ); tableSelection = new ve.dm.TableSelection( tableRange, 0, 1, 1, 1 ); assert.deepEqual( surface.getFragment( tableSelection ).getAnnotations().getHashes(), [ ve.dm.example.boldHash, ve.dm.example.strongHash ], 'Non-comparable in first cell: [B,I] ∩ [Strong] = [B,Strong]' ); tableSelection = new ve.dm.TableSelection( tableRange, 0, 0, 2, 0 ); assert.deepEqual( surface.getFragment( tableSelection ).getAnnotations( true ).getHashes(), [ ve.dm.example.boldHash, ve.dm.example.strongHash, ve.dm.example.italicHash ], 'Get all annotations' ); } ); QUnit.test( 'hasAnnotations', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ); assert.strictEqual( surface.getLinearFragment( new ve.Range( 1, 2 ) ).hasAnnotations(), false, 'Plain text has none' ); assert.strictEqual( surface.getLinearFragment( new ve.Range( 2, 3 ) ).hasAnnotations(), true, 'Bold text has some' ); } ); QUnit.test( 'adjustLinearSelection', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), fragment = surface.getLinearFragment( new ve.Range( 20, 21 ) ); let adjustedFragment = fragment.adjustLinearSelection( -19, 35 ); assert.notStrictEqual( fragment, adjustedFragment, 'adjustLinearSelection produces a new fragment' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' ); assert.equalRange( adjustedFragment.getSelection().getRange(), new ve.Range( 1, 56 ), 'new range is used' ); adjustedFragment = fragment.adjustLinearSelection(); assert.deepEqual( adjustedFragment, fragment, 'fragment is clone if no parameters supplied' ); } ); QUnit.test( 'truncateLinearSelection', ( assert ) => { const range = new ve.Range( 100, 200 ), doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), fragment = surface.getLinearFragment( range ); assert.equalRange( fragment.truncateLinearSelection( 50 ).getSelection().getRange(), new ve.Range( 100, 150 ), 'truncate 50' ); assert.equalRange( fragment.truncateLinearSelection( 150 ).getSelection().getRange(), range, 'truncate 150 does nothing' ); assert.equalRange( fragment.truncateLinearSelection( -50 ).getSelection().getRange(), new ve.Range( 150, 200 ), 'truncate -50' ); assert.equalRange( fragment.truncateLinearSelection( -150 ).getSelection().getRange(), range, 'truncate -150 does nothing' ); } ); QUnit.test( 'collapseToStart/End', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), fragment = surface.getLinearFragment( new ve.Range( 20, 21 ) ); let collapsedFragment = fragment.collapseToStart(); assert.notStrictEqual( fragment, collapsedFragment, 'collapseToStart produces a new fragment' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' ); assert.equalRange( collapsedFragment.getSelection().getRange(), new ve.Range( 20 ), 'new range is used' ); collapsedFragment = fragment.collapseToEnd(); assert.notStrictEqual( fragment, collapsedFragment, 'collapseToEnd produces a new fragment' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 20, 21 ), 'old fragment is not changed' ); assert.equalRange( collapsedFragment.getSelection().getRange(), new ve.Range( 21 ), 'range is at end when collapseToEnd is set' ); } ); QUnit.test( 'expandLinearSelection (annotation)', ( assert ) => { const doc = ve.dm.example.createExampleDocumentFromData( [ { type: 'paragraph' }, ...'Foo', [ 'b', [ ve.dm.example.bold ] ], [ 'a', [ ve.dm.example.bold ] ], [ 'r', [ ve.dm.example.bold ] ], [ 'b', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'a', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'z', [ ve.dm.example.bold, ve.dm.example.italic ] ], { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ), surface = new ve.dm.Surface( doc ), cases = [ { msg: 'expands to bold annotation', annotation: ve.dm.example.bold, range: new ve.Range( 5, 6 ), expected: new ve.Range( 4, 10 ) }, { msg: 'direction preserved', annotation: ve.dm.example.bold, range: new ve.Range( 6, 5 ), expected: new ve.Range( 10, 4 ) }, { msg: 'overlaps existing selection', annotation: ve.dm.example.bold, range: new ve.Range( 2, 7 ), expected: new ve.Range( 2, 10 ) }, { msg: 'no change when annotation not present', annotation: ve.dm.example.italic, range: new ve.Range( 5, 6 ), expected: new ve.Range( 5, 6 ) }, { msg: 'no change when no annotations present', annotation: ve.dm.example.bold, range: new ve.Range( 1, 2 ), expected: new ve.Range( 1, 2 ) }, { msg: 'matches nested annotation', annotation: ve.dm.example.italic, range: new ve.Range( 9, 10 ), expected: new ve.Range( 7, 10 ) } ]; cases.forEach( ( caseItem ) => { const fragment = surface.getLinearFragment( caseItem.range ).expandLinearSelection( 'annotation', ve.dm.example.createAnnotation( caseItem.annotation ) ); assert.equalHash( fragment.getSelection().getRange(), caseItem.expected, caseItem.msg ); } ); } ); QUnit.test( 'expandLinearSelection (closest)', ( assert ) => { const cases = [ { msg: 've.dm.BranchNode selects surrounding paragraph', range: new ve.Range( 1 ), type: ve.dm.BranchNode, expected: new ve.dm.LinearSelection( new ve.Range( 0, 5 ) ) }, { msg: 've.dm.BranchNode selects surrounding paragraph in empty paragraph', doc: 'alienWithEmptyData', range: new ve.Range( 1 ), type: ve.dm.BranchNode, expected: new ve.dm.LinearSelection( new ve.Range( 0, 2 ) ) }, { msg: 've.dm.BranchNode selects surrounding paragraph when entire paragrpah selected', range: new ve.Range( 1, 4 ), type: ve.dm.BranchNode, expected: new ve.dm.LinearSelection( new ve.Range( 0, 5 ) ) }, { msg: 'invalid type results in null fragment', range: new ve.Range( 20, 21 ), type: function () {}, expected: new ve.dm.NullSelection() } ]; cases.forEach( ( caseItem ) => { const surface = new ve.dm.Surface( ve.dm.example.createExampleDocument( caseItem.doc ) ); const fragment = surface.getLinearFragment( caseItem.range ).expandLinearSelection( 'closest', caseItem.type ); assert.equalHash( fragment.getSelection(), caseItem.expected, caseItem.msg ); } ); } ); QUnit.test( 'expandLinearSelection (word)', ( assert ) => { const cases = [ { phrase: 'the quick brown fox', range: new ve.Range( 6, 13 ), expected: 'quick brown', msg: 'range starting and ending in latin words' }, { phrase: 'the quick brown fox', range: new ve.Range( 18, 12 ), expected: 'brown fox', msg: 'backwards range starting and ending in latin words' }, { phrase: 'the quick brown fox', range: new ve.Range( 7 ), expected: 'quick', msg: 'zero-length range' } ]; cases.forEach( ( caseItem ) => { const doc = new ve.dm.Document( caseItem.phrase.split( '' ) ); const surface = new ve.dm.Surface( doc ); const fragment = surface.getLinearFragment( caseItem.range ); const newFragment = fragment.expandLinearSelection( 'word' ); const range = newFragment.getSelection().getRange(); const word = caseItem.phrase.slice( range.start, range.end ); assert.strictEqual( word, caseItem.expected, caseItem.msg + ': text' ); assert.strictEqual( caseItem.range.isBackwards(), range.isBackwards(), caseItem.msg + ': range direction' ); } ); } ); QUnit.test( 'removeContent', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), originalDoc = ve.dm.example.createExampleDocument(), expectedDoc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), expectedData = ve.copy( expectedDoc.data.slice( 0, 1 ) ) .concat( ve.copy( expectedDoc.data.slice( 4, 5 ) ) ) .concat( ve.copy( expectedDoc.data.slice( 55 ) ) ); let fragment = surface.getLinearFragment( new ve.Range( 1, 56 ) ); fragment.removeContent(); assert.deepEqual( doc.getData(), expectedData, 'removing content drops fully covered nodes and strips partially covered ones' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 1, 3 ), 'removing content results in a fragment covering just remaining structure' ); surface.undo(); assert.deepEqual( doc.getData(), originalDoc.getData(), 'content restored after undo' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 1, 56 ), 'range restored after undo' ); fragment = surface.getLinearFragment( new ve.Range( 1, 4 ) ); fragment.removeContent(); assert.deepEqual( doc.getData( new ve.Range( 0, 2 ) ), [ { type: 'heading', attributes: { level: 1 } }, { type: '/heading' } ], 'removing content empties node' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 1 ), 'removing content collapses range' ); } ); ve.test.utils.runSurfaceFragmentDeleteTest = function ( assert, html, range, directionAfterRemove, expectedData, expectedRange, msg ) { let doc; if ( html ) { doc = ve.dm.converter.getModelFromDom( ve.createDocumentFromHtml( html ) ); } else { doc = ve.dm.example.createExampleDocument(); } const surface = new ve.dm.Surface( doc ); const fragment = surface.getLinearFragment( range ); const data = ve.copy( fragment.getDocument().getFullData() ); expectedData( data ); fragment.delete( directionAfterRemove ); assert.deepEqualWithDomElements( fragment.getDocument().getFullData(), data, msg + ': data' ); assert.equalRange( fragment.getSelection().getRange(), expectedRange, msg + ': range' ); }; QUnit.test( 'delete', ( assert ) => { const cases = [ { range: new ve.Range( 1, 4 ), directionAfterRemove: -1, expectedData: function ( data ) { data.splice( 1, 3 ); }, expectedRange: new ve.Range( 1 ), msg: 'Selection deleted by backspace' }, { range: new ve.Range( 1, 4 ), directionAfterRemove: 1, expectedData: function ( data ) { data.splice( 1, 3 ); }, expectedRange: new ve.Range( 1 ), msg: 'Selection deleted by delete' }, { range: new ve.Range( 39, 41 ), directionAfterRemove: 1, expectedData: function ( data ) { data.splice( 39, 2 ); }, expectedRange: new ve.Range( 39 ), msg: 'Focusable node deleted if selected first' }, { range: new ve.Range( 39, 41 ), expectedData: function ( data ) { data.splice( 39, 2 ); }, expectedRange: new ve.Range( 39 ), msg: 'Focusable node deleted by cut' }, { range: new ve.Range( 0, 63 ), directionAfterRemove: -1, expectedData: function ( data ) { data.splice( 0, 61, { type: 'paragraph' }, { type: '/paragraph' } ); }, expectedRange: new ve.Range( 1 ), msg: 'Backspace after select all spanning entire document creates empty paragraph' }, { html: '<div rel="ve:Alien">Foo</div><p>Bar</p>', range: new ve.Range( 0, 6 ), directionAfterRemove: -1, expectedData: function ( data ) { data.splice( 0, 7, { type: 'paragraph' }, { type: '/paragraph' } ); }, expectedRange: new ve.Range( 1 ), msg: 'Delete all when document starts with a focusable node' }, { html: '<div rel="ve:Alien">Foo</div><p>Bar</p><div rel="ve:Alien">Baz</div>', range: new ve.Range( 0, 9 ), directionAfterRemove: -1, expectedData: function ( data ) { data.splice( 0, 9, { type: 'paragraph' }, { type: '/paragraph' } ); }, expectedRange: new ve.Range( 1 ), msg: 'Delete all when document starts and ends with a focusable node' }, { html: '<p>foo</p><meta><p>bar</p>', range: new ve.Range( 3, 9 ), directionAfterRemove: -1, expectedData: function ( data ) { const meta = data.slice( 5, 7 ); data.splice( 3, 6 ); data.splice( 0, 0, ...meta ); }, expectedRange: new ve.Range( 5 ), msg: 'Partial removal across meta (p -> p)' }, { html: '<h2>foo</h2><meta><p>bar</p>', range: new ve.Range( 3, 9 ), directionAfterRemove: -1, expectedData: function ( data ) { const meta = data.slice( 5, 7 ); const ar = data.slice( 9, 11 ); data.splice( 5, 7 ); data.splice( 3, 1, ...ar ); data.splice( 6, 0, ...meta ); }, expectedRange: new ve.Range( 3 ), msg: 'Partial removal across meta (h2 -> p)' } ]; cases.forEach( ( caseItem ) => { ve.test.utils.runSurfaceFragmentDeleteTest( assert, caseItem.html, caseItem.range, caseItem.directionAfterRemove, caseItem.expectedData, caseItem.expectedRange, caseItem.msg ); } ); } ); QUnit.test( 'insertContent/insertDocument', ( assert ) => { let doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), fragment = surface.getLinearFragment( new ve.Range( 3, 4 ) ); fragment.insertContent( [ 'a' ], true ); assert.deepEqual( doc.getData( new ve.Range( 3, 4 ) ), [ [ 'a', [ ve.dm.example.italicHash ] ] ], 'inserting content (annotate=true) replaces selection with new annotated content' ); fragment = surface.getLinearFragment( new ve.Range( 3, 4 ) ); fragment.insertContent( [ 'b' ] ); assert.deepEqual( doc.getData( new ve.Range( 3, 4 ) ), [ 'b' ], 'inserting content (annotate=false) replaces selection with new plain content' ); fragment = surface.getLinearFragment( new ve.Range( 1, 4 ) ); fragment.insertContent( [ ...'123' ] ); assert.deepEqual( doc.getData( new ve.Range( 1, 4 ) ), [ ...'123' ], 'inserting content replaces selection with new content' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 1, 4 ), 'inserting content results in range around content' ); surface.breakpoint(); fragment = surface.getLinearFragment( new ve.Range( 4 ) ); fragment.insertContent( '321' ); assert.deepEqual( doc.getData( new ve.Range( 4, 7 ) ), [ '3', '2', '1' ], 'strings get converted into data when inserting content' ); surface.undo(); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 4 ), 'range restored after undo' ); fragment = surface.getLinearFragment( new ve.Range( 0 ) ); fragment.insertContent( 'foo\nbar' ); assert.deepEqual( doc.getData( new ve.Range( 0, 10 ) ), [ { type: 'paragraph' }, ...'foo', { type: '/paragraph' }, { type: 'paragraph' }, ...'bar', { type: '/paragraph' } ], 'newlines converted to paragraphs' ); fragment = surface.getLinearFragment( new ve.Range( 1 ) ); fragment.insertContent( [ { type: 'table' }, { type: '/table' } ] ); assert.deepEqual( doc.getData( new ve.Range( 0, 2 ) ), [ { type: 'table' }, { type: '/table' } ], 'table insertion at start of heading is moved outside of heading' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 0, 2 ), 'range covers inserted content in moved position (left)' ); // Set up document and surface from scratch doc = ve.dm.example.createExampleDocument(); surface = new ve.dm.Surface( doc ); fragment = surface.getLinearFragment( new ve.Range( 4 ) ); fragment.insertContent( [ { type: 'list' }, { type: '/list' } ] ); assert.deepEqual( doc.getData( new ve.Range( 5, 7 ) ), [ { type: 'list' }, { type: '/list' } ], 'list insertion at end of heading is moved outside of heading' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 5, 7 ), 'range covers inserted content in moved position (right)' ); // Set up document and surface from scratch doc = ve.dm.example.createExampleDocument(); surface = new ve.dm.Surface( doc ); fragment = surface.getLinearFragment( new ve.Range( 2, 3 ) ); fragment.insertDocument( new ve.dm.Document( [ { type: 'paragraph' }, { type: 'exampleUnboldable' }, { type: '/exampleUnboldable' }, 'x', { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ), new ve.Range( 1, 4 ), true ); assert.deepEqual( doc.getData( new ve.Range( 2, 5 ) ), [ { type: 'exampleUnboldable' }, { type: '/exampleUnboldable' }, [ 'x', [ ve.dm.example.boldHash ] ] ], 'Unboldable node pasted into bold doesn\'t get bolded' ); surface.undo(); fragment = surface.getLinearFragment( new ve.Range( 3, 4 ) ); fragment.insertDocument( new ve.dm.Document( [ { type: 'paragraph' }, { type: 'alienInline' }, { type: '/alienInline' }, { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ), new ve.Range( 1, 3 ), true ); assert.deepEqual( doc.getData( new ve.Range( 3, 5 ) ), [ { type: 'alienInline', annotations: [ ve.dm.example.italicHash ] }, { type: '/alienInline' } ], 'Inline node inserted in annotation gets annotated' ); doc = ve.dm.example.createExampleDocumentFromData( [ { type: 'paragraph' }, [ 'F', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ); surface = new ve.dm.Surface( doc ); fragment = surface.getLinearFragment( new ve.Range( 2 ) ); fragment.insertContent( ve.dm.example.preprocessAnnotations( [ // Annotated with a differently-hashing bold attribute [ 'x', [ { type: 'textStyle/bold', attributes: { nodeName: 'b', irrelevant: true } } ] ] ], doc.store ).data, true ); assert.deepEqual( doc.getData( new ve.Range( 2, 3 ) ), [ [ 'x', [ ve.dm.example.boldHash ] ] ], 'inserting content (annotate=true) reuses comparable annotations on existing content' ); doc = ve.dm.example.createExampleDocumentFromData( [ { type: 'paragraph' }, [ 'F', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ); surface = new ve.dm.Surface( doc ); fragment = surface.getLinearFragment( new ve.Range( 2 ) ); fragment.insertDocument( ve.dm.example.createExampleDocumentFromData( [ { type: 'paragraph' }, [ 'x', [ { type: 'textStyle/bold', attributes: { nodeName: 'b', irrelevant: true } } ] ], { type: '/paragraph' }, { type: 'internalList' }, { type: '/internalList' } ] ), new ve.Range( 1, 3 ), true ); assert.deepEqual( doc.getData( new ve.Range( 2, 3 ) ), [ [ 'x', [ ve.dm.example.boldHash ] ] ], 'inserting document (annotate=true) reuses comparable annotations on existing content' ); } ); QUnit.test( 'changeAttributes', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), fragment = surface.getLinearFragment( new ve.Range( 0, 5 ) ); fragment.changeAttributes( { level: 3 } ); assert.deepEqual( doc.getData( new ve.Range( 0, 1 ) ), [ { type: 'heading', attributes: { level: 3 } } ], 'changing attributes affects covered nodes' ); } ); QUnit.test( 'wrapNodes/unwrapNodes', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), originalDoc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ); let fragment = surface.getLinearFragment( new ve.Range( 55, 61 ) ); // Make 2 paragraphs into 2 lists of 1 item each fragment.wrapNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.deepEqual( doc.getData( new ve.Range( 55, 69 ) ), [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' }, { type: 'paragraph' }, 'l', { type: '/paragraph' }, { type: '/listItem' }, { type: '/list' }, { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' }, { type: 'paragraph' }, 'm', { type: '/paragraph' }, { type: '/listItem' }, { type: '/list' } ], 'wrapping nodes can add multiple levels of wrapping to multiple elements' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 55, 69 ), 'new range contains wrapping elements' ); fragment.unwrapNodes( 0, 2 ); assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 55, 61 ), 'range after unwrapping is same as original range' ); // Make a 1 paragraph into 1 list with 1 item fragment = surface.getLinearFragment( new ve.Range( 9, 12 ) ); fragment.wrapNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.deepEqual( doc.getData( new ve.Range( 9, 16 ) ), [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' }, { type: 'paragraph' }, 'd', { type: '/paragraph' }, { type: '/listItem' }, { type: '/list' } ], 'wrapping nodes can add multiple levels of wrapping to a single element' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 9, 16 ), 'new range contains wrapping elements' ); fragment.unwrapNodes( 0, 2 ); assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 9, 12 ), 'range after unwrapping is same as original range' ); fragment = surface.getLinearFragment( new ve.Range( 8, 34 ) ); fragment.unwrapNodes( 3, 1 ); assert.deepEqual( fragment.getData(), doc.getData( new ve.Range( 5, 29 ) ), 'unwrapping multiple outer nodes and an inner node' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 5, 29 ), 'new range contains inner elements' ); } ); QUnit.test( 'rewrapNodes', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), expectedDoc = ve.dm.example.createExampleDocument(), expectedSurface = new ve.dm.Surface( expectedDoc ), expectedFragment = expectedSurface.getLinearFragment( new ve.Range( 43, 55 ) ); let fragment = surface.getLinearFragment( new ve.Range( 43, 55 ) ); // Set up wrapped nodes in example document fragment.wrapNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); expectedFragment.wrapNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); // Range is now 43, 59 // Compare a rewrap operation with its equivalent unwrap + wrap // This type of test can only exist if the intermediate state is valid fragment.rewrapNodes( 2, [ { type: 'definitionList' }, { type: 'definitionListItem', attributes: { style: 'term' } } ] ); expectedFragment.unwrapNodes( 0, 2 ); expectedFragment.wrapNodes( [ { type: 'definitionList' }, { type: 'definitionListItem', attributes: { style: 'term' } } ] ); assert.deepEqual( doc.getData(), expectedDoc.getData(), 'rewrapping multiple nodes via a valid intermediate state produces the same document as unwrapping then wrapping' ); assert.equalHash( fragment.getSelection(), expectedFragment.getSelection(), 'new range contains rewrapping elements' ); // Rewrap paragrphs as headings // The intermediate stage (plain text attached to the document) would be invalid // if performed as an unwrap and a wrap const expectedData = ve.copy( doc.getData() ); fragment = surface.getLinearFragment( new ve.Range( 59, 65 ) ); fragment.rewrapNodes( 1, [ { type: 'heading', attributes: { level: 1 } } ] ); expectedData.splice( 59, 1, { type: 'heading', attributes: { level: 1 } } ); expectedData.splice( 61, 1, { type: '/heading' } ); expectedData.splice( 62, 1, { type: 'heading', attributes: { level: 1 } } ); expectedData.splice( 64, 1, { type: '/heading' } ); assert.deepEqual( doc.getData(), expectedData, 'rewrapping paragraphs as headings' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 59, 65 ), 'new range contains rewrapping elements' ); } ); QUnit.test( 'wrapAllNodes', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), originalDoc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), expectedData = ve.copy( doc.getData() ); let fragment = surface.getLinearFragment( new ve.Range( 55, 61 ) ); // Make 2 paragraphs into 1 lists of 1 item with 2 paragraphs fragment.wrapAllNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.deepEqual( doc.getData( new ve.Range( 55, 65 ) ), [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' }, { type: 'paragraph' }, 'l', { type: '/paragraph' }, { type: 'paragraph' }, 'm', { type: '/paragraph' }, { type: '/listItem' }, { type: '/list' } ], 'wrapping nodes can add multiple levels of wrapping to multiple elements' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 55, 65 ), 'new range contains wrapping elements' ); fragment.unwrapNodes( 0, 2 ); assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 55, 61 ), 'range after unwrapping is same as original range' ); // Make a 1 paragraph into 1 list with 1 item fragment = surface.getLinearFragment( new ve.Range( 9, 12 ) ); fragment.wrapAllNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.deepEqual( doc.getData( new ve.Range( 9, 16 ) ), [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' }, { type: 'paragraph' }, 'd', { type: '/paragraph' }, { type: '/listItem' }, { type: '/list' } ], 'wrapping nodes can add multiple levels of wrapping to a single element' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 9, 16 ), 'new range contains wrapping elements' ); fragment.unwrapNodes( 0, 2 ); assert.deepEqual( doc.getData(), originalDoc.getData(), 'unwrapping 2 levels restores document to original state' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 9, 12 ), 'range after unwrapping is same as original range' ); fragment = surface.getLinearFragment( new ve.Range( 5, 37 ) ); assert.throws( () => { fragment.unwrapNodes( 0, 20 ); }, /cannot unwrap by greater depth/, 'error thrown trying to unwrap more nodes that it is possible to contain' ); expectedData.splice( 5, 4 ); expectedData.splice( 29, 4 ); fragment.unwrapNodes( 0, 4 ); assert.deepEqual( doc.getData(), expectedData, 'unwrapping 4 levels (table, tableSection, tableRow and tableCell)' ); } ); QUnit.test( 'rewrapAllNodes', ( assert ) => { const doc = ve.dm.example.createExampleDocument(), originalDoc = ve.dm.example.createExampleDocument(), surface = new ve.dm.Surface( doc ), expectedDoc = ve.dm.example.createExampleDocument(), expectedSurface = new ve.dm.Surface( expectedDoc ), expectedFragment = expectedSurface.getLinearFragment( new ve.Range( 5, 37 ) ); let fragment = surface.getLinearFragment( new ve.Range( 5, 37 ) ); // Compare a rewrap operation with its equivalent unwrap + wrap // This type of test can only exist if the intermediate state is valid fragment.rewrapAllNodes( 4, [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); expectedFragment.unwrapNodes( 0, 4 ); expectedFragment.wrapAllNodes( [ { type: 'list', attributes: { style: 'bullet' } }, { type: 'listItem' } ] ); assert.deepEqual( doc.getData(), expectedDoc.getData(), 'rewrapping multiple nodes via a valid intermediate state produces the same document as unwrapping then wrapping' ); assert.equalHash( fragment.getSelection(), expectedFragment.getSelection(), 'new range contains rewrapping elements' ); // Reverse of first test fragment.rewrapAllNodes( 2, [ { type: 'table' }, { type: 'tableSection', attributes: { style: 'body' } }, { type: 'tableRow' }, { type: 'tableCell', attributes: { style: 'data' } } ] ); const expectedData = originalDoc.getData(); assert.deepEqual( doc.getData(), expectedData, 'rewrapping multiple nodes via a valid intermediate state produces the same document as unwrapping then wrapping' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 5, 37 ), 'new range contains rewrapping elements' ); // Rewrap a heading as a paragraph // The intermediate stage (plain text attached to the document) would be invalid // if performed as an unwrap and a wrap fragment = surface.getLinearFragment( new ve.Range( 0, 5 ) ); fragment.rewrapAllNodes( 1, [ { type: 'paragraph' } ] ); expectedData.splice( 0, 1, { type: 'paragraph' } ); expectedData.splice( 4, 1, { type: '/paragraph' } ); assert.deepEqual( doc.getData(), expectedData, 'rewrapping a heading as a paragraph' ); assert.equalRange( fragment.getSelection().getRange(), new ve.Range( 0, 5 ), 'new range contains rewrapping elements' ); } ); QUnit.test( 'isolateAndUnwrap', ( assert ) => { const cases = [ { type: 'heading', range: new ve.Range( 12, 20 ), expected: ( data ) => { data.splice( 11, 0, { type: 'listItem' } ); data.splice( 12, 1 ); data.splice( 20, 1, { type: '/listItem' } ); }, base: ve.dm.example.baseUri, msg: 'isolating paragraph in list item "Item 2" for heading' } ]; cases.forEach( ( caseItem ) => ve.test.utils.runIsolateTest( assert, caseItem ) ); } );
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка