import $ from '$qui/lib/jquery.module.js'
import Logger from '$qui/lib/logger.module.js'
import {Mixin} from '$qui/base/mixwith.js'
import StockIcon from '$qui/icons/stock-icon.js'
import VisibilityManager from '$qui/utils/visibility-manager.js'
import * as Window from '$qui/window.js'
const logger = Logger.get('qui.views.commonviews.structuredview')
/** @lends qui.views.commonviews.StructuredViewMixin */
const StructuredViewMixin = Mixin((superclass = Object) => {
/**
* A view with top, body and bottom elements. Designed to be mixed together with {@link qui.views.ViewMixin}.
* @alias qui.views.commonviews.StructuredViewMixin
* @mixin
*/
class StructuredViewMixin extends superclass {
/**
* @constructs
* @param {?String} [title] view title (set to `null` if you don't want a view top at all)
* @param {qui.icons.Icon} [icon] view icon
* @param {Boolean} [minimizable] indicates that the view should be minimizable by clicking on its top bar
* (defaults to `false`)
* @param {Boolean} [minimized] indicates that the view should be initially minimized (defaults to `false`)
* @param {Boolean} [largeTop] indicates that the view top bar should be larger (defaults to `true`)
* @param {Boolean} [topless] indicates that the view should not have a top bar (defaults to `false`)
* @param {Boolean} [closable] set to `true` to display a close button on the top bar (defaults to `false`,
* ignored when `minimizable` is `true`)
* @param {...*} args parent class parameters
*/
constructor({
title = null,
icon = null,
minimizable = false,
minimized = false,
largeTop = true,
topless = false,
closable = false,
...args
} = {}) {
super(args)
this._title = title
this._icon = icon
this._minimizable = minimizable
this._minimized = minimized
this._largeTop = largeTop
this._topless = topless
this._closable = closable
this._topDiv = null
this._bodyDiv = null
this._bottomDiv = null
this._bodyVisibilityManager = null
}
/* HTML */
initHTML(html) {
html.addClass('qui-structured-view')
this._topDiv = this._makeTop()
html.append(this._topDiv)
if (!this._icon) {
html.addClass('iconless')
}
if (this._largeTop) {
html.addClass('large-top')
}
if (this._topless) {
html.addClass('topless')
}
if (this._closable) {
html.addClass('closable')
}
if (this._minimizable) {
html.addClass('minimizable')
this._topDiv.addClass('qui-base-button')
this._topDiv.on('click', function () {
this.toggleMinimized()
}.bind(this))
}
this._bodyDiv = this.makeBody()
this._bodyDiv.addClass('qui-structured-view-body')
this._bodyVisibilityManager = new VisibilityManager({
element: this._bodyDiv,
heightTransition: true
})
html.append(this._bodyDiv)
if (this._minimizable) {
if (this._minimized) {
this._bodyVisibilityManager.hideElement()
html.addClass('minimized')
}
else if (this._topDiv) {
this._topDiv.addClass('selected')
}
}
this._bottomDiv = this.makeBottom()
if (this._bottomDiv) {
this._bottomDiv.addClass('qui-structured-view-bottom')
html.append(this._bottomDiv)
}
}
_makeTop() {
let topDiv = $('<div></div>', {class: 'qui-structured-view-top'})
let iconDiv = $('<div></div>', {class: 'qui-structured-view-icon'})
topDiv.append(iconDiv)
if (this._icon) {
this.prepareIcon(this._icon).applyTo(iconDiv)
}
let titleSpan = $('<span></span>', {class: 'qui-structured-view-title'})
titleSpan.text(this._title || '')
topDiv.append(titleSpan)
if (this._minimizable) {
let minimizeIconDiv = $('<div></div>', {class: 'qui-structured-view-minimize-button'})
new StockIcon({
name: 'fat-arrow', variant: 'interactive', activeVariant: 'white', selectedVariant: 'white'
}).alter({scale: this._largeTop ? 1 : 0.75}).applyTo(minimizeIconDiv)
topDiv.append(minimizeIconDiv)
}
if (this._closable && !this._minimizable) {
let closeIconDiv = $('<div></div>', {class: 'qui-base-button qui-structured-view-close-button'})
new StockIcon({
name: 'close', variant: 'interactive',
activeVariant: 'interactive-active', selectedVariant: 'interactive'
}).alter({scale: this._largeTop ? 1 : 0.75}).applyTo(closeIconDiv)
topDiv.append(closeIconDiv)
closeIconDiv.on('click', function () {
this.close().catch().then(function () {
logger.debug('breadcrumb navigation cancelled by rejected page close')
})
}.bind(this))
}
return topDiv
}
/**
* Implement this method to create the actual body of the view.
* @abstract
* @returns {jQuery}
*/
makeBody() {
}
/**
* Implement this method to create the bottom part of the view.
* @returns {jQuery}
*/
makeBottom() {
return null
}
/**
* Return the top element.
* @returns {jQuery}
*/
getTop() {
/* Make sure the HTML is created */
this.getHTML()
return this._topDiv
}
/**
* Return the body element.
* @returns {jQuery}
*/
getBody() {
/* Make sure the HTML is created */
this.getHTML()
return this._bodyDiv
}
/**
* Return the bottom element.
* @returns {?jQuery}
*/
getBottom() {
/* Make sure the HTML is created */
this.getHTML()
return this._bottomDiv
}
/* Title and icon */
/**
* Return the view title.
* @returns {?String}
*/
getTitle() {
return this._title
}
/**
* Set the view title.
* @param {String} title the new title
*/
setTitle(title) {
this._title = title
this.getTop().children('span.qui-structured-view-title').html(title || '')
}
/**
* Return the view icon.
* @returns {qui.icons.Icon}
*/
getIcon() {
return this._icon
}
/**
* Set the view icon.
* @param {?qui.icons.Icon} icon the new icon (`null` to disable icon)
*/
setIcon(icon) {
this._icon = icon
let iconDiv = this.getTop().children('div.qui-structured-view-icon')
if (this._icon) {
this.getHTML().removeClass('iconless')
this.prepareIcon(this._icon).applyTo(iconDiv)
}
else {
this.getHTML().addClass('iconless')
iconDiv.html('')
}
}
/**
* Prepare the view icon, altering its attributes as needed, before applying it.
* @param {qui.icons.Icon} icon
* @returns {qui.icons.Icon}
*/
prepareIcon(icon) {
if (!(icon instanceof StockIcon)) {
return icon
}
if (this._minimizable) {
icon = icon.alterDefault({
variant: 'interactive',
activeVariant: 'white',
selectedVariant: 'white'
})
}
else {
icon = icon.alterDefault({variant: Window.isSmallScreen() ? 'white' : 'foreground'})
}
return icon
}
/* Minimization */
/**
* Minimize the view.
*/
minimize() {
if (this._minimized) {
return
}
this._minimized = true
this.getHTML().addClass('minimized')
this.getTop().removeClass('selected')
this._bodyVisibilityManager.hideElement()
this.onMinimize()
}
/**
* Restore the view's minimization to normal state.
*/
unminimize() {
if (!this._minimized) {
return
}
this._minimized = false
this.getHTML().removeClass('minimized')
this.getTop().addClass('selected')
this._bodyVisibilityManager.showElement()
this.onUnminimize()
}
/**
* Toggle the view's minimization state.
*/
toggleMinimized() {
if (this.isMinimized()) {
this.unminimize()
}
else {
this.minimize()
}
}
/**
* Tell if the view is minimized or not.
* @returns {Boolean}
*/
isMinimized() {
return this._minimized
}
/**
* Tell if the view is minimizable or not.
* @returns {Boolean}
*/
isMinimizable() {
return this._minimizable
}
/**
* Called when the view is minimized.
*/
onMinimize() {
}
/**
* Called when the view is unminimized.
*/
onUnminimize() {
}
}
return StructuredViewMixin
})
export default StructuredViewMixin