coral-spectrum/coral-component-shell/src/scripts/ShellOrgSwitcher.js
/**
* Copyright 2019 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {List} from '../../../coral-component-list';
import {SelectableCollection} from '../../../coral-collection';
import orgSwitcher from '../templates/orgSwitcher';
import {commons, i18n} from '../../../coral-utils';
const CLASSNAME = '_coral-Shell-orgSwitcher';
/**
Minimum number of entries required to show search control.
@type {Number}
@ignore
*/
const SEARCH_VISIBILITY_THRESHOLD = 6;
/**
@class Coral.Shell.OrgSwitcher
@classdesc A Shell OrgSwitcher component
@htmltag coral-shell-orgswitcher
@extends {List}
*/
class ShellOrgSwitcher extends List {
/** @ignore */
constructor() {
super();
// Events
this._delegateEvents({
'coral-search:clear': '_showAll',
'coral-search:input': '_performSearch',
'coral-search:submit': '_selectFirst',
'coral-shell-organization:change': '_onOrganizationChange',
// private
'coral-shell-organization:_selectedchanged': '_onItemSelectedChanged',
'coral-shell-suborganization:_selectedchanged': '_onSubItemSelectedChanged'
});
// Templates
this._elements = {
footer: this.querySelector('coral-shell-orgswitcher-footer') || document.createElement('coral-shell-orgswitcher-footer')
};
orgSwitcher.call(this._elements, {commons, i18n});
// Used for eventing
this._oldSelection = null;
// Item handling
this.items._startHandlingItems(true);
}
/**
The item collection.
@type {SelectableCollection}
@readonly
*/
get items() {
// Construct the collection on first request:
if (!this._items) {
this._items = new SelectableCollection({
host: this,
itemTagName: 'coral-shell-organization',
itemSelector: 'coral-shell-organization, coral-shell-suborganization',
container: this._elements.items,
onItemAdded: this._onCollectionChange,
onItemRemoved: this._onCollectionChange
});
}
return this._items;
}
/**
The search field placeholder.
@default ''
@type {String}
@htmlattribute placeholder
*/
get placeholder() {
return this._elements.search.placeholder;
}
set placeholder(value) {
this._elements.search.placeholder = value;
}
/**
Content zone where the buttons are located.
@type {ShellOrgSwitcherFooter}
@contentzone
*/
get footer() {
return this._getContentZone(this._elements.footer);
}
set footer(value) {
this._setContentZone('content', value, {
handle: 'footer',
tagName: 'coral-shell-orgswitcher-footer',
insert: function (content) {
this.appendChild(content);
}
});
}
/** @private */
get _itemTagName() {
// Used for Collection
return 'coral-shell-organization';
}
/** @private */
_onItemSelectedChanged(event) {
event.stopImmediatePropagation();
const item = event.target;
this._validateSelection(item);
}
/** @private */
_onSubItemSelectedChanged(event) {
event.stopImmediatePropagation();
const item = event.target;
// If a sub organization is selected, deselect all selected organization items
if (item.hasAttribute('selected')) {
this.items._getAllSelected().forEach((itemElement) => {
if (itemElement.tagName === 'CORAL-SHELL-ORGANIZATION') {
this._preventTriggeringEvents = true;
itemElement.removeAttribute('selected');
}
});
this._preventTriggeringEvents = false;
}
}
/** @private */
_onOrganizationChange() {
this._triggerChangeEvent();
}
/**
Returns the selected workspace.
@type {HTMLElement}
@readonly
*/
get selectedItem() {
return this.items._getLastSelected();
}
/** @private */
_selectFirst(event) {
event.stopPropagation();
const first = this.items.first();
if (first) {
first.setAttribute('selected', '');
}
}
/** @private */
_validateSelection(item) {
// gets the current selection
const selection = this.items._getAllSelected();
const selectionCount = selection.length;
if (selectionCount > 1) {
for (let i = 0 ; i < selectionCount ; i++) {
if (selection[i] !== item) {
// Don't trigger change events
this._preventTriggeringEvents = true;
selection[i].removeAttribute('selected');
}
}
// We can trigger change events again
this._preventTriggeringEvents = false;
}
this._triggerChangeEvent();
}
/** @private */
_triggerChangeEvent() {
const selectedItem = this.selectedItem;
const oldSelection = this._oldSelection;
if (!this._preventTriggeringEvents && selectedItem !== oldSelection) {
this.trigger('coral-shell-orgswitcher:change', {
oldSelection: oldSelection,
selection: selectedItem
});
this._oldSelection = selectedItem;
}
}
/** @private */
_showAll(event) {
event.stopPropagation();
this._elements.resultMessage.hidden = true;
// Show all items
this.items.getAll().forEach((item) => {
item.hidden = false;
if (item.items) {
// Show all sub-items
item.items.getAll().forEach((itemElement) => {
itemElement.hidden = false;
});
}
});
}
/** @private */
_performSearch(event) {
event.stopPropagation();
const searchTerm = this._elements.search.value.toLowerCase();
this._elements.resultMessage.hidden = true;
// Hide items that don't match
let resultCount = 0;
this.items.getAll().forEach((item) => {
let matched = item.content.textContent.toLowerCase().indexOf(searchTerm) !== -1;
let childMatched = false;
if (item.items) {
item.items.getAll().forEach((itemElement) => {
const elementMatch = itemElement.content.textContent.toLowerCase().indexOf(searchTerm) !== -1;
childMatched = childMatched || elementMatch;
itemElement.hidden = !elementMatch;
});
}
matched = matched || childMatched;
item.hidden = !matched;
if (matched) {
resultCount++;
}
});
if (resultCount === 0) {
this._elements.resultMessage.hidden = false;
}
}
/** @private */
_moveItems() {
this.setAttribute('id', this.id || commons.getUID());
Array.prototype.forEach.call(this.querySelectorAll(`#${this.id} > coral-shell-organization`), (item) => {
this._elements.items.appendChild(item);
});
}
/** @private */
_onCollectionChange(item) {
// Move all items into the right place
this._moveItems();
// Select the last selected item
this._validateSelection(item);
// if mincountforsearch is set and number of organizations are less than or equal to it, hide the search
if (this.items.length <= SEARCH_VISIBILITY_THRESHOLD) {
this._elements.search.hide();
} else {
this._elements.search.show();
}
}
get _contentZones() {
return {'coral-shell-orgswitcher-footer': 'footer'};
}
/** @ignore */
static get observedAttributes() {
return super.observedAttributes.concat(['placeholder']);
}
/** @ignore */
render() {
super.render();
this.classList.add(CLASSNAME);
// Move the items into the right place
this._moveItems();
const container = this.querySelector('[handle="container"]');
// Support cloneNode
if (container) {
this._elements.container = container;
this._elements.items = this.querySelector('._coral-Shell-orgSwitcher-items');
this._elements.search = this.querySelector('._coral-Shell-orgSwitcher-search');
this._elements.resultMessage = this.querySelector('._coral-Shell-orgSwitcher-resultMessage');
this._items._container = this._elements.items;
} else {
this.appendChild(this._elements.container);
}
// Call content zone insert
this.footer = this._elements.footer;
// Don't trigger events once connected
this._preventTriggeringEvents = true;
this._validateSelection();
this._preventTriggeringEvents = false;
this._oldSelection = this.selectedItem;
}
/**
Triggered when the {@link ShellOrgSwitcher} selected organization has changed.
@typedef {CustomEvent} coral-shell-orgswitcher:change
@property {HTMLElement} detail.oldSelection
The prior selected organization item.
@property {HTMLElement} detail.selection
The newly selected organization item.
*/
}
export default ShellOrgSwitcher;