Merge Pane functionality into Component.

Work in progress.
This commit is contained in:
Jürg Lehni 2014-10-04 18:58:11 +02:00
parent e46a1d24da
commit 73529f0170
5 changed files with 123 additions and 149 deletions

View file

@ -96,7 +96,7 @@ var DomElement = new function() {
for (var name in key)
if (key.hasOwnProperty(name))
DomElement.set(el, name, key[name]);
} else if (!el || value === undefined) {
} else if (!el || value == null) {
return el;
} else if (special.test(key)) {
el[key] = value;

View file

@ -118,9 +118,8 @@ var paper = new function(undefined) {
/*#*/ include('ui/MouseEvent.js');
/*#*/ if (__options.palette) {
/*#*/ include('ui/Pane.js');
/*#*/ include('ui/Palette.js');
/*#*/ include('ui/Component.js');
/*#*/ include('ui/Palette.js');
/*#*/ }
/*#*/ include('tool/ToolEvent.js');

View file

@ -78,53 +78,98 @@ var Component = Base.extend(Callback, /** @lends Component# */{
return new Color(value).toCSS(
DomElement.get(this._input, 'type') === 'color');
}
},
row: {},
column: {}
}
},
// Default values for internals
_visible: true,
_enabled: true,
initialize: function Component(pane, name, props, values, row, parent) {
initialize: function Component(parent, name, props, values, row) {
if (!name)
name = 'component-' + this._id;
var value = Base.pick(values[name], props.value);
this._id = Component._id = (Component._id || 0) + 1;
this._pane = pane;
this._parent = parent;
this._name = name;
this._row = row;
this._parent = parent; // The parent component, if any.
if (!parent || parent._type !== 'row')
DomElement.set(row, 'id', 'palettejs-row-' + name);
var type = this._type = props.type in this._types
? props.type
: 'options' in props
? 'list'
: 'onClick' in props
? 'button'
: typeof value,
: value !== undefined
? typeof value
: undefined,
meta = this._meta = this._types[type] || { type: type },
that = this,
create = DomElement.create,
element = null,
isRow = type === 'row',
isColumn = type === 'column';
if (isRow || isColumn) {
var childPane = this._childPane = new Pane(props, values, this,
isRow && row);
if (isRow) {
pane._numCells = childPane._numCells;
} else { // isColumn
element = childPane._table;
element = null;
if (!type) {
var horizontal = props.horizontal,
// On the root element, we need to create the table and row even
// if it's a horizontal layout.
table = this._table = !(horizontal && row) && DomElement.create(
'table', {
class: 'palettejs-pane' // XXX
}),
components = this._components = {},
currentRow = row,
numCells = 0;
this._numCells = 0;
for (var key in props) {
var component = props[key];
if (Base.isPlainObject(component)) {
// Create the rows for vertical elements, as well as
// horizontal root elements.
if (table && !(horizontal && currentRow)) {
currentRow = DomElement.addChildren(table, ['tr', {
class: 'palettejs-row',
id: horizontal ? null : 'palettejs-row-' + key
}])[0];
// Set _row for the horizontal root element.
if (horizontal)
this._row = currentRow;
}
components[key] = new Component(this, key, component,
values, currentRow);
numCells = Math.max(numCells, this._numCells);
// Do not reset cell counter if all components go to the
// same parent row.
if (!horizontal)
this._numCells = 0;
// Remove the entry now from the object that was provided to
// create the component since the leftovers will be injected
// into the created component through #_set() below.
delete props[key];
}
}
this._numCells = numCells;
if (horizontal && parent)
parent._numCells = numCells;
Base.each(components, function(component, key) {
if (numCells > 2 && component._cell && !horizontal)
DomElement.set(component._cell, 'colspan', numCells - 1);
// Replace each entry in values with getters/setters so we can
// directly link the value to the component and observe change.
Base.define(values, key, {
enumerable: true,
configurable: true,
get: function() {
return component.getValue();
},
set: function(val) {
component.setValue(val);
}
});
});
// Add child components directly to this component, so we can access
// it through the same path as in the components object literal that
// was passed.
Base.set(this, childPane._components);
Base.set(this, components);
element = row && table;
} else {
var that = this;
element = this._input = create(meta.tag || 'input', {
class: 'palettejs-input',
id: 'palettejs-input-' + name,
@ -152,13 +197,14 @@ var Component = Base.extend(Callback, /** @lends Component# */{
}, [ element ])
]);
// We just added two cells to the row:
pane._numCells += 2;
if (parent)
parent._numCells += 2;
}
// Attach default 'change' even that delegates to palette
// Attach default 'change' even that delegates to parent component.
this.attach('change', function(value) {
if (!this._dontFire)
pane.fire('change', this, this._name, value);
if (!this._dontFire && parent)
parent.fire('change', this, this._name, value);
});
this._dontFire = true;
// Now that everything is set up, copy over values fro, props.
@ -171,8 +217,6 @@ var Component = Base.extend(Callback, /** @lends Component# */{
this.setValue(value);
// Start firing change events after we have initialized.
this._dontFire = false;
// Store link to component in the pane's components object.
pane._components[name] = this;
values[name] = this._defaultValue = this._value;
},
@ -229,7 +273,7 @@ var Component = Base.extend(Callback, /** @lends Component# */{
},
setValue: function(value) {
if (this._childPane)
if (this._components)
return;
var meta = this._meta,
key = meta.value || 'value',
@ -264,19 +308,20 @@ var Component = Base.extend(Callback, /** @lends Component# */{
return this._enabled;
},
setEnabled: function(enabled, _fromPalette) {
if (_fromPalette) {
// When called from Palette#setEnabled, we have to remember the
setEnabled: function(enabled, _fromParent) {
if (_fromParent) {
// When called from the parent component, we have to remember the
// component's previous enabled state when disabling the palette,
// so we can restore it when enabling the palette again.
var prev = Base.pick(this._previousEnabled, this._enabled);
this._previousEnabled = enabled ? undefined : prev; // clear
enabled = enabled && prev;
}
if (this._input) {
if (this._components) {
for (var i in this._components)
this._components[i].setEnabled(enabled, true);
} else {
DomElement.set(this._input, 'disabled', !enabled);
} else if (this._childPane) {
this._childPane.setEnabled(enabled);
}
this._enabled = !!enabled;
},
@ -316,8 +361,9 @@ var Component = Base.extend(Callback, /** @lends Component# */{
},
reset: function() {
if (this._childPane) {
this._childPane.reset();
if (this._components) {
for (var i in this._components)
this._components[i].reset();
} else {
this.setValue(this._defaultValue);
}

View file

@ -13,9 +13,8 @@
/**
* @name Palette
* @class
* @extends Pane
*/
/* var Palette = */ Pane.extend(/** @lends Palette# */{
/* var Palette = */ Base.extend(/** @lends Palette# */{
_class: 'Palette',
// DOCS: Palette#initialize(props)
@ -33,13 +32,24 @@
values = props.values;
}
this._title = title;
Pane.call(this, components, values);
this._values = values;
this._components = components;
// Create one root component that handles the layout and contains all
// the components.
var root = this._root = new Component(null, 'root', components, values),
that = this;
root.attach('change', function(value) {
that.fire('change', this, this._name, value);
});
// Write the created components back into the passed components object,
// so they are exposed and can easily be accessed from the outside.
Base.set(components, root._components);
var parent = DomElement.find('.palettejs-panel')
|| DomElement.find('body').appendChild(
DomElement.create('div', { class: 'palettejs-panel' }));
this._element = parent.appendChild(
DomElement.create('div', { class: 'palettejs-palette' },
[this._table]));
[root._table]));
if (props)
this._set(props, { title: true, components: true, values: true });
// Link to the current scope's palettes list.
@ -48,6 +58,30 @@
(this._palettes = paper.palettes).push(this);
},
getComponents: function() {
return this._components;
},
getValues: function() {
return this._values;
},
getEnabled: function() {
return this._root.getEnabled();
},
setEnabled: function(enabled) {
return this._root.setEnabled(enabled);
},
/**
* Resets the values of the components to their
* {@link Component#defaultValue}.
*/
reset: function() {
this._root.reset();
},
remove: function() {
DomElement.remove(this._element);
var palettes = this._palettes;

View file

@ -1,105 +0,0 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
* http://scratchdisk.com/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
/**
* @name Pane
* @class
*/
var Pane = Base.extend(Callback, /** @lends Pane# */{
_class: 'Pane',
_events: [ 'onChange' ],
// Defaults for internals
_enabled: true,
initialize: function Pane(components, values, parent, parentRow) {
if (!values)
values = {};
this._table = !parentRow && DomElement.create('table', {
class: 'palettejs-pane'
});
// NOTE: We modify the actual passed components in the root pane, and
// also the values objects, so the newly created components and their
// values can easily be referenced from outside.
var comps = this._components = parent ? {} : components;
this._values = values;
var numCells = 0;
this._numCells = 0;
for (var name in components) {
var component = components[name];
if (Base.isPlainObject(component)) {
var row = parentRow || DomElement.addChildren(this._table,
['tr', { class: 'palettejs-row' }])[0];
new Component(this, name, component, values, row, parent);
numCells = Math.max(numCells, this._numCells);
// Do not reset cell counter if all components go to the same
// parent row.
if (!parentRow)
this._numCells = 0;
if (parent) {
// If this is a child pane, remove the entry now from the
// object that was provided to create it, since the left
// overs will be injected into the parent component through
// #_set()
delete components[name];
}
}
}
this._numCells = numCells;
Base.each(comps, function(component, name) {
// Update colspan in all components that are not nested in another
// component.
if (numCells > 2 && component._cell
&& (!parent || parent._type === 'column')) {
DomElement.set(component._cell, 'colspan', numCells - 1);
}
// Now replace each entry in values with a getter / setters so we
// can directly link the value to the component and observe change.
Base.define(values, name, {
enumerable: true,
configurable: true,
get: function() {
return component.getValue();
},
set: function(val) {
component.setValue(val);
}
});
});
},
getComponents: function() {
return this._components;
},
getValues: function() {
return this._values;
},
getEnabled: function() {
return this._enabled;
},
setEnabled: function(enabled) {
this._enabled = enabled;
for (var i in this._components)
this._components[i].setEnabled(enabled, true);
},
/**
* Resets the values of the components to their
* {@link Component#defaultValue}.
*/
reset: function() {
for (var i in this._components)
this._components[i].reset();
}
});