Fix Item#importJSON() to preserve #parent on existing, already inserted items.

Closes #1041
This commit is contained in:
Jürg Lehni 2016-06-10 17:45:02 +02:00
parent e7f7d7c5d1
commit ed3e283802
5 changed files with 33 additions and 20 deletions

View file

@ -35,12 +35,11 @@ contribute to the code.
### Changed ### Changed
- Significant overhaul and improvements of boolean path operations - Significant overhaul and improvements of boolean path operations
`PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()` `PathItem#unite()`, `#subtract()`, `#intersect()`, `#exclude()`, `#divide()`:
(#936):
- Improve handling of self-intersecting paths and non-zero fill-rules. - Improve handling of self-intersecting paths and non-zero fill-rules.
- Handle operations on identical paths. - Handle operations on identical paths.
- Improve handling of near-collinear lines. - Improve handling of near-collinear lines.
- Better handle self-intersecting paths that merely "touch" themselves. - Handle self-intersecting paths that merely "touch" themselves.
- Handle situations where all encountered intersections are part of overlaps. - Handle situations where all encountered intersections are part of overlaps.
- Methods that accepted a `time` parameter or boolean second parameter causing - Methods that accepted a `time` parameter or boolean second parameter causing
the argument to be interpreted as curve-time instead of offset are now the argument to be interpreted as curve-time instead of offset are now
@ -196,8 +195,6 @@ contribute to the code.
(#453). (#453).
- Don't block touch actions when using paper in JavaScript mode (#686). - Don't block touch actions when using paper in JavaScript mode (#686).
- Convert touch event coordinates to project coordinates (#633). - Convert touch event coordinates to project coordinates (#633).
- Fix problems with group selection structures after `group#importJSON()`
(#785).
- Fix exceptions when a top-level layer is selected. - Fix exceptions when a top-level layer is selected.
- Don't allow layers to turn up in hit-tests (#608). - Don't allow layers to turn up in hit-tests (#608).
- Maintain `Raster#source` correctly on Node.js (#914). - Maintain `Raster#source` correctly on Node.js (#914).
@ -207,7 +204,6 @@ contribute to the code.
when it is a child items array of a `CompoundPath`. when it is a child items array of a `CompoundPath`.
- Correctly handle `#strokeScaling` in `Shape` hit-tests (#697). - Correctly handle `#strokeScaling` in `Shape` hit-tests (#697).
- Support clip-masks in hit-testing (#671). - Support clip-masks in hit-testing (#671).
- `#importJSON()` no longer generates callstack exceeded exceptions (#764).
- Fix incorrect `#hitTest()` and `#contains()` cases (#819, #884). - Fix incorrect `#hitTest()` and `#contains()` cases (#819, #884).
- Update documentation to note appropriate use for `#simplify()` (#920). - Update documentation to note appropriate use for `#simplify()` (#920).
- `#importSVG()` now supports percentage dimensions and - `#importSVG()` now supports percentage dimensions and
@ -226,6 +222,11 @@ contribute to the code.
- `#importJSON()` and `#exportJSON()` now handle non-`Item` objects correctly - `#importJSON()` and `#exportJSON()` now handle non-`Item` objects correctly
(#392). (#392).
- `#exportSVG()` now exports empty paths if used as a clip-mask. - `#exportSVG()` now exports empty paths if used as a clip-mask.
- `#importJSON()` no longer generates callstack exceeded exceptions (#764).
- Fix problems with group selection structures after `Group#importJSON()`
(#785).
- Fix an issue in `Item#importJSON()` where `#parent` is `null` when calling it
on existing, already inserted items (#1041).
- Correct issue when using paper-core in Node.js (#975). - Correct issue when using paper-core in Node.js (#975).
- Fix `event.delta` on mousedrag events (#981). - Fix `event.delta` on mousedrag events (#981).
- Improve handling of XML attribute namespaces for IE's XMLSerializer() (#984). - Improve handling of XML attribute namespaces for IE's XMLSerializer() (#984).

View file

@ -502,13 +502,7 @@ Base.inject(/** @lends Base# */{
var useTarget = isRoot && target var useTarget = isRoot && target
&& target.constructor === ctor, && target.constructor === ctor,
obj = useTarget ? target obj = useTarget ? target
: Base.create(ctor.prototype), : Base.create(ctor.prototype);
// When reusing an object, try to (re)initialize it
// through _initialize (Item), fall-back to
// initialize (Color & co), then _set.
init = useTarget
? obj._initialize || obj.initialize || obj._set
: ctor;
// NOTE: We don't set insert false for layers since we // NOTE: We don't set insert false for layers since we
// want these to be created on the fly in the active // want these to be created on the fly in the active
// project into which we're importing (except for if // project into which we're importing (except for if
@ -519,7 +513,9 @@ Base.inject(/** @lends Base# */{
if (Base.isPlainObject(arg)) if (Base.isPlainObject(arg))
arg.insert = false; arg.insert = false;
} }
init.apply(obj, args); // When reusing an object, initialize it through #_set()
// instead of the constructor function:
(useTarget ? obj._set : ctor).apply(obj, args);
// Clear target to only use it once. // Clear target to only use it once.
if (useTarget) if (useTarget)
target = null; target = null;

View file

@ -1044,9 +1044,9 @@ Path.inject(/** @lends Path# */{
intercepts = []; intercepts = [];
for (var i = 0, l = curves.length; i < l; i++) { for (var i = 0, l = curves.length; i < l; i++) {
var values = curves[i].values; var values = curves[i].values;
if ((curves[i].winding === 1 if (curves[i].winding === 1
&& y > values[1] && y <= values[7] && y > values[1] && y <= values[7]
|| y >= values[7] && y < values[1])) { || y >= values[7] && y < values[1]) {
var count = Curve.solveCubic(values, 1, y, roots, 0, 1); var count = Curve.solveCubic(values, 1, y, roots, 0, 1);
for (var j = count - 1; j >= 0; j--) { for (var j = count - 1; j >= 0; j--) {
intercepts.push(Curve.getPoint(values, roots[j]).x); intercepts.push(Curve.getPoint(values, roots[j]).x);

View file

@ -485,6 +485,7 @@ var Color = Base.extend(new function() {
// We are storing color internally as an array of components // We are storing color internally as an array of components
var slice = Array.prototype.slice, var slice = Array.prototype.slice,
args = arguments, args = arguments,
reading = this.__read,
read = 0, read = 0,
type, type,
components, components,
@ -508,7 +509,7 @@ var Color = Base.extend(new function() {
alpha = args[2]; alpha = args[2];
} else { } else {
// For deserialization, shift out and process normally. // For deserialization, shift out and process normally.
if (this.__read) if (reading)
read = 1; // Will be increased below read = 1; // Will be increased below
// Shift type out of the arguments, and process normally. // Shift type out of the arguments, and process normally.
args = slice.call(args, 1); args = slice.call(args, 1);
@ -536,10 +537,11 @@ var Color = Base.extend(new function() {
: 'gray'; : 'gray';
var length = types[type].length; var length = types[type].length;
alpha = values[length]; alpha = values[length];
if (this.__read) if (reading) {
read += values === arguments read += values === arguments
? length + (alpha != null ? 1 : 0) ? length + (alpha != null ? 1 : 0)
: 1; : 1;
}
if (values.length > length) if (values.length > length)
values = slice.call(values, 0, length); values = slice.call(values, 0, length);
} else if (argType === 'string') { } else if (argType === 'string') {
@ -601,7 +603,7 @@ var Color = Base.extend(new function() {
alpha = arg.alpha; alpha = arg.alpha;
} }
} }
if (this.__read && type) if (reading && type)
read = 1; read = 1;
} }
// Default fallbacks: rgb, black // Default fallbacks: rgb, black
@ -621,10 +623,13 @@ var Color = Base.extend(new function() {
this._components = components; this._components = components;
this._properties = types[this._type]; this._properties = types[this._type];
this._alpha = alpha; this._alpha = alpha;
if (this.__read) if (reading)
this.__read = read; this.__read = read;
}, },
// Have #_set point to #initialize, as used by Base.importJSON()
_set: '#initialize',
_serialize: function(options, dictionary) { _serialize: function(options, dictionary) {
var components = this.getComponents(); var components = this.getComponents();
return Base.serialize( return Base.serialize(

View file

@ -245,3 +245,14 @@ test('Color#importJSON()', function() {
return color.equals(path.fillColor); return color.equals(path.fillColor);
}, true); }, true);
}); });
test('Path#importJSON()', function() {
var path = new Path();
var layer = project.activeLayer;
equals(function() { return path.parent === layer; }, true);
path.importJSON('["Path",{"segments":[[[50,100],[0,27.61424],[0,-27.61424]],[[100,50],[-27.61424,0],[27.61424,0]],[[150,100],[0,-27.61424],[0,27.61424]],[[100,150],[27.61424,0],[-27.61424,0]]],"closed":true,"fillColor":[1,0,0]}]');
equals(function() { return path.bounds; }, { x: 50, y: 50, width: 100, height: 100 });
equals(function() { return path.fillColor; }, { red: 1, green: 0, blue: 0 });
equals(function() { return layer.firstChild === path; }, true);
equals(function() { return path.parent === layer; }, true);
});