SvgImport: Implement onError() callback

Closes #969
This commit is contained in:
Jürg Lehni 2016-02-14 14:52:37 +01:00
parent 79d446136a
commit 2025bd1a77
8 changed files with 92 additions and 67 deletions

View file

@ -525,10 +525,13 @@ Base.exports.PaperScript = (function() {
// same order the script tags appear.
// If the async attribute is specified on the script element,
// request the source asynchronously and execute as soon as
// it is retreived.
Http.request('get', src, function(code) {
execute(code, scope, src);
}, async);
// it is retrieved.
Http.request({
url: src, async: async,
onLoad: function(code) {
execute(code, scope, src);
}
});
} else {
// We can simply get the code form the script tag.
execute(script.innerHTML, scope, script.baseURI);

View file

@ -2223,7 +2223,10 @@ new function() { // Injection scope for hit-test functions shared with project
* @option options.onLoad {Function} the callback function to call once the
* SVG content is loaded from the given URL receiving two arguments: the
* converted `item` and the original `svg` data as a string. Only
* required when loading from external files.
* required when loading from external resources.
* @option options.onError {Function} the callback function to call if an
* error occurs during loading. Only required when loading from external
* resources.
* @option [options.applyMatrix={@link PaperScope#settings}.applyMatrix]
* {Boolean} whether imported items should have their transformation
* matrices applied to their contents or not

View file

@ -775,10 +775,13 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
*
* @option [options.expandShapes=false] {Boolean} whether imported shape
* items should be expanded to path items
* @option options.onLoad(item, svg) {Function} the callback function to
* call once the SVG content is loaded from the given URL receiving two
* arguments: the converted `item` and the original `svg` data as a
* string. Only required when loading from external files.
* @option options.onLoad {Function} the callback function to call once the
* SVG content is loaded from the given URL receiving two arguments: the
* converted `item` and the original `svg` data as a string. Only
* required when loading from external resources.
* @option options.onError {Function} the callback function to call if an
* error occurs during loading. Only required when loading from external
* resources.
* @option [options.applyMatrix={@link PaperScope#settings}.applyMatrix]
* {Boolean} whether imported items should have their transformation
* matrices applied to their contents or not

View file

@ -11,23 +11,32 @@
*/
var Http = {
request: function(method, url, callback, async) {
request: function(options) {
// Code borrowed from Coffee Script and extended:
async = (async === undefined) ? true : async;
var ctor = window.ActiveXObject || window.XMLHttpRequest,
xhr = new ctor('Microsoft.XMLHTTP');
xhr.open(method.toUpperCase(), url, async);
xhr.open((options.method || 'get').toUpperCase(), options.url,
Base.pick(options.async, true));
if ('overrideMimeType' in xhr)
xhr.overrideMimeType('text/plain');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var status = xhr.status;
if (status === 0 || status === 200) {
callback.call(xhr, xhr.responseText);
} else {
throw new Error('Could not load ' + url + ' (Error '
+ status + ')');
xhr.onload = function() {
var status = xhr.status;
if (status === 0 || status === 200) {
if (options.onLoad) {
options.onLoad.call(xhr, xhr.responseText);
}
} else {
xhr.onerror();
}
};
xhr.onerror = function() {
var status = xhr.status,
message = 'Could not load "' + options.url + '" (Status: '
+ status + ')';
if (options.onError) {
options.onError(message, status);
} else {
throw new Error(message);
}
};
return xhr.send(null);

View file

@ -635,7 +635,7 @@ new function() {
return item;
}
function importSVG(source, options, isRoot) {
function importSVG(source, options) {
if (!source)
return null;
options = typeof options === 'function' ? { onLoad: options }
@ -644,51 +644,65 @@ new function() {
// Remember current scope so we can restore it in onLoad.
scope = paper;
function onLoadCallback(svg) {
function onLoad(svg) {
paper = scope;
var item = importSVG(svg, options, isRoot),
var item = importSVG(svg, options, true),
onLoad = options.onLoad;
if (onLoad)
onLoad.call(this, item, svg);
}
if (isRoot) {
// Have the group not pass on all transformations to its children,
// as this is how SVG works too.
// See if it's a string but handle markup separately
if (typeof source === 'string' && !/^.*</.test(source)) {
// First see if we're meant to import an element with the given
// id.
node = document.getElementById(source);
// Check if the string does not represent SVG data, in which
// case it must be the URL of a SVG to be loaded.
if (node) {
source = null;
} else {
return Http.request('get', source, onLoadCallback);
}
} else if (typeof File !== 'undefined' && source instanceof File) {
// Load local file through FileReader
var reader = new FileReader();
reader.onload = function() {
onLoadCallback(reader.result);
};
return reader.readAsText(source);
function onError(message, status) {
var onError = options.onError;
if (onError) {
onError.call(this, message, status);
} else {
throw new Error(message);
}
}
// Have the group not pass on all transformations to its children,
// as this is how SVG works too.
// See if it's a string but handle markup separately
if (typeof source === 'string' && !/^.*</.test(source)) {
// First see if we're meant to import an element with the given
// id.
node = document.getElementById(source);
// Check if the string does not represent SVG data, in which
// case it must be the URL of a SVG to be loaded.
if (node) {
source = null;
} else {
Http.request({
url: source, async: true,
onLoad: onLoad, onError: onError
});
}
} else if (typeof File !== 'undefined' && source instanceof File) {
// Load local file through FileReader
var reader = new FileReader();
reader.onload = function() {
onLoad(reader.result);
};
reader.onerror = function() {
onError(reader.error);
};
return reader.readAsText(source);
}
if (typeof source === 'string') {
node = new window.DOMParser().parseFromString(source,
'image/svg+xml');
}
if (!node.nodeName)
throw new Error('Unsupported SVG source: ' + source);
return importNode(node, options, isRoot);
return importNode(node, options, true);
}
// NOTE: Documentation is in Item#importSVG()
Item.inject({
importSVG: function(node, options) {
return this.addChild(importSVG(node, options, true));
return this.addChild(importSVG(node, options));
}
});
@ -696,7 +710,7 @@ new function() {
Project.inject({
importSVG: function(node, options) {
this.activate();
return importSVG(node, options, true);
return importSVG(node, options);
}
});
};

View file

@ -122,31 +122,18 @@ test('Import complex CompoundPath and clone', function() {
function importSVG(assert, url, message, options) {
var done = assert.async();
if (!message)
message = 'The imported SVG "' + url + '" should visually be the same '
+ 'as the rasterized original SVG data.';
project.importSVG(url, {
onLoad: function(item, svg) {
function getValue(name) {
return parseFloat(svg.getAttribute(name));
if (!message) {
message = 'The imported SVG "' + url + '" should visually be '
+ 'the same as the rasterized original SVG data.';
}
/*
var size = new Size(getValue('width'), getValue('height'));
var group = new Group({
children: [
new Shape.Rectangle({
clipMask: true,
size: size
}),
item
]
});
*/
compareSVG(done, item, svg, message, options);
},
onError: function(error) {
// TODO: Implement in SvgImport first!
pushFailure('Loading SVG from a valid URL should not give an error.');
var ok = !!(options && options.expectError);
QUnit.push(ok, false, !ok, ok && message
|| 'Loading SVG from a valid URL should not give an error.');
done();
}
});
@ -164,4 +151,10 @@ if (!isNode) {
importSVG(assert, 'assets/' + name);
});
});
test('Import inexistent file', function(assert) {
importSVG(assert, 'assets/inexistent.svg',
'Load an inexistent SVG file should trigger an error',
{ expectError: true });
});
}