/*global define, $, window */
/*jslint white: true */
/**
* UI submodule
*
* @module RAMP
* @submodule UI
* @main UI
*/
/**
* A class for handling most of the GUI on the page.
*
* @class GUI
* @static
* @uses dojo/_base/array
* @uses dojo/topic
* @uses dojo/_base/lang
* @uses dojo/Deferred
* @uses dojo/domReady!
* @uses GlobalStorage
* @uses Util
* @uses Dictionary
* @uses PopupManager
* @uses templates/sub_panel_Template.html
* @uses templates/sub_panel_content_Template.html
*/
define([
// Dojo
"dojo/_base/array", "dojo/topic", "dojo/_base/lang", "dojo/Deferred",
// Ramp
"ramp/globalStorage", "ramp/eventManager",
// Text
"dojo/text!./templates/sub_panel_Template.html",
"dojo/text!./templates/sub_panel_content_Template.html",
// Util
"utils/util", "utils/dictionary", "utils/popupManager",
// Dom Ready
"dojo/domReady!"
],
function (
// Dojo
dojoArray, topic, lang, Deferred,
// Ramp
GlobalStorage, EventManager,
// Text
subPanelTemplate,
subPanelContentTemplate,
// Util
util, utilDict, popupManager) {
"use strict";
var jWindow = $(window),
wbHead = $("#wb-head"),
wbCore = $("#wb-core"),
wbMainIn = $("#wb-main-in"),
wbFoot = $("#wb-foot"),
panelTabs = $("ul#tabs"),
mapDiv = $("#map-div"),
mapContent = $("#mapContent"),
loadIndicator = mapContent.find("#map-load-indicator"),
subPanels = {},
// subPanelAttribute definition
/**
* A class holding properties of the SubPanel.
*
* @class SubPanelSettings
* @for SubPanel
*/
subPanelAttr = {
/**
* A name used to identify the subpanel being opened (e.g. "Details", "Metadata")
*
* @property panelName
* @for SubPanelSettings
* @type {String}
* @default ""
*/
panelName: "",
/**
* Title of the content to be displayed on the SubPanel (e.g. "CESI Water Quality Indicators")
*
* @property title
* @type {String}
* @default ""
*/
title: "",
/**
* The text inside the subpanel. Can be String or a jQuery object. All nodes sporting CSS class
* ".shorten-candidate" are treated to the shortening procedure - long strings are curtailed, and [more/less] links are placed at their ends.
*
* @property content
* @type {String | jObject}
* @default null
*/
content: null,
/**
* The node after which the panel will be inserted (e.g. node.find(".layer-details")).
*
* @property target
* @type {jObject}
* @default null
*/
target: null,
/**
* The name of the module that requested to open the SubPanel (e.g. "filterManager"). Used for identification of the panel's loyalty.
*
* @property origin
* @type {String}
* @default ""
*/
origin: "",
/**
* A unique id of the SubPanel. If none provided, a random one is generated. It is used to determine the animation and update function
* to run on content update.
*
* @property guid
* @type {String}
* @default ""
*/
guid: "",
/**
* Indicates that the open SubPanel request is a content update to the already opened SubPanel.
* Does not trigger any of the `doOn-` or `doAfter-` functions.
*
* __Use case:__ the uses clicks on the metadata button.
* 1. A request to open a SubPanel is sent with only the title since the metadata content is not yet available
* 2. Metadata is fetched from the server
* 3. A second request to open a SubPanel is sent having `update` set to `true` and featuring the __same__ `guid` as the first request
* 4. Only the content of the SubPanel is updated; no extra animations are triggered
*
* @property update
* @type {Boolean}
* @default false
*/
update: false,
/**
* The callback function when the panel starts the opening animation; also triggered by updating panel content; can be triggered many times.
*
* @property doOnOpen
* @type {Function}
* @default null
*/
doOnOpen: null,
/**
* The callback function when the panel finishes the opening animation; also triggered by updating panel content; can be triggered many times.
*
* @property doAfterOpen
* @type {Function}
* @default null
*/
doAfterOpen: null,
/**
* The callback function when the panel starts the closing animation; also triggered by updating panel content; can be triggered many times.
*
* @property doOnHide
* @type {Function}
* @default null
*/
doOnHide: null,
/**
* The callback function when the panel becomes hidden; also triggered by updating panel content; can be triggered many times.
*
* @property doAfterHide
* @type {Function}
* @default null
*/
doAfterHide: null,
/**
* The callback function when the panel is completely closed, its nodes destroyed; can be triggered only once in a lifespan of the panel.
*
* @property doOnDestroy
* @type {Function}
* @default null
*/
doOnDestroy: null,
/**
* The callback function executed after the SubPanel content is updated.
* __Doesn't work correctly yet.__
*
* @property doAfterUpdate
* @type {Function}
* @default null
*/
doAfterUpdate: null,
/**
* The target number of chars after which a content text node will be shortened.
*
* @property showChars
* @type {Number}
* @default 170
*/
showChars: 170
},
// Panel Prototype
/**
* [subPanelPrototype description]
*
* @class SubPanel
* @constructor
* @for GUI
*/
subPanelPrototype = {
/**
* Indicates if the closing animation is under way.
*
* @property _closing
* @private
* @for SubPanel
* @type {Boolean}
* @default false
*/
_closing: false,
/**
* Holds a deferred that would destory the panel after the closing animation completes. May be interrupted.
*
* @property _destroyDeferred
* @type {Deferred}
* @private
* @default null
*/
_destroyDeferred: null,
/**
* SubPanel attributes
*
* @property _attr
* @private
* @default null
* @type {SubPanelSettings}
*/
_attr: null,
/**
* Indicates if the SubPanel is visible at the moment. Doesn't make the panel visible or invisible, just prevents animations on the content
* to run when it is set to `true`.
*
* @property _visible
* @private
* @default false
* @type {Boolean}
*/
_visible: false,
/**
* The outermost `div` of the SubPanel.
*
* @property container
* @default null
* @type {jObject}
*/
container: null,
/**
* The inner `div` of the SubPanel. Closing and opening animations are run on this `div`.
*
* @property panel
* @default null
* @type {jQobject}
*/
panel: null,
/**
* `div` housing the content of the SubPanel, including its title.
*
* @property _subPanelContentDiv
* @private
* @default null
* @type {jObject}
*/
_subPanelContentDiv: null,
/**
* Heading of the content in the SubPanel.
*
* @property _panelTitle
* @private
* @default null
* @type {jObject}
*/
_panelTitle: null,
/**
* `div` housing the content of the SubPanel, excluding its title.
*
* @property _panelContentDiv
* @private
* @default null
* @type {jObject}
*/
_panelContentDiv: null,
/**
* Default duration of the SubPanel animation in milliseconds.
*
* @property _animatePanelDuration
* @private
* @default 400
* @type {Number}
*/
_animatePanelDuration: 400,
/**
* Apply the shortening plugin to the panel data
*
* @method parseContent
* @param {jObject} data Content to be shortened
* @return {jObject} Content with after shortening long text nodes
*/
parseContent: function (data) {
//console.log(this._attr.showChars, jQuery.type(data), data);
return (jQuery.type(data) === "object" ? data : $(data))
.find(".shorten-candidate").shorten({
showChars: this._attr.showChars
})
.removeClass("shorten-candidate").end();
},
/**
* Returns this SubPanel's settings object.
*
* @method getAttributes
* @return {SubPanelSettings} This SubPanel's settings
*/
getAttributes: function () {
return this._attr;
},
/**
* Returns this SubPanel's container `div`.
*
* @method getContainer
* @return {jobject} This SubPanel's `div`
*/
getContainer: function () {
return this.container;
},
/**
* Retursn the inner `div` of the SubPanel
*
* @method getPanel
* @return {jObject} The inner `div` of the SubPanel
*/
getPanel: function () {
return this.panel;
},
/**
* Returns the `origin` of this SubPanel.
*
* @method getOrigin
* @return {String} The `origin` of this SubPanel
*/
getOrigin: function () {
return this._attr.origin;
},
/**
* Returns the `guid` of this SubPanel.
*
* @method getOrigin
* @return {String} The `guid` of this SubPanel
*/
getGuid: function () {
return this._attr.guid;
},
/**
* Destroys this SubPanel.
*
* @method destroy
* @param {Number} speed The duration of the animation in milliseconds
* @param {Deferred} deferred The deffered to be resolved after the SubPanel is destroyed
*/
destroy: function (speed, deferred) {
if (this._attr.doOnHide) {
this._attr.doOnHide();
}
this._closing = true;
this._destroyDeferred = deferred;
// remove CSS animation class to prevent flickering
this._subPanelContentDiv.find(".fadeInDown").removeClass("fadeInDown");
sidePanel.getContainer().after(this.container);
adjutSubPanelDimensions(this);
this.panel
.stop() // stop opening animation if it's present
.animate({
left: "100%"
}, (speed || this._animatePanelDuration), "easeOutCirc",
lang.hitch(this,
function () {
if (this._attr.doAfterHide) {
this._attr.doAfterHide();
}
if (this._attr.doOnDestroy) {
this._attr.doOnDestroy();
}
this._visible = false;
subPanelChange(false, this._attr.origin, null);
this.container.remove();
if (deferred) {
deferred.resolve(true);
}
}
)
);
},
/**
* Reopens the SubPanel - stops the closing animation and initiates the opening animation.
*
* @method reopen
*/
reopen: function () {
this.panel.stop();
this._closing = false;
if (this._destroyDeferred) {
this._destroyDeferred.cancel();
this._destroyDeferred = null;
}
this.open();
},
/**
* Opens the SubPanel. Sends out `EventManager.GUI.SUBPANEL_CHANGE` event.
*
* @method open
*/
open: function () {
if (this._attr.doOnOpen) {
this._attr.doOnOpen();
}
this._visible = true;
subPanelChange(true, this._attr.origin, this.container);
this.panel.animate({
left: 0
}, this._animatePanelDuration, "easeOutCirc",
lang.hitch(this,
function () {
if (this._attr.doAfterOpen) {
this._attr.doAfterOpen();
}
}
)
);
},
/**
* Assigns a new origin to the SubPanel.
*
* @method changeOrigin
* @param {String} newOrigin The new origin of the SubPanel.
*/
changeOrigin: function (newOrigin) {
this._attr.origin = newOrigin;
},
/**
* Shifts the SubPanel to the new node in the DOM.
*
* @method shiftTarget
* @param {jObject} newTarget A node in the DOM to shift the SubPanel to
*/
shiftTarget: function (newTarget) {
if (this._attr.target !== newTarget) {
// remove animation class to prevent flickering of data
this._subPanelContentDiv.find(".fadeInDown").removeClass("fadeInDown");
newTarget.after(this.container);
this._attr.target = newTarget;
}
},
/**
* Creates a new instance of SubPanel.
*
* @method create
* @param {SubPanelSettings} a Settings for the SubPanel
*/
create: function (a) {
var subPanelContent,
subPanelString,
parsedContent;
console.log("create panel, ", a.origin);
a.guid = a.guid || util.guid();
lang.mixin(this._attr, a);
subPanelContent = String.format(subPanelContentTemplate, this._attr.panelName, this._attr.title);
subPanelString = String.format(subPanelTemplate, subPanelContent);
this.container = this._attr.target.after(subPanelString).parent().find(".sub-panel-container");
this.panel = this.container.find(".sub-panel");
this._subPanelContentDiv = this.panel.find(".sub-panel-content");
this._panelTitle = this.panel.find(".panel-title");
this._panelContentDiv = this.panel.find(".panel-content-div");
// set content
parsedContent = this.parseContent(this._attr.content);
this._panelContentDiv.empty().append(parsedContent);
this.update(this._attr);
},
/**
* Performs an update of the content and title of the SubPanel, running appropriate animation and `doOn-` / `doAfter-` functions.
*
* @method update
* @param {SubPanelSettings} a New settings for the SubPanel
*/
update: function (a) {
// helper functions
var animateContentDuration = 300,
sOut = '<ul class="loadingAnimation"><li></li><li></li><li></li><li></li><li></li><li></li></ul>',
updateDefered = [new Deferred(), new Deferred()],
animateContent = function (node, newData, d) {
if (newData) {
node.addClass('animated fadeOutDown');
window.setTimeout(lang.hitch(this,
function () {
node
//.html(newData)
.empty().append(newData)
.removeClass("fadeOutDown")
.addClass('animated fadeInDown'); //.find(".shorten-candidate").shorten();
d.resolve();
}),
animateContentDuration);
}
},
setContent = function (node, oldData, newData, parsedData, visible, d) {
newData = (newData === null) ? parsedData = sOut : newData;
if (newData) {
if (newData !== oldData) {
if (visible) {
//ideally, need to wait until the animation completes before proceedding?
animateContent(node, parsedData, d);
} else {
node.empty().append(parsedData);
d.resolve();
}
} else {
d.resolve();
}
} else {
d.resolve();
}
},
updateContent = lang.hitch(this,
function (a) {
this._subPanelContentDiv.animate({
scrollTop: 0
}, animateContentDuration, "easeOutCirc");
setContent(this._panelTitle, this._attr.title, a.title, a.title, this._visible, updateDefered[0]);
setContent(this._panelContentDiv, this._attr.content, a.content, this.parseContent(a.content), this._visible, updateDefered[1]);
lang.mixin(this._attr, a);
}
);
// doAfterUpdate should be called AFTER update (animation) completes...
util.afterAll(updateDefered, function () {
if (a.doAfterUpdate) {
a.doAfterUpdate();
}
});
// panel is closing; new data is not an update
if (this._closing && !a.update) {
//
if (this._attr.guid !== a.guid) {
if (this._attr.doOnHide) {
this._attr.doOnHide();
}
if (this._attr.doAfterHide) {
this._attr.doAfterHide();
}
// move panel to the new target
a.target.after(this.container);
updateContent(a);
}
this.reopen();
// panel is not closing
} else if (!this._closing) {
// data is not an update
if (!a.update && this._attr.guid !== a.guid) {
if (this._attr.doOnHide) {
this._attr.doOnHide();
}
if (this._attr.doAfterHide) {
this._attr.doAfterHide();
}
// move panel to the new target
a.target.after(this.container);
updateContent(a);
if (a.doOnOpen) {
a.doOnOpen();
}
if (a.doAfterOpen) {
a.doAfterOpen();
}
}
// guid is the same - data can update or not (should be an update)
//if (a.update && attr.guid === a.guid) {
if (this._attr.guid === a.guid) {
updateContent(a);
}
}
}
},
mapToolbar = $("#map-toolbar"),
helpToggle = $("#helpToggle"),
helpSectionContainer = $("#help-section-container"),
helpSection = $("#help-section"),
addLayerToggle = $("#addLayer-toggle"),
addLayerSectionContainer = $("#addLayer-section-container"),
//AddLayerSection = $("#addLayer-section"),
viewPortHeight,
footerHeight = wbFoot.height(),
/**
* Specifies the hight of the footer in the full-screen mode. Should be smaller than `footerHeight`.
*
* @property footerDelta
* @private
* @type {Number}
*/
footerDelta = 20, // the height of the footer in the fullscreen mode
fullScreenToggle = $("#fullScreenToggle"),
titleBanner = $("#gcwu-bnr"),
titleBannerHalfHeight = $("#gcwu-title-in .ui-link").height() / 2,
/**
* The height difference between the normal and full-screen modes.
*
* @property fullScreenDelta2
* @private
* @type {Number}
*/
fullScreenDelta2 = $("nav[role='navigation']:first").height() +
$("#gcwu-psnb-in").height() +
titleBannerHalfHeight +
12 + footerDelta,
megaMenuDiv = $("#gcwu-psnb-in"),
megaMenu = megaMenuDiv.find('.mb-menu'),
navigation = $("nav[role='navigation']:first"),
megamenuBar = megaMenuDiv.find(".wet-boew-menubar"),
subTitleText = $(".cn-site-title-italic"),
cssButtonPressedClass = "button-pressed",
cssExpandedClass = "state-expanded",
helpPanelPopup,
addLayerPanelPopup,
sidePanel;
/**
* SidePanel Class
*
* @class SidePanel
* @constructor
* @for GUI
*/
sidePanel = (function () {
var mapDiv = $("#map-div"),
panelDiv = $("#panel-div"),
panelToggle = $("#panel-toggle"),
popup,
panelWidthDefault;
/**
* Publishes `PANEL_CHANGE` event when the visibility of the SidePanel changes.
*
* @method panelChange
* @param {Boolean} visible Indicates whether the SidePanel is visible or not
* @for SidePanel
* @private
*/
function panelChange(visible) {
topic.publish(EventManager.GUI.PANEL_CHANGE, {
visible: visible
});
}
/**
* Return the default width of the SidePanel.
*
* @method getPanelWidthDefault
* @private
* @return {Number} The default width of the SidePanel
*/
function getPanelWidthDefault() {
if (!panelWidthDefault) {
panelWidthDefault = panelDiv.width();
}
return panelWidthDefault;
}
/**
* Slides the SidePanel open.
*
* @method openPanel
* @private
* @param {Deferred} d A deferred to be resolved upon completion of the animation
*/
function openPanel(d) {
/*panelDiv.show();
mapDiv.animate({
width: mapDiv.width() - getPanelWidthDefault()
}, "slow", "easeOutCirc");
panelDiv.animate({
right: 0
}, "slow", "easeOutCirc", function () {
layoutChange();
panelChange(true);
d.resolve();
});*/
$(".viewport").removeClass("side-panel-mode");
window.setTimeout(function () {
layoutChange();
panelChange(true);
d.resolve();
}, 500);
}
/**
* Slide the SidePanel close
*
* @method closePanel
* @private
* @param {Deferred} d A deferred to be resolved upon completion of the animation
*/
function closePanel(d) {
// animating map
// mapDiv.animate({
// width: mapDiv.width() + getPanelWidthDefault()
// }, "slow", "easeOutCirc");
// // animating panel
// panelDiv.animate({
// right: -getPanelWidthDefault()
// }, "slow", "easeOutCirc", function () {
// panelDiv.hide();
// util.subscribeOnce("map/update-end", function () {
// console.log("map/update-end from gui");
// panelChange(false);
// });
// layoutChange();
// d.resolve();
// });
$(".viewport").addClass("side-panel-mode");
//mapDiv.css({ "width": mapDiv.width() + getPanelWidthDefault() });
//panelDiv.css({ "right": -getPanelWidthDefault() });
window.setTimeout(function () {
util.subscribeOnce("map/update-end", function () {
console.log("map/update-end from gui");
panelChange(false);
});
layoutChange();
d.resolve();
}, 500);
}
return {
/**
* Initialize a newly create SidePanel.
*
* @method init
*/
init: function () {
popup = popupManager.registerPopup(panelToggle, "click",
openPanel, {
activeClass: cssExpandedClass,
closeHandler: closePanel
}
);
topic.subscribe(EventManager.GUI.PANEL_TOGGLE, function () {
popup.toggle();
});
},
/**
* Retunrs the outter most `div` of this SidePanel.
*
* @method getContainer
* @return {jObject} The outter most `div` of this SidePanel
*/
getContainer: function () {
return panelDiv;
},
/**
* Gets the width of this SidePanel.
*
* @method width
* @return {Number} The width of this SidePanel
*/
width: function () {
return panelDiv.filter(":visible").width();
}
};
} ());
/**
* Create a new SubPanel with the settings provided.
*
* @private
* @method newSubPanel
* @param {SubPanelSettings} attr SubPanel settings
* @return {SubPanel} A newly created SubPanel
* @for GUI
*/
function newSubPanel(attr) {
var subPanel = Object.create(subPanelPrototype);
subPanel._attr = Object.create(subPanelAttr);
subPanel.create(attr);
adjutSubPanelDimensions(subPanel);
return subPanel;
}
/**
* Fires an event when the layout of the page changes.
*
* @method layoutChange
* @private
*/
function layoutChange() {
topic.publish(EventManager.GUI.LAYOUT_CHANGE);
}
/**
* Fires an even when the subpanel closes or opens.
*
* @method subPanelChange
* @private
* @param {Boolean} visible indicates whether the panel is visible or not
* @param {String} origin origin of the subpanel
* @param {JObject} container subpanel container
*/
function subPanelChange(visible, origin, container) {
topic.publish(EventManager.GUI.SUBPANEL_CHANGE, {
visible: visible,
origin: origin,
container: container,
offsetLeft: (container) ? container.width() + 25 + sidePanel.width() : sidePanel.width()
});
}
/**
* Adjusts dimensions of the help panel relative to the mapContent `div`.
*
* @method adjustHelpDimensions
* @private
*/
function adjustHelpDimensions() {
helpSection.css({
"max-height": mapContent.height() - 56 // 56 is an arbitrary-wide gap between the help panel and the upper toolbar
});
}
/**
* Adjusts the dimensions and position of the SubPanel when layout of the page is changing.
*
* @method adjutSubPanelDimensions
* @private
* @param {SubPanel} subPanel SubPanel whose dimensions and position need to be adjusted
*/
function adjutSubPanelDimensions(subPanel) {
function adjust(p, d) {
if (p) {
p.getContainer()
.height(viewPortHeight - mapToolbar.height());
/*.position({
my: "right top",
at: "right top+32",
of: "#map-div" // mapContent
});*/
if (d) {
d.resolve(true);
}
}
}
if (subPanel) {
adjust(subPanel);
} else {
util.executeOnDone(subPanels, adjust);
}
}
/**
* Adjust the height of the body of the page on initial load and every page resize.
*
* @method adjustHeight
* @private
*/
function adjustHeight() {
viewPortHeight = jWindow.height() - wbHead.filter(":visible").height() - wbFoot.height();
wbCore.height(viewPortHeight);
mapContent.height(viewPortHeight - mapToolbar.height());
adjustHelpDimensions();
layoutChange();
}
/**
* Adjusts the width of the slide out panel and the map section.
*
* @method adjustWidth
* @private
*/
function adjustWidth() {
adjustHeight();
mapDiv.width(wbMainIn.width() - sidePanel.width());
adjutSubPanelDimensions();
}
/**
* Animate the footer during full-screen transitions.
*
* @method toggleFooter
* @private
*/
function toggleFooter() {
wbFoot.animate({
height: footerHeight - Math.max(0, footerDelta)
}, "slow");
footerDelta *= -1;
}
/**
* Adjust the SubPanels to the full-screen mode of the page.
*
* @method toggleSubPanelContainer
* @private
*/
function toggleSubPanelContainer() {
function adjust(p, d) {
if (p) {
p.getContainer().animate({
height: viewPortHeight + fullScreenDelta2 - 32,
top: p.getContainer().position().top - fullScreenDelta2 + footerDelta
}, "slow");
if (d) {
d.resolve(true);
}
}
}
util.executeOnDone(subPanels, adjust);
}
/**
* Creates and opens a new SubPanel with given settings.
* If the SubPanel with the requested `origin` is already present, updates its content.
*
* @method showSubPanel
* @private
* @param {SubPanelSettings} attr Settings for the SubPanel instance
*/
function showSubPanel(attr) {
var deferred = new Deferred(),
subPanel;
deferred.then(function () {
attr = subPanel.getAttributes();
subPanel = subPanels[attr.origin];
subPanel.open();
subPanel.getPanel().find(".sub-panel-toggle").on("click",
lang.hitch(this, function () {
hideSubPanel(attr);
}));
loadIndicator.animate({
right: subPanel.getPanel().width() + 6
}, "easeOutCirc");
});
// take over the panel spawned by other components
if (attr.consumeOrigin && subPanels[attr.consumeOrigin]) {
subPanel = subPanels[attr.consumeOrigin];
subPanel.changeOrigin(attr.origin);
subPanel.shiftTarget(attr.target);
delete subPanels[attr.consumeOrigin];
subPanels[attr.origin] = subPanel;
}
if (subPanels[attr.origin]) {
// if the panel exists, just update it
subPanels[attr.origin].update(attr);
} else if (!attr.update) {
// create if doesn't
subPanel = newSubPanel(attr);
subPanels[attr.origin] = subPanel;
// close all other panels; and open the newly created one after all others are closed
util.executeOnDone(subPanels,
function (p, d) {
if (p && p.getOrigin() !== attr.origin) {
hideSubPanel({
origin: p.getOrigin()
}, 200, d);
} else {
d.resolve(true);
}
},
deferred);
}
}
/**
* Closes the SubPanel whose `origin` is specified in the `attr` parameter.
*
* @method hideSubPanel
* @private
* @param {SubPanelSettings} attr only `origin` attribute is required here
* @param {Number} speed Duration of the closing animation
* @param {Deferred} d The deferred object to be resolved upon successful closing of the panel
*/
function hideSubPanel(attr, speed, d) {
var deferred = new Deferred(function () {
if (d) {
d.cancel();
}
});
deferred.then(function () {
// remove the panel from from the object after it closes
delete subPanels[attr.origin]; // more on delete: http://perfectionkills.com/understanding-delete/
if (d) {
d.resolve(true);
}
});
if (subPanels[attr.origin]) {
subPanels[attr.origin].destroy(speed, deferred);
loadIndicator.animate({
right: 3
}, "easeOutCirc");
}
}
/**
* Moves the SubPanel with the specified `origin` in the DOM hierarchy to the new specified `target`; if `target` is not specified, the SubPanel is attached to the SidePanel.
*
* @method dockSubPanel
* @private
* @param {SubPanelSettings} attr Settings for the SubPanel; only `target` and `origin` are required here
*/
function dockSubPanel(attr) {
var target = attr.target || sidePanel.getContainer(),
subPanel = subPanels[attr.origin];
if (subPanel) {
//console.log("docking subpanel");
subPanel.shiftTarget(target);
}
}
/**
* Finds a SubPanel with `origin` equal to the supplied `consumeOrigin` and
* + changes its `origin` to the supplied `origin`
* + moves the SubPanel in the DOM hierarchy and attaches it to the specified target
*
* @method captureSubPanel
* @private
* @param {SubPanelSettings} attr Settings for the SubPanel; only `origin`, `consumeOrigin` and `target` are required here
*/
function captureSubPanel(attr) {
var subPanel;
if (attr.consumeOrigin === attr.origin && subPanels[attr.consumeOrigin]) {
subPanel = subPanels[attr.origin];
subPanel.shiftTarget(attr.target);
} else if (attr.consumeOrigin && subPanels[attr.consumeOrigin]) {
subPanel = subPanels[attr.consumeOrigin];
subPanel.changeOrigin(attr.origin);
subPanel.shiftTarget(attr.target);
delete subPanels[attr.consumeOrigin];
subPanels[attr.origin] = subPanel;
}
}
/**
* Toggles the FullScreen mode of the application
*
* @method toggleFullScreenMode
* @private
* @param {boolean} fullscreen true/undefined - expand; false - collapse
*/
function toggleFullScreenMode(fullscreen) {
megaMenu.css({
position: "static"
});
subTitleText.css({
position: "static"
});
toggleSubPanelContainer();
toggleFooter();
wbCore.animate({
height: viewPortHeight + fullScreenDelta2
}, "slow");
titleBanner.animate({
height: titleBanner.height() - titleBannerHalfHeight
}, "slow");
if (util.isUndefined(fullscreen)) {
// If expand is undefined, we toggle
titleBannerHalfHeight *= -1;
fullScreenDelta2 *= -1;
} else if (fullscreen) {
titleBannerHalfHeight = -1;
fullScreenDelta2 = -Math.abs(fullScreenDelta2);
} else {
titleBannerHalfHeight = 1;
fullScreenDelta2 = Math.abs(fullScreenDelta2);
}
var strings = GlobalStorage.config.stringResources;
fullScreenToggle.text(fullScreenDelta2 < 0 ? strings.txtShowHeaders : strings.txtFullScreen);
navigation.slideToggle("slow");
//subTitleText.slideToggle("fast");
megaMenuDiv.slideToggle("slow",
function () {
megaMenu.removeAttr('style');
// needed to prevent "disappearing toolbar" effect
megamenuBar.css({
"min-height": "32px"
});
adjustHeight();
adjutSubPanelDimensions();
});
// fullScreenDelta2 is positive when the map is collapsed
// and negative when the map is expanded
// Event used in BookmarkLink
topic.publish(EventManager.GUI.FULLSCREEN_CHANGE, {
fullscreen: (fullScreenDelta2 < 0)
});
}
return {
/**
* Call load to initialize the GUI module.
*
* @method load
* @param {Number} id ID of this module
* @param {?} req ???
* @param {Function} load The callback function
*/
load: function (id, req, load) {
// measure available space on every page resize
//jWindow.on("resize", adjustWidth);
sidePanel.init();
// registring help popup
helpPanelPopup = popupManager.registerPopup(helpToggle, "click",
function (d) {
topic.publish(EventManager.GUI.HELP_PANEL_CHANGE, {
visible: true
});
console.log(EventManager.GUI.HELP_PANEL_CHANGE + "; visible:", true);
helpSectionContainer.slideToggle("fast", function () {
d.resolve();
});
}, {
activeClass: cssButtonPressedClass,
target: helpSectionContainer,
closeHandler: function (d) {
topic.publish(EventManager.GUI.HELP_PANEL_CHANGE, {
visible: false
});
console.log(EventManager.GUI.HELP_PANEL_CHANGE + "; visible:", false);
helpSectionContainer.slideToggle("fast", function () {
d.resolve();
});
}
}
);
topic.subscribe(EventManager.BookmarkLink.GETLINKPANEL_CHANGED, function (attr) {
if (helpPanelPopup.isOpen() && attr.visible) {
helpPanelPopup.close();
}
});
//Start AddLayer popup controller
addLayerPanelPopup = popupManager.registerPopup(addLayerToggle, "click",
function (d) {
topic.publish(EventManager.GUI.ADD_LAYER_PANEL_CHANGE, {
visible: true
});
console.log(EventManager.GUI.ADD_LAYER_PANEL_CHANGE + " visible:", true);
addLayerSectionContainer.slideToggle("fast", function () {
d.resolve();
});
}, {
activeClass: cssButtonPressedClass,
target: addLayerSectionContainer,
closeHandler: function (d) {
topic.publish(EventManager.GUI.ADD_LAYER_PANEL_CHANGE, {
visible: false
});
console.log(EventManager.GUI.ADD_LAYER_PANEL_CHANGE + " visible:", false);
addLayerSectionContainer.slideToggle("fast", function () {
d.resolve();
});
}
}
);
topic.subscribe(EventManager.BookmarkLink.GETLINKPANEL_CHANGED, function (attr) {
if (addLayerPanelPopup.isOpen() && attr.visible) {
addLayerPanelPopup.close();
}
});
$("#addLayer-add").on("click", function () {
topic.publish(EventManager.Map.ADD_LAYER, null);
addLayerSectionContainer.slideToggle("fast");
});
//End Add Layer
//start extended grid
topic.subscribe("gui/grid/expand", function () {
$(".viewport").toggleClass("data-panel-mode");
// console.log("grid expansion event started");
// $("#map-div").addClass("wb-invisible");
// $("#panel-div").addClass("wb-invisible");
// $("#panel-fullgrid").removeClass("wb-invisible");
});
// $("#full-grid-collapse").on("click", function () {
// topic.publish("gui/grid/collapse");
// });
// topic.subscribe("gui/grid/collapse", function () {
// console.log("grid collapse event started");
// $("#map-div").removeClass("wb-invisible");
// $("#panel-div").removeClass("wb-invisible");
// $("#panel-fullgrid").addClass("wb-invisible");
// });
// $("#full-grid-test").on("click", function () {
// topic.publish(EventManager.GUI.SUBPANEL_OPEN, {
// panelName: "Grid Details",
// title: "Title",
// content: "<p>panel content!!!!</p>",
// target: $("#fullgrid-top-panel"),
// origin: "fullgrid-top-panel",
// consumeOrigin: "fullgrid-top-panel",
// guid: 1000,
// doOnOpen: function () {
// },
// doOnHide: function () {
// },
// doOnDestroy: function () {
// }
// });
// });
//end extended grid
//fullScreenToggle.click(toggleFullScreenMode);
fullScreenToggle.click(function () {
$('body').toggleClass("full-screen");
window.setTimeout(function () {
layoutChange();
}, 500);
});
topic.subscribe(EventManager.GUI.TOGGLE_FULLSCREEN, function (evt) {
toggleFullScreenMode(evt.expand);
$('body').toggleClass("full-screen");
});
topic.subscribe(EventManager.GUI.SUBPANEL_OPEN, function (attr) {
showSubPanel(attr);
});
topic.subscribe(EventManager.GUI.SUBPANEL_CLOSE, function (attr) {
if (attr.origin === "all") {
utilDict.forEachEntry(subPanels, function (key) {
//attr.origin = key;
hideSubPanel({
origin: key
});
});
} else {
dojoArray.forEach(attr.origin.split(","), function (element) {
//attr.origin = element;
hideSubPanel({
origin: element
});
});
}
});
topic.subscribe(EventManager.GUI.SUBPANEL_DOCK, function (attr) {
dockSubPanel(attr);
});
topic.subscribe(EventManager.GUI.SUBPANEL_CAPTURE, function (attr) {
var na;
if (attr.consumeOrigin === "all") {
utilDict.forEachEntry(subPanels, function (key) {
na = Object.create(attr);
na.consumeOrigin = key;
captureSubPanel(na);
});
} else {
dojoArray.forEach(attr.consumeOrigin.split(","), function (element) {
na = Object.create(attr);
na.consumeOrigin = element;
captureSubPanel(na);
});
}
console.log(EventManager.GUI.SUBPANEL_CAPTURE);
});
panelTabs.find("li a").click(function () {
topic.publish(EventManager.GUI.TAB_SELECTED, {
id: this.id,
tabName: this.attributes["data-panel-name"].value
});
panelTabs.find("li:not(.active) a").each(
function () {
topic.publish(EventManager.GUI.TAB_DESELECTED, {
id: this.id,
tabName: this.attributes["data-panel-name"].value
});
});
});
//adjustWidth();
// if the vertical space is too small, trigger the full-screen
if (mapContent.height() < jWindow.height() * 0.6) {
//toggleFullScreenMode(true);
}
popupManager.registerPopup($("#tools"), "hoverIntent",
function (d) {
$("#tools-container").slideDown("fast", function () { d.resolve(); });
},
{
activeClass: cssButtonPressedClass,
target: $("#tools-container"),
closeHandler: function (d) {
$("#tools-container").slideUp("fast", function () { d.resolve(); });
},
timeout: 500
}
);
// return the callback
load();
}
};
}
);