blob: 10d7fa90d68b85fd8b0891094c07c4fb0c75dbc9 [file] [log] [blame]
var mercury = require('mercury');
var insertCss = require('insert-css');
var AttributeHook = require('../../lib/mercury/attribute-hook');
var sidebar = require('../sidebar/index');
var mainContent = require('../main-content/index');
var css = require('./index.css');
var h = mercury.h;
module.exports = create;
module.exports.render = render;
/*
* Page level layout of the application
*/
function create() {
var state = mercury.varhash({
/*
* Whether the sidebar drawer is visible
* @type {boolean}
*/
sidebarOpened: mercury.value(false),
/*
* Title text to display in the toolbar
* @type {string}
*/
title: mercury.value(''),
/*
* Toast messages to display
* @type {Array<Object>}
*/
toasts: mercury.array([])
});
var events = mercury.input([
'openSidebar',
'closeSidebar',
'deferRemoveToast',
]);
wireUpEvents(state, events);
return {
state: state,
events: events
};
}
/*
* Draw the full page of the application, which consists of a sidebar and main
* panel. The sidebar is usually hidden but acts as a selector for the content
* shown in the main panel. This content is rendered in the full browser window.
*
* See @app.js for the state definition. See @sidebar/index.js and
* @main-content/index.js for their rendering functions.
*/
function render(state, events) {
insertCss(css);
if(!state.navigation.pageKey) {
return mercury.h('paper-loading');
}
var panelAttributes = {
// Keep the drawer collapsed for any width size
'responsiveWidth': new AttributeHook('10000px'),
// If drawer is open, clicking anywhere should close it
'ev-click': (state.viewport.sidebarOpened ?
mercury.event(events.viewport.closeSidebar) : null),
'selected': new AttributeHook(state.viewport.sidebarOpened ?
'drawer' : 'main')
};
return h('core-drawer-panel.panel', panelAttributes, [
h('core-header-panel.drawer', {
'drawer': new AttributeHook(true)
}, [
renderSideToolbar(state, events),
sidebar.render(state, events)
]),
h('core-header-panel.main', {
'main': new AttributeHook(true)
}, [
renderMainToolbar(state, events),
mainContent.render(state, events),
renderToasts(state, events)
])
]);
}
/*
* The title of the sidebar.
*/
function renderSideToolbar(state, events) {
return h('core-toolbar.toolbar', [
h('h1.title', 'Namespace Browser')
]);
}
/*
* The title of the main content.
*/
function renderMainToolbar(state, events) {
return h('core-toolbar.toolbar', [
h('paper-icon-button.drawer-toggle', {
'id': 'drawerToggle',
'icon': new AttributeHook('menu'),
'ev-click': mercury.event(events.viewport.openSidebar)
}),
h('h2.title', state.viewport.title),
mainContent.renderHeader(state,events)
]);
}
/*
* Draws all the toasts stored in the state. Old toasts remain hidden.
*
* TODO(alexfandrianto): In order to limit mercury state, we attempt to purge
* state.viewport.toasts. core-overlay-close-completed isn't always fired if
* too many occur in the same time range, so setTimeout upon core-overlay-open-
* completed works to solve that.
* TODO(alexfandrianto): Try to get autoCloseDisabled accepted by Polymer so
* that the paper-toast behavior is more consistent.
*/
function renderToasts(state, events) {
return h('div.toasts', state.viewport.toasts.map(function(toast) {
return renderToast(toast, events);
}));
}
/*
* Draws a short duration toast to inform the user.
*/
var toastDuration = 3000; // ms
function renderToast(toast, events) {
// The toast type affects the css class
var cssClass = toast.type || 'info';
// If there is an event attached to the toast, draw it here.
var children = [];
if (toast.actionText) {
children.push(h('div', {
'ev-click': toast.action
}, toast.actionText));
}
return h('paper-toast.' + cssClass, {
'key': toast.key, // unique per toast => only drawn once
'text': new AttributeHook(toast.text),
'opened': new AttributeHook(true),
'duration': new AttributeHook(toastDuration),
'autoCloseDisabled': new AttributeHook(true),
// Clean up the old toasts after enough time has passed.
'ev-core-overlay-open-completed': mercury.event(
events.viewport.deferRemoveToast,
toast.key
)
}, children);
}
/*
* Wire up events that we know how to handle.
*/
function wireUpEvents(state, events) {
events.openSidebar(function() {
state.sidebarOpened.set(true);
});
events.closeSidebar(function() {
state.sidebarOpened.set(false);
});
events.deferRemoveToast(function(key) {
// Remove the toast after a reasonable delay.
setTimeout(function() {
// Filter out the toast whose key matches.
state.put('toasts', state.toasts.filter(function(toast) {
return !toast.key.equals(key);
}));
}, toastDuration);
});
}