smoosic
Version:
<sub>[Github site](https://github.com/Smoosic/smoosic) | [source documentation](https://smoosic.github.io/Smoosic/release/docs/modules.html) | [change notes](https://aarondavidnewman.github.io/Smoosic/changes.html) | [application](https://smoosic.github.i
308 lines (301 loc) • 9.83 kB
text/typescript
// [Smoosic](https://github.com/AaronDavidNewman/Smoosic)
// Copyright (c) Aaron David Newman 2021.
import { SuiComponentBase, SuiDialogNotifier, SuiComponentParent, SuiBaseComponentParams } from '../components/baseComponent';
import { buildDom } from '../../../common/htmlHelpers';
import { SuiScoreViewOperations } from '../../../render/sui/scoreViewOperations';
import { SuiButtonComponentParams } from './button';
declare var $: any;
/**
* @category SuiDialog
*/
export interface SuiButtonComponentRowParameters {
label: string,
classes: string
buttons: SuiButtonComponentParams[]
}
/**
* @category SuiDialog
*/
export interface SuiButtonArrayParameters {
label: string,
rows: SuiButtonComponentRowParameters[]
}
/**
* @category SuiDialog
*/
declare interface SuiButtonCompositeParams extends SuiButtonComponentParams {
parentControl: SuiComponentParent
}
/**
* An array of related buttons in a dialog, e.g. for articulations
* @category SuiDialog
*/
export class SuiButtonArrayButton extends SuiComponentBase {
icon: string;
classes: string;
position?: string;
text?: string;
iButtonState: number = SuiButtonArrayButton.buttonState.initial;
parentControl: SuiComponentParent;
static buttonStateString: string[] = ['initial', 'pushed', 'disabled'];
static buttonState: Record<string, number> = {
'initial': 0, 'pushed': 1 , 'disabled': 2
}
constructor(dialog: SuiDialogNotifier, parameters: SuiButtonCompositeParams) {
super(dialog, parameters);
this.id = `${dialog.getId()}-${parameters.id}`;
this.dialog = dialog;
this.text = parameters.text;
this.icon = parameters.icon;
this.classes = parameters.classes;
this.parentControl = parameters.parentControl;
}
get buttonStateString() {
return SuiButtonArrayButton.buttonStateString[this.buttonState];
}
get buttonState() {
return this.iButtonState;
}
set buttonState(value: number) {
this.iButtonState = value;
this.clearState();
$(`#${this.id}`).addClass(this.buttonStateString);
}
clearState() {
SuiButtonArrayButton.buttonStateString.forEach((ss) => $(`#${this.id}`).removeClass(ss));
}
get iconHtml() {
const b = buildDom;
const state: string = SuiButtonArrayButton.buttonStateString[this.iButtonState];
const classes = `${this.classes} ${state}`;
const q = b('button').attr('id', this.id).classes(classes).append(
b('span').classes(this.icon).attr('aria-label',this.label)
);
return q;
}
get textHtml() {
const b = buildDom;
const state: string = SuiButtonArrayButton.buttonStateString[this.iButtonState];
const text = this.text ?? '';
const classes = `${this.classes} ${state}`;
const q = b('button').attr('id', this.id).classes(classes).append(
b('span').classes(this.icon).attr('aria-label',this.label)).append(
b('span').classes('button-text').text(text)
);
return q;
}
get html() {
const q = this.text?.length ? this.textHtml : this.iconHtml;
return q;
}
updateControls() {
const updateEl = $('#' + this.parameterId);
$(updateEl).html('');
$(updateEl).append(this.html.dom());
this.bind();
}
bind() {
$(`#${this.id}`).off('click').on('click',
(ev: any) => {
this.changeFlag = true;
this.parentControl.changed();
this.changeFlag = false;
});
}
}
/**
* @category SuiDialog
*/
export interface SuiButtonComponentRow {
label: string,
classes: string,
buttons: SuiButtonArrayButton[]
}
export type getButtonsFcn = () => SuiButtonArrayParameters;
/**
* @category SuiDialog
*/
export abstract class SuiButtonArrayBase extends SuiComponentParent {
view: SuiScoreViewOperations;
buttonRows: SuiButtonComponentRow[] = [];
pressed: string = '';
shellCreated: boolean = false;
constructor(dialog: SuiDialogNotifier, parameter: SuiBaseComponentParams, buttonFactory: getButtonsFcn) {
super(dialog, parameter);
this.dialog = dialog;
const rowParams = buttonFactory();
rowParams.rows.forEach((bparams) => {
const row: SuiButtonComponentRow = {
label: bparams.label,
classes: bparams.classes,
buttons: []
};
this.buttonRows.push(row);
bparams.buttons.forEach((bp) => {
const param = {
parentControl: this, ...bp
}
row.buttons.push(new SuiButtonArrayButton(dialog, param));
});
});
this.view = this.dialog.getView();
}
updateControls() {
const updateEl = $('#' + this.parameterId);
$(updateEl).html('');
$(updateEl).append(this.html.dom());
this.bind();
}
get html() {
const b = buildDom;
if (!this.shellCreated) {
const q = b('div').classes(this.makeClasses('multiControl smoControl buttonArray'))
.attr('id', this.parameterId);
this.shellCreated = true;
return q;
}
const q = b('div').classes('button-row-container');
for (let i = 0; i < this.buttonRows.length; ++i) {
const buttonRow = this.buttonRows[i];
const r = b('div').classes(`button-array-row`);
const s = b('div').classes('button-array-label')
.append(b('span').classes(`${buttonRow.classes}`).text(buttonRow.label));
const t = b('div').classes('button-array-buttons');
buttonRow.buttons.forEach((bb) => {
t.append(bb.html);
});
r.append(s);
r.append(t);
q.append(r);
}
return q;
}
abstract changed(): void;
abstract bind():void;
}
/**
* A button array component with single-select behavior
* @category SuiDialog
*/
export class SuiButtonArrayComponent extends SuiButtonArrayBase {
pressed: string = '';
shellCreated: boolean = false;
initialValue: boolean = true;
constructor(dialog: SuiDialogNotifier, parameter: SuiBaseComponentParams, buttonFactory: getButtonsFcn) {
super(dialog, parameter, buttonFactory);
}
getValue(): string {
return this.pressed;
}
updateValues() {
const rowKeys = Object.keys(this.buttonRows);
for (let i = 0; i < rowKeys.length; ++i) {
const buttonRow = this.buttonRows[i];
buttonRow.buttons.forEach((bb) => {
// If the button is being pressed by the user
if (bb.changeFlag) {
// toggle button state.
if (bb.buttonState === SuiButtonArrayButton.buttonState.pushed) {
bb.buttonState = SuiButtonArrayButton.buttonState.initial;
this.pressed = '';
} else {
this.pressed = bb.smoName;
bb.buttonState = SuiButtonArrayButton.buttonState.pushed;
}
} else if (this.initialValue) {
// if the condition was met when the dialog was created
if (this.pressed === bb.smoName) {
bb.buttonState = SuiButtonArrayButton.buttonState.pushed;
}
} else {
bb.buttonState = SuiButtonArrayButton.buttonState.initial;
}
});
}
}
setValue(val: string) {
this.pressed = val;
this.updateValues();
this.updateControls();
this.initialValue = false;
}
changed() {
this.changeFlag = true;
this.updateValues();
this.updateControls();
this.handleChanged();
this.changeFlag = false;
}
bind() {
const rowKeys = Object.keys(this.buttonRows);
for (let i = 0; i < rowKeys.length; ++i) {
const buttonRow = this.buttonRows[i];
buttonRow.buttons.forEach((bb) => {
bb.bind();
});
}
}
}
/**
* A button array with multi-select behavior.
* @category SuiDialog
*/
export class SuiButtonArrayMSComponent extends SuiButtonArrayBase {
pressedArray: string[] = [];
initialValue: boolean = true;
constructor(dialog: SuiDialogNotifier, parameter: SuiBaseComponentParams, buttonFactory: getButtonsFcn) {
super(dialog, parameter, buttonFactory);
}
getValue(): string[] {
return this.pressedArray;
}
setValue(val: string[]) {
this.pressedArray = val;
this.updateValues();
this.updateControls();
this.initialValue = false;
}
updateValues() {
const rowKeys = Object.keys(this.buttonRows);
const pressed: string[] = [];
for (let i = 0; i < rowKeys.length; ++i) {
const buttonRow = this.buttonRows[i];
buttonRow.buttons.forEach((bb) => {
// If this button was just pressed
if (bb.changeFlag) {
if (this.pressedArray.indexOf(bb.smoName) >= 0) {
bb.buttonState = SuiButtonArrayButton.buttonState.initial;
} else {
bb.buttonState = SuiButtonArrayButton.buttonState.pushed;
pressed.push(bb.smoName);
}
} else if (this.initialValue) { // or if the initial value is being set
if (this.pressedArray.indexOf(bb.smoName) >= 0) {
bb.buttonState = SuiButtonArrayButton.buttonState.pushed;
pressed.push(bb.smoName);
}
} else if (bb.buttonState === SuiButtonArrayButton.buttonState.pushed) {
// if the button was not changed, but pressed already
pressed.push(bb.smoName);
}
});
}
this.pressedArray = pressed;
}
changed() {
this.changeFlag = true;
this.updateValues();
this.updateControls();
this.handleChanged();
this.changeFlag = false;
}
bind() {
const rowKeys = Object.keys(this.buttonRows);
for (let i = 0; i < rowKeys.length; ++i) {
const buttonRow = this.buttonRows[i];
buttonRow.buttons.forEach((bb) => {
bb.bind();
});
}
}
}