all files / src/dm/ ve.dm.MetaList.js

86.21% Statements 50/58
61.11% Branches 11/18
66.67% Functions 8/12
86.21% Lines 50/58
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192                              439×       439×   439× 439×     439×   439×           439× 7920× 75× 75×                                                     1074×   1074× 20× 52×   20× 20× 20×                 1135× 1135× 18× 18× 18× 18× 18×                                                                                                                                                              
/*!
 * VisualEditor DataModel MetaList class.
 *
 * @copyright 2011-2019 VisualEditor Team and others; see http://ve.mit-license.org
 */
 
/**
 * DataModel meta item.
 *
 * @class
 * @mixins OO.EventEmitter
 *
 * @constructor
 * @param {ve.dm.Surface} surface Surface model
 */
ve.dm.MetaList = function VeDmMetaList( surface ) {
	var items,
		metaList = this;
 
	// Mixin constructors
	OO.EventEmitter.call( this );
 
	this.surface = surface;
	this.document = surface.getDocument();
 
	// Sorted array of attached ve.dm.MetaItem nodes in document order
	this.items = items = [];
 
	this.document.connect( this, {
		nodeAttached: 'onNodeAttached',
		nodeDetached: 'onNodeDetached'
	} );
 
	// Add any ve.dm.MetaItem nodes already present in the document
	this.document.documentNode.traverse( function ( node ) {
		if ( node instanceof ve.dm.MetaItem ) {
			items.push( node );
			node.attachToMetaList( metaList );
		}
	} );
};
 
/* Inheritance */
 
OO.mixinClass( ve.dm.MetaList, OO.EventEmitter );
 
/* Events */
 
/**
 * @event insert
 * @param {ve.dm.MetaItem} item Item that was inserted
 */
 
/**
 * @event remove
 * @param {ve.dm.MetaItem} item Item that was removed
 */
 
/* Methods */
 
/**
 * If a ve.dm.MetaItem was attached, insert it into items in document order
 *
 * @param {ve.dm.Node} node The node that was attached
 */
ve.dm.MetaList.prototype.onNodeAttached = function ( node ) {
	var i,
		offsetPath = node.getOffsetPath();
	if ( node instanceof ve.dm.MetaItem ) {
		i = OO.binarySearch( this.items, function searchFunc( other ) {
			return ve.compareTuples( offsetPath, other.getOffsetPath() );
		}, true );
		this.items.splice( i, 0, node );
		node.attachToMetaList( this );
		this.emit( 'insert', node );
	}
};
 
/**
 * If a ve.dm.MetaItem was detached, remove it from items
 *
 * @param {ve.dm.Node} node The node that was detached
 */
ve.dm.MetaList.prototype.onNodeDetached = function ( node ) {
	var i;
	if ( node instanceof ve.dm.MetaItem ) {
		i = this.items.indexOf( node );
		Eif ( i !== -1 ) {
			node.detachFromMetaList( this );
			this.items.splice( i, 1 );
			this.emit( 'remove', node );
		}
	}
};
 
ve.dm.MetaList.prototype.indexOf = function ( item, group ) {
	var items = group ? this.getItemsInGroup( group ) : this.items;
	return items.indexOf( item );
};
 
/**
 * Get all items in a group.
 *
 * This function returns a shallow copy, so the array isn't returned by reference but the items
 * themselves are.
 *
 * @param {string} group Group
 * @return {ve.dm.MetaItem[]} Array of items in the group (shallow copy)
 */
ve.dm.MetaList.prototype.getItemsInGroup = function ( group ) {
	return this.items.filter( function ( item ) {
		return item.getGroup() === group;
	} );
};
 
/**
 * Get all items in the list.
 *
 * This function returns a shallow copy, so the array isn't returned by reference but the items
 * themselves are.
 *
 * @return {ve.dm.MetaItem[]} Array of items in the list
 */
ve.dm.MetaList.prototype.getAllItems = function () {
	return this.items.slice( 0 );
};
 
/**
 * Insert new metadata into the document. This builds and processes a transaction that inserts
 * metadata into the document.
 *
 * Pass a plain object rather than a MetaItem into this function unless you know what you're doing.
 *
 * @param {Object|ve.dm.MetaItem} meta Metadata element (or MetaItem) to insert
 * @param {number} offset Document offset to insert at; must be a valid offset for metadata;
 * defaults to document end
 */
ve.dm.MetaList.prototype.insertMeta = function ( meta, offset ) {
	var closeMeta, tx;
	Iif ( arguments[ 2 ] !== undefined ) {
		throw new Error( 'Old "index" argument is no longer supported' );
	}
	Iif ( meta instanceof ve.dm.MetaItem ) {
		meta = meta.getElement();
	}
	closeMeta = { type: '/' + meta.type };
	Eif ( offset === undefined ) {
		offset = this.document.getDocumentRange().end;
	}
	tx = ve.dm.TransactionBuilder.static.newFromInsertion( this.document, offset, [ meta, closeMeta ] );
	this.surface.change( tx );
};
 
/**
 * Remove a meta item from the document. This builds and processes a transaction that removes the
 * associated metadata from the document.
 *
 * @param {ve.dm.MetaItem} item Item to remove
 */
ve.dm.MetaList.prototype.removeMeta = function ( item ) {
	var tx;
	tx = ve.dm.TransactionBuilder.static.newFromRemoval(
		this.document,
		item.getOuterRange(),
		true
	);
	this.surface.change( tx );
};
 
/**
 * Replace a MetaItem with another in-place.
 *
 * Pass a plain object rather than a MetaItem into this function unless you know what you're doing.
 *
 * @param {ve.dm.MetaItem} oldItem Old item to replace
 * @param {Object|ve.dm.MetaItem} meta Metadata element (or MetaItem) to insert
 */
ve.dm.MetaList.prototype.replaceMeta = function ( oldItem, meta ) {
	var closeMeta, tx;
	Iif ( meta instanceof ve.dm.MetaItem ) {
		meta = meta.getElement();
	}
	closeMeta = { type: '/' + meta.type };
	tx = ve.dm.TransactionBuilder.static.newFromReplacement(
		this.document,
		oldItem.getOuterRange(),
		[ meta, closeMeta ],
		true
	);
	this.surface.change( tx );
};