/**
* Copyright (C) 2005-2016 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* <p>This widget provides a simple way in which you can keep a "header" and/or "footer" always visible whilst
* any overflowing main content is scrolled. The [header]{@link module:alfresco/layout/FixedHeaderFooter#widgetsForHeader},
* [footer]{@link module:alfresco/layout/FixedHeaderFooter#widgetsForFooter} and
* [main content]{@link module:alfresco/layout/FixedHeaderFooter#widgetsForFooter} should be defined as standard
* widget models.</p>
* <p>The overall [height]{@link module:alfresco/layout/FixedHeaderFooter#height} of the widget can be explicitly
* set but can also be left (or set) to the default value of "auto" which will make the widget take up all the available
* space in the client window below it.</p>
*
* @example <caption>Example configuration:</caption>
* {
* name: "alfresco/layout/FixedHeaderFooter",
* config: {
* height: "auto",
* widgetsForHeader: [
* {
* name: "alfresco/menus/AlfMenuBar",
* config: {
* widgets: [
* {
* name: "alfresco/menus/AlfMenuBarItem",
* config: {
* label: "Menu item in header"
* }
* }
* ]
* }
* }
* ],
* widgets: [
* {
* name: "alfresco/lists/AlfList",
* config: {
* currentData: {
* items: [
* { name: "one" }, { name: "two" }, { name: "three" }
* ]
* },
* widgets: [
* {
* name: "alfresco/lists/views/HtmlListView",
* config: {
* propertyToRender: "name"
* }
* }
* ]
* }
* }
* ],
* widgetsForFooter: [
* {
* name: "alfresco/menus/AlfMenuBar",
* config: {
* popupMenusAbove: true,
* widgets: [
* {
* name: "alfresco/menus/AlfMenuBarItem",
* config: {
* label: "Menu item in footer"
* }
* }
* ]
* }
* }
* ]
* }
* }
*
* @module alfresco/layout/FixedHeaderFooter
* @extends module:alfresco/core/ProcessWidgets
* @author Martin Doyle
* @author Dave Draper
*/
define(["alfresco/core/ProcessWidgets",
"alfresco/core/ResizeMixin",
"alfresco/layout/HeightMixin",
"alfresco/layout/DynamicVisibilityResizingMixin",
"dojo/_base/array",
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/aspect",
"dojo/dom-class",
"dojo/dom-construct",
"dojo/dom-style",
"dojo/topic",
"dojo/text!./templates/FixedHeaderFooter.html"],
function(ProcessWidgets, ResizeMixin, HeightMixin, DynamicVisibilityResizingMixin, array, declare, lang, aspect,
domClass, domConstruct, domStyle, topic, template) {
return declare([ProcessWidgets, ResizeMixin, HeightMixin, DynamicVisibilityResizingMixin], {
/**
* The base class for the widget
*
* @instance
* @type {string}
* @default
*/
baseClass: "alfresco-layout-FixedHeaderFooter",
/**
* An array of the CSS files to use with this widget.
*
* @instance
* @type {object[]}
* @default [{cssFile:"./css/FixedHeaderFooter.css"}]
*/
cssRequirements: [{
cssFile: "./css/FixedHeaderFooter.css"
}],
/**
* If this widget is placed into a widget that has padding then this allowance can be configured which
* will be substituted from the calculated height to take padding into account so that an outer scroll
* bar is not required on the page. This defaults to 0 and has only been provided for potential
* convenience. This value will only be used on when [height]{@link module:alfresco/layout/FixedHeaderFooter#height}
* is set to "auto" (which is also the default).
*
* @instance
* @type {number}
* @default
* @deprecated Since 1.0.36 use [heightAdjustment]{@link module:alfresco/layout/HeightMixin#heightAdjustment} instead
*/
autoHeightPaddingAllowance: 0,
/**
* The height of the widget (in CSS units). The default value is "auto" which means that the
* height of the widget will automatically be set to take up the available space from its current
* position to the bottom of the window or document (whichever is smallest) so that the entire
* widget is visible on page load. If a percentage height is set it is imperative that the enclosing
* DOM element has a fixed height (e.g. a value in pixels) otherwise the height will be calculated
* as 0.
*
* @instance
* @type {string}
* @default
* @deprecated Since 1.0.36 use [heightMode]{@link module:alfresco/layout/HeightMixin#heightMode} instead
*/
height: "AUTO",
/**
* If this is configured to be true the height of the widget will be reset as the browser window is resized.
* This will only occur when [height]{@link module:alfresco/layout/FixedHeaderFooter#height} is set to "auto"
* (which is also the default).
*
* @instance
* @type {boolean}
* @default
*/
recalculateAutoHeightOnResize: true,
/**
* The HTML template to use for the widget.
*
* @instance
* @type {String}
*/
templateString: template,
/**
* Run after widget has been created
*
* @instance
*/
postCreate: function alfresco_layout_FixedHeaderFooter__postCreate() {
// Get the details of the header and footer widgets that needs to iterate over looking
// for visibility configuration topics to subscribe to...
var widgets = [];
if (this.widgetsForHeader && typeof this.widgetsForHeader.concat === "function")
{
widgets = this.widgetsForHeader.concat(widgets);
}
if (this.widgetsForFooter && typeof this.widgetsForFooter.concat === "function")
{
widgets = this.widgetsForFooter.concat(widgets);
}
this.visibilityRuleTopics = this.getVisibilityRuleTopics(widgets);
// We need to potentially resize sometimes ... use these triggers
this.alfSetupResizeSubscriptions(this.onResize, this);
// This is to fix the fact that the FixedHeaderFooter didn't originally use the
// HeightMixin and was expecting a "height" rather than a "heightMode" attribute.
// It was also expecting "auto" rather than "AUTO" so for backwards compatibility
// we convert non-numeric values to be all uppercase.
if (this.height !== "AUTO" && this.heightMode === "AUTO")
{
this.heightMode = this.height;
if (typeof this.heightMode.toUpperCase === "function")
{
this.heightMode = this.heightMode.toUpperCase();
}
}
if (this.autoHeightPaddingAllowance && !this.heightAdjustment)
{
this.heightAdjustment = this.autoHeightPaddingAllowance;
}
this.setHeight(this.domNode);
// Add in the widgets
this._doProcessWidgets([
{
widgets: this.widgetsForHeader,
node: this.header
},
{
widgets: this.widgets,
node: this.content
},
{
widgets: this.widgetsForFooter,
node: this.footer
}
]);
// Do the resize
this.onResize();
this.alfPublishResizeEvent(this.domNode);
// Setup the header resize listener
this.own(this.addResizeListener(this.header));
},
/**
* <p>Setup a listener that will call [alfPublishResizeEvent]{@link module:alfresco/core/ResizeMixin#alfPublishResizeEvent}
* whenever a resize is detected in the header.</p>
*
* <p><strong>NOTE:</strong> This method is no longer called by the postCreate method, and will be removed in a future version</p>
*
* @instance
* @since 1.0.41
* @deprecated Since 1.0.42 - use [ResizeMixin.addResizeListener]{@link module:alfresco/core/ResizeMixin#addResizeListener} instead.
*/
addHeaderResizeListener: function alfresco_layout_FixedHeaderFooter__addHeaderResizeListener() {
this.addResizeListener(this.header, this.domNode);
},
/**
* Extends the [inherited function]{@link module:alfresco/core/CoreWidgetProcessing#allWidgetsProcessed}
* to set up subscriptions for the [visibilityRuleTopics]{@link module:alfresco/layout/DynamicVisibilityResizingMixin#visibilityRuleTopics}
* that are returned by calling [getVisibilityRuleTopics]{@link module:alfresco/layout/DynamicVisibilityResizingMixin#getVisibilityRuleTopics}.
* The subscriptions need to be created after the widgets have been created in order that their visibility
* is adjusted before the [onResize]{@link module:alfresco/layout/FixedHeaderFooter#onResize} function that is bound
* to is called.
*
* @instance
* @param {object[]} widgets The widgets that have been created
* @since 1.0.38
*/
allWidgetsProcessed: function alfresco_layout_FixedHeaderFooter__allWidgetsProcessed(/*jshint unused:false*/ widgets) {
this._allWidgetsProcessedCount--;
if (this._allWidgetsProcessedCount === 0)
{
this.subscribeToVisibilityRuleTopics(this.onResize);
}
},
/**
* Call the processWidgets function for all provided widgets
*
* @instance
* @param {object[]} widgetInfos The widget information as objects with 'widgets' and 'node' properties
*/
_doProcessWidgets: function alfresco_layout_FixedHeaderFooter___doProcessWidgets(widgetInfos) {
this._allWidgetsProcessedCount = widgetInfos.length;
array.forEach(widgetInfos, function(widgetInfo) {
var widgets = widgetInfo.widgets,
node = widgetInfo.node;
if (widgets && widgets.length)
{
this.processWidgets(widgets, node);
}
else
{
domClass.add(node, "hidden");
}
}, this);
},
/**
* Resize the header/content/footer containers so that the
* content fits between the header and footer.
*
* @instance
*/
onResize: function alfresco_layout_FixedHeaderFooter__onResize() {
if (this.recalculateAutoHeightOnResize === true)
{
this.setHeight(this.domNode);
}
var widgetHeight = this.domNode.offsetHeight,
headerHeight = this.header.offsetHeight,
footerHeight = this.footer.offsetHeight;
domStyle.set(this.content, {
top: headerHeight + "px",
height: (widgetHeight - headerHeight - footerHeight) + "px"
});
}
});
});