diff --git a/src/d3/d3Renderer.js b/src/d3/d3Renderer.js index 9c8c428f08..40bc50e4b9 100644 --- a/src/d3/d3Renderer.js +++ b/src/d3/d3Renderer.js @@ -223,7 +223,6 @@ var d3Renderer = function (arg) { /** * Set the translation, scale, and zoom for the current view. - * @note rotation not yet supported * @private */ this._setTransform = function () { diff --git a/src/ui/domWidget.js b/src/ui/domWidget.js index 40c7b4eb83..2fb3b26727 100644 --- a/src/ui/domWidget.js +++ b/src/ui/domWidget.js @@ -2,6 +2,17 @@ var widget = require('./widget'); var inherit = require('../inherit'); var registerWidget = require('../registry').registerWidget; +/** + * Create a new instance of class domWidget. + * + * @class + * @alias geo.gui.domWidget + * @extends geo.gui.widget + * @param {object} arg + * @param {geo.widget} [parent] A parent widget for this widget. + * @param {string} [el='div'] The type of DOM element to create. + * @returns {geo.domWidget} + */ var domWidget = function (arg) { 'use strict'; if (!(this instanceof domWidget)) { @@ -17,6 +28,8 @@ var domWidget = function (arg) { * Initializes DOM Widget. * Sets the canvas for the widget, does parent/child relationship management, * appends it to it's parent and handles any positioning logic. + * + * @returns {this} */ this._init = function () { if (arg.hasOwnProperty('parent')) { @@ -24,18 +37,18 @@ var domWidget = function (arg) { } m_this._createCanvas(); - m_this._appendChild(); + m_this._appendCanvasToParent(); m_this.canvas().addEventListener('mousedown', function (e) { e.stopPropagation(); }); m_this.reposition(); + return m_this; }; /** - * Creates the widget canvas. - * This is just a simple DOM element (based on args.el, or defaults to a div) + * Creates the widget canvas. This is a DOM element (`arg.el` or a div). */ this._createCanvas = function () { m_this.canvas(document.createElement(arg.el || m_default_canvas)); diff --git a/src/ui/legendWidget.js b/src/ui/legendWidget.js index 57dc86d61f..393444e962 100644 --- a/src/ui/legendWidget.js +++ b/src/ui/legendWidget.js @@ -26,9 +26,7 @@ var legendWidget = function (arg) { m_group = null, m_border = null, m_spacing = 20, // distance in pixels between lines - m_padding = 12, // padding in pixels inside the border - s_createCanvas = this._createCanvas, - s_appendChild = this._appendChild; + m_padding = 12; // padding in pixels inside the border /** * Get or set the category array associated with @@ -212,8 +210,8 @@ var legendWidget = function (arg) { // adding categories redraws the entire thing by calling _init, see // the m_top.remove() line below if (!m_top) { - s_createCanvas(); - s_appendChild(); + m_this._createCanvas(); + m_this._appendCanvasToParent(); } // total size = interior size + 2 * padding + 2 * width of the border diff --git a/src/ui/sliderWidget.js b/src/ui/sliderWidget.js index d274b6c4eb..f387f2a809 100644 --- a/src/ui/sliderWidget.js +++ b/src/ui/sliderWidget.js @@ -21,8 +21,6 @@ var sliderWidget = function (arg) { var m_this = this, s_exit = this._exit, - s_createCanvas = this._createCanvas, - s_appendChild = this._appendChild, m_xscale, m_yscale, m_plus, @@ -91,8 +89,8 @@ var sliderWidget = function (arg) { * @private */ this._init = function () { - s_createCanvas(); - s_appendChild(); + m_this._createCanvas(); + m_this._appendCanvasToParent(); m_this.reposition(); diff --git a/src/ui/svgWidget.js b/src/ui/svgWidget.js index 98f4bc6b4f..c66e7253b0 100644 --- a/src/ui/svgWidget.js +++ b/src/ui/svgWidget.js @@ -1,22 +1,24 @@ -var domWidget = require('./domWidget'); +var widget = require('./widget'); var inherit = require('../inherit'); var registerWidget = require('../registry').registerWidget; /** - * Create a new instance of class geo.gui.svgWidget + * Create a new instance of class geo.gui.svgWidget. * - * Due to the nature of d3 creating DOM elements as it inserts them, calls to appendChild - * don't appear in this widget. + * Due to the nature of d3 creating DOM elements as it inserts them, calls to + * appendChild don't appear in this widget. * * The canvas of an svgWidget always refers to the actual svg element. - * The parentCanvas can refer to another widgets svg element, dom element, or the - * UI layers dom element. + * The parentCanvas can refer to another widget's svg element, dom element, or + * the UI layer's dom element. * See {@link geo.gui.widget#parentCanvas}. * - * @class geo.gui.svgWidget - * @extends geo.gui.domWidget + * @class + * @alias geo.gui.svgWidget + * @extends geo.gui.widget + * @param {object} arg + * @param {geo.widget} [parent] A parent widget for this widget. * @returns {geo.gui.svgWidget} - * */ var svgWidget = function (arg) { 'use strict'; @@ -24,14 +26,20 @@ var svgWidget = function (arg) { return new svgWidget(arg); } - domWidget.call(this, arg); + widget.call(this, arg); var d3Renderer = require('../d3/d3Renderer'); var m_this = this, + s_exit = this._exit, m_renderer = null; - this._init = function (arg) { + /** + * Initializes SVG Widget. + * + * @returns {this} + */ + this._init = function () { var d3Parent; if (arg.hasOwnProperty('parent')) { arg.parent.addChild(m_this); @@ -47,12 +55,25 @@ var svgWidget = function (arg) { }); m_this.reposition(); + return m_this; + }; + + /** + * Clean up the widget. + */ + this._exit = function () { + if (m_renderer) { + m_renderer._exit(); + } + s_exit(); }; /** * Creates the canvas for the svg widget. - * This directly uses the {@link geo.d3.d3Renderer} as a helper to do all of the heavy - * lifting. + * This directly uses the {@link geo.d3.d3Renderer} as a helper to do all of + * the heavy lifting. + * + * @param {d3Selector} d3Parent The canvas's parent element. */ this._createCanvas = function (d3Parent) { var rendererOpts = { @@ -75,7 +96,7 @@ var svgWidget = function (arg) { return this; }; -inherit(svgWidget, domWidget); +inherit(svgWidget, widget); registerWidget('dom', 'svg', svgWidget); module.exports = svgWidget; diff --git a/src/ui/widget.js b/src/ui/widget.js index e89dad4371..42d4f001df 100644 --- a/src/ui/widget.js +++ b/src/ui/widget.js @@ -1,18 +1,19 @@ var inherit = require('../inherit'); var sceneObject = require('../sceneObject'); +var $ = require('jquery'); /** * @typedef {object} geo.gui.widget.position * @property {string|number} [top] The position to the top of the container. - * A string css position or a number. If a number is used, it will be treated as px value. - * @property {string|number} [right] The position to the right of the container. - * Value is used similarly to the top property. - * @property {string|number} [bottom] The position to the bottom of the container. - * Value is used similarly to the top property. + * A string css position or a number in pixels. + * @property {string|number} [right] The position to the right of the + * container. A string css position or a number in pixels. + * @property {string|number} [bottom] The position to the bottom of the + * container. A string css position or a number in pixels. * @property {string|number} [left] The position to the left of the container. - * Value is used similarly to the top property. + * @property {string|number} [top] The position to the top of the container. * @property {*} [...] Additional css properties that affect position are - allowed. See the css specification for details. + * allowed. See the css specification for details. */ /** @@ -32,10 +33,10 @@ var widget = function (arg) { if (!(this instanceof widget)) { return new widget(arg); } + arg = arg || {}; sceneObject.call(this, arg); var geo_event = require('../event'); - var createFeature = require('../registry').createFeature; var m_this = this, s_exit = this._exit, @@ -45,6 +46,8 @@ var widget = function (arg) { if (arg.parent !== undefined && !(arg.parent instanceof widget)) { throw new Error('Parent must be of type geo.gui.widget'); + } else if (arg.parent) { + m_this.parent(arg.parent); } /** @@ -59,54 +62,31 @@ var widget = function (arg) { /** * Clean up the widget. - * */ this._exit = function () { m_this.children().forEach(function (child) { - m_this._deleteFeature(child); + m_this.removeChild(child); + child._exit(); }); m_this.layer().geoOff(geo_event.pan, m_this.repositionEvent); - m_this.parentCanvas().removeChild(m_this.canvas()); + if (m_this.parentCanvas().removeChild && m_this.canvas()) { + try { + m_this.parentCanvas().removeChild(m_this.canvas()); + } catch (err) { + // fail gracefully if the canvas is not a child of the parentCanvas + } + } s_exit(); }; - /** - * Create a new feature. - * - * @param {string} featureName Name of the feature to create. - * @param {object} arg Options for the new feature. - * @returns {geo.feature} The new feature. - */ - this._createFeature = function (featureName, arg) { - - var newFeature = createFeature( - featureName, m_this, m_this.renderer(), arg); - - m_this.addChild(newFeature); - m_this.modified(); - return newFeature; - }; - - /** - * Delete feature. - * - * @param {geo.feature} feature The feature to delete. - * @returns {this} - */ - this._deleteFeature = function (feature) { - m_this.removeChild(feature); - feature._exit(); - return m_this; - }; - /** * Return the layer associated with this widget. * * @returns {geo.layer} */ this.layer = function () { - return m_layer; + return m_layer || (m_this.parent() && m_this.parent().layer()); }; /** @@ -133,11 +113,11 @@ var widget = function (arg) { }; /** - * Appends a child to the widget. + * Appends the canvas to the parent canvas. * The widget determines how to append itself to a parent, the parent can * either be another widget, or the UI Layer. */ - this._appendChild = function () { + this._appendCanvasToParent = function () { m_this.parentCanvas().appendChild(m_this.canvas()); }; @@ -148,7 +128,7 @@ var widget = function (arg) { * @returns {HTMLElement} The canvas of the widget's parent. */ this.parentCanvas = function () { - if (m_this.parent === undefined) { + if (!m_this.parent()) { return m_this.layer().canvas(); } return m_this.parent().canvas(); @@ -169,11 +149,17 @@ var widget = function (arg) { this.position = function (pos, actualValue) { if (pos !== undefined) { this.layer().geoOff(geo_event.pan, m_this.repositionEvent); + var clearPosition = {}; + for (var attr in m_position) { + if (m_position.hasOwnProperty(attr)) { + clearPosition[attr] = null; + } + } m_position = pos; if (m_position.hasOwnProperty('x') && m_position.hasOwnProperty('y')) { this.layer().geoOn(geo_event.pan, m_this.repositionEvent); } - this.reposition(); + this.reposition($.extend(clearPosition, m_this.position())); return this; } if (m_position.hasOwnProperty('x') && m_position.hasOwnProperty('y') && !actualValue) { @@ -199,17 +185,23 @@ var widget = function (arg) { */ this.reposition = function (position) { position = position || m_this.position(); - m_this.canvas().style.position = 'absolute'; - - for (var cssAttr in position) { - if (position.hasOwnProperty(cssAttr)) { - // if the property is a number, add px to it, otherwise set it to the - // specified value. Setting a property to null clears it. Setting to - // undefined doesn't alter it. - if (/^\s*(-|\+)?(\d+(\.\d*)?|\d*\.\d+)([eE](-|\+)?\d+)?\s*$/.test(position[cssAttr])) { - m_this.canvas().style[cssAttr] = ('' + position[cssAttr]).trim() + 'px'; - } else { - m_this.canvas().style[cssAttr] = position[cssAttr]; + if (m_this.canvas() && m_this.canvas().style) { + m_this.canvas().style.position = 'absolute'; + + for (var cssAttr in position) { + if (position.hasOwnProperty(cssAttr)) { + // if the property is a number, add px to it, otherwise set it to the + // specified value. Setting a property to null clears it. Setting to + // undefined doesn't alter it. + if (/^\s*(-|\+)?(\d+(\.\d*)?|\d*\.\d+)([eE](-|\+)?\d+)?\s*$/.test(position[cssAttr])) { + // tris ensures that the number is a float with no more than 3 + // decimal places (Chrome does this automatically, but doing so + // explicitly makes testing more consistent). It will be an + // integer when possible. + m_this.canvas().style[cssAttr] = parseFloat(parseFloat(position[cssAttr]).toFixed(3)) + 'px'; + } else { + m_this.canvas().style[cssAttr] = position[cssAttr]; + } } } } @@ -227,9 +219,10 @@ var widget = function (arg) { }; /** - * Report if the widget is completely within the viewport. + * Report if the top left of widget (or its current x, y position) is within + * the viewport. * - * @returns {boolean} True if the widget is completely within the viewport. + * @returns {boolean} True if the widget is within the viewport. */ this.isInViewport = function () { var position = m_this.position(); diff --git a/tests/cases/domWidget.js b/tests/cases/domWidget.js new file mode 100644 index 0000000000..fa3866cbd1 --- /dev/null +++ b/tests/cases/domWidget.js @@ -0,0 +1,38 @@ +var $ = require('jquery'); +var geo = require('../test-utils').geo; +var createMap = require('../test-utils').createMap; + +describe('geo.gui.domWidget', function () { + 'use strict'; + + describe('create', function () { + it('direct create', function () { + var map, layer, widget, widget2; + map = createMap(); + layer = map.createLayer('ui'); + + widget = geo.gui.domWidget({layer: layer}); + expect(widget instanceof geo.gui.domWidget).toBe(true); + expect(widget.parent()).toBe(null); + widget2 = geo.gui.domWidget({layer: layer, parent: widget}); + expect(widget2 instanceof geo.gui.domWidget).toBe(true); + expect(widget2.parent()).toBe(widget); + }); + }); + + describe('Check private class methods', function () { + var map, layer, widget, widget2; + + it('_init and _createCanvas', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.domWidget({layer: layer}); + expect(widget._init()).toBe(widget); + expect($(widget.canvas()).is('div')).toBe(true); + widget2 = geo.gui.domWidget({layer: layer, parent: widget, el: 'span'}); + expect(widget2._init()).toBe(widget2); + expect($(widget2.canvas()).is('div')).toBe(false); + expect($(widget2.canvas()).is('span')).toBe(true); + }); + }); +}); diff --git a/tests/cases/feature.js b/tests/cases/feature.js index 99f2707f10..29b03ae63e 100644 --- a/tests/cases/feature.js +++ b/tests/cases/feature.js @@ -47,7 +47,7 @@ describe('geo.feature', function () { expect(feat.renderer()).toBe(null); }); }); - describe('Check private class mathods', function () { + describe('Check private class methods', function () { var map, layer, feat, points = {index: [], found: []}, box = [], events = {}; it('_init', function () { diff --git a/tests/cases/svgWidget.js b/tests/cases/svgWidget.js new file mode 100644 index 0000000000..aa4647a117 --- /dev/null +++ b/tests/cases/svgWidget.js @@ -0,0 +1,46 @@ +var geo = require('../test-utils').geo; +var createMap = require('../test-utils').createMap; + +describe('geo.gui.svgWidget', function () { + 'use strict'; + + describe('create', function () { + it('direct create', function () { + var map, layer, widget, widget2; + map = createMap(); + layer = map.createLayer('ui'); + + widget = geo.gui.svgWidget({layer: layer}); + expect(widget instanceof geo.gui.svgWidget).toBe(true); + expect(widget.parent()).toBe(null); + widget2 = geo.gui.svgWidget({layer: layer, parent: widget}); + expect(widget2 instanceof geo.gui.svgWidget).toBe(true); + expect(widget2.parent()).toBe(widget); + }); + }); + + describe('Check private class methods', function () { + var map, layer, widget, widget2; + + it('_init and _createCanvas', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.svgWidget({layer: layer}); + expect(widget._init()).toBe(widget); + widget2 = geo.gui.svgWidget({layer: layer, parent: widget}); + expect(widget2._init()).toBe(widget2); + }); + + it('_exit', function () { + var count; + map = createMap(); + layer = map.createLayer('ui'); + count = layer.node().children().length; + widget = geo.gui.svgWidget({layer: layer}); + widget._init(); + expect(layer.node().children().length).toBe(count + 1); + expect(widget._exit()).toBe(undefined); + expect(layer.node().children().length).toBe(count); + }); + }); +}); diff --git a/tests/cases/textFeature.js b/tests/cases/textFeature.js index 28b971040f..a44c5d8b34 100644 --- a/tests/cases/textFeature.js +++ b/tests/cases/textFeature.js @@ -110,7 +110,7 @@ describe('geo.textFeature', function () { }); }); - describe('Check private class mathods', function () { + describe('Check private class methods', function () { var map, layer, text; it('_init', function () { map = createMap(); diff --git a/tests/cases/widget.js b/tests/cases/widget.js new file mode 100644 index 0000000000..60e105aeec --- /dev/null +++ b/tests/cases/widget.js @@ -0,0 +1,252 @@ +var geo = require('../test-utils').geo; +var $ = require('jquery'); +var createMap = require('../test-utils').createMap; +var closeToEqual = require('../test-utils').closeToEqual; + +describe('geo.gui.widget', function () { + 'use strict'; + + describe('create', function () { + it('direct create', function () { + var map, layer, widget; + map = createMap(); + layer = map.createLayer('ui'); + + widget = geo.gui.widget(); + expect(widget instanceof geo.gui.widget).toBe(true); + expect(widget.layer()).toBe(null); + + widget = geo.gui.widget({layer: layer}); + expect(widget instanceof geo.gui.widget).toBe(true); + expect(widget.layer()).toBe(layer); + expect(widget.parentCanvas()).toBe(layer.canvas()); + + expect(function () { + geo.gui.widget({layer: layer, parent: {}}); + }).toThrow(new Error('Parent must be of type geo.gui.widget')); + + widget = geo.gui.widget({parent: geo.gui.widget({layer: layer})}); + expect(widget instanceof geo.gui.widget).toBe(true); + expect(widget.parentCanvas()).toBe(null); + }); + }); + + describe('Check private class methods', function () { + var map, layer, widget; + + it('_init', function () { + var modTime; + + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + modTime = widget.getMTime(); + expect(widget._init()).toBe(widget); + expect(widget.getMTime()).toBeGreaterThan(modTime); + }); + it('_exit', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + widget._init(); + expect(widget._exit()).toBe(undefined); + + widget = geo.gui.widget({layer: layer}); + widget._init(); + var canvas = widget.canvas(document.createElement('div')); + widget._appendCanvasToParent(canvas); + expect(widget._exit()).toBe(undefined); + }); + + it('_createCanvas', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + widget._init(); + expect(function () { + widget._createCanvas(); + }).toThrow(new Error('Must be defined in derived classes')); + }); + it('_appendCanvasToParent', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + widget._init(); + var canvas = widget.canvas(document.createElement('div')); + var children = $(widget.parentCanvas()).children(); + expect(widget._appendCanvasToParent(canvas)).toBe(undefined); + expect($(widget.parentCanvas()).children().length).toBe(children.length + 1); + }); + }); + + describe('Check public class methods', function () { + var map, layer, widget; + + it('layer', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + widget._init(); + expect(widget.layer()).toBe(layer); + }); + it('canvas', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + expect(widget.canvas()).toBe(null); + var div = document.createElement('div'); + expect(widget.canvas(div)).toBe(widget); + expect(widget.canvas()).toBe(div); + }); + it('parentCanvas', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + expect(widget.parentCanvas()).toBe(layer.canvas()); + var widget2 = geo.gui.widget({layer: layer, parent: widget}); + expect(widget2.parentCanvas()).toBe(null); + var div = document.createElement('div'); + widget.canvas(div); + expect(widget2.parentCanvas()).toBe(div); + }); + it('position', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + expect(widget.position()).toEqual({left: 0, top: 0}); + expect(widget.position(undefined, true)).toEqual({left: 0, top: 0}); + expect(widget.position({right: '10px', bottom: '5px'})).toBe(widget); + expect(widget.position()).toEqual({right: '10px', bottom: '5px'}); + expect(widget.position(undefined, true)).toEqual({right: '10px', bottom: '5px'}); + expect(widget.position({x: -3, y: 3})).toBe(widget); + expect(closeToEqual(widget.position(), {left: 285.87, top: 145.85, right: null, bottom: null})).toBe(true); + expect(widget.position(undefined, true)).toEqual({x: -3, y: 3}); + map.pan({x: -5, y: 20}); + expect(closeToEqual(widget.position(), {left: 280.87, top: 165.85, right: null, bottom: null})).toBe(true); + expect(widget.position(undefined, true)).toEqual({x: -3, y: 3}); + /* test that position updates the canvas as we expect */ + var div = document.createElement('div'); + widget = geo.gui.widget({layer: layer}); + widget.canvas(div).reposition(); + expect(div.style.left).toBe('0px'); + expect(div.style.right).toBe(''); + widget.position({right: 10, bottom: 20}); + expect(div.style.left).toBe(''); + expect(div.style.right).toBe('10px'); + widget.position({right: '10%', bottom: 20}); + expect(div.style.left).toBe(''); + expect(div.style.right).toBe('10%'); + }); + it('reposition and repositionEvent', function () { + map = createMap(); + layer = map.createLayer('ui'); + widget = geo.gui.widget({layer: layer}); + var div = document.createElement('div'); + widget.canvas(div); + widget.position({right: '10px', bottom: '5px'}); + expect(widget.reposition()).toBe(widget); + expect($(div).css('right')).toBe('10px'); + expect(widget.reposition({right: 20, bottom: 10})).toBe(widget); + expect($(div).css('right')).toBe('20px'); + widget.position({x: -3, y: 3}); + expect(widget.reposition()).toBe(widget); + expect($(div).css('left')).toBe('285.867px'); + // pan triggers repositionEvent + map.pan({x: -5, y: 20}); + expect($(div).css('left')).toBe('280.867px'); + }); + }); +}); + +describe('widget api', function () { + 'use strict'; + + function makeMap() { + var map; + + map = createMap({ + center: { + x: -98.0, + y: 39.5 + }, + zoom: 5 + }, {width: '500px', height: '400px'}); + + var uiLayer = map.createLayer('ui'); + map.draw(); + return {map: map, uiLayer: uiLayer}; + } + + it('a widget should have the UI layer as its parent', function () { + var widget = makeMap().uiLayer.createWidget('dom'); + + expect(widget.parent()).toEqual(jasmine.any(geo.gui.uiLayer)); + }); + + it('a widget stuck to albany shouldn\'t be in the viewport ' + + 'if we pan to moscow', + function () { + var o = makeMap(), widget = o.uiLayer.createWidget( + 'dom', { + position: { + x: -73.7572, + y: 42.6525 + } + } + ); + + o.map.center({x: 37.6167, y: 55.7500}); + expect(widget.isInViewport()).toBe(false); + }); + + it('a widget stuck to albany should be in the viewport if albany is', function () { + var o = makeMap(), + widget = o.uiLayer.createWidget('dom', { + position: { + x: -73.7572, + y: 42.6525 + } + }); + + o.map.center({x: -73.7572, y: 42.6525}); + expect(widget.isInViewport()).toBe(true); + + }); + + it('a widget stuck to the top left should always be in the viewport', function () { + var o = makeMap(), widget = o.uiLayer.createWidget('dom'); + + expect($(widget.canvas()).position()).toEqual({top: 0, left: 0}); + + o.map.center({x: 37.6167, y: 55.7500}); + expect(widget.isInViewport()).toBe(true); + expect($(widget.canvas()).position()).toEqual({top: 0, left: 0}); + }); + + it('Widgets positions can be changed', function () { + var o = makeMap(), widget = o.uiLayer.createWidget('dom', { + position: {left: 15, top: 10}}); + + expect($(widget.canvas()).position()).toEqual({top: 10, left: 15}); + widget.position({top: null, bottom: '20%', left: 10}); + expect(widget.position()).toEqual({top: null, bottom: '20%', left: 10}); + expect($(widget.canvas()).position()).toEqual({top: 320, left: 10}); + }); + + it('nested widgets should be properly structured', function () { + var o = makeMap(); + var domWidget = o.uiLayer.createWidget('dom'); + var svgWidget = o.uiLayer.createWidget('svg', { + parent: domWidget + }); + var widgetCount = $(o.uiLayer.canvas()).children().length; + + expect($(svgWidget.canvas()).parent()[0]).toBe($(domWidget.canvas())[0]); + + // Only top level widgets are children of the UI Layer + // So removing the domWidget will also remove the svgWidget, but only + // reduce the number of widgets the UILayer has as children by 1 + domWidget._exit(); + expect($(o.uiLayer.canvas()).children().length).toBe(widgetCount - 1); + }); +}); diff --git a/tests/cases/widgetApi.js b/tests/cases/widgetApi.js deleted file mode 100644 index 895e7bfc6a..0000000000 --- a/tests/cases/widgetApi.js +++ /dev/null @@ -1,96 +0,0 @@ -var geo = require('../test-utils').geo; -var createMap = require('../test-utils').createMap; -var $ = require('jquery'); - -describe('widget api', function () { - 'use strict'; - - function makeMap() { - var map; - - map = createMap({ - center: { - x: -98.0, - y: 39.5 - }, - zoom: 5 - }, {width: '500px', height: '400px'}); - - var uiLayer = map.createLayer('ui'); - map.draw(); - return {map: map, uiLayer: uiLayer}; - } - - it('a widget should have the UI layer as its parent', function () { - var widget = makeMap().uiLayer.createWidget('dom'); - - expect(widget.parent()).toEqual(jasmine.any(geo.gui.uiLayer)); - }); - - it('a widget stuck to albany shouldn\'t be in the viewport ' + - 'if we pan to moscow', - function () { - var o = makeMap(), widget = o.uiLayer.createWidget( - 'dom', { - position: { - x: -73.7572, - y: 42.6525 - } - } - ); - - o.map.center({x: 37.6167, y: 55.7500}); - expect(widget.isInViewport()).toBe(false); - }); - - it('a widget stuck to albany should be in the viewport if albany is', function () { - var o = makeMap(), - widget = o.uiLayer.createWidget('dom', { - position: { - x: -73.7572, - y: 42.6525 - } - }); - - o.map.center({x: -73.7572, y: 42.6525}); - expect(widget.isInViewport()).toBe(true); - - }); - - it('a widget stuck to the top left should always be in the viewport', function () { - var o = makeMap(), widget = o.uiLayer.createWidget('dom'); - - expect($(widget.canvas()).position()).toEqual({top: 0, left: 0}); - - o.map.center({x: 37.6167, y: 55.7500}); - expect(widget.isInViewport()).toBe(true); - expect($(widget.canvas()).position()).toEqual({top: 0, left: 0}); - }); - - it('Widgets positions can be changed', function () { - var o = makeMap(), widget = o.uiLayer.createWidget('dom', { - position: {left: 15, top: 10}}); - - expect($(widget.canvas()).position()).toEqual({top: 10, left: 15}); - widget.position({top: null, bottom: '20%', left: 10}); - expect(widget.position()).toEqual({top: null, bottom: '20%', left: 10}); - expect($(widget.canvas()).position()).toEqual({top: 320, left: 10}); - }); - - it('nested widgets should be properly structured', function () { - var o = makeMap(); - var domWidget = o.uiLayer.createWidget('dom'); - var svgWidget = o.uiLayer.createWidget('svg', { - parent: domWidget - }); - var widgetCount = $(o.uiLayer.canvas()).children().length; - - expect($(svgWidget.canvas()).parent()[0]).toBe($(domWidget.canvas())[0]); - - // Only top level widgets are children of the UI Layer - // So removing the domWidget will also remove the svgWidget, but only - // reduce the number of widgets the UILayer has as children by 1 - domWidget._exit(); - expect($(o.uiLayer.canvas()).children().length).toBe(widgetCount - 1); - }); -});