Implement a new strategy for importing JSON, where it is imported into the item itself, not its children list, if the class match.

This commit is contained in:
Jürg Lehni 2013-11-01 11:26:11 +01:00
parent 70ae7486e9
commit c76dae5b06
2 changed files with 40 additions and 28 deletions

View file

@ -390,46 +390,51 @@ Base.inject(/** @lends Base# */{
* deserializable types through Base.exports, and the values following * deserializable types through Base.exports, and the values following
* in the array are the arguments to their initialize function. * in the array are the arguments to their initialize function.
* Any other value is passed on unmodified. * Any other value is passed on unmodified.
* The passed data is recoursively traversed and converted, leaves first * The passed json data is recoursively traversed and converted, leaves
* first
*/ */
deserialize: function(obj, data) { deserialize: function(json, target, _data) {
var res = obj; var res = json;
// A data side-car to deserialize that can hold any kind of 'global' // A _data side-car to deserialize that can hold any kind of
// data across a deserialization. It's currently just used to hold // 'global' data across a deserialization. It's currently only used
// dictionary definitions. // to hold dictionary definitions.
data = data || {}; _data = _data || {};
if (Array.isArray(obj)) { if (Array.isArray(json)) {
// See if it's a serialized type. If so, the rest of the array // See if it's a serialized type. If so, the rest of the array
// are the arguments to #initialize(). Either way, we simply // are the arguments to #initialize(). Either way, we simply
// deserialize all elements of the array. // deserialize all elements of the array.
var type = obj[0], var type = json[0],
// Handle stored dictionary specially, since we need to // Handle stored dictionary specially, since we need to
// keep is a lookup table to retrieve referenced items from. // keep is a lookup table to retrieve referenced items from.
isDictionary = type === 'dictionary'; isDictionary = type === 'dictionary';
if (!isDictionary) { if (!isDictionary) {
// First see if this is perhaps a dictionary reference, and // First see if this is perhaps a dictionary reference, and
// if so return its definition instead. // if so return its definition instead.
if (data.dictionary && obj.length == 1 && /^#/.test(type)) if (_data.dictionary && json.length == 1 && /^#/.test(type))
return data.dictionary[type]; return _data.dictionary[type];
type = Base.exports[type]; type = Base.exports[type];
} }
res = []; res = [];
// Skip first type entry for arguments // Skip first type entry for arguments
for (var i = type ? 1 : 0, l = obj.length; i < l; i++) for (var i = type ? 1 : 0, l = json.length; i < l; i++)
res.push(Base.deserialize(obj[i], data)); res.push(Base.deserialize(json[i], null, _data));
if (isDictionary) { if (isDictionary) {
data.dictionary = res[0]; _data.dictionary = res[0];
} else if (type) { } else if (type) {
// Create serialized type and pass collected arguments to // Create serialized type and pass collected arguments to
// constructor(). // constructor().
var args = res; var args = res;
res = Base.create(type.prototype); // If a target is provided and its of the right type,
// import right into it.
res = target instanceof type
? target
: Base.create(type.prototype);
type.apply(res, args); type.apply(res, args);
} }
} else if (Base.isPlainObject(obj)) { } else if (Base.isPlainObject(json)) {
res = {}; res = {};
for (var key in obj) for (var key in json)
res[key] = Base.deserialize(obj[key], data); res[key] = Base.deserialize(json[key], null, _data);
} }
return res; return res;
}, },
@ -438,9 +443,9 @@ Base.inject(/** @lends Base# */{
return JSON.stringify(Base.serialize(obj, options)); return JSON.stringify(Base.serialize(obj, options));
}, },
importJSON: function(json) { importJSON: function(json, target) {
return Base.deserialize( return Base.deserialize(
typeof json === 'string' ? JSON.parse(json) : json); typeof json === 'string' ? JSON.parse(json) : json, target);
}, },
/** /**

View file

@ -1306,9 +1306,9 @@ var Item = Base.extend(Callback, /** @lends Item# */{
// Insert is true by default. // Insert is true by default.
if (insert || insert === undefined) if (insert || insert === undefined)
copy.insertAbove(this); copy.insertAbove(this);
// Only copy over these fields if they are actually defined in 'this' // Only copy over these fields if they are actually defined in 'this',
// TODO: Consider moving this to Base once it's useful in more than one // meaning the default value has been overwritten (default is on
// place // prototype).
var keys = ['_locked', '_visible', '_blendMode', '_opacity', var keys = ['_locked', '_visible', '_blendMode', '_opacity',
'_clipMask', '_guide']; '_clipMask', '_guide'];
for (var i = 0, l = keys.length; i < l; i++) { for (var i = 0, l = keys.length; i < l; i++) {
@ -1649,15 +1649,22 @@ var Item = Base.extend(Callback, /** @lends Item# */{
*/ */
/** /**
* Imports (deserializes) the stored JSON data into this item's * Imports (deserializes) the stored JSON data into this item. If the data
* {@link Item#children} list. * describes an item of the same class or a parent class of the item, the
* Note that the item is not cleared first. You can call * data is imported into the item itself. If not, the imported item is added
* {@link Item#removeChildren()} to do so. * to this item's {@link Item#children} list. Note that not all type of
* items can have children.
* *
* @param {String} json the JSON data to import from. * @param {String} json the JSON data to import from.
*/ */
importJSON: function(json) { importJSON: function(json) {
return this.addChild(Base.importJSON(json)); // Try importing into `this`. If another item is returned, try adding
// it as a child (this won't be successful on some classes, returning
// null).
var res = Base.importJSON(json, this);
return res !== this
? this.addChild(res)
: res;
}, },
/** /**