752e31b910dbf30e2b803437da522585eca28528Matt Sweeney /**
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Provides advanced positioning support for Node via a Plugin
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * for centering and alignment.
31acd99497fcc9fc72f15c5553fe356d64fb9d03Matt Sweeney * @module align-plugin
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney */
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney var OFFSET_WIDTH = 'offsetWidth',
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney OFFSET_HEIGHT = 'offsetHeight',
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney undefined = undefined;
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney /**
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Node plugin which can be used to align a node with another node,
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * region, or the viewport.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney *
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * @class Plugin.Align
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * @param {Object} User configuration object
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney */
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney function Align(config) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (config.host) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney this._host = config.host;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney Align.prototype = {
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney /**
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Aligns node with a point on another node or region.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Possible alignment points are:
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dl>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>tl</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>top left</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>tr</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>top right</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>bl</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>bottom left</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>br</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>bottom right</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>tc</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>top center</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>bc</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>bottom center</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>rc</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>right center</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dt>lc</dt>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * <dd>left center</dd>
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney * <dt>cc</dt>
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney * <dd>center center</dd>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * </dl>
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * @method to
ac9a31a10e6b74ccde5140bc7696b4364724dedcLuke Smith * @param region {String || Node || HTMLElement || Object} The node or
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * region to align with. Defaults to the viewport region.
ac9a31a10e6b74ccde5140bc7696b4364724dedcLuke Smith * @param regionPoint {String} The point of the region to align with.
ac9a31a10e6b74ccde5140bc7696b4364724dedcLuke Smith * @param point {String} The point of the node aligned to the region.
ac9a31a10e6b74ccde5140bc7696b4364724dedcLuke Smith * @param resize {Boolean} Whether or not the node should re-align when
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * the window is resized. Defaults to false.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney */
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney to: function(region, regionPoint, point, syncOnResize) {
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney // cache original args for syncing
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney this._syncArgs = Y.Array(arguments);
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (region.top === undefined) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney region = Y.one(region).get('region');
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (region) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney var xy = [region.left, region.top],
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney offxy = [region.width, region.height],
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney points = Align.points,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney node = this._host,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney NULL = null,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney size = node.getAttrs([OFFSET_HEIGHT, OFFSET_WIDTH]),
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney nodeoff = [0 - size[OFFSET_WIDTH], 0 - size[OFFSET_HEIGHT]], // reverse offsets
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney regionFn0 = regionPoint ? points[regionPoint.charAt(0)]: NULL,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney regionFn1 = (regionPoint && regionPoint !== 'cc') ? points[regionPoint.charAt(1)] : NULL,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney nodeFn0 = point ? points[point.charAt(0)] : NULL,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney nodeFn1 = (point && point !== 'cc') ? points[point.charAt(1)] : NULL;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (regionFn0) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney xy = regionFn0(xy, offxy, regionPoint);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (regionFn1) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney xy = regionFn1(xy, offxy, regionPoint);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (nodeFn0) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney xy = nodeFn0(xy, nodeoff, point);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (nodeFn1) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney xy = nodeFn1(xy, nodeoff, point);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (xy && node) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney node.setXY(xy);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney this._resize(syncOnResize);
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return this;
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney },
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney sync: function() {
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney this.to.apply(this, this._syncArgs);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return this;
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney },
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney _resize: function(add) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney var handle = this._handle;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (add && !handle) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney this._handle = Y.on('resize', this._onresize, window, this);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney } else if (!add && handle) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney handle.detach();
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney },
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney _onresize: function() {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney var self = this;
31acd99497fcc9fc72f15c5553fe356d64fb9d03Matt Sweeney setTimeout(function() { // for performance
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney self.sync();
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney });
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney },
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney /**
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Aligns the center of a node to the center of another node or region.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * @method center
ac9a31a10e6b74ccde5140bc7696b4364724dedcLuke Smith * @param region {Node || HTMLElement || Object} optional The node or
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * region to align with. Defaults to the viewport region.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * the window is resized. If centering to viewport, this defaults
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * to true, otherwise default is false.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney */
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney center: function(region, resize) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney this.to(region, 'cc', 'cc', resize);
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return this;
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney },
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney /**
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * Removes the resize handler, if any. This is called automatically
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * when unplugged from the host node.
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney * @method destroy
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney */
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney destroy: function() {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney var handle = this._handle;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (handle) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney handle.detach();
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney }
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney };
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney Align.points = {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney 't': function(xy, off) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return xy;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney },
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney 'r': function(xy, off) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return [xy[0] + off[0], xy[1]];
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney },
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney 'b': function(xy, off) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return [xy[0], xy[1] + off[1]];
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney },
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney 'l': function(xy, off) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return xy;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney },
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney 'c': function(xy, off, point) {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney var axis = (point[0] === 't' || point[0] === 'b') ? 0 : 1,
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney ret, val;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney if (point === 'cc') {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney ret = [xy[0] + off[0] / 2, xy[1] + off[1] / 2];
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney } else {
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney val = xy[axis] + off[axis] / 2;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney ret = (axis) ? [xy[0], val] : [val, xy[1]];
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney return ret;
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney }
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney };
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney Align.NAME = 'Align';
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney Align.NS = 'align';
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney
eb2ea4a236bb9b9bc726a4ba7ed9fdef81246381Matt Sweeney Align.prototype.constructor = Align;
b0614bd702ed299874c87fd5d4d48bccda498c73Matt Sweeney
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney Y.namespace('Plugin');
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney Y.Plugin.Align = Align;
752e31b910dbf30e2b803437da522585eca28528Matt Sweeney