[Code Style] Use prototypes in Layout bundle

WTD-1482
This commit is contained in:
Victor Woeltjen 2015-08-12 13:45:48 -07:00
parent a9e2d48036
commit ed53808556
15 changed files with 615 additions and 596 deletions

View File

@ -39,20 +39,16 @@ define(
* @param {Scope} $scope the controller's Angular scope * @param {Scope} $scope the controller's Angular scope
*/ */
function FixedController($scope, $q, dialogService, telemetrySubscriber, telemetryFormatter) { function FixedController($scope, $q, dialogService, telemetrySubscriber, telemetryFormatter) {
var gridSize = DEFAULT_GRID_SIZE, var self = this,
dragging,
subscription, subscription,
elementProxies = [],
names = {}, // Cache names by ID names = {}, // Cache names by ID
values = {}, // Cache values by ID values = {}, // Cache values by ID
elementProxiesById = {}, elementProxiesById = {};
handles = [],
moveHandle,
selection;
// Convert from element x/y/width/height to an // Convert from element x/y/width/height to an
// apropriate ng-style argument, to position elements. // appropriate ng-style argument, to position elements.
function convertPosition(elementProxy) { function convertPosition(elementProxy) {
var gridSize = self.gridSize;
// Multiply position/dimensions by grid size // Multiply position/dimensions by grid size
return { return {
left: (gridSize[0] * elementProxy.x()) + 'px', left: (gridSize[0] * elementProxy.x()) + 'px',
@ -64,7 +60,7 @@ define(
// Update the style for a selected element // Update the style for a selected element
function updateSelectionStyle() { function updateSelectionStyle() {
var element = selection && selection.get(); var element = self.selection && self.selection.get();
if (element) { if (element) {
element.style = convertPosition(element); element.style = convertPosition(element);
} }
@ -74,7 +70,7 @@ define(
function generateDragHandle(elementHandle) { function generateDragHandle(elementHandle) {
return new FixedDragHandle( return new FixedDragHandle(
elementHandle, elementHandle,
gridSize, self.gridSize,
updateSelectionStyle, updateSelectionStyle,
$scope.commit $scope.commit
); );
@ -85,17 +81,6 @@ define(
return element.handles().map(generateDragHandle); return element.handles().map(generateDragHandle);
} }
// Select an element
function select(element) {
if (selection) {
// Update selection...
selection.select(element);
// ...as well as move, resize handles
moveHandle = generateDragHandle(element);
handles = generateDragHandles(element);
}
}
// Update the displayed value for this object // Update the displayed value for this object
function updateValue(telemetryObject) { function updateValue(telemetryObject) {
var id = telemetryObject && telemetryObject.getId(), var id = telemetryObject && telemetryObject.getId(),
@ -121,9 +106,9 @@ define(
// Update element positions when grid size changes // Update element positions when grid size changes
function updateElementPositions(layoutGrid) { function updateElementPositions(layoutGrid) {
// Update grid size from model // Update grid size from model
gridSize = layoutGrid || DEFAULT_GRID_SIZE; self.gridSize = layoutGrid || DEFAULT_GRID_SIZE;
elementProxies.forEach(function (elementProxy) { self.elementProxies.forEach(function (elementProxy) {
elementProxy.style = convertPosition(elementProxy); elementProxy.style = convertPosition(elementProxy);
}); });
} }
@ -154,7 +139,7 @@ define(
function refreshElements() { function refreshElements() {
// Cache selection; we are instantiating new proxies // Cache selection; we are instantiating new proxies
// so we may want to restore this. // so we may want to restore this.
var selected = selection && selection.get(), var selected = self.selection && self.selection.get(),
elements = (($scope.configuration || {}).elements || []), elements = (($scope.configuration || {}).elements || []),
index = -1; // Start with a 'not-found' value index = -1; // Start with a 'not-found' value
@ -164,20 +149,20 @@ define(
} }
// Create the new proxies... // Create the new proxies...
elementProxies = elements.map(makeProxyElement); self.elementProxies = elements.map(makeProxyElement);
// Clear old selection, and restore if appropriate // Clear old selection, and restore if appropriate
if (selection) { if (self.selection) {
selection.deselect(); self.selection.deselect();
if (index > -1) { if (index > -1) {
select(elementProxies[index]); self.select(self.elementProxies[index]);
} }
} }
// Finally, rebuild lists of elements by id to // Finally, rebuild lists of elements by id to
// facilitate faster update when new telemetry comes in. // facilitate faster update when new telemetry comes in.
elementProxiesById = {}; elementProxiesById = {};
elementProxies.forEach(function (elementProxy) { self.elementProxies.forEach(function (elementProxy) {
var id = elementProxy.id; var id = elementProxy.id;
if (elementProxy.element.type === 'fixed.telemetry') { if (elementProxy.element.type === 'fixed.telemetry') {
// Provide it a cached name/value to avoid flashing // Provide it a cached name/value to avoid flashing
@ -232,7 +217,9 @@ define(
// Refresh displayed elements // Refresh displayed elements
refreshElements(); refreshElements();
// Select the newly-added element // Select the newly-added element
select(elementProxies[elementProxies.length - 1]); self.select(
self.elementProxies[self.elementProxies.length - 1]
);
// Mark change as persistable // Mark change as persistable
if ($scope.commit) { if ($scope.commit) {
$scope.commit("Dropped an element."); $scope.commit("Dropped an element.");
@ -249,8 +236,8 @@ define(
// Store the position of this element. // Store the position of this element.
addElement({ addElement({
type: "fixed.telemetry", type: "fixed.telemetry",
x: Math.floor(position.x / gridSize[0]), x: Math.floor(position.x / self.gridSize[0]),
y: Math.floor(position.y / gridSize[1]), y: Math.floor(position.y / self.gridSize[1]),
id: id, id: id,
stroke: "transparent", stroke: "transparent",
color: "#cccccc", color: "#cccccc",
@ -260,12 +247,17 @@ define(
}); });
} }
this.gridSize = DEFAULT_GRID_SIZE;
this.elementProxies = [];
this.generateDragHandle = generateDragHandle;
this.generateDragHandles = generateDragHandles;
// Track current selection state // Track current selection state
selection = $scope.selection; this.selection = $scope.selection;
// Expose the view's selection proxy // Expose the view's selection proxy
if (selection) { if (this.selection) {
selection.proxy(new FixedProxy(addElement, $q, dialogService)); this.selection.proxy(new FixedProxy(addElement, $q, dialogService));
} }
// Refresh list of elements whenever model changes // Refresh list of elements whenever model changes
@ -285,72 +277,79 @@ define(
// Position panes where they are dropped // Position panes where they are dropped
$scope.$on("mctDrop", handleDrop); $scope.$on("mctDrop", handleDrop);
}
return {
/** /**
* Get the size of the grid, in pixels. The returned array * Get the size of the grid, in pixels. The returned array
* is in the form `[x, y]`. * is in the form `[x, y]`.
* @returns {number[]} the grid size * @returns {number[]} the grid size
* @memberof platform/features/layout.FixedController# * @memberof platform/features/layout.FixedController#
*/ */
getGridSize: function () { FixedController.prototype.getGridSize = function () {
return gridSize; return this.gridSize;
}, };
/** /**
* Get an array of elements in this panel; these are * Get an array of elements in this panel; these are
* decorated proxies for both selection and display. * decorated proxies for both selection and display.
* @returns {Array} elements in this panel * @returns {Array} elements in this panel
* @memberof platform/features/layout.FixedController#
*/ */
getElements: function () { FixedController.prototype.getElements = function () {
return elementProxies; return this.elementProxies;
}, };
/** /**
* Check if the element is currently selected, or (if no * Check if the element is currently selected, or (if no
* argument is supplied) get the currently selected element. * argument is supplied) get the currently selected element.
* @returns {boolean} true if selected * @returns {boolean} true if selected
* @memberof platform/features/layout.FixedController#
*/ */
selected: function (element) { FixedController.prototype.selected = function (element) {
var selection = this.selection;
return selection && ((arguments.length > 0) ? return selection && ((arguments.length > 0) ?
selection.selected(element) : selection.get()); selection.selected(element) : selection.get());
}, };
/** /**
* Set the active user selection in this view. * Set the active user selection in this view.
* @param element the element to select * @param element the element to select
* @memberof platform/features/layout.FixedController#
*/ */
select: select, FixedController.prototype.select = function select(element) {
/** if (this.selection) {
* Clear the current user selection. // Update selection...
* @memberof platform/features/layout.FixedController# this.selection.select(element);
*/ // ...as well as move, resize handles
clearSelection: function () { this.mvHandle = this.generateDragHandle(element);
if (selection) { this.resizeHandles = this.generateDragHandles(element);
selection.deselect();
handles = [];
moveHandle = undefined;
}
},
/**
* Get drag handles.
* @returns {Array} drag handles for the current selection
* @memberof platform/features/layout.FixedController#
*/
handles: function () {
return handles;
},
/**
* Get the handle to handle dragging to reposition an element.
* @returns {FixedDragHandle} the drag handle
* @memberof platform/features/layout.FixedController#
*/
moveHandle: function () {
return moveHandle;
} }
}; };
/**
* Clear the current user selection.
*/
FixedController.prototype.clearSelection = function () {
if (this.selection) {
this.selection.deselect();
this.resizeHandles = [];
this.mvHandle = undefined;
} }
};
/**
* Get drag handles.
* @returns {platform/features/layout.FixedDragHandle[]}
* drag handles for the current selection
*/
FixedController.prototype.handles = function () {
return this.resizeHandles;
};
/**
* Get the handle to handle dragging to reposition an element.
* @returns {platform/features/layout.FixedDragHandle} the drag handle
*/
FixedController.prototype.moveHandle = function () {
return this.mvHandle;
};
return FixedController; return FixedController;
} }

View File

@ -37,14 +37,21 @@ define(
* @constructor * @constructor
*/ */
function FixedDragHandle(elementHandle, gridSize, update, commit) { function FixedDragHandle(elementHandle, gridSize, update, commit) {
var self = {}, this.elementHandle = elementHandle;
dragging; this.gridSize = gridSize;
this.update = update;
this.commit = commit;
}
// Generate ng-style-appropriate style for positioning /**
function getStyle() { * Get a CSS style to position this drag handle.
* @returns CSS style object (for `ng-style`)
* @memberof platform/features/layout.FixedDragHandle#
*/
FixedDragHandle.prototype.style = function () {
// Adjust from grid to pixel coordinates // Adjust from grid to pixel coordinates
var x = elementHandle.x() * gridSize[0], var x = this.elementHandle.x() * this.gridSize[0],
y = elementHandle.y() * gridSize[1]; y = this.elementHandle.y() * this.gridSize[1];
// Convert to a CSS style centered on that point // Convert to a CSS style centered on that point
return { return {
@ -53,69 +60,53 @@ define(
width: DRAG_HANDLE_SIZE[0] + 'px', width: DRAG_HANDLE_SIZE[0] + 'px',
height: DRAG_HANDLE_SIZE[1] + 'px' height: DRAG_HANDLE_SIZE[1] + 'px'
}; };
} };
// Begin a drag gesture
function startDrag() {
// Cache initial x/y positions
dragging = { x: elementHandle.x(), y: elementHandle.y() };
}
// Reposition during drag
function continueDrag(delta) {
if (dragging) {
// Update x/y positions (snapping to grid)
elementHandle.x(
dragging.x + Math.round(delta[0] / gridSize[0])
);
elementHandle.y(
dragging.y + Math.round(delta[1] / gridSize[1])
);
// Invoke update callback
if (update) {
update();
}
}
}
// Conclude a drag gesture
function endDrag() {
// Clear cached state
dragging = undefined;
// Mark change as complete
if (commit) {
commit("Dragged handle.");
}
}
return {
/**
* Get a CSS style to position this drag handle.
* @returns CSS style object (for `ng-style`)
* @memberof platform/features/layout.FixedDragHandle#
*/
style: getStyle,
/** /**
* Start a drag gesture. This should be called when a drag * Start a drag gesture. This should be called when a drag
* begins to track initial state. * begins to track initial state.
* @memberof platform/features/layout.FixedDragHandle#
*/ */
startDrag: startDrag, FixedDragHandle.prototype.startDrag = function startDrag() {
// Cache initial x/y positions
this.dragging = {
x: this.elementHandle.x(),
y: this.elementHandle.y()
};
};
/** /**
* Continue a drag gesture; update x/y positions. * Continue a drag gesture; update x/y positions.
* @param {number[]} delta x/y pixel difference since drag * @param {number[]} delta x/y pixel difference since drag
* started * started
* @memberof platform/features/layout.FixedDragHandle#
*/ */
continueDrag: continueDrag, FixedDragHandle.prototype.continueDrag = function (delta) {
if (this.dragging) {
// Update x/y positions (snapping to grid)
this.elementHandle.x(
this.dragging.x + Math.round(delta[0] / this.gridSize[0])
);
this.elementHandle.y(
this.dragging.y + Math.round(delta[1] / this.gridSize[1])
);
// Invoke update callback
if (this.update) {
this.update();
}
}
};
/** /**
* End a drag gesture. This should be callled when a drag * End a drag gesture. This should be callled when a drag
* concludes to trigger commit of changes. * concludes to trigger commit of changes.
* @memberof platform/features/layout.FixedDragHandle#
*/ */
endDrag: endDrag FixedDragHandle.prototype.endDrag = function () {
}; // Clear cached state
this.dragging = undefined;
// Mark change as complete
if (this.commit) {
this.commit("Dragged handle.");
} }
};
return FixedDragHandle; return FixedDragHandle;
} }

View File

@ -37,14 +37,24 @@ define(
* when adding a new element will require user input * when adding a new element will require user input
*/ */
function FixedProxy(addElementCallback, $q, dialogService) { function FixedProxy(addElementCallback, $q, dialogService) {
var factory = new ElementFactory(dialogService); this.factory = new ElementFactory(dialogService);
this.$q = $q;
this.addElementCallback = addElementCallback;
}
return {
/** /**
* Add a new visual element to this view. * Add a new visual element to this view. Supported types are:
* @memberof platform/features/layout.FixedProxy# *
* * `fixed.image`
* * `fixed.box`
* * `fixed.text`
* * `fixed.line`
*
* @param {string} type the type of element to add
*/ */
add: function (type) { FixedProxy.prototype.add = function (type) {
var addElementCallback = this.addElementCallback;
// Place a configured element into the view configuration // Place a configured element into the view configuration
function addElement(element) { function addElement(element) {
// Configure common properties of the element // Configure common properties of the element
@ -59,10 +69,8 @@ define(
} }
// Defer creation to the factory // Defer creation to the factory
$q.when(factory.createElement(type)).then(addElement); this.$q.when(this.factory.createElement(type)).then(addElement);
}
}; };
}
return FixedProxy; return FixedProxy;
} }

View File

@ -31,24 +31,19 @@ define(
* They cannot contain folders. * They cannot contain folders.
* @constructor * @constructor
* @memberof platform/features/layout * @memberof platform/features/layout
* @implements {Policy.<View, DomainObject>}
*/ */
function LayoutCompositionPolicy() { function LayoutCompositionPolicy() {
return { }
/**
* Is the type identified by the candidate allowed to LayoutCompositionPolicy.prototype.allow = function (candidate, context) {
* contain the type described by the context?
* @memberof platform/features/layout.LayoutCompositionPolicy#
*/
allow: function (candidate, context) {
var isFolderInLayout = var isFolderInLayout =
candidate && candidate &&
context && context &&
candidate.instanceOf('layout') && candidate.instanceOf('layout') &&
context.instanceOf('folder'); context.instanceOf('folder');
return !isFolderInLayout; return !isFolderInLayout;
}
}; };
}
return LayoutCompositionPolicy; return LayoutCompositionPolicy;
} }

View File

@ -45,11 +45,7 @@ define(
* @param {Scope} $scope the controller's Angular scope * @param {Scope} $scope the controller's Angular scope
*/ */
function LayoutController($scope) { function LayoutController($scope) {
var gridSize = DEFAULT_GRID_SIZE, var self = this;
activeDrag,
activeDragId,
rawPositions = {},
positions = {};
// Utility function to copy raw positions from configuration, // Utility function to copy raw positions from configuration,
// without writing directly to configuration (to avoid triggering // without writing directly to configuration (to avoid triggering
@ -62,47 +58,6 @@ define(
return copy; return copy;
} }
// Convert from { positions: ..., dimensions: ... } to an
// apropriate ng-style argument, to position frames.
function convertPosition(raw) {
// Multiply position/dimensions by grid size
return {
left: (gridSize[0] * raw.position[0]) + 'px',
top: (gridSize[1] * raw.position[1]) + 'px',
width: (gridSize[0] * raw.dimensions[0]) + 'px',
height: (gridSize[1] * raw.dimensions[1]) + 'px'
};
}
// Generate default positions for a new panel
function defaultDimensions() {
return MINIMUM_FRAME_SIZE.map(function (min, i) {
return Math.max(
Math.ceil(min / gridSize[i]),
DEFAULT_DIMENSIONS[i]
);
});
}
// Generate a default position (in its raw format) for a frame.
// Use an index to ensure that default positions are unique.
function defaultPosition(index) {
return {
position: [index, index],
dimensions: defaultDimensions()
};
}
// Store a computed position for a contained frame by its
// domain object id. Called in a forEach loop, so arguments
// are as expected there.
function populatePosition(id, index) {
rawPositions[id] =
rawPositions[id] || defaultPosition(index || 0);
positions[id] =
convertPosition(rawPositions[id]);
}
// Compute panel positions based on the layout's object model // Compute panel positions based on the layout's object model
function lookupPanels(ids) { function lookupPanels(ids) {
var configuration = $scope.configuration || {}; var configuration = $scope.configuration || {};
@ -112,27 +67,32 @@ define(
ids = ids || []; ids = ids || [];
// Pull panel positions from configuration // Pull panel positions from configuration
rawPositions = shallowCopy(configuration.panels || {}, ids); self.rawPositions =
shallowCopy(configuration.panels || {}, ids);
// Clear prior computed positions // Clear prior computed positions
positions = {}; self.positions = {};
// Update width/height that we are tracking // Update width/height that we are tracking
gridSize = ($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE; self.gridSize =
($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE;
// Compute positions and add defaults where needed // Compute positions and add defaults where needed
ids.forEach(populatePosition); ids.forEach(function (id, index) {
self.populatePosition(id, index);
});
} }
// Update grid size when it changed // Update grid size when it changed
function updateGridSize(layoutGrid) { function updateGridSize(layoutGrid) {
var oldSize = gridSize; var oldSize = self.gridSize;
gridSize = layoutGrid || DEFAULT_GRID_SIZE; self.gridSize = layoutGrid || DEFAULT_GRID_SIZE;
// Only update panel positions if this actually changed things // Only update panel positions if this actually changed things
if (gridSize[0] !== oldSize[0] || gridSize[1] !== oldSize[1]) { if (self.gridSize[0] !== oldSize[0] ||
lookupPanels(Object.keys(positions)); self.gridSize[1] !== oldSize[1]) {
lookupPanels(Object.keys(self.positions));
} }
} }
@ -150,8 +110,8 @@ define(
// Store the position of this panel. // Store the position of this panel.
$scope.configuration.panels[id] = { $scope.configuration.panels[id] = {
position: [ position: [
Math.floor(position.x / gridSize[0]), Math.floor(position.x / self.gridSize[0]),
Math.floor(position.y / gridSize[1]) Math.floor(position.y / self.gridSize[1])
], ],
dimensions: DEFAULT_DIMENSIONS dimensions: DEFAULT_DIMENSIONS
}; };
@ -160,13 +120,39 @@ define(
$scope.commit("Dropped a frame."); $scope.commit("Dropped a frame.");
} }
// Populate template-facing position for this id // Populate template-facing position for this id
populatePosition(id); self.populatePosition(id);
// Layout may contain embedded views which will // Layout may contain embedded views which will
// listen for drops, so call preventDefault() so // listen for drops, so call preventDefault() so
// that they can recognize that this event is handled. // that they can recognize that this event is handled.
e.preventDefault(); e.preventDefault();
} }
// End drag; we don't want to put $scope into this
// because it triggers "cpws" (copy window or scope)
// errors in Angular.
this.endDragInScope = function () {
// Write to configuration; this is watched and
// saved by the EditRepresenter.
$scope.configuration =
$scope.configuration || {};
// Make sure there is a "panels" field in the
// view configuration.
$scope.configuration.panels =
$scope.configuration.panels || {};
// Store the position of this panel.
$scope.configuration.panels[self.activeDragId] =
self.rawPositions[self.activeDragId];
// Mark this object as dirty to encourage persistence
if ($scope.commit) {
$scope.commit("Moved frame.");
}
};
this.positions = {};
this.rawPositions = {};
this.gridSize = DEFAULT_GRID_SIZE;
this.$scope = $scope;
// Watch for changes to the grid size in the model // Watch for changes to the grid size in the model
$scope.$watch("model.layoutGrid", updateGridSize); $scope.$watch("model.layoutGrid", updateGridSize);
@ -175,8 +161,51 @@ define(
// Position panes where they are dropped // Position panes where they are dropped
$scope.$on("mctDrop", handleDrop); $scope.$on("mctDrop", handleDrop);
}
// Convert from { positions: ..., dimensions: ... } to an
// apropriate ng-style argument, to position frames.
LayoutController.prototype.convertPosition = function (raw) {
var gridSize = this.gridSize;
// Multiply position/dimensions by grid size
return { return {
left: (gridSize[0] * raw.position[0]) + 'px',
top: (gridSize[1] * raw.position[1]) + 'px',
width: (gridSize[0] * raw.dimensions[0]) + 'px',
height: (gridSize[1] * raw.dimensions[1]) + 'px'
};
};
// Generate default positions for a new panel
LayoutController.prototype.defaultDimensions = function () {
var gridSize = this.gridSize;
return MINIMUM_FRAME_SIZE.map(function (min, i) {
return Math.max(
Math.ceil(min / gridSize[i]),
DEFAULT_DIMENSIONS[i]
);
});
};
// Generate a default position (in its raw format) for a frame.
// Use an index to ensure that default positions are unique.
LayoutController.prototype.defaultPosition = function (index) {
return {
position: [index, index],
dimensions: this.defaultDimensions()
};
};
// Store a computed position for a contained frame by its
// domain object id. Called in a forEach loop, so arguments
// are as expected there.
LayoutController.prototype.populatePosition = function (id, index) {
this.rawPositions[id] =
this.rawPositions[id] || this.defaultPosition(index || 0);
this.positions[id] =
this.convertPosition(this.rawPositions[id]);
};
/** /**
* Get a style object for a frame with the specified domain * Get a style object for a frame with the specified domain
* object identifier, suitable for use in an `ng-style` * object identifier, suitable for use in an `ng-style`
@ -184,13 +213,13 @@ define(
* @param {string} id the object identifier * @param {string} id the object identifier
* @returns {Object.<string, string>} an object with * @returns {Object.<string, string>} an object with
* appropriate left, width, etc fields for positioning * appropriate left, width, etc fields for positioning
* @memberof platform/features/layout.LayoutController#
*/ */
getFrameStyle: function (id) { LayoutController.prototype.getFrameStyle = function (id) {
// Called in a loop, so just look up; the "positions" // Called in a loop, so just look up; the "positions"
// object is kept up to date by a watch. // object is kept up to date by a watch.
return positions[id]; return this.positions[id];
}, };
/** /**
* Start a drag gesture to move/resize a frame. * Start a drag gesture to move/resize a frame.
* *
@ -210,56 +239,37 @@ define(
* in the frame being manipulated * in the frame being manipulated
* @param {number[]} posFactor the position factor * @param {number[]} posFactor the position factor
* @param {number[]} dimFactor the dimensions factor * @param {number[]} dimFactor the dimensions factor
* @memberof platform/features/layout.LayoutController#
*/ */
startDrag: function (id, posFactor, dimFactor) { LayoutController.prototype.startDrag = function (id, posFactor, dimFactor) {
activeDragId = id; this.activeDragId = id;
activeDrag = new LayoutDrag( this.activeDrag = new LayoutDrag(
rawPositions[id], this.rawPositions[id],
posFactor, posFactor,
dimFactor, dimFactor,
gridSize this.gridSize
); );
}, };
/** /**
* Continue an active drag gesture. * Continue an active drag gesture.
* @param {number[]} delta the offset, in pixels, * @param {number[]} delta the offset, in pixels,
* of the current pointer position, relative * of the current pointer position, relative
* to its position when the drag started * to its position when the drag started
* @memberof platform/features/layout.LayoutController#
*/ */
continueDrag: function (delta) { LayoutController.prototype.continueDrag = function (delta) {
if (activeDrag) { if (this.activeDrag) {
rawPositions[activeDragId] = this.rawPositions[this.activeDragId] =
activeDrag.getAdjustedPosition(delta); this.activeDrag.getAdjustedPosition(delta);
populatePosition(activeDragId); this.populatePosition(this.activeDragId);
}
},
/**
* End the active drag gesture. This will update the
* view configuration.
* @memberof platform/features/layout.LayoutController#
*/
endDrag: function () {
// Write to configuration; this is watched and
// saved by the EditRepresenter.
$scope.configuration =
$scope.configuration || {};
// Make sure there is a "panels" field in the
// view configuration.
$scope.configuration.panels =
$scope.configuration.panels || {};
// Store the position of this panel.
$scope.configuration.panels[activeDragId] =
rawPositions[activeDragId];
// Mark this object as dirty to encourage persistence
if ($scope.commit) {
$scope.commit("Moved frame.");
}
} }
}; };
} /**
* End the active drag gesture. This will update the
* view configuration.
*/
LayoutController.prototype.endDrag = function () {
this.endDragInScope();
};
return LayoutController; return LayoutController;
} }

View File

@ -54,9 +54,15 @@ define(
* @memberof platform/features/layout * @memberof platform/features/layout
*/ */
function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) { function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) {
this.rawPosition = rawPosition;
this.posFactor = posFactor;
this.dimFactor = dimFactor;
this.gridSize = gridSize;
}
// Convert a delta from pixel coordinates to grid coordinates, // Convert a delta from pixel coordinates to grid coordinates,
// rounding to whole-number grid coordinates. // rounding to whole-number grid coordinates.
function toGridDelta(pixelDelta) { function toGridDelta(gridSize, pixelDelta) {
return pixelDelta.map(function (v, i) { return pixelDelta.map(function (v, i) {
return Math.round(v / gridSize[i]); return Math.round(v / gridSize[i]);
}); });
@ -83,33 +89,27 @@ define(
}); });
} }
function getAdjustedPosition(pixelDelta) {
var gridDelta = toGridDelta(pixelDelta);
return {
position: max(add(
rawPosition.position,
multiply(gridDelta, posFactor)
), [0, 0]),
dimensions: max(add(
rawPosition.dimensions,
multiply(gridDelta, dimFactor)
), [1, 1])
};
}
return {
/** /**
* Get a new position object in grid coordinates, with * Get a new position object in grid coordinates, with
* position and dimensions both offset appropriately * position and dimensions both offset appropriately
* according to the factors supplied in the constructor. * according to the factors supplied in the constructor.
* @param {number[]} pixelDelta the offset from the * @param {number[]} pixelDelta the offset from the
* original position, in pixels * original position, in pixels
* @memberof platform/features/layout.LayoutDrag#
*/ */
getAdjustedPosition: getAdjustedPosition LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
return {
position: max(add(
this.rawPosition.position,
multiply(gridDelta, this.posFactor)
), [0, 0]),
dimensions: max(add(
this.rawPosition.dimensions,
multiply(gridDelta, this.dimFactor)
), [1, 1])
};
}; };
}
return LayoutDrag; return LayoutDrag;

View File

@ -48,7 +48,6 @@ define(
* Get/set this element's fill color. (Omitting the * Get/set this element's fill color. (Omitting the
* argument makes this act as a getter.) * argument makes this act as a getter.)
* @method * @method
* @memberof BoxProxy
* @param {string} fill the new fill color * @param {string} fill the new fill color
* @returns {string} the fill color * @returns {string} the fill color
* @memberof platform/features/layout.BoxProxy# * @memberof platform/features/layout.BoxProxy#

View File

@ -89,28 +89,27 @@ define(
* @constructor * @constructor
*/ */
function ElementFactory(dialogService) { function ElementFactory(dialogService) {
return { this.dialogService = dialogService;
}
/** /**
* Create a new element for the fixed position view. * Create a new element for the fixed position view.
* @param {string} type the type of element to create * @param {string} type the type of element to create
* @returns {Promise|object} the created element, or a promise * @returns {Promise|object} the created element, or a promise
* for that element * for that element
* @memberof platform/features/layout.ElementFactory#
*/ */
createElement: function (type) { ElementFactory.prototype.createElement = function (type) {
var initialState = INITIAL_STATES[type] || {}; var initialState = INITIAL_STATES[type] || {};
// Clone that state // Clone that state
initialState = JSON.parse(JSON.stringify(initialState)); initialState = JSON.parse(JSON.stringify(initialState));
// Show a dialog to configure initial state, if appropriate // Show a dialog to configure initial state, if appropriate
return DIALOGS[type] ? dialogService.getUserInput( return DIALOGS[type] ? this.dialogService.getUserInput(
DIALOGS[type], DIALOGS[type],
initialState initialState
) : initialState; ) : initialState;
}
}; };
}
return ElementFactory; return ElementFactory;
} }

View File

@ -56,14 +56,14 @@ define(
* @param {Array} elements the full array of elements * @param {Array} elements the full array of elements
*/ */
function ElementProxy(element, index, elements) { function ElementProxy(element, index, elements) {
var handles = [ new ResizeHandle(element, 1, 1) ]; this.resizeHandles = [ new ResizeHandle(element, 1, 1) ];
return {
/** /**
* The element as stored in the view configuration. * The element as stored in the view configuration.
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
element: element, this.element = element;
/** /**
* Get and/or set the x position of this element. * Get and/or set the x position of this element.
* Units are in fixed position grid space. * Units are in fixed position grid space.
@ -71,7 +71,8 @@ define(
* @returns {number} the x position * @returns {number} the x position
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
x: new AccessorMutator(element, 'x', clamp), this.x = new AccessorMutator(element, 'x', clamp);
/** /**
* Get and/or set the y position of this element. * Get and/or set the y position of this element.
* Units are in fixed position grid space. * Units are in fixed position grid space.
@ -79,14 +80,16 @@ define(
* @returns {number} the y position * @returns {number} the y position
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
y: new AccessorMutator(element, 'y', clamp), this.y = new AccessorMutator(element, 'y', clamp);
/** /**
* Get and/or set the stroke color of this element. * Get and/or set the stroke color of this element.
* @param {string} [stroke] the new stroke color (if setting) * @param {string} [stroke] the new stroke color (if setting)
* @returns {string} the stroke color * @returns {string} the stroke color
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
stroke: new AccessorMutator(element, 'stroke'), this.stroke = new AccessorMutator(element, 'stroke');
/** /**
* Get and/or set the width of this element. * Get and/or set the width of this element.
* Units are in fixed position grid space. * Units are in fixed position grid space.
@ -94,7 +97,8 @@ define(
* @returns {number} the width * @returns {number} the width
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
width: new AccessorMutator(element, 'width'), this.width = new AccessorMutator(element, 'width');
/** /**
* Get and/or set the height of this element. * Get and/or set the height of this element.
* Units are in fixed position grid space. * Units are in fixed position grid space.
@ -102,15 +106,22 @@ define(
* @returns {number} the height * @returns {number} the height
* @memberof platform/features/layout.ElementProxy# * @memberof platform/features/layout.ElementProxy#
*/ */
height: new AccessorMutator(element, 'height'), this.height = new AccessorMutator(element, 'height');
this.index = index;
this.elements = elements;
}
/** /**
* Change the display order of this element. * Change the display order of this element.
* @param {string} o where to move this element; * @param {string} o where to move this element;
* one of "top", "up", "down", or "bottom" * one of "top", "up", "down", or "bottom"
* @memberof platform/features/layout.ElementProxy#
*/ */
order: function (o) { ElementProxy.prototype.order = function (o) {
var delta = ORDERS[o] || 0, var index = this.index,
elements = this.elements,
element = this.element,
delta = ORDERS[o] || 0,
desired = Math.max( desired = Math.max(
Math.min(index + delta, elements.length - 1), Math.min(index + delta, elements.length - 1),
0 0
@ -123,28 +134,29 @@ define(
elements.splice(desired, 0, element); elements.splice(desired, 0, element);
// Track change in index (proxy should be recreated // Track change in index (proxy should be recreated
// anyway, but be consistent) // anyway, but be consistent)
index = desired; this.index = desired;
} }
}, };
/** /**
* Remove this element from the fixed position view. * Remove this element from the fixed position view.
* @memberof platform/features/layout.ElementProxy#
*/ */
remove: function () { ElementProxy.prototype.remove = function () {
if (elements[index] === element) { var index = this.index;
elements.splice(index, 1); if (this.elements[index] === this.element) {
this.elements.splice(index, 1);
} }
}, };
/** /**
* Get handles to control specific features of this element, * Get handles to control specific features of this element,
* e.g. corner size. * e.g. corner size.
* @memberof platform/features/layout.ElementProxy# * @return {platform/features/layout.ElementHandle[]} handles
* for moving/resizing this element
*/ */
handles: function () { ElementProxy.prototype.handles = function () {
return handles; return this.resizeHandles;
}
}; };
}
return ElementProxy; return ElementProxy;
} }

View File

@ -38,6 +38,7 @@ define(
* configuration * configuration
* @param index the element's index within its array * @param index the element's index within its array
* @param {Array} elements the full array of elements * @param {Array} elements the full array of elements
* @augments {platform/features/layout.ElementProxy}
*/ */
function ImageProxy(element, index, elements) { function ImageProxy(element, index, elements) {
var proxy = new ElementProxy(element, index, elements); var proxy = new ElementProxy(element, index, elements);

View File

@ -37,16 +37,23 @@ define(
* @param {string} yProperty field which stores x position * @param {string} yProperty field which stores x position
* @param {string} xOther field which stores x of other end * @param {string} xOther field which stores x of other end
* @param {string} yOther field which stores y of other end * @param {string} yOther field which stores y of other end
* @implements {platform/features/layout.ElementHandle}
*/ */
function LineHandle(element, xProperty, yProperty, xOther, yOther) { function LineHandle(element, xProperty, yProperty, xOther, yOther) {
return { this.element = element;
/** this.xProperty = xProperty;
* Get/set the x position of the lower-right corner this.yProperty = yProperty;
* of the handle-controlled element, changing size this.xOther = xOther;
* as necessary. this.yOther = yOther;
* @memberof platform/features/layout.LineHandle# }
*/
x: function (value) { LineHandle.prototype.x = function (value) {
var element = this.element,
xProperty = this.xProperty,
yProperty = this.yProperty,
xOther = this.xOther,
yOther = this.yOther;
if (arguments.length > 0) { if (arguments.length > 0) {
// Ensure we stay in view // Ensure we stay in view
value = Math.max(value, 0); value = Math.max(value, 0);
@ -57,14 +64,15 @@ define(
} }
} }
return element[xProperty]; return element[xProperty];
}, };
/**
* Get/set the y position of the lower-right corner LineHandle.prototype.y = function (value) {
* of the handle-controlled element, changing size var element = this.element,
* as necessary. xProperty = this.xProperty,
* @memberof platform/features/layout.LineHandle# yProperty = this.yProperty,
*/ xOther = this.xOther,
y: function (value) { yOther = this.yOther;
if (arguments.length > 0) { if (arguments.length > 0) {
// Ensure we stay in view // Ensure we stay in view
value = Math.max(value, 0); value = Math.max(value, 0);
@ -75,9 +83,7 @@ define(
} }
} }
return element[yProperty]; return element[yProperty];
}
}; };
}
return LineHandle; return LineHandle;

View File

@ -35,6 +35,7 @@ define(
* configuration * configuration
* @param index the element's index within its array * @param index the element's index within its array
* @param {Array} elements the full array of elements * @param {Array} elements the full array of elements
* @augments {platform/features/layout.ElementProxy}
*/ */
function LineProxy(element, index, elements) { function LineProxy(element, index, elements) {
var proxy = new ElementProxy(element, index, elements), var proxy = new ElementProxy(element, index, elements),

View File

@ -25,6 +25,11 @@ define(
function () { function () {
'use strict'; 'use strict';
/**
* @interface platform/features/layout.ElementHandle
* @private
*/
/** /**
* Handle for changing width/height properties of an element. * Handle for changing width/height properties of an element.
* This is used to support drag handles for different * This is used to support drag handles for different
@ -33,43 +38,34 @@ define(
* @constructor * @constructor
*/ */
function ResizeHandle(element, minWidth, minHeight) { function ResizeHandle(element, minWidth, minHeight) {
// Ensure reasonable defaults this.element = element;
minWidth = minWidth || 0;
minHeight = minHeight || 0;
return { // Ensure reasonable defaults
/** this.minWidth = minWidth || 0;
* Get/set the x position of the lower-right corner this.minHeight = minHeight || 0;
* of the handle-controlled element, changing size }
* as necessary.
* @memberof platform/features/layout.ResizeHandle# ResizeHandle.prototype.x = function (value) {
*/ var element = this.element;
x: function (value) {
if (arguments.length > 0) { if (arguments.length > 0) {
element.width = Math.max( element.width = Math.max(
minWidth, this.minWidth,
value - element.x value - element.x
); );
} }
return element.x + element.width; return element.x + element.width;
}, };
/**
* Get/set the y position of the lower-right corner ResizeHandle.prototype.y = function (value) {
* of the handle-controlled element, changing size var element = this.element;
* as necessary.
* @memberof platform/features/layout.ResizeHandle#
*/
y: function (value) {
if (arguments.length > 0) { if (arguments.length > 0) {
element.height = Math.max( element.height = Math.max(
minHeight, this.minHeight,
value - element.y value - element.y
); );
} }
return element.y + element.height; return element.y + element.height;
}
}; };
}
return ResizeHandle; return ResizeHandle;

View File

@ -41,6 +41,7 @@ define(
* configuration * configuration
* @param index the element's index within its array * @param index the element's index within its array
* @param {Array} elements the full array of elements * @param {Array} elements the full array of elements
* @augments {platform/features/layout.ElementProxy}
*/ */
function TelemetryProxy(element, index, elements) { function TelemetryProxy(element, index, elements) {
var proxy = new TextProxy(element, index, elements); var proxy = new TextProxy(element, index, elements);

View File

@ -38,6 +38,7 @@ define(
* configuration * configuration
* @param index the element's index within its array * @param index the element's index within its array
* @param {Array} elements the full array of elements * @param {Array} elements the full array of elements
* @augments {platform/features/layout.ElementProxy}
*/ */
function TextProxy(element, index, elements) { function TextProxy(element, index, elements) {
var proxy = new BoxProxy(element, index, elements); var proxy = new BoxProxy(element, index, elements);