/*! * VisualEditor DataModel example data sets. * * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt * @license The MIT License (MIT); see LICENSE.txt */ /** * @class * @singleton * @ignore */ ve.dm.example = {}; /* Methods */ /** * Convert arrays of shorthand annotations in a data fragment to AnnotationSets with real * annotation objects, and wraps the result in a ve.dm.ElementLinearData object. * * Shorthand notation for annotations is: * [ 'a', [ { 'type': 'link', 'attributes': { 'href': '...' } ] ] * * The actual storage format has an instance of ve.dm.LinkAnnotation instead of the plain object, * and an instance of ve.dm.AnnotationSet instead of the array. * * @method * @param {Array} data Linear model data * @param {ve.dm.IndexValueStore} [store] Index-value store to use, creates one if undefined * @returns {ve.dm.FlatLinearData} Linear data store * @throws {Error} Example data passed to preprocessAnnotations by reference */ ve.dm.example.preprocessAnnotations = function ( data, store ) { var i, key; // Sanity check to make sure ve.dm.example data has not been passed in // by reference. Always use ve#copy. for ( i in ve.dm.example ) { if ( data === ve.dm.example[i] ) { throw new Error( 'Example data passed to preprocessAnnotations by reference' ); } } store = store || new ve.dm.IndexValueStore(); for ( i = 0; i < data.length; i++ ) { key = data[i].annotations ? 'annotations' : 1; // check for shorthand annotation objects in array if ( ve.isArray( data[i][key] ) && data[i][key][0].type ) { data[i][key] = ve.dm.example.createAnnotationSet( store, data[i][key] ).getIndexes(); } } return new ve.dm.FlatLinearData( store, data ); }; /** * Create an annotation object from shorthand notation. * @method * @param {Object} annotation Plain object with type and attributes properties * @returns {ve.dm.Annotation} Instance of the right ve.dm.Annotation subclass */ ve.dm.example.createAnnotation = function ( annotation ) { return ve.dm.annotationFactory.create( annotation.type, annotation ); }; /** * Create an AnnotationSet from an array of shorthand annotations. * * This calls ve.dm.example.createAnnotation() for each element and puts the result in an * AnnotationSet. * * @method * @param {Array} annotations Array of annotations in shorthand format * @returns {ve.dm.AnnotationSet} */ ve.dm.example.createAnnotationSet = function ( store, annotations ) { var i; for ( i = 0; i < annotations.length; i++ ) { annotations[i] = ve.dm.example.createAnnotation( annotations[i] ); } return new ve.dm.AnnotationSet( store, store.indexes( annotations ) ); }; /* Some common annotations in shorthand format */ ve.dm.example.bold = { 'type': 'textStyle/bold', 'attributes': { 'nodeName': 'b' } }; ve.dm.example.italic = { 'type': 'textStyle/italic', 'attributes': { 'nodeName': 'i' } }; ve.dm.example.underline = { 'type': 'textStyle/underline', 'attributes': { 'nodeName': 'u' } }; ve.dm.example.span = { 'type': 'textStyle/span', 'attributes': { 'nodeName': 'span' } }; ve.dm.example.big = { 'type': 'textStyle/big', 'attributes': { 'nodeName': 'big' } }; ve.dm.example.code = { 'type': 'textStyle/code', 'attributes': { 'nodeName': 'code' } }; ve.dm.example.tt = { 'type': 'textStyle/code', 'attributes': { 'nodeName': 'tt' } }; /** * Creates a document from example data. * * Defaults to ve.dm.example.data if no name is supplied. * * @param {string} [name='data'] Named element of ve.dm.example * @param {ve.dm.IndexValueStore} [store] A specific index-value store to use, optionally. * @returns {ve.dm.Document} Document * @throws {Error} Example data not found */ ve.dm.example.createExampleDocument = function ( name, store ) { return ve.dm.example.createExampleDocumentFromObject( name, store, ve.dm.example ); }; /** * Helper function for ve.dm.createExampleDocument. * * @param {string} [name='data'] Named element of ve.dm.example * @param {ve.dm.IndexValueStore} [store] A specific index-value store to use, optionally. * @param {Object} [object] Collection of test documents, keyed by name * @returns {ve.dm.Document} Document * @throws {Error} Example data not found */ ve.dm.example.createExampleDocumentFromObject = function ( name, store, object ) { var doc, i; name = name || 'data'; store = store || new ve.dm.IndexValueStore(); if ( object[name] === undefined ) { throw new Error( 'Example data \'' + name + '\' not found' ); } doc = new ve.dm.Document( ve.dm.example.preprocessAnnotations( ve.copy( object[name] ), store ) ); // HACK internalList isn't populated when creating a document from data if ( object[name].internalItems ) { for ( i = 0; i < object[name].internalItems.length; i++ ) { doc.internalList.queueItemHtml( object[name].internalItems[i].group, object[name].internalItems[i].key, object[name].internalItems[i].body ); } } if ( object[name].internalListNextUniqueNumber ) { doc.internalList.nextUniqueNumber = object[name].internalListNextUniqueNumber; } return doc; }; /** * Looks up a value in a node tree. * * @method * @param {ve.Node} root Root node to lookup from * @param {number...} [paths] Index path * @returns {ve.Node} Node at given path */ ve.dm.example.lookupNode = function ( root ) { var i, node = root; for ( i = 1; i < arguments.length; i++ ) { node = node.children[arguments[i]]; } return node; }; ve.dm.example.createDomElement = function ( type, attributes ) { var key, element = document.createElement( type ); for ( key in attributes ) { element.setAttribute( key, attributes[key] ); } return element; }; ve.dm.example.testDir = window.VE_TESTDIR || '.'; ve.dm.example.imgSrc = ve.dm.example.testDir + '/example.png'; ve.dm.example.fullImgSrc = ve.resolveUrl( ve.dm.example.imgSrc, document ); ve.dm.example.image = { html: 'Example', data: { 'type': 'image', 'attributes' : { 'src': ve.dm.example.imgSrc, 'alt': 'Example', 'width': 100, 'height': 50 }, 'htmlAttributes': [ { 'values': { 'src': ve.dm.example.imgSrc, 'alt': 'Example', 'width': '100', 'height': '50' }, 'computed': { 'src': ve.dm.example.fullImgSrc } } ] } }; /** * Serialized HTML. * * This is what the parser will emit. * TODO remove some of the

s here to test automatic wrapping */ ve.dm.example.html = '

abc

' + '' + '' + '' + '' + '
' + '

d

' + '
    ' + '
  • ' + '

    e

    ' + '
      ' + '
    • ' + '

      f

      ' + '
    • ' + '
    ' + '
  • ' + '
' + '
    ' + '
  1. ' + '

    g

    ' + '
  2. ' + '
' + '
' + '
h' + ve.dm.example.image.html + 'i
'+ '
' + '
' + '

j

' + '
' + '
' + '

k

' + '
' + '
' + '

l

' + '

m

'; /* * Linear data. * * This is what we convert serialized HTML from the parser into so we can work with it more easily. * * There are three types of components in content data: * * {string} Plain text character * * {Array} Annotated character * 0: {string} Character * 1: {Object} List of references to immutable annotation objects, keyed by JSON * serializations of their values (hashes) * * {Object} Opening or closing structural element * type: {string} Symbolic node type name, if closing element first character will be "/" * [attributes]: {Object} List of symbolic attribute name and literal value pairs */ ve.dm.example.data = [ // 0 - Beginning of heading { 'type': 'heading', 'attributes': { 'level': 1 } }, // 1 - Plain "a" 'a', // 2 - Bold "b" ['b', [ ve.dm.example.bold ]], // 3 - Italic "c" ['c', [ ve.dm.example.italic ]], // 4 - End of heading { 'type': '/heading' }, // 5 - Beginning of table { 'type': 'table' }, // 6 - Beginning of body { 'type': 'tableSection', 'attributes': { 'style': 'body' } }, // 7 - Beginning of row { 'type': 'tableRow' }, // 8 - Beginning of cell { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, // 9 - Beginning of paragraph { 'type': 'paragraph' }, // 10 - Plain "d" 'd', // 11 - End of paragraph { 'type': '/paragraph' }, // 12 - Beginning of bullet list { 'type': 'list', 'attributes': { 'style': 'bullet' } }, // 13 - Beginning of list item { 'type': 'listItem' }, // 14 - Beginning of paragraph { 'type': 'paragraph' }, // 15 - Plain "e" 'e', // 16 - End of paragraph { 'type': '/paragraph' }, // 17 - Beginning of nested bullet list { 'type': 'list', 'attributes': { 'style': 'bullet' } }, // 18 - Beginning of nested bullet list item { 'type': 'listItem' }, // 19 - Beginning of paragraph { 'type': 'paragraph' }, // 20 - Plain "f" 'f', // 21 - End of paragraph { 'type': '/paragraph' }, // 22 - End of nested bullet list item { 'type': '/listItem' }, // 23 - End of nested bullet list { 'type': '/list' }, // 24 - End of bullet list item { 'type': '/listItem' }, // 25 - End of bullet list { 'type': '/list' }, // 26 - Beginning of numbered list { 'type': 'list', 'attributes': { 'style': 'number' } }, // 27 - Beginning of numbered list item { 'type': 'listItem' }, // 28 - Beginning of paragraph { 'type': 'paragraph' }, // 29 - Plain "g" 'g', // 30 - End of paragraph { 'type': '/paragraph' }, // 31 - End of item { 'type': '/listItem' }, // 32 - End of lis t { 'type': '/list' }, // 33 - End of cell { 'type': '/tableCell' }, // 34 - End of row { 'type': '/tableRow' }, // 35 - End of body { 'type': '/tableSection' }, // 36 - End of table { 'type': '/table' }, // 37 - Beginning of preformatted { 'type': 'preformatted' }, // 38 - Plain "h" 'h', // 39 - Beginning of inline image ve.dm.example.image.data, // 40 - End of inline image { 'type': '/image' }, // 41 - Plain "i" 'i', // 42 - End of preformatted { 'type': '/preformatted' }, // 43 - Beginning of definition list { 'type': 'definitionList' }, // 44 - Beginning of definition list term item { 'type': 'definitionListItem', 'attributes': { 'style': 'term' } }, // 45 - Beginning of paragraph { 'type': 'paragraph' }, // 46 - Plain "j" 'j', // 47 - End of paragraph { 'type': '/paragraph' }, // 48 - End of definition list term item { 'type': '/definitionListItem' }, // 49 - Beginning of definition list definition item { 'type': 'definitionListItem', 'attributes': { 'style': 'definition' } }, // 50 - Beginning of paragraph { 'type': 'paragraph' }, // 51 - Plain "k" 'k', // 52 - End of paragraph { 'type': '/paragraph' }, // 53 - End of definition list definition item { 'type': '/definitionListItem' }, // 54 - End of definition list { 'type': '/definitionList' }, // 55 - Beginning of paragraph { 'type': 'paragraph' }, // 56 - Plain "l" 'l', // 57 - End of paragraph { 'type': '/paragraph' }, // 58 - Beginning of paragraph { 'type': 'paragraph' }, // 59 - Plain "m" 'm', // 60 - End of paragraph { 'type': '/paragraph' }, // 61 - Beginning of internalList { 'type': 'internalList' }, // 62 - End of internalList { 'type': '/internalList' } // 63 - End of document ]; ve.dm.example.alienData = [ // 0 - Open alienBlock { 'type': 'alienBlock' }, // 1 - Close alienBlock { 'type': '/alienBlock' }, // 2 - Open paragraph { 'type': 'paragraph' }, // 3 - Plain character 'a' 'a', // 4 - Open alienInline { 'type': 'alienBlock' }, // 5 - Close alienInline { 'type': '/alienBlock' }, // 6 - Plain character 'b' 'b', // 7 - Close paragraph { 'type': '/paragraph' }, // 8 - Open alienBlock { 'type': 'alienBlock' }, // 9 - Close alienBlock { 'type': '/alienBlock' }, // 10 - Beginning of internalList { 'type': 'internalList' }, // 11 - End of internalList { 'type': '/internalList' } // 12 - End of document ]; ve.dm.example.internalData = [ { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': 'internalItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': '/internalItem' }, { 'type': 'internalItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': '/internalItem' }, { 'type': '/internalList' }, { 'type': 'paragraph' }, 'Q', 'u', 'u', 'x', { 'type': '/paragraph' } ]; ve.dm.example.internalData.internalItems = [ { 'group': 'test', 'key': 'bar', 'body': 'Bar' }, { 'group': 'test', 'key': 'baz', 'body': 'Baz' } ]; ve.dm.example.withMeta = [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', 'r', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'z', { 'type': '/paragraph' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'internalList' }, { 'type': '/internalList' } ]; ve.dm.example.withMetaPlainData = [ { 'type': 'paragraph' }, 'F', 'o', 'o', 'B', 'a', 'r', 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ]; ve.dm.example.withMetaMetaData = [ [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } } ], undefined, undefined, undefined, [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } } ], undefined, undefined, [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } } ], undefined, [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } } ], undefined, [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } } ], undefined, undefined ]; ve.dm.example.listWithMeta = [ // 0 - Beginning of list { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'list' }, // 1 - Beginning of first list item { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'listItem', 'attributes': { 'styles': ['bullet'] } }, // 2 - Beginning of paragraph { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'paragraph' }, // 3 - Plain "a" { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'a', // 4 - End of paragraph { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, // 5 - End of first list item { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/listItem' }, // 6 - Beginning of second list item { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'listItem', 'attributes': { 'styles': ['bullet'] } }, // 7 - Beginning of paragraph { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'paragraph' }, // 8 - Plain "b" { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'b', // 9 - End of paragraph { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, // 10 - End of second list item { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/listItem' }, // 11 - End of list { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/list' }, // 12 - Trailing metadata { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' } ]; ve.dm.example.complexTableHtml = '' + '
Foo
Bar
Baz
QuuxWhee
'; ve.dm.example.complexTable = [ { 'type': 'table' }, { 'type': 'tableCaption' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': '/tableCaption' }, { 'type': 'tableSection', 'attributes': { 'style': 'header' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'header' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': 'tableSection', 'attributes': { 'style': 'footer' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'Q', 'u', 'u', 'x', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'W', 'h', 'e', 'e', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ]; ve.dm.example.inlineAtEdges = [ { 'type': 'paragraph' }, ve.dm.example.image.data, { 'type': '/image' }, 'F', 'o', 'o', { 'type': 'alienInline', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienInline' }, { 'type': '/paragraph' } ]; ve.dm.example.emptyBranch = [ { 'type': 'table' }, { 'type': '/table' } ]; /** * Sample content data index. * * This is part of what a ve.dm.DocumentFragment generates when given linear data. * * (21) branch nodes * (01) document node * (01) heading node * (01) table node * (01) tableRow node * (01) tableCell node * (06) paragraph nodes * (03) list nodes * (03) listItem nodes * (01) preformatted node * (01) definitionList node * (02) definitionListItem nodes * (10) leaf nodes * (09) text nodes * (01) image node */ ve.dm.example.tree = new ve.dm.DocumentNode( [ // Heading with "abc" new ve.dm.HeadingNode( [new ve.dm.TextNode( 3 )], ve.dm.example.data[0] ), new ve.dm.TableNode( [ new ve.dm.TableSectionNode( [ new ve.dm.TableRowNode( [ new ve.dm.TableCellNode( [ // Paragraph with "d" new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[9] ), new ve.dm.ListNode( [ // 1st level bullet list item with "e" new ve.dm.ListItemNode( [ new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[14] ), new ve.dm.ListNode( [ // 2nd level bullet list item with "f" new ve.dm.ListItemNode( [ new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[19] ) ], ve.dm.example.data[18] ) ], ve.dm.example.data[17] ) ], ve.dm.example.data[13] ) ], ve.dm.example.data[12] ), new ve.dm.ListNode( [ // Numbered list item with "g" new ve.dm.ListItemNode( [ new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[28] ) ], ve.dm.example.data[27] ) ], ve.dm.example.data[26] ) ], ve.dm.example.data[8] ) ], ve.dm.example.data[7] ) ], ve.dm.example.data[6] ) ], ve.dm.example.data[5] ), // Preformatted with "h[example.png]i" new ve.dm.PreformattedNode( [ new ve.dm.TextNode( 1 ), new ve.dm.ImageNode( [], ve.dm.example.data[39] ), new ve.dm.TextNode( 1 ) ], ve.dm.example.data[37] ), new ve.dm.DefinitionListNode( [ // Definition list term item with "j" new ve.dm.DefinitionListItemNode( [ new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[45] ) ], ve.dm.example.data[44] ), // Definition list definition item with "k" new ve.dm.DefinitionListItemNode( [ new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[50] ) ], ve.dm.example.data[49] ) ], ve.dm.example.data[43] ), new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[55] ), new ve.dm.ParagraphNode( [new ve.dm.TextNode( 1 )], ve.dm.example.data[58] ), new ve.dm.InternalListNode( [], ve.dm.example.data[61] ) ] ); ve.dm.example.conversions = { 'definitionListItem term': { 'domElement': ve.dm.example.createDomElement( 'dt' ), 'dataElement': { 'type': 'definitionListItem', 'attributes': { 'style': 'term' } } }, 'definitionListItem definition': { 'domElement': ve.dm.example.createDomElement( 'dd' ), 'dataElement': { 'type': 'definitionListItem', 'attributes': { 'style': 'definition' } } }, 'definitionList definition': { 'domElement': ve.dm.example.createDomElement( 'dl' ), 'dataElement': { 'type': 'definitionList' } }, 'heading level 1': { 'domElement': ve.dm.example.createDomElement( 'h1' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 1 } } }, 'heading level 2': { 'domElement': ve.dm.example.createDomElement( 'h2' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 2 } } }, 'heading level 3': { 'domElement': ve.dm.example.createDomElement( 'h3' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 3 } } }, 'heading level 4': { 'domElement': ve.dm.example.createDomElement( 'h4' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 4 } } }, 'heading level 5': { 'domElement': ve.dm.example.createDomElement( 'h5' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 5 } } }, 'heading level 6': { 'domElement': ve.dm.example.createDomElement( 'h6' ), 'dataElement': { 'type': 'heading', 'attributes': { 'level': 6 } } }, 'image': { 'domElement': ve.dm.example.createDomElement( 'img' ), 'dataElement': { 'type': 'image' } }, 'listItem': { 'domElement': ve.dm.example.createDomElement( 'li' ), 'dataElement': { 'type': 'listItem' } }, 'list bullet': { 'domElement': ve.dm.example.createDomElement( 'ul' ), 'dataElement': { 'type': 'list', 'attributes': { 'style': 'bullet' } } }, 'list number': { 'domElement': ve.dm.example.createDomElement( 'ol' ), 'dataElement': { 'type': 'list', 'attributes': { 'style': 'number' } } }, 'paragraph': { 'domElement': ve.dm.example.createDomElement( 'p' ), 'dataElement': { 'type': 'paragraph' } }, 'preformatted': { 'domElement': ve.dm.example.createDomElement( 'pre' ), 'dataElement': { 'type': 'preformatted' } }, 'tableCell': { 'domElement': ve.dm.example.createDomElement( 'td' ), 'dataElement': { 'type': 'tableCell', 'attributes': { 'style': 'data' } } }, 'table': { 'domElement': ve.dm.example.createDomElement( 'table' ), 'dataElement': { 'type': 'table' } }, 'tableRow': { 'domElement': ve.dm.example.createDomElement( 'tr' ), 'dataElement': { 'type': 'tableRow' } }, 'paragraph with data-mw attribute': { 'domElement': ve.dm.example.createDomElement( 'p', { 'data-mw': '{"test":1234}' } ), 'dataElement': { 'type': 'paragraph', 'htmlAttributes': [ { 'values': { 'data-mw': '{"test":1234}' } } ] } }, 'paragraph with style attribute': { 'domElement': ve.dm.example.createDomElement( 'p', { 'style': 'color:blue' } ), 'dataElement': { 'type': 'paragraph', 'htmlAttributes': [ { 'values': { 'style': 'color:blue' } } ] } } }; ve.dm.example.domToDataCases = { 'paragraph with plain text': { 'body': '

abc

', 'data': [ { 'type': 'paragraph' }, 'a', 'b', 'c', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'annotated text with bold, italic, underline formatting': { 'body': '

abc

', 'data': [ { 'type': 'paragraph' }, ['a', [ ve.dm.example.bold ]], ['b', [ ve.dm.example.italic ]], ['c', [ ve.dm.example.underline ]], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'equivalent annotations': { 'body': '

abcdef', 'data': [ { 'type': 'paragraph' }, ['a', [ ve.dm.example.code ]], 'b', ['c', [ ve.dm.example.tt ]], 'd', ['e', [ ve.dm.example.code ]], ['f', [ ve.dm.example.tt ]], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'normalizedBody': '

abcdef' }, 'additive annotations': { 'body': '

abcdef

', 'data': [ { 'type': 'paragraph' }, ['a', [ ve.dm.example.big ]], ['b', [ ve.dm.example.big, ve.dm.example.big ]], ['c', [ ve.dm.example.big ]], ['d', [ ve.dm.example.bold ]], ['e', [ ve.dm.example.bold, ve.dm.example.bold ]], ['f', [ ve.dm.example.bold ]], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'additive annotations overlapping other annotations': { 'body': '

abc

', 'data': [ { 'type': 'paragraph' }, ['a', [ ve.dm.example.italic, ve.dm.example.big ]], ['b', [ ve.dm.example.italic, ve.dm.example.big, ve.dm.example.big, ve.dm.example.bold ]], ['c', [ ve.dm.example.italic, ve.dm.example.big, ve.dm.example.bold ]], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'strip leading whitepsace in paragraphs': { 'data': [ { 'type': 'paragraph' }, ' ', 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'paragraph' }, ' ', '\t', ' ', '\t', 'b', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'heading', 'attributes': { 'level': 2 } }, ' ', ' ', 'b', 'a', 'z', { 'type': '/heading' }, { 'type': 'preformatted' }, ' ', '\t', 'q', 'u', 'u', 'x', { 'type': '/preformatted' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'normalizedBody': '

foo

bar

baz

 \tquux
' }, 'image': { 'body': ve.dm.example.image.html, 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, ve.dm.example.image.data, { 'type' : '/image' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'paragraph with alienInline inside': { 'body': '

abc

', 'data': [ { 'type': 'paragraph' }, 'a', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'b' ).toArray() } }, { 'type': '/alienInline' }, 'c', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'paragraphs with an alienBlock between them': { 'body': '

abc

abc

def

', 'data': [ { 'type': 'paragraph' }, 'a', 'b', 'c', { 'type': '/paragraph' }, { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
abc
' ).toArray() } }, { 'type': '/alienBlock' }, { 'type': 'paragraph' }, 'd', 'e', 'f', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'annotated inline nodes': { 'body': '

abc' + '
d
e

', 'data': [ { 'type': 'paragraph' }, 'a', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'b' ).toArray() }, 'annotations': [ ve.dm.example.bold ] }, { 'type': '/alienInline' }, { 'type': 'alienInline', 'attributes': { 'domElements': $( 'c' ).toArray() }, 'annotations': [ ve.dm.example.bold, ve.dm.example.italic ] }, { 'type': '/alienInline' }, { 'type': 'break', 'annotations': [ ve.dm.example.italic ] }, { 'type': '/break' }, ['d', [ ve.dm.example.italic ]], 'e', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'annotated metadata': { 'body': '

bar

', 'data': [ { 'type': 'paragraph' }, { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, [ 'b', [ ve.dm.example.bold ] ], [ 'a', [ ve.dm.example.bold ] ], [ 'r', [ ve.dm.example.bold ] ], { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'annotated comment metadata in a wrapper': { 'body': 'barquux', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, [ 'b', [ ve.dm.example.bold ] ], [ 'a', [ ve.dm.example.bold ] ], [ 'r', [ ve.dm.example.bold ] ], { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, [ 'q', [ ve.dm.example.bold ] ], [ 'u', [ ve.dm.example.bold ] ], [ 'u', [ ve.dm.example.bold ] ], [ 'x', [ ve.dm.example.bold ] ], { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'annotated element metadata in a wrapper with content': { 'body': 'foo', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, [ 'f', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], { 'type': 'alienMeta', 'annotations': [ ve.dm.example.bold ], 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'comment metadata in a wrapper followed by annotated text': { 'body': 'FooBaz', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, [ 'B', [ ve.dm.example.bold ] ], [ 'a', [ ve.dm.example.bold ] ], [ 'z', [ ve.dm.example.bold ] ], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content': { 'body': 'abc', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'a', 'b', 'c', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content with inline node': { 'body': '1
2', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, '1', { 'type': 'break' }, { 'type': '/break' }, '2', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content starting with inline node': { 'body': ve.dm.example.image.html + '12', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, ve.dm.example.image.data, { 'type': '/image' }, '1', '2', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content with inline alien': { 'body': '1baz2', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, '1', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'baz' ).toArray() } }, { 'type': '/alienInline' }, '2', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content with block alien': { 'body': '1
baz
2', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, '1', { 'type': '/paragraph' }, { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
baz
' ).toArray() } }, { 'type': '/alienBlock' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, '2', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content starting with inline alien': { 'body': 'FooBar', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, { 'type': 'alienInline', 'attributes': { 'domElements': $( 'Foo' ).toArray() } }, { 'type': '/alienInline' }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content ending with inline alien': { 'body': 'FooBar', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'Bar' ).toArray() } }, { 'type': '/alienInline' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content with about group': { 'body': '1foobar2', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, '1', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'foobar' ).toArray() } }, { 'type': '/alienInline' }, '2', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content between structural nodes': { 'body': '
abc
', 'data': [ { 'type': 'table' }, { 'type': '/table' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'a', 'b', 'c', { 'type': '/paragraph' }, { 'type': 'table' }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping of bare content between paragraphs': { 'body': '

abc

def

', 'data': [ { 'type': 'paragraph' }, 'a', 'b', 'c', { 'type': '/paragraph' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'd', 'e', 'f', { 'type': '/paragraph' }, { 'type': 'paragraph' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'wrapping prevents empty list items': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'empty' } }, { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty document': { 'body': '', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'empty' } }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty document with meta': { 'body': '', 'data': [ { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'paragraph', 'internal': { 'generated': 'empty' } }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty document with content added by the editor': { 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'empty' } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'normalizedBody': '

Foo

' }, 'empty list item with content added by the editor': { 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'empty' } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'normalizedBody': '' }, 'example document': { 'body': ve.dm.example.html, 'data': ve.dm.example.data }, 'empty annotation': { 'body': '

FooBar

', 'data': [ { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty annotation in wrapper paragraph': { 'body': 'FooBar', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'nested empty annotation': { 'body': '

FooBar

', 'data': [ { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty annotation inside nonempty annotation': { 'body': '

Foo

', 'data': [ { 'type': 'paragraph' }, [ 'F', [ ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.italic ] ], { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() }, 'annotations': [ ve.dm.example.italic ] }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'empty annotation with comment': { 'body': '

FooBaz

', 'data': [ { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'list item with space followed by link': { 'body': '', 'head': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ' ] } }, [ 'b', [ { 'type': 'link', 'attributes': { 'href': 'Foobar' }, 'htmlAttributes': [ { 'values': { 'href': 'Foobar' }, 'computed': { 'href': 'http://example.com/Foobar' } } ] } ] ], [ 'a', [ { 'type': 'link', 'attributes': { 'href': 'Foobar' }, 'htmlAttributes': [ { 'values': { 'href': 'Foobar' }, 'computed': { 'href': 'http://example.com/Foobar' } } ] } ] ], [ 'r', [ { 'type': 'link', 'attributes': { 'href': 'Foobar' }, 'htmlAttributes': [ { 'values': { 'href': 'Foobar' }, 'computed': { 'href': 'http://example.com/Foobar' } } ] } ] ], { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace between unwrapped inline nodes': { 'body': 'c d\ne', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, { 'type': 'alienInline', 'attributes': { 'domElements': $( 'c' ).toArray() } }, { 'type': '/alienInline' }, ' ', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'd' ).toArray() } }, { 'type': '/alienInline' }, '\n', { 'type': 'alienInline', 'attributes': { 'domElements': $( 'e' ).toArray() } }, { 'type': '/alienInline' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation in headings': { 'body': '

Foo

Bar

Baz

Quux

', 'data': [ { 'type': 'heading', 'attributes': { 'level': 2 } }, 'F', 'o', 'o', { 'type': '/heading' }, { 'type': 'heading', 'attributes': { 'level': 2 }, 'internal': { 'whitespace': [ undefined, ' ' ] } }, 'B', 'a', 'r', { 'type': '/heading' }, { 'type': 'heading', 'attributes': { 'level': 2 }, 'internal': { 'whitespace': [ undefined, undefined, ' ' ] } }, 'B', 'a', 'z', { 'type': '/heading' }, { 'type': 'heading', 'attributes': { 'level': 2 }, 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, 'Q', 'u', 'u', 'x', { 'type': '/heading' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation in list items': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, ' ' ]} }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ' ], 'generated': 'wrapper' } }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, undefined, ' ' ] } }, { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, undefined, undefined, ' ' ], 'generated': 'wrapper' } }, 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, ' ', ' '] } }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ', undefined, undefined, ' ' ], 'generated': 'wrapper' } }, 'Q', 'u', 'u', 'x', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with annotations': { 'body': '

Foo

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, [ ' ', [ ve.dm.example.italic ] ], [ ' ', [ ve.dm.example.italic ] ], [ 'F', [ ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.italic ] ], [ ' ', [ ve.dm.example.italic ] ], [ ' ', [ ve.dm.example.italic ] ], [ ' ', [ ve.dm.example.italic ] ], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'outer whitespace preservation in a list with bare text and a wrapper paragraph': { 'body': '\n\t\n\t\n', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': { 'whitespace': [ '\n', '\n\n', '\t\n', '\t\n\t\n' ] } }, { 'type': 'listItem', 'internal': { 'whitespace': [ '\n\n', '\n\n\n', '\n\n\n\n', '\n\n\n\n\n' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ '\n\n\n', undefined, undefined, '\n\n\n\n' ] } }, 'B', 'a', ' ', 'r', 'e', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem', 'internal': { 'whitespace': [ '\n\n\n\n\n', '\t', '\t\t\t\t', '\t\n' ] } }, { 'type': 'paragraph', 'internal': { 'whitespace': [ '\t', '\t\t', '\t\t\t', '\t\t\t\t' ] } }, 'P', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ '\n', '\t\n\t\n' ] }, 'outer whitespace preservation in a list with bare text and a sublist': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': { 'whitespace': [ undefined, '\n', '\t\t\t' ] } }, { 'type': 'listItem', 'internal': { 'whitespace': [ '\n', '\n\n', '\t\t', '\t\t\t' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ '\n\n', undefined, undefined, '\n\n\n' ] } }, 'B', 'a', ' ', 'r', 'e', { 'type': '/paragraph' }, { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': { 'whitespace': [ '\n\n\n', '\n\n\n\n', '\t', '\t\t' ] } }, { 'type': 'listItem', 'internal': { 'whitespace': [ '\n\n\n\n', ' ', ' ', '\t' ] } }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ', ' ', ' ', ' '] } }, 'P', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation leaves non-edge content whitespace alone': { 'body': '

A B C\t\t\tD\t\t\t

\nE\n\nF\n\n\n\n\n\n\nG H ', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', '\t\t\t', '\n' ] } }, 'A', ' ', ' ', 'B', ' ', ' ', ' ', [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ 'C', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], '\t', '\t', 'D', { 'type': '/paragraph' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ '\n', undefined, undefined, ' ' ] } }, 'E', '\n', '\n', 'F', '\n', '\n', '\n', [ '\n', [ ve.dm.example.bold ] ], [ '\n', [ ve.dm.example.bold ] ], [ '\n', [ ve.dm.example.bold ] ], [ '\n', [ ve.dm.example.bold ] ], [ 'G', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], ' ', ' ', 'H', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ undefined, ' ' ] }, 'whitespace preservation with non-edge content whitespace with nested annotations': { 'body': '

A B C\t\t\tD\t\t\t\t\t\t\tE\n\n\nF\n\n\n

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', '\n\n\n' ] } }, 'A', ' ', ' ', 'B', ' ', ' ', ' ', [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ ' ', [ ve.dm.example.bold ] ], [ 'C', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'D', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], [ 'E', [ ve.dm.example.bold ] ], [ '\n', [ ve.dm.example.bold ] ], '\n', '\n', 'F', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with tightly nested annotations': { 'body': '

A B \t\tC\t\t\t\n\nD\n\n\n

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', '\n\n\n' ] } }, 'A', ' ', ' ', 'B', ' ', ' ', ' ', [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'C', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], '\n', '\n', 'D', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with nested annotations with whitespace on the left side': { 'body': '

A B \n\t\t\tC\t\t\t\n\nD\n\n\n

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', '\n\n\n' ] } }, 'A', ' ', ' ', 'B', ' ', ' ', ' ', [ '\n', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'C', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], '\n', '\n', 'D', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with nested annotations with whitespace on the right side': { 'body': '

A B \t\tC\t\t\t\n\t\n\nD\n\n\n

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', '\n\n\n' ] } }, 'A', ' ', ' ', 'B', ' ', ' ', ' ', [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ 'C', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\t', [ ve.dm.example.bold, ve.dm.example.italic ] ], [ '\n', [ ve.dm.example.bold ] ], [ '\t', [ ve.dm.example.bold ] ], '\n', '\n', 'D', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with aliens': { 'body': '

\tFoo\t\t\t\t\tBar\t\t\t\t\nBaz\n\n\n\n\nQuux\n\n\n\n \tWhee \n

\t\n
\n\tYay \t
\n ', 'data': [ { 'type': 'alienBlock', 'attributes': { 'domElements': $( '

' ).toArray() }, 'internal': { 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, { 'type': '/alienBlock' }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ', '\t', ' \n', '\t\n' ] } }, 'F', 'o', 'o', '\t', '\t', { 'type': 'alienInline', 'attributes': { 'domElements': $( '\t\t\tBar\t\t\t\t' ).toArray() } }, { 'type': '/alienInline' }, '\n', 'B', 'a', 'z', '\n', '\n', { 'type': 'alienInline', 'attributes': { 'domElements': $( '\n\n\nQuux\n\n\n\n' ).toArray() } }, { 'type': '/alienInline' }, ' ', '\t', 'W', 'h', 'e', 'e', { 'type': '/paragraph' }, { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
\n\tYay \t
' ).toArray() }, 'internal': { 'whitespace': [ '\t\n', undefined, undefined, ' \n ' ] } }, { 'type': '/alienBlock' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ ' ', ' \n ' ] }, 'whitespace preservation not triggered inside
': {
		'body': '\n
\n\n\nFoo\n\n\nBar\n\n\n\n
\n\n\n\n\n', 'data': [ { 'type': 'preformatted', 'internal': { 'whitespace': ['\n', undefined, undefined, '\n\n\n\n\n' ] } }, '\n', '\n', 'F', 'o', 'o', '\n', '\n', '\n', 'B', 'a', 'r', '\n', '\n', '\n', '\n', { 'type': '/preformatted' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ '\n', '\n\n\n\n\n' ] }, 'whitespace preservation in table cell starting with text and ending with annotation': { 'body': '
Foo Bar
', 'data': [ { 'type': 'table' }, { 'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', ' ', [ 'B', [ ve.dm.example.bold ] ], [ 'a', [ ve.dm.example.bold ] ], [ 'r', [ ve.dm.example.bold ] ], { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with wrapped text and comments': { 'body': ' \nFoo', 'data': [ { 'type': 'alienMeta', 'internal': { 'whitespace': [ undefined, undefined, undefined, ' ' ] }, 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'internal': { 'whitespace': [ ' ', undefined, undefined, '\n' ] }, 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ '\n' ] } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with comments at end of wrapper paragraph': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, 'b', 'a', 'r', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'q', 'u', 'u', 'x', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with comment at end of wrapper paragraph': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ ' ' ] } }, 'b', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() }, 'internal': { 'whitespace': [ undefined, undefined, undefined, ' ' ] } }, { 'type': '/alienMeta' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with multiple comments at end of wrapper paragraph': { 'body': '', 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem', 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, 'f', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() }, 'internal': { 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, { 'type': '/alienMeta' }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() }, 'internal': { 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, { 'type': '/alienMeta' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with comment at start or end of element': { 'body': '

bar

', 'data': [ { 'type': 'paragraph', 'internal': { 'whitespace': [ undefined, ' ', ' ' ] } }, { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, 'b', 'a', 'r', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace surrounding metadata in a wrapper': { 'body': 'Foo \nBar', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, [ 'F', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], [ 'o', [ ve.dm.example.bold ] ], ' ', { 'type': 'alienMeta', 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, '\n', [ 'B', [ ve.dm.example.italic ] ], [ 'a', [ ve.dm.example.italic ] ], [ 'r', [ ve.dm.example.italic ] ], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation in empty branch node': { 'body': '\n\n
', 'data': [ { 'type': 'table', 'internal': { 'whitespace': [ undefined, '\n\n' ] } }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'mismatching whitespace data is ignored': { 'data': [ { 'type': 'list', 'attributes': { 'style': 'bullet' }, 'internal': { 'whitespace': [ ' ', ' ', ' ', ' ' ] } }, { 'type': 'listItem', 'internal': { 'whitespace': [ ' ', ' ', ' ', ' ' ] } }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ', '\t', '\n', ' ' ] } }, 'A', { 'type': '/paragraph' }, { 'type': 'paragraph', 'internal': { 'whitespace': [ ' ' ] } }, 'B', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ '\t', '\n' ], 'normalizedBody': '' }, 'order of nested annotations is preserved': { 'body': '

Foo

', 'data': [ { 'type': 'paragraph' }, [ 'F', [ ve.dm.example.bold, ve.dm.example.underline, ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.bold, ve.dm.example.underline, ve.dm.example.italic ] ], [ 'o', [ ve.dm.example.bold, ve.dm.example.underline, ve.dm.example.italic ] ], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'nested annotations are closed and reopened in the correct order': { 'body': '

Foobarbaz

', 'head': '', 'data': [ { 'type': 'paragraph' }, [ 'F', [ { 'type': 'link', 'attributes': { 'href': 'Foo' }, 'htmlAttributes': [ { 'values': { 'href': 'Foo' }, 'computed': { 'href': 'http://example.com/Bar/Foo' } } ] } ] ], [ 'o', [ { 'type': 'link', 'attributes': { 'href': 'Foo' }, 'htmlAttributes': [ { 'values': { 'href': 'Foo' }, 'computed': { 'href': 'http://example.com/Bar/Foo' } } ] }, ve.dm.example.bold ] ], [ 'o', [ { 'type': 'link', 'attributes': { 'href': 'Foo' }, 'htmlAttributes': [ { 'values': { 'href': 'Foo' }, 'computed': { 'href': 'http://example.com/Bar/Foo' } } ] }, ve.dm.example.bold, ve.dm.example.italic ] ], [ 'b', [ { 'type': 'link', 'attributes': { 'href': 'Foo' }, 'htmlAttributes': [ { 'values': { 'href': 'Foo' }, 'computed': { 'href': 'http://example.com/Bar/Foo' } } ] }, ve.dm.example.italic ] ], [ 'a', [ ve.dm.example.italic ] ], [ 'r', [ ve.dm.example.italic, ve.dm.example.bold ] ], [ 'b', [ ve.dm.example.italic ] ], [ 'a', [ ve.dm.example.italic, ve.dm.example.underline ] ], [ 'z', [ ve.dm.example.italic ] ], { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'about grouping': { 'body': '
Foo
' + '
Bar
' + '
Baz
' + 'Quux' + '

Whee

' + 'Yay' + '
Blah
' + 'Meh', 'data': [ { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
Foo
' + '
Bar
' ).toArray() } }, { 'type': '/alienBlock' }, { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
Baz
' + 'Quux' ).toArray() } }, { 'type': '/alienBlock' }, { 'type': 'paragraph' }, 'W', 'h', 'e', 'e', { 'type': '/paragraph' }, { 'type': 'alienBlock', 'attributes': { 'domElements': $( 'Yay' + '
Blah
' ).toArray() } }, { 'type': '/alienBlock' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, { 'type': 'alienInline', 'attributes': { 'domElements': $( 'Meh' ).toArray() } }, { 'type': '/alienInline' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace preservation with an about group': { 'body': '
\tFoo\t\t
\t\t\t' + '
Bar
', 'data': [ { 'type': 'alienBlock', 'attributes': { 'domElements': $( '
\tFoo\t\t
\t\t\t' + '
Bar
' ).toArray() }, 'internal': { 'whitespace': [ ' ', undefined, undefined, ' ' ] } }, { 'type': '/alienBlock' }, { 'type': 'internalList' }, { 'type': '/internalList' } ], 'innerWhitespace': [ ' ', ' ' ] }, 'block node inside annotation node is alienated': { 'body': '\n

Bar

', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, [ '\n', [ ve.dm.example.span ] ], { 'type': 'alienInline', 'attributes': { 'domElements': $( '

Bar

' ).toArray() }, 'annotations': [ ve.dm.example.span ] }, { 'type': '/alienInline' }, { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'block node inside annotation node surrounded by tables': { 'body': '
\n

Bar

', 'data': [ { 'type': 'table' }, { 'type': '/table' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, [ '\n', [ ve.dm.example.span ] ], { 'type': 'alienInline', 'attributes': { 'domElements': $( '

Bar

' ).toArray() }, 'annotations': [ ve.dm.example.span ] }, { 'type': '/alienInline' }, { 'type': '/paragraph' }, { 'type': 'table' }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'block node inside annotation node is alienated and continues wrapping': { 'body': 'Foo\n

Bar

Baz', 'data': [ { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'F', 'o', 'o', [ '\n', [ ve.dm.example.span ] ], { 'type': 'alienInline', 'attributes': { 'domElements': $( '

Bar

' ).toArray() }, 'annotations': [ ve.dm.example.span ] }, { 'type': '/alienInline' }, 'B', 'a', 'z', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'whitespace before meta node in wrapping mode': { 'body': '
Foo\n
', 'data': [ { 'type': 'table' }, { 'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' }, 'internal': { 'whitespace': [ undefined, undefined, '\n' ] } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper', 'whitespace': [ undefined, undefined, undefined, '\n' ] } }, 'F', 'o', 'o', { 'type': '/paragraph' }, { 'type': 'alienMeta', 'internal': { 'whitespace': [ '\n' ] }, 'attributes': { 'domElements': $( '' ).toArray() } }, { 'type': '/alienMeta' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': '/table' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] }, 'table with caption, head, foot and body': { 'body': ve.dm.example.complexTableHtml, 'data': ve.dm.example.complexTable }, 'div set to RTL with paragraph inside': { 'body': '

abcde

', 'data': [ { 'type': 'div', 'htmlAttributes': [ { 'values': { 'style': 'direction: rtl;' } } ] }, { 'type': 'paragraph' }, 'a', ['b', [ ve.dm.example.bold ]], 'c', ['d', [ ve.dm.example.italic ]], 'e', { 'type': '/paragraph' }, { 'type': '/div' }, { 'type': 'internalList' }, { 'type': '/internalList' } ] } }; ve.dm.example.isolationHtml = '
  • Item 1
  • Item 2
  • Item 3
' + 'Paragraph' + '
  • Item 4
  • Item 5
  • Item 6
' + '
Cell 1Cell 2Cell 3
Cell 4
' + 'Not allowed by dm:' + '
  • Title in list

  • Preformatted in list
' + '
    1. Nested 1
    2. Nested 2
    3. Nested 3
' + '
  • P1

    P2

    P3

'; ve.dm.example.isolationData = [ // 0 { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', ' ', '1', { 'type': '/paragraph' }, // 10 { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', ' ', '2', { 'type': '/paragraph' }, // 20 { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', ' ', '3', { 'type': '/paragraph' }, // 30 { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'P', 'a', 'r', 'a', 'g', 'r', 'a', // 40 'p', 'h', { 'type': '/paragraph' }, { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', // 50 ' ', '4', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', // 60 ' ', '5', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'I', 't', 'e', 'm', // 70 ' ', '6', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'table' }, { 'type': 'tableSection', 'attributes': { 'style': 'body' } }, { 'type': 'tableRow' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, // 80 'C', 'e', 'l', 'l', ' ', '1', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, // 90 'C', 'e', 'l', 'l', ' ', '2', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, // 100 'C', 'e', 'l', 'l', ' ', '3', { 'type': '/paragraph' }, { 'type': '/tableCell' }, { 'type': '/tableRow' }, { 'type': 'tableRow' }, // 110 { 'type': 'tableCell', 'attributes': { 'style': 'data' } }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'C', 'e', 'l', 'l', ' ', '4', { 'type': '/paragraph' }, { 'type': '/tableCell' }, // 120 { 'type': '/tableRow' }, { 'type': '/tableSection' }, { 'type': '/table' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'N', 'o', 't', ' ', 'a', 'l', // 130 'l', 'o', 'w', 'e', 'd', ' ', 'b', 'y', ' ', 'd', // 140 'm', ':', { 'type': '/paragraph' }, { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'heading', 'attributes': { 'level': 1 } }, 'T', 'i', 't', 'l', // 150 'e', ' ', 'i', 'n', ' ', 'l', 'i', 's', 't', { 'type': '/heading' }, // 160 { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'preformatted' }, 'P', 'r', 'e', 'f', 'o', 'r', 'm', // 170 'a', 't', 't', 'e', 'd', ' ', 'i', 'n', ' ', 'l', // 180 'i', 's', 't', { 'type': '/preformatted' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, { 'type': 'list', 'attributes': { 'style': 'number' } }, { 'type': 'listItem' }, // 190 { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'N', 'e', 's', 't', 'e', 'd', ' ', '1', { 'type': '/paragraph' }, // 200 { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'N', 'e', 's', 't', 'e', 'd', ' ', // 210 '2', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': 'listItem' }, { 'type': 'paragraph', 'internal': { 'generated': 'wrapper' } }, 'N', 'e', 's', 't', 'e', // 220 'd', ' ', '3', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'list', 'attributes': { 'style': 'bullet' } }, { 'type': 'listItem' }, // 230 { 'type': 'paragraph' }, 'P', '1', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'P', '2', { 'type': '/paragraph' }, { 'type': 'paragraph' }, 'P', // 240 '3', { 'type': '/paragraph' }, { 'type': '/listItem' }, { 'type': '/list' }, { 'type': 'internalList' }, { 'type': '/internalList' } // 246 ]; ve.dm.example.UnboldableNode = function ( lenght, element ) { // Parent constructor ve.dm.LeafNode.call( this, 0, element ); }; OO.inheritClass( ve.dm.example.UnboldableNode, ve.dm.LeafNode ); ve.dm.example.UnboldableNode.static.name = 'exampleUnboldable'; ve.dm.example.UnboldableNode.static.isContent = true; ve.dm.example.UnboldableNode.static.blacklistedAnnotationTypes = [ 'textStyle/bold' ]; ve.dm.example.UnboldableNode.static.matchTagNames = []; ve.dm.modelRegistry.register( ve.dm.example.UnboldableNode ); ve.dm.example.annotationData = [ { 'type': 'paragraph' }, 'F', 'o', 'o', { 'type': 'exampleUnboldable' }, { 'type': '/exampleUnboldable' }, 'B', 'a', 'r', { 'type': '/paragraph' }, { 'type': 'internalList' }, { 'type': '/internalList' } ]; ve.dm.example.selectNodesCases = [ { 'range': new ve.Range( 1 ), 'mode': 'branches', 'expected': [ // heading { 'node': [ 0 ], 'range': new ve.Range( 1 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 0, 5 ), 'parentOuterRange': new ve.Range( 0, 63 ) } ] }, { 'range': new ve.Range( 10 ), 'mode': 'branches', 'expected': [ // table/tableSection/tableRow/tableCell/paragraph { 'node': [ 1, 0, 0, 0, 0 ], 'range': new ve.Range( 10 ), 'index': 0, 'nodeRange': new ve.Range( 10, 11 ), 'nodeOuterRange': new ve.Range( 9, 12 ), 'parentOuterRange': new ve.Range( 8, 34 ) } ] }, { 'range': new ve.Range( 20 ), 'mode': 'branches', 'expected': [ // table/tableSection/tableRow/tableCell/list/listItem/list/listItem/paragraph { 'node': [ 1, 0, 0, 0, 1, 0, 1, 0, 0 ], 'range': new ve.Range( 20 ), 'index': 0, 'nodeRange': new ve.Range( 20, 21 ), 'nodeOuterRange': new ve.Range( 19, 22 ), 'parentOuterRange': new ve.Range( 18, 23 ) } ] }, { 'range': new ve.Range( 1, 20 ), 'mode': 'branches', 'expected': [ // heading { 'node': [ 0 ], 'range': new ve.Range( 1, 4 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 0, 5 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // table/tableSection/tableRow/tableCell/paragraph { 'node': [ 1, 0, 0, 0, 0 ], 'index': 0, 'nodeRange': new ve.Range( 10, 11 ), 'nodeOuterRange': new ve.Range( 9, 12 ), 'parentOuterRange': new ve.Range( 8, 34 ) }, // table/tableSection/tableRow/tableCell/list/listItem/paragraph { 'node': [ 1, 0, 0, 0, 1, 0, 0 ], 'index': 0, 'nodeRange': new ve.Range( 15, 16 ), 'nodeOuterRange': new ve.Range( 14, 17 ), 'parentOuterRange': new ve.Range( 13, 25 ) }, // table/tableSection/tableRow/tableCell/list/listItem/list/listItem/paragraph { 'node': [ 1, 0, 0, 0, 1, 0, 1, 0, 0 ], 'range': new ve.Range( 20 ), 'index': 0, 'nodeRange': new ve.Range( 20, 21 ), 'nodeOuterRange': new ve.Range( 19, 22 ), 'parentOuterRange': new ve.Range( 18, 23 ) } ] }, { 'range': new ve.Range( 1 ), 'mode': 'branches', 'expected': [ // heading { 'node': [ 0 ], 'range': new ve.Range( 1 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 0, 5 ), 'parentOuterRange': new ve.Range( 0, 63 ) } ] }, { 'range': new ve.Range( 0, 3 ), 'mode': 'leaves', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'range': new ve.Range( 1, 3 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) } ], 'msg': 'partial leaf results have ranges with global offsets' }, { 'range': new ve.Range( 0, 11 ), 'mode': 'leaves', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) }, // table/tableSection/tableRow/tableCell/paragraph/text { 'node': [ 1, 0, 0, 0, 0, 0 ], 'index': 0, 'nodeRange': new ve.Range( 10, 11 ), 'nodeOuterRange': new ve.Range( 10, 11 ), 'parentOuterRange': new ve.Range( 9, 12 ) } ], 'msg': 'leaf nodes do not have ranges, leaf nodes from different levels' }, { 'range': new ve.Range( 29, 43 ), 'mode': 'leaves', 'expected': [ // table/tableSection/tableRow/tableCell/list/listItem/paragraph/text { 'node': [ 1, 0, 0, 0, 2, 0, 0, 0 ], 'index': 0, 'nodeRange': new ve.Range( 29, 30 ), 'nodeOuterRange': new ve.Range( 29, 30 ), 'parentOuterRange': new ve.Range( 28, 31 ) }, // preformatted/text { 'node': [ 2, 0 ], 'index': 0, 'nodeRange': new ve.Range( 38, 39 ), 'nodeOuterRange': new ve.Range( 38, 39 ), 'parentOuterRange': new ve.Range( 37, 43 ) }, // preformatted/image { 'node': [ 2, 1 ], 'index': 1, 'nodeRange': new ve.Range( 40, 40 ), 'nodeOuterRange': new ve.Range( 39, 41 ), 'parentOuterRange': new ve.Range( 37, 43 ) }, // preformatted/text { 'node': [ 2, 2 ], 'index': 2, 'nodeRange': new ve.Range( 41, 42 ), 'nodeOuterRange': new ve.Range( 41, 42 ), 'parentOuterRange': new ve.Range( 37, 43 ) } ], 'msg': 'leaf nodes that are not text nodes' }, { 'range': new ve.Range( 2, 16 ), 'mode': 'siblings', 'expected': [ // heading { 'node': [ 0 ], 'range': new ve.Range( 2, 4 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 0, 5 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // table { 'node': [ 1 ], 'range': new ve.Range( 6, 16 ), 'index': 1, 'nodeRange': new ve.Range( 6, 36 ), 'nodeOuterRange': new ve.Range( 5, 37 ), 'parentOuterRange': new ve.Range( 0, 63 ) } ], 'msg': 'siblings at the document level' }, { 'range': new ve.Range( 2, 51 ), 'mode': 'siblings', 'expected': [ // heading { 'node': [ 0 ], 'range': new ve.Range( 2, 4 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 0, 5 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // table { 'node': [ 1 ], 'index': 1, 'nodeRange': new ve.Range( 6, 36 ), 'nodeOuterRange': new ve.Range( 5, 37 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // preformatted { 'node': [ 2 ], 'index': 2, 'nodeRange': new ve.Range( 38, 42 ), 'nodeOuterRange': new ve.Range( 37, 43 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // definitionList { 'node': [ 3 ], 'range': new ve.Range( 44, 51 ), 'index': 3, 'nodeRange': new ve.Range( 44, 54 ), 'nodeOuterRange': new ve.Range( 43, 55 ), 'parentOuterRange': new ve.Range( 0, 63 ) } ], 'msg': 'more than 2 siblings at the document level' }, { 'range': new ve.Range( 1, 1 ), 'mode': 'leaves', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'range': new ve.Range( 1, 1 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) } ], 'msg': 'zero-length range at the start of a text node returns text node rather than parent' }, { 'range': new ve.Range( 4, 4 ), 'mode': 'leaves', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'range': new ve.Range( 4, 4 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) } ], 'msg': 'zero-length range at the end of a text node returns text node rather than parent' }, { 'range': new ve.Range( 2, 3 ), 'mode': 'leaves', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'range': new ve.Range( 2, 3 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) } ], 'msg': 'range entirely within one leaf node' }, { 'range': new ve.Range( 5, 5 ), 'mode': 'leaves', 'expected': [ // document { 'node': [], 'range': new ve.Range( 5, 5 ), // no 'index' because documentNode has no parent 'indexInNode': 1, 'nodeRange': new ve.Range( 0, 63 ), 'nodeOuterRange': new ve.Range( 0, 63 ) } ], 'msg': 'zero-length range between two children of the document' }, { 'range': new ve.Range( 0, 0 ), 'mode': 'leaves', 'expected': [ // document { 'node': [], 'range': new ve.Range( 0, 0 ), // no 'index' because documentNode has no parent 'indexInNode': 0, 'nodeRange': new ve.Range( 0, 63 ), 'nodeOuterRange': new ve.Range( 0, 63 ) } ], 'msg': 'zero-length range at the start of the document' }, { 'range': new ve.Range( 32, 39 ), 'mode': 'leaves', 'expected': [ // table/tableSection/tableRow/tableCell/list { 'node': [ 1, 0, 0, 0, 2 ], 'range': new ve.Range( 32, 32 ), 'index': 2, 'indexInNode': 1, 'nodeRange': new ve.Range( 27, 32 ), 'nodeOuterRange': new ve.Range( 26, 33 ) }, // preformatted/text { 'node': [ 2, 0 ], // no 'range' because the text node is covered completely 'index': 0, 'nodeRange': new ve.Range( 38, 39 ), 'nodeOuterRange': new ve.Range( 38, 39 ), 'parentOuterRange': new ve.Range( 37, 43 ) } ], 'msg': 'range with 5 closings and a text node' }, { 'range': new ve.Range( 2, 57 ), 'mode': 'covered', 'expected': [ // heading/text { 'node': [ 0, 0 ], 'range': new ve.Range( 2, 4 ), 'index': 0, 'nodeRange': new ve.Range( 1, 4 ), 'nodeOuterRange': new ve.Range( 1, 4 ), 'parentOuterRange': new ve.Range( 0, 5 ) }, // table { 'node': [ 1 ], // no 'range' because the table is covered completely 'index': 1, 'nodeRange': new ve.Range( 6, 36 ), 'nodeOuterRange': new ve.Range( 5, 37 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // preformatted { 'node': [ 2 ], // no 'range' because the node is covered completely 'index': 2, 'nodeRange': new ve.Range( 38, 42 ), 'nodeOuterRange': new ve.Range( 37, 43 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // definitionList { 'node': [ 3 ], // no 'range' because the node is covered completely 'index': 3, 'nodeRange': new ve.Range( 44, 54 ), 'nodeOuterRange': new ve.Range( 43, 55 ), 'parentOuterRange': new ve.Range( 0, 63 ) }, // paragraph/text { 'node': [ 4, 0 ], // no 'range' because the text node is covered completely 'index': 0, 'nodeRange': new ve.Range( 56, 57 ), 'nodeOuterRange': new ve.Range( 56, 57 ), 'parentOuterRange': new ve.Range( 55, 58 ) } ], 'msg': 'range from the first heading into the second-to-last paragraph, in covered mode' }, { 'range': new ve.Range( 14, 14 ), 'mode': 'siblings', 'expected': [ // table/tableSection/tableRow/tableCell/list/listItem { 'node': [ 1, 0, 0, 0, 1, 0 ], 'range': new ve.Range( 14, 14 ), 'index': 0, 'indexInNode': 0, 'nodeRange': new ve.Range( 14, 24 ), 'nodeOuterRange': new ve.Range( 13, 25 ) } ], 'msg': 'zero-length range at the beginning of a listItem, in siblings mode' }, { 'range': new ve.Range( 25, 27 ), 'mode': 'covered', 'expected': [ // table/tableSection/tableRow/tableCell/list { 'node': [ 1, 0, 0, 0, 1 ], 'range': new ve.Range( 25, 25 ), 'index': 1, 'indexInNode': 1, 'nodeRange': new ve.Range( 13, 25 ), 'nodeOuterRange': new ve.Range( 12, 26 ) }, // table/tableSection/tableRow/tableCell/list { 'node': [ 1, 0, 0, 0, 2 ], 'range': new ve.Range( 27, 27 ), 'index': 2, 'indexInNode': 0, 'nodeRange': new ve.Range( 27, 32 ), 'nodeOuterRange': new ve.Range( 26, 33 ) } ], 'msg': 'range covering a list closing and a list opening' }, { 'range': new ve.Range( 39, 39 ), 'mode': 'leaves', 'expected': [ // preformatted/text { 'node': [ 2, 0 ], 'range': new ve.Range( 39, 39 ), 'index': 0, 'nodeRange': new ve.Range( 38, 39 ), 'nodeOuterRange': new ve.Range( 38, 39 ), 'parentOuterRange': new ve.Range( 37, 43 ) } ], 'msg': 'zero-length range in text node before inline node' }, { 'range': new ve.Range( 41, 41 ), 'mode': 'leaves', 'expected': [ // preformatted/text { 'node': [ 2, 2 ], 'range': new ve.Range( 41, 41 ), 'index': 2, 'nodeRange': new ve.Range( 41, 42 ), 'nodeOuterRange': new ve.Range( 41, 42 ), 'parentOuterRange': new ve.Range( 37, 43 ) } ], 'msg': 'zero-length range in text node after inline node' }, { 'doc': 'emptyBranch', 'range': new ve.Range( 1 ), 'mode': 'leaves', 'expected': [ // table { 'node': [ 0 ], 'range': new ve.Range( 1, 1 ), 'index': 0, 'indexInNode': 0, 'nodeRange': new ve.Range( 1, 1 ), 'nodeOuterRange': new ve.Range( 0, 2 ), 'parentOuterRange': new ve.Range( 0, 2 ) } ], 'msg': 'Zero-length range in empty branch node' } ];