mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-25 06:46:26 +00:00
Array.prototype.splice polyfill for Opera
Apparently they can't get their basic ECMAScript right. In 2013. It doesn't come up that often, because you don't splice an array with more than 256 elements every day. Only implemented in ve.batchSplice for now, as that function does handle thousands of elements routinely. Other callers of .splice() can simply use that instead. Bug: 50385 Change-Id: I281a61d55c6f7df5f28627a1df80f2a001110607
This commit is contained in:
parent
330c39215c
commit
a01b92dcc4
|
@ -360,36 +360,80 @@
|
|||
* performance tests should be conducted on each use of this method to verify this is true for the
|
||||
* particular use. Also, browsers change fast, never assume anything, always test everything.
|
||||
*
|
||||
* @param {Array} arr Array to remove from and insert into. Will be modified
|
||||
* Includes a replacement for broken implementation of Array.prototype.splice() found in Opera 12.
|
||||
*
|
||||
* @param {Array|ve.dm.BranchNode} arr Object supporting .splice() to remove from and insert into. Will be modified
|
||||
* @param {number} offset Offset in arr to splice at. This may NOT be negative, unlike the
|
||||
* 'index' parameter in Array#splice
|
||||
* @param {number} remove Number of elements to remove at the offset. May be zero
|
||||
* @param {Array} data Array of items to insert at the offset. May not be empty if remove=0
|
||||
* @returns {Array} Array of items removed
|
||||
*/
|
||||
ve.batchSplice = function ( arr, offset, remove, data ) {
|
||||
// We need to splice insertion in in batches, because of parameter list length limits which vary
|
||||
// cross-browser - 1024 seems to be a safe batch size on all browsers
|
||||
var index = 0, batchSize = 1024, toRemove = remove, spliced, removed = [];
|
||||
if ( data.length === 0 ) {
|
||||
// Special case: data is empty, so we're just doing a removal
|
||||
// The code below won't handle that properly, so we do it here
|
||||
return arr.splice( offset, remove );
|
||||
ve.batchSplice = ( function () {
|
||||
var arraySplice;
|
||||
|
||||
// This yields 'true' on Opera 12.15.
|
||||
function isSpliceBroken() {
|
||||
var n = 256, a = [];
|
||||
a[n] = 'a';
|
||||
|
||||
a.splice( n + 1, 0, 'b' );
|
||||
|
||||
return a[n] !== 'a';
|
||||
}
|
||||
while ( index < data.length ) {
|
||||
// Call arr.splice( offset, remove, i0, i1, i2, ..., i1023 );
|
||||
// Only set remove on the first call, and set it to zero on subsequent calls
|
||||
spliced = arr.splice.apply(
|
||||
arr, [index + offset, toRemove].concat( data.slice( index, index + batchSize ) )
|
||||
);
|
||||
if ( toRemove > 0 ) {
|
||||
removed = spliced;
|
||||
|
||||
if ( !isSpliceBroken() ) {
|
||||
arraySplice = Array.prototype.splice;
|
||||
} else {
|
||||
// Standard Array.prototype.splice() function implemented using .slice() and .push().
|
||||
arraySplice = function ( offset, remove/*, data... */ ) {
|
||||
var data, begin, removed, end;
|
||||
|
||||
data = Array.prototype.slice.call( arguments, 2 );
|
||||
|
||||
begin = this.slice( 0, offset );
|
||||
removed = this.slice( offset, remove );
|
||||
end = this.slice( offset + remove );
|
||||
|
||||
this.length = 0;
|
||||
// This polyfill only been discovered to be necessary on Opera
|
||||
// and it seems to handle up to 1048575 function parameters.
|
||||
this.push.apply( this, begin );
|
||||
this.push.apply( this, data );
|
||||
this.push.apply( this, end );
|
||||
|
||||
return removed;
|
||||
};
|
||||
}
|
||||
|
||||
return function ( arr, offset, remove, data ) {
|
||||
// We need to splice insertion in in batches, because of parameter list length limits which vary
|
||||
// cross-browser - 1024 seems to be a safe batch size on all browsers
|
||||
var splice, index = 0, batchSize = 1024, toRemove = remove, spliced, removed = [];
|
||||
|
||||
splice = ve.isArray( arr ) ? arraySplice : arr.splice;
|
||||
|
||||
if ( data.length === 0 ) {
|
||||
// Special case: data is empty, so we're just doing a removal
|
||||
// The code below won't handle that properly, so we do it here
|
||||
return splice.call( arr, offset, remove );
|
||||
}
|
||||
index += batchSize;
|
||||
toRemove = 0;
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
while ( index < data.length ) {
|
||||
// Call arr.splice( offset, remove, i0, i1, i2, ..., i1023 );
|
||||
// Only set remove on the first call, and set it to zero on subsequent calls
|
||||
spliced = splice.apply(
|
||||
arr, [index + offset, toRemove].concat( data.slice( index, index + batchSize ) )
|
||||
);
|
||||
if ( toRemove > 0 ) {
|
||||
removed = spliced;
|
||||
}
|
||||
index += batchSize;
|
||||
toRemove = 0;
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
}() );
|
||||
|
||||
/**
|
||||
* Insert one array into another.
|
||||
|
|
Loading…
Reference in a new issue