Merge "Throw ve.Error instead of string literals"

This commit is contained in:
Krinkle 2012-08-08 04:20:47 +00:00 committed by Gerrit Code Review
commit 08b349d7dd
34 changed files with 134 additions and 93 deletions

View file

@ -101,6 +101,7 @@ $wgResourceModules += array(
'scripts' => array(
// ve
've/ve.js',
've/ve.Error.js',
've/ve.EventEmitter.js',
've/init/ve.init.js',
've/init/ve.init.Platform.js',

View file

@ -57,6 +57,7 @@ $html = '<div>' . file_get_contents( $page ) . '</div>';
<script src="../../modules/jquery/jquery.json.js"></script>
<script src="../../modules/ve/ve.js"></script>
<script src="../../modules/ve/ve.debug.js"></script>
<script src="../../modules/ve/ve.Error.js"></script>
<script src="../../modules/ve/ve.EventEmitter.js"></script>
<script src="../../modules/ve/ve.Factory.js"></script>
<script src="../../modules/ve/ve.Position.js"></script>

View file

@ -157,7 +157,7 @@ ve.ce.TextNode.annotationRenderers = {
*/
ve.ce.TextNode.prototype.onUpdate = function ( force ) {
if ( !force && !this.root.getSurface ) {
throw 'Can not update a text node that is not attached to a document';
throw new ve.Error( 'Can not update a text node that is not attached to a document' );
}
if ( force === true || this.root.getSurface().render === true ) {
var $new = $( '<span>' ).html( this.getHtml() ).contents();

View file

@ -66,11 +66,11 @@ ve.ce.BranchNode.getDomWrapperType = function ( model, key ) {
var types,
value = model.getAttribute( key );
if ( value === undefined ) {
throw 'Undefined attribute: ' + key;
throw new ve.Error( 'Undefined attribute: ' + key );
}
types = ve.ce.nodeFactory.lookup( model.getType() ).domWrapperElementTypes;
if ( types[value] === undefined ) {
throw 'Invalid attribute value: ' + value;
throw new ve.Error( 'Invalid attribute value: ' + value );
}
return types[value];
};

View file

@ -30,7 +30,7 @@ ve.ce.NodeFactory.prototype.canNodeBeSplit = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.canBeSplit;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/* Inheritance */

View file

@ -75,7 +75,7 @@ ve.dm.Converter.getDataContentFromText = function ( text, annotations ) {
*/
ve.dm.Converter.prototype.onNodeRegister = function ( dataElementType, constructor ) {
if ( constructor.converters === undefined ) {
throw 'Missing conversion data in node implementation of ' + dataElementType;
throw new ve.Error( 'Missing conversion data in node implementation of ' + dataElementType );
} else if ( constructor.converters !== null ) {
var i,
domElementTypes = constructor.converters.domElementTypes,
@ -100,7 +100,7 @@ ve.dm.Converter.prototype.onNodeRegister = function ( dataElementType, construct
*/
ve.dm.Converter.prototype.onAnnotationRegister = function ( dataElementType, constructor ) {
if ( constructor.converters === undefined ) {
throw 'Missing conversion data in annotation implementation of ' + dataElementType;
throw new ve.Error( 'Missing conversion data in annotation implementation of ' + dataElementType );
} else if ( constructor.converters !== null ) {
var i,
domElementTypes = constructor.converters.domElementTypes,

View file

@ -93,7 +93,7 @@ ve.dm.Document = function ( data, parentDocument ) {
parentStack = stack[stack.length - 2];
if ( !parentStack ) {
// This can only happen if we got unbalanced data
throw 'Unbalanced input passed to document';
throw new ve.Error( 'Unbalanced input passed to document' );
}
if ( children.length === 0 &&
@ -574,7 +574,7 @@ ve.dm.Document.prototype.getAnnotatedRangeFromSelection = function ( range, anno
*/
ve.dm.Document.prototype.offsetContainsMatchingAnnotations = function ( offset, pattern ) {
if ( !( pattern instanceof RegExp ) ) {
throw 'Invalid Pattern. Pattern not instance of RegExp';
throw new ve.Error( 'Invalid Pattern. Pattern not instance of RegExp' );
}
var hash,
annotations = ve.isArray( this.data[offset] ) ?
@ -599,7 +599,7 @@ ve.dm.Document.prototype.offsetContainsMatchingAnnotations = function ( offset,
*/
ve.dm.Document.prototype.getMatchingAnnotationsFromOffset = function ( offset, pattern ) {
if ( !( pattern instanceof RegExp ) ) {
throw 'Invalid Pattern. Pattern not instance of RegExp';
throw new ve.Error( 'Invalid Pattern. Pattern not instance of RegExp' );
}
var hash,
matches = {},
@ -626,7 +626,7 @@ ve.dm.Document.prototype.getMatchingAnnotationsFromOffset = function ( offset, p
*/
ve.dm.Document.getMatchingAnnotations = function ( annotations, pattern ) {
if ( !( pattern instanceof RegExp ) ) {
throw 'Invalid Pattern. Pattern not instance of RegExp';
throw new ve.Error( 'Invalid Pattern. Pattern not instance of RegExp' );
}
var hash,
matches = {};
@ -1045,16 +1045,16 @@ ve.dm.Document.prototype.fixupInsertion = function ( data, offset ) {
closingStack.push( parentNode );
parentNode = parentNode.getParent();
if ( !parentNode ) {
throw 'Inserted data is trying to close the root node ' +
'(at index ' + index + ')';
throw new ve.Error( 'Inserted data is trying to close the root node ' +
'(at index ' + index + ')' );
}
parentType = expectedType;
// Validate
// FIXME this breaks certain input, should fix it up, not scream and die
if ( element.type !== '/' + expectedType ) {
throw 'Type mismatch, expected /' + expectedType +
' but got ' + element.type + ' (at index ' + index + ')';
throw new ve.Error( 'Type mismatch, expected /' + expectedType +
' but got ' + element.type + ' (at index ' + index + ')' );
}
}
}
@ -1112,8 +1112,8 @@ ve.dm.Document.prototype.fixupInsertion = function ( data, offset ) {
if ( !parentsOK ) {
// We can't have this as the parent
if ( allowedParents.length === 0 ) {
throw 'Cannot insert ' + childType + ' because it ' +
' cannot have a parent (at index ' + i + ')';
throw new ve.Error( 'Cannot insert ' + childType + ' because it ' +
' cannot have a parent (at index ' + i + ')' );
}
// Open an allowed node around this node
childType = allowedParents[0];
@ -1151,9 +1151,9 @@ ve.dm.Document.prototype.fixupInsertion = function ( data, offset ) {
reopenElements.push( parentNode.getClonedElement() );
parentNode = parentNode.getParent();
if ( !parentNode ) {
throw 'Cannot insert ' + childType + ' even ' +
throw new ve.Error( 'Cannot insert ' + childType + ' even ' +
' after closing all containing nodes ' +
'(at index ' + i + ')';
'(at index ' + i + ')' );
}
parentType = parentNode.getType();
}

View file

@ -268,7 +268,7 @@ ve.dm.DocumentSynchronizer.prototype.synchronize = function () {
if ( action.type in ve.dm.DocumentSynchronizer.synchronizers ) {
ve.dm.DocumentSynchronizer.synchronizers[action.type].call( this, action );
} else {
throw 'Invalid action type ' + action.type;
throw new ve.Error( 'Invalid action type ' + action.type );
}
}
// Emit events in the event queue

View file

@ -154,7 +154,7 @@ ve.dm.Node.prototype.getOuterRange = function () {
*/
ve.dm.Node.prototype.setLength = function ( length ) {
if ( length < 0 ) {
throw 'Length cannot be negative';
throw new ve.Error( 'Length cannot be negative' );
}
// Compute length adjustment from old length
var diff = length - this.length;

View file

@ -31,7 +31,7 @@ ve.dm.NodeFactory.prototype.getChildNodeTypes = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.childNodeTypes;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -46,7 +46,7 @@ ve.dm.NodeFactory.prototype.getParentNodeTypes = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.parentNodeTypes;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -64,7 +64,7 @@ ve.dm.NodeFactory.prototype.canNodeHaveChildren = function ( type ) {
var types = this.registry[type].rules.childNodeTypes;
return types === null || ( ve.isArray( types ) && types.length > 0 );
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -81,7 +81,7 @@ ve.dm.NodeFactory.prototype.canNodeHaveGrandchildren = function ( type ) {
!this.registry[type].rules.canContainContent &&
!this.registry[type].rules.isContent;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -96,7 +96,7 @@ ve.dm.NodeFactory.prototype.isNodeWrapped = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.isWrapped;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -111,7 +111,7 @@ ve.dm.NodeFactory.prototype.canNodeContainContent = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.canContainContent;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/**
@ -126,7 +126,7 @@ ve.dm.NodeFactory.prototype.isNodeContent = function ( type ) {
if ( type in this.registry ) {
return this.registry[type].rules.isContent;
}
throw 'Unknown node type: ' + type;
throw new ve.Error( 'Unknown node type: ' + type );
};
/* Inheritance */

View file

@ -82,7 +82,7 @@ ve.dm.Transaction.newFromRemoval = function ( doc, range ) {
selection = doc.selectNodes( range, 'covered' );
if ( selection.length === 0 ) {
// Empty selection? Something is wrong!
throw 'Invalid range, cannot remove from ' + range.start + ' to ' + range.end;
throw new ve.Error( 'Invalid range, cannot remove from ' + range.start + ' to ' + range.end );
}
first = selection[0];
last = selection[selection.length - 1];
@ -169,11 +169,11 @@ ve.dm.Transaction.newFromAttributeChange = function ( doc, offset, key, value )
data = doc.getData();
// Verify element exists at offset
if ( data[offset].type === undefined ) {
throw 'Can not set attributes to non-element data';
throw new ve.Error( 'Can not set attributes to non-element data' );
}
// Verify element is not a closing
if ( data[offset].type.charAt( 0 ) === '/' ) {
throw 'Can not set attributes on closing element';
throw new ve.Error( 'Can not set attributes on closing element' );
}
// Retain up to element
tx.pushRetain( offset );
@ -362,7 +362,7 @@ ve.dm.Transaction.newFromWrap = function ( doc, range, unwrapOuter, wrapOuter, u
// the range, so compensate for that
tx.pushRetain( range.start - unwrapOuter.length );
} else if ( range.start < unwrapOuter.length ) {
throw 'unwrapOuter is longer than the data preceding the range';
throw new ve.Error( 'unwrapOuter is longer than the data preceding the range' );
}
// Replace the opening elements for the outer unwrap&wrap
@ -371,8 +371,8 @@ ve.dm.Transaction.newFromWrap = function ( doc, range, unwrapOuter, wrapOuter, u
unwrapOuterData = doc.data.slice( range.start - unwrapOuter.length, range.start );
for ( i = 0; i < unwrapOuterData.length; i++ ) {
if ( unwrapOuterData[i].type !== unwrapOuter[i].type ) {
throw 'Element in unwrapOuter does not match: expected ' +
unwrapOuter[i].type + ' but found ' + unwrapOuterData[i].type;
throw new ve.Error( 'Element in unwrapOuter does not match: expected ' +
unwrapOuter[i].type + ' but found ' + unwrapOuterData[i].type );
}
}
// Instead of putting in unwrapOuter as given, put it in the
@ -397,9 +397,9 @@ ve.dm.Transaction.newFromWrap = function ( doc, range, unwrapOuter, wrapOuter, u
unwrapEachData = doc.data.slice( i, i + unwrapEach.length );
for ( j = 0; j < unwrapEachData.length; j++ ) {
if ( unwrapEachData[j].type !== unwrapEach[j].type ) {
throw 'Element in unwrapEach does not match: expected ' +
throw new ve.Error( 'Element in unwrapEach does not match: expected ' +
unwrapEach[j].type + ' but found ' +
unwrapEachData[j].type;
unwrapEachData[j].type );
}
}
// Instead of putting in unwrapEach as given, put it in the
@ -524,7 +524,7 @@ ve.dm.Transaction.prototype.translateRange = function ( range ) {
*/
ve.dm.Transaction.prototype.pushRetain = function ( length ) {
if ( length < 0 ) {
throw 'Invalid retain length, can not retain backwards:' + length;
throw new ve.Error( 'Invalid retain length, can not retain backwards:' + length );
}
if ( length ) {
var end = this.operations.length - 1;

View file

@ -115,7 +115,7 @@ ve.dm.TransactionProcessor.processors.annotate = function ( op ) {
} else if ( op.method === 'clear' ) {
target = this.reversed ? this.set : this.clear;
} else {
throw 'Invalid annotation method ' + op.method;
throw new ve.Error( 'Invalid annotation method ' + op.method );
}
hash = $.toJSON( op.annotation );
@ -150,7 +150,7 @@ ve.dm.TransactionProcessor.processors.attribute = function ( op ) {
to = this.reversed ? op.from : op.to,
from = this.reversed ? op.to : op.from;
if ( element.type === undefined ) {
throw 'Invalid element error, can not set attributes on non-element data';
throw new ve.Error( 'Invalid element error, can not set attributes on non-element data' );
}
if ( to === undefined ) {
// Clear
@ -346,7 +346,7 @@ ve.dm.TransactionProcessor.processors.replace = function ( op ) {
// Get the next operation
operation = this.nextOperation();
if ( !operation ) {
throw 'Unbalanced set of replace operations found';
throw new ve.Error( 'Unbalanced set of replace operations found' );
}
}
// From all the affected ranges we have gathered, compute a range that covers all
@ -384,7 +384,7 @@ ve.dm.TransactionProcessor.prototype.executeOperation = function ( op ) {
if ( op.type in ve.dm.TransactionProcessor.processors ) {
ve.dm.TransactionProcessor.processors[op.type].call( this, op );
} else {
throw 'Invalid operation error. Operation type is not supported: ' + op.type;
throw new ve.Error( 'Invalid operation error. Operation type is not supported: ' + op.type );
}
};
@ -426,9 +426,9 @@ ve.dm.TransactionProcessor.prototype.applyAnnotations = function ( to ) {
element = item.type !== undefined;
if ( element ) {
if ( item.type.charAt( 0 ) === '/' ) {
throw 'Invalid transaction, cannot annotate a branch closing element';
throw new ve.Error( 'Invalid transaction, cannot annotate a branch closing element' );
} else if ( ve.dm.nodeFactory.canNodeHaveChildren( item.type ) ) {
throw 'Invalid transaction, cannot annotate a branch opening element';
throw new ve.Error( 'Invalid transaction, cannot annotate a branch opening element' );
}
}
annotated = element ? 'annotations' in item : ve.isArray( item );
@ -436,13 +436,13 @@ ve.dm.TransactionProcessor.prototype.applyAnnotations = function ( to ) {
// Set and clear annotations
for ( hash in this.set ) {
if ( hash in annotations ) {
throw 'Invalid transaction, annotation to be set is already set';
throw new ve.Error( 'Invalid transaction, annotation to be set is already set' );
}
annotations[hash] = this.set[hash];
}
for ( hash in this.clear ) {
if ( !( hash in annotations ) ) {
throw 'Invalid transaction, annotation to be cleared is not set';
throw new ve.Error( 'Invalid transaction, annotation to be cleared is not set' );
}
delete annotations[hash];
}

View file

@ -28,7 +28,7 @@ ve.init.Platform = function () {
* @returns {RegExp} Regular expression object
*/
ve.init.Platform.prototype.getExternalLinkUrlProtocolsRegExp = function () {
throw 've.init.Platform.getExternalLinkUrlProtocolsRegExp must be overridden in subclass';
throw new ve.Error( 've.init.Platform.getExternalLinkUrlProtocolsRegExp must be overridden in subclass' );
};
/**
@ -39,7 +39,7 @@ ve.init.Platform.prototype.getExternalLinkUrlProtocolsRegExp = function () {
* @returns {String} Remote modules URL
*/
ve.init.Platform.prototype.getModulesUrl = function () {
throw 've.init.Platform.getModulesUrl must be overridden in subclass';
throw new ve.Error( 've.init.Platform.getModulesUrl must be overridden in subclass' );
};
/**
@ -50,7 +50,7 @@ ve.init.Platform.prototype.getModulesUrl = function () {
* @param {Object} messages Map of message-key/message-string pairs
*/
ve.init.Platform.prototype.addMessages = function ( messages ) {
throw 've.init.Platform.addMessages must be overridden in subclass';
throw new ve.Error( 've.init.Platform.addMessages must be overridden in subclass' );
};
/**
@ -63,7 +63,7 @@ ve.init.Platform.prototype.addMessages = function ( messages ) {
* @returns {String} Localized message
*/
ve.init.Platform.prototype.getMessage = function ( key ) {
throw 've.init.Platform.getMessage must be overridden in subclass';
throw new ve.Error( 've.init.Platform.getMessage must be overridden in subclass' );
};
/* Inheritance */

View file

@ -26,7 +26,7 @@ QUnit.test( 'canNodeBeSplit', 2, function ( assert ) {
assert.throws( function () {
factory.canNodeBeSplit( 'node-factory-node-stub' );
},
/^Unknown node type: node-factory-node-stub$/,
ve.Error,
'throws an exception when getting split rules for a node of an unregistered type'
);
factory.register( 'node-factory-node-stub', ve.ce.NodeFactoryNodeStub );

View file

@ -19,7 +19,7 @@ QUnit.test( 'constructor', 4, function ( assert ) {
{ 'type': 'paragraph' }
] );
},
/^Unbalanced input passed to document$/,
ve.Error,
'unbalanced input causes exception'
);

View file

@ -62,7 +62,7 @@ QUnit.test( 'setLength', 2, function ( assert ) {
// Length can not be negative
node.setLength( -1 );
},
/^Length cannot be negative$/,
ve.Error,
'throws exception if length is negative'
);
} );

View file

@ -33,7 +33,7 @@ QUnit.test( 'getChildNodeTypes', 2, function ( assert ) {
assert.throws( function () {
factory.getChildNodeTypes( 'node-factory-node-stub', 23, { 'bar': 'baz' } );
},
/^Unknown node type: node-factory-node-stub$/,
ve.Error,
'throws an exception when getting allowed child nodes of a node of an unregistered type'
);
factory.register( 'node-factory-node-stub', ve.dm.NodeFactoryNodeStub );
@ -49,7 +49,7 @@ QUnit.test( 'getParentNodeTypes', 2, function ( assert ) {
assert.throws( function () {
factory.getParentNodeTypes( 'node-factory-node-stub', 23, { 'bar': 'baz' } );
},
/^Unknown node type: node-factory-node-stub$/,
ve.Error,
'throws an exception when getting allowed parent nodes of a node of an unregistered type'
);
factory.register( 'node-factory-node-stub', ve.dm.NodeFactoryNodeStub );
@ -65,7 +65,7 @@ QUnit.test( 'canNodeHaveChildren', 2, function ( assert ) {
assert.throws( function () {
factory.canNodeHaveChildren( 'node-factory-node-stub', 23, { 'bar': 'baz' } );
},
/^Unknown node type: node-factory-node-stub$/,
ve.Error,
'throws an exception when checking if a node of an unregistered type can have children'
);
factory.register( 'node-factory-node-stub', ve.dm.NodeFactoryNodeStub );
@ -81,7 +81,7 @@ QUnit.test( 'canNodeHaveGrandchildren', 2, function ( assert ) {
assert.throws( function () {
factory.canNodeHaveGrandchildren( 'node-factory-node-stub', 23, { 'bar': 'baz' } );
},
/^Unknown node type: node-factory-node-stub$/,
ve.Error,
'throws an exception when checking if a node of an unregistered type can have grandchildren'
);
factory.register( 'node-factory-node-stub', ve.dm.NodeFactoryNodeStub );

View file

@ -471,11 +471,11 @@ QUnit.test( 'newFromAttributeChange', function ( assert ) {
},
'non-element': {
'args': [doc, 1, 'level', 2],
'exception': /^Can not set attributes to non-element data$/
'exception': ve.Error
},
'closing element': {
'args': [doc, 4, 'level', 2],
'exception': /^Can not set attributes on closing element$/
'exception': ve.Error
}
};
runConstructorTests( assert, ve.dm.Transaction.newFromAttributeChange, cases );
@ -704,15 +704,15 @@ QUnit.test( 'newFromWrap', function ( assert ) {
},
'checks integrity of unwrapOuter parameter': {
'args': [doc, new ve.Range( 13, 32 ), [ { 'type': 'table' } ], [], [], []],
'exception': /^Element in unwrapOuter does not match: expected table but found list$/
'exception': ve.Error
},
'checks integrity of unwrapEach parameter': {
'args': [doc, new ve.Range( 13, 32 ), [ { 'type': 'list' } ], [], [ { 'type': 'paragraph' } ], []],
'exception': /^Element in unwrapEach does not match: expected paragraph but found listItem$/
'exception': ve.Error
},
'checks that unwrapOuter fits before the range': {
'args': [doc, new ve.Range( 1, 4 ), [ { 'type': 'listItem' }, { 'type': 'paragraph' } ], [], [], []],
'exception': /^unwrapOuter is longer than the data preceding the range$/
'exception': ve.Error
}
};
runConstructorTests(

View file

@ -62,7 +62,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushStopAnnotating', 'invalid-method', { 'type': 'textStyle/bold' }]
],
'exception': /^Invalid annotation method/
'exception': ve.Error
},
'annotating branch opening element throws an exception': {
'calls': [
@ -70,7 +70,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushStopAnnotating', 'set', { 'type': 'textStyle/bold' }]
],
'exception': /^Invalid transaction, cannot annotate a branch opening element$/
'exception': ve.Error
},
'annotating branch closing element throws an exception': {
'calls': [
@ -79,7 +79,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushStopAnnotating', 'set', { 'type': 'textStyle/bold' }]
],
'exception': /^Invalid transaction, cannot annotate a branch closing element$/
'exception': ve.Error
},
'setting duplicate annotations throws an exception': {
'calls': [
@ -88,7 +88,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushStopAnnotating', 'set', { 'type': 'textStyle/bold' }]
],
'exception': /^Invalid transaction, annotation to be set is already set$/
'exception': ve.Error
},
'removing non-existent annotations throws an exception': {
'calls': [
@ -97,7 +97,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushStopAnnotating', 'clear', { 'type': 'textStyle/bold' }]
],
'exception': /^Invalid transaction, annotation to be cleared is not set$/
'exception': ve.Error
},
'changing, removing and adding attributes': {
'calls': [
@ -120,7 +120,7 @@ QUnit.test( 'commit/rollback', function ( assert ) {
['pushRetain', 1],
['pushReplaceElementAttribute', 'foo', 23, 42]
],
'exception': /^Invalid element error, can not set attributes on non-element data$/
'exception': ve.Error
},
'inserting text': {
'calls': [

View file

@ -15,6 +15,7 @@
<!-- Load application -->
<!-- ext.visualEditor.base -->
<script src="../ve.js"></script>
<script src="../ve.Error.js"></script>
<script src="../ve.EventEmitter.js"></script>
<script src="../init/ve.init.js"></script>
<script src="../init/ve.init.Platform.js"></script>

View file

@ -152,7 +152,7 @@ QUnit.test( 'traverseLeafNodes', 1, function ( assert ) {
{
'node': children[1],
'from': children[2],
'exception': /^from parameter passed to traverseLeafNodes\(\) must be a descendant$/,
'exception': ve.Error,
'desc': 'Passing a sibling for from results in an exception'
}
];

View file

@ -22,7 +22,7 @@ QUnit.test( 'register', 1, function ( assert ) {
function () {
factory.register( 'factory-object-stub', 'not-a-function' );
},
/^Constructor must be a function, cannot be a string$/,
ve.Error,
'throws an exception when trying to register a non-function value as a constructor'
);
} );
@ -33,7 +33,7 @@ QUnit.test( 'create', 2, function ( assert ) {
function () {
factory.create( 'factory-object-stub', 23, { 'bar': 'baz' } );
},
/^Unknown object type: factory-object-stub$/,
ve.Error,
'throws an exception when trying to create a object of an unregistered type'
);
factory.register( 'factory-object-stub', ve.FactoryObjectStub );

View file

@ -44,7 +44,7 @@ ve.ui.ButtonTool = function ( toolbar, name, title ) {
/* Methods */
ve.ui.ButtonTool.prototype.onClick = function () {
throw 'ButtonTool.onClick not implemented in this subclass:' + this.constructor;
throw new ve.Error( 'ButtonTool.onClick not implemented in this subclass:' + this.constructor );
};
ve.ui.ButtonTool.prototype.updateEnabled = function () {

View file

@ -63,7 +63,7 @@ ve.ui.DropdownTool = function ( toolbar, name, title, items ) {
/* Methods */
ve.ui.DropdownTool.prototype.onSelect = function ( item ) {
throw 'DropdownTool.onSelect not implemented in this subclass:' + this.constructor;
throw new ve.Error( 'DropdownTool.onSelect not implemented in this subclass:' + this.constructor );
};
/* Inheritance */

View file

@ -226,7 +226,7 @@ ve.ui.Context.prototype.clear = function () {
ve.ui.Context.prototype.openInspector = function ( name ) {
if ( !( name in this.inspectors ) ) {
throw 'Missing inspector error. Can not open nonexistent inspector: ' + name;
throw new ve.Error( 'Missing inspector error. Can not open nonexistent inspector: ' + name );
}
this.inspectors[name].open();
this.resizeInspectorFrame( this.inspectors[name] );
@ -251,7 +251,7 @@ ve.ui.Context.prototype.getInspector = function ( name ) {
ve.ui.Context.prototype.addInspector = function ( name, inspector ) {
if ( name in this.inspectors ) {
throw 'Duplicate inspector error. Previous registration with the same name: ' + name;
throw new ve.Error( 'Duplicate inspector error. Previous registration with the same name: ' + name );
}
inspector.$.hide();
this.inspectors[name] = inspector;
@ -276,7 +276,7 @@ ve.ui.Context.prototype.resizeInspectorFrame = function ( inspector ) {
ve.ui.Context.prototype.removeInspector = function ( name ) {
if ( name in this.inspectors ) {
throw 'Missing inspector error. Can not remove nonexistent inspector: ' + name;
throw new ve.Error( 'Missing inspector error. Can not remove nonexistent inspector: ' + name );
}
this.inspectors[name].detach();
delete this.inspectors[name];

View file

@ -68,7 +68,7 @@ ve.ui.Menu.prototype.addItem = function ( item, before ) {
// Items that don't have custom DOM elements will be auto-created
if ( !item.$ ) {
if ( !item.name ) {
throw 'Invalid menu item error. Items must have a name property.';
throw new ve.Error( 'Invalid menu item error. Items must have a name property.' );
}
if ( item.label ) {
item.$ = $( '<div class="es-menuView-item"></div>' )

View file

@ -27,7 +27,7 @@ ve.ui.Tool.tools = {};
/* Methods */
ve.ui.Tool.prototype.updateState = function () {
throw 'Tool.updateState not implemented in this subclass:' + this.constructor;
throw new ve.Error( 'Tool.updateState not implemented in this subclass:' + this.constructor );
};
ve.ui.Tool.prototype.clearState = function () {

View file

@ -202,13 +202,13 @@ ve.BranchNode.prototype.traverseLeafNodes = function ( callback, from, reverse )
if ( !p ) {
// n is a root node and we haven't reached this
// That means from isn't a descendant of this
throw 'from parameter passed to traverseLeafNodes() must be a descendant';
throw new ve.Error( 'from parameter passed to traverseLeafNodes() must be a descendant' );
}
// Find the index of n in p
i = p.indexOf( n );
if ( i === -1 ) {
// This isn't supposed to be possible
throw 'Tree corruption detected: node isn\'t in its parent\'s children array';
throw new ve.Error( 'Tree corruption detected: node isn\'t in its parent\'s children array' );
}
indexStack.push( i );
// Move up

View file

@ -85,14 +85,14 @@ ve.Document.prototype.selectNodes = function ( range, mode ) {
mode = mode || 'leaves';
if ( mode !== 'leaves' && mode !== 'covered' && mode !== 'siblings' ) {
throw 'Invalid mode: ' + mode;
throw new ve.Error( 'Invalid mode: ' + mode );
}
if ( start < 0 || start > doc.getLength() ) {
throw 'Invalid start offset: ' + start;
throw new ve.Error( 'Invalid start offset: ' + start );
}
if ( end < 0 || end > doc.getLength() ) {
throw 'Invalid end offset: ' + end;
throw new ve.Error( 'Invalid end offset: ' + end );
}
if ( !doc.children || doc.children.length === 0 ) {

38
modules/ve/ve.Error.js Normal file
View file

@ -0,0 +1,38 @@
/**
* VisualEditor Error class.
*
* @copyright 2011-2012 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
/**
* Error.
*
* @class
* @constructor
* @param {String} message Human-readable description of the error
* @param {String} fileName The name of the file containing the code that caused the exception
* @param {Number} lineNumber The line number of the code that caused the exception
*/
ve.Error = function () {
// Inheritance
Error.apply( this, arguments );
};
/* Methods */
/**
* Gets a human-readable description of the error, including the error type.
*
* @method
* @returns {String} Error type and description
*/
ve.Error.prototype.toString = function () {
return this.name + ': ' + this.message;
};
/* Inheritance */
ve.Error.prototype = new Error();
ve.Error.prototype.constructor = ve.Error;
ve.Error.prototype.name = 've.Error';

View file

@ -29,7 +29,7 @@ ve.EventEmitter = function () {
*/
ve.EventEmitter.prototype.emit = function ( type ) {
if ( type === 'error' && !( 'error' in this.events ) ) {
throw 'Missing error handler error.';
throw new ve.Error( 'Missing error handler error.' );
}
if ( !( type in this.events ) ) {
return false;
@ -55,7 +55,7 @@ ve.EventEmitter.prototype.emit = function ( type ) {
*/
ve.EventEmitter.prototype.addListener = function ( type, listener ) {
if ( typeof listener !== 'function' ) {
throw 'Invalid listener error. Function expected.';
throw new ve.Error( 'Invalid listener error. Function expected.' );
}
this.emit( 'newListener', type, listener );
if ( type in this.events ) {
@ -94,7 +94,7 @@ ve.EventEmitter.prototype.addListenerMethod = function ( target, event, method )
if ( typeof target[method] === 'function' ) {
target[method].apply( target, Array.prototype.slice.call( arguments, 0 ) );
} else {
throw 'Listener method error. Target has no such method: ' + method;
throw new ve.Error( 'Listener method error. Target has no such method: ' + method );
}
} );
};
@ -148,7 +148,7 @@ ve.EventEmitter.prototype.once = function ( type, listener ) {
*/
ve.EventEmitter.prototype.removeListener = function ( type, listener ) {
if ( typeof listener !== 'function' ) {
throw 'Invalid listener error. Function expected.';
throw new ve.Error( 'Invalid listener error. Function expected.' );
}
if ( !( type in this.events ) || !this.events[type].length ) {
return this;

View file

@ -36,7 +36,7 @@ ve.Factory = function () {
*/
ve.Factory.prototype.register = function ( type, constructor ) {
if ( typeof constructor !== 'function' ) {
throw 'Constructor must be a function, cannot be a ' + typeof constructor;
throw new ve.Error( 'Constructor must be a function, cannot be a ' + typeof constructor );
}
this.registry[type] = constructor;
this.emit( 'register', type, constructor );
@ -63,7 +63,7 @@ ve.Factory.prototype.create = function ( type, a, b ) {
if ( type in this.registry ) {
return new this.registry[type]( a, b );
}
throw 'Unknown object type: ' + type;
throw new ve.Error( 'Unknown object type: ' + type );
};
/**

View file

@ -43,7 +43,7 @@ ve.Node = function ( type ) {
* @throws {Error} if not overridden
*/
ve.Node.prototype.canHaveChildren = function () {
throw 've.Node.canHaveChildren must be overridden in subclass';
throw new ve.Error( 've.Node.canHaveChildren must be overridden in subclass' );
};
/**
@ -55,7 +55,7 @@ ve.Node.prototype.canHaveChildren = function () {
* @throws {Error} if not overridden
*/
ve.Node.prototype.canHaveGrandchildren = function () {
throw 've.Node.canHaveGrandchildren must be overridden in subclass';
throw new ve.Error( 've.Node.canHaveGrandchildren must be overridden in subclass' );
};
/**
@ -67,7 +67,7 @@ ve.Node.prototype.canHaveGrandchildren = function () {
* @throws {Error} if not overridden
*/
ve.Node.prototype.isWrapped = function () {
throw 've.Node.isWrapped must be overridden in subclass';
throw new ve.Error( 've.Node.isWrapped must be overridden in subclass' );
};
/**
@ -79,7 +79,7 @@ ve.Node.prototype.isWrapped = function () {
* @throws {Error} if not overridden
*/
ve.Node.prototype.getLength = function () {
throw 've.Node.getLength must be overridden in subclass';
throw new ve.Error( 've.Node.getLength must be overridden in subclass' );
};
/**
@ -91,7 +91,7 @@ ve.Node.prototype.getLength = function () {
* @throws {Error} if not overridden
*/
ve.Node.prototype.getOuterLength = function () {
throw 've.Node.getOuterLength must be overridden in subclass';
throw new ve.Error( 've.Node.getOuterLength must be overridden in subclass' );
};
/* Methods */

View file

@ -45,7 +45,7 @@ ve.Range.newFromTranslatedRange = function ( range, distance ) {
ve.Range.newCoveringRange = function ( ranges ) {
var minStart, maxEnd, i;
if ( !ranges || ranges.length === 0 ) {
throw 'newCoveringRange() requires at least one range';
throw new ve.Error( 'newCoveringRange() requires at least one range' );
}
minStart = ranges[0].start;
maxEnd = ranges[0].end;