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
200 lines (195 loc) • 6.58 kB
text/typescript
// [Smoosic](https://github.com/AaronDavidNewman/Smoosic)
// Copyright (c) Aaron David Newman 2021.
import { SuiScoreViewOperations } from '../../render/sui/scoreViewOperations';
import { SmoLibrary } from '../fileio/library';
import { SuiDialogParams } from './dialog';
import { DialogDefinitionOption } from './components/baseComponent';
import { TreeComponentOption, SuiTreeComponent } from './components/tree';
import { SuiComponentAdapter, SuiDialogAdapterBase } from './adapter';
import { SmoUiConfiguration } from '../configuration';
declare var $: any;
/**
* A link to a remote music file
* @category SuiDialog
*/
export interface LibraryDefinitionElement {
smoName: string,
control: string,
root: string,
label: string,
options?: DialogDefinitionOption[]
}
/**
* A set of library links
* @category SuiDialog
*/
export interface LibraryDefinition {
label: string,
elements: LibraryDefinitionElement[],
staticText: Record<string, string>[]
}
/**
* The Smoosic music library.
* @category SuiDialog
*/
export class SuiLibraryAdapter extends SuiComponentAdapter {
topLib: SmoLibrary;
elements: LibraryDefinition | null = null;
selectedUrl: string = '';
libHash: Record<string, SmoLibrary> = {};
config: SmoUiConfiguration;
selectedLib: SmoLibrary | null;
tree: Record<string, SmoLibrary> = {};
// If the selected lib is a leaf node (a score), this is the same as that
selectedScore: SmoLibrary | null = null;
constructor(view: SuiScoreViewOperations, config: SmoUiConfiguration) {
super(view);
this.config = config;
this.topLib = new SmoLibrary({ url: this.config.libraryUrl });
this.libHash = {};
this.selectedLib = null;
}
loadPromise() {
}
initialize(): Promise<void> {
const self = this;
return new Promise<void>((resolve) => {
self.topLib.load().then(() => {
self.libHash[self.topLib.url!] = self.topLib;
resolve();
});
});
}
static addChildRecurse(options: TreeComponentOption[], parent: SmoLibrary, child: SmoLibrary) {
options.push({ label: child.metadata.name, value: child.url, parent: parent.url, format: child.format, expanded: false });
child.children.forEach((gchild) => {
SuiLibraryAdapter.addChildRecurse(options, child, gchild);
});
}
static createOptions(topLib: SmoLibrary) {
const options: TreeComponentOption[] = [];
topLib.children.forEach((child) => {
SuiLibraryAdapter.addChildRecurse(options, topLib, child);
});
return options;
}
buildTreeRecurse(children: SmoLibrary[]) {
children.forEach((child) => {
this.tree[child.url!] = child;
this.buildTreeRecurse(child.children);
});
}
buildTree() {
this.tree = {};
this.buildTreeRecurse(this.topLib.children);
}
async commit() {
}
async cancel() {
}
async loadOptions(options: TreeComponentOption[]): Promise<void> {
const self = this;
return new Promise<void>((resolve) => {
if (self.selectedLib!.format === 'library') {
if (!self.selectedLib!.loaded) {
self.selectedLib!.load().then(() => {
const nops = SuiLibraryAdapter.createOptions(self.topLib);
nops.forEach((option) => {
options.push(option);
});
resolve();
});
} else {
const nops = SuiLibraryAdapter.createOptions(self.topLib);
nops.forEach((option) => {
options.push(option);
});
resolve();
}
}
else {
self.selectedScore = this.selectedLib;
resolve();
}
});
}
async _loadScore() {
await this.view.loadRemoteScore(this.selectedScore!.url!);
}
get selectedLibrary(): SmoLibrary | null {
return this.selectedLib;
}
get smoLibrary() {
return this.selectedUrl;
}
set smoLibrary(value: string) {
this.selectedUrl = value;
this.buildTree();
this.selectedLib = this.tree[this.selectedUrl];
if (this.selectedLib.format !== 'library') {
this.selectedScore = this.selectedLib;
} else {
this.selectedScore = null;
}
}
}
/**
* Display the library tree control
* @category SuiDialog
*/
export class SuiLibraryDialog extends SuiDialogAdapterBase<SuiLibraryAdapter> {
static dialogElements: LibraryDefinition = {
label: 'Music Library', elements: [{
smoName: 'smoLibrary',
control: 'SuiTreeComponent',
root: '',
label: 'Selection',
options: []
}],
staticText: []
};
static _createElements(topLib: SmoLibrary) {
const elements: LibraryDefinition = JSON.parse(JSON.stringify(SuiLibraryDialog.dialogElements));
const tree = elements.elements[0];
tree.root = topLib.url!;
(tree.options as any) = SuiLibraryAdapter.createOptions(topLib);
return elements;
}
static _createAndDisplay(parameters: SuiDialogParams, adapter: SuiLibraryAdapter) {
const elements = SuiLibraryDialog._createElements(adapter.topLib);
const dg = new SuiLibraryDialog(parameters, elements, adapter);
dg.display();
}
/** Library requires a load first, so createAndDisplayDialog won't work on it */
static async createAndDisplay(parameters: SuiDialogParams, config: SmoUiConfiguration) {
const adapter = new SuiLibraryAdapter(parameters.view, config);
await adapter.initialize();
SuiLibraryDialog._createAndDisplay(parameters, adapter);
}
constructor(parameters: SuiDialogParams, dialogElements: LibraryDefinition, adapter: SuiLibraryAdapter) {
super(dialogElements, { adapter, ...parameters });
}
async commit() {
if (this.adapter.selectedScore !== null) {
await this.adapter._loadScore();
} else {
this.complete();
}
}
get smoLibraryCtrl() {
return this.cmap.smoLibraryCtrl as SuiTreeComponent;
}
async changed() {
const okButton = $(this.dgDom.element).find('.ok-button');
super.changed();
if (this.adapter.selectedLib!.format === 'library') {
$(okButton).prop('disabled', true);
const options: TreeComponentOption[] = [];
await this.adapter.loadOptions(options);
this.smoLibraryCtrl.updateOptions(options);
$(this.smoLibraryCtrl._getInputElement()).find('li[data-value="'+this.smoLibraryCtrl.getValue()+'"] button.expander').click();
} else {
$(okButton).prop('disabled', false);
}
}
}