From 30517fe817050f2f650cbe9b776676163fd9541b Mon Sep 17 00:00:00 2001 From: Paul Klink Date: Mon, 23 Nov 2020 14:53:42 +1100 Subject: [PATCH] api-test developed. Improved Layout handling including adding LayoutManager.loadLayout() --- .gitignore | 6 +- api-extractor.json | 364 +++++++ api-test/app.ts | 166 +++ api-test/boolean-component.ts | 21 + api-test/color-component.ts | 57 + api-test/index.html | 30 + api-test/main.ts | 22 + api-test/predefined-layouts.ts | 455 ++++++++ api-test/styles.css | 40 + api-test/test.less | 43 + api-test/text-component.ts | 46 + api-test/tsconfig.json | 21 + api-test/webpack.config.js | 81 ++ doc/input/.gitignore | 4 + etc/.gitignore | 4 + index.d.ts | 894 ---------------- package-lock.json | 1002 +++++++++++++++++- package.json | 31 +- src/index.ts | 31 +- src/js_es6/config/config.ts | 298 +++--- src/js_es6/config/user-config.ts | 420 +++++--- src/js_es6/container/component-container.ts | 40 +- src/js_es6/controls/browser-popout.ts | 74 +- src/js_es6/controls/drag-proxy.ts | 24 +- src/js_es6/controls/drag-source.ts | 37 +- src/js_es6/controls/header.ts | 41 +- src/js_es6/controls/tab.ts | 21 +- src/js_es6/errors/external-error.ts | 5 +- src/js_es6/golden-layout.ts | 38 +- src/js_es6/items/component-item.ts | 67 +- src/js_es6/items/content-item.ts | 91 +- src/js_es6/items/{root.ts => ground-item.ts} | 126 ++- src/js_es6/items/row-or-column.ts | 92 +- src/js_es6/items/stack.ts | 104 +- src/js_es6/layout-manager.ts | 585 +++++----- src/js_es6/utils/config-minifier.ts | 10 +- src/js_es6/utils/event-emitter.ts | 26 +- src/js_es6/utils/i18n-strings.ts | 11 +- src/js_es6/utils/react-component-handler.ts | 8 +- src/js_es6/utils/types.ts | 24 +- src/js_es6/utils/utils.ts | 14 +- src/less/goldenlayout-base.less | 8 + src/scss/goldenlayout-base.scss | 453 ++++++++ src/scss/themes/_goldenlayout-var-theme.scss | 7 +- tsconfig.base.json | 17 +- tsconfig.cjs.json | 1 + tsconfig.module.api.json | 7 + tsconfig.module.full.json | 2 +- tsconfig.module.json | 5 +- 49 files changed, 4091 insertions(+), 1883 deletions(-) create mode 100644 api-extractor.json create mode 100644 api-test/app.ts create mode 100644 api-test/boolean-component.ts create mode 100644 api-test/color-component.ts create mode 100644 api-test/index.html create mode 100644 api-test/main.ts create mode 100644 api-test/predefined-layouts.ts create mode 100644 api-test/styles.css create mode 100644 api-test/test.less create mode 100644 api-test/text-component.ts create mode 100644 api-test/tsconfig.json create mode 100644 api-test/webpack.config.js create mode 100644 doc/input/.gitignore create mode 100644 etc/.gitignore delete mode 100644 index.d.ts rename src/js_es6/items/{root.ts => ground-item.ts} (61%) create mode 100644 src/scss/goldenlayout-base.scss create mode 100644 tsconfig.module.api.json diff --git a/.gitignore b/.gitignore index dd8753279..da0107948 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,11 @@ typings .idea .vscode npm-debug.log -dist +/dist /doc debug.log /debug.log +/lib +/api-test/dist +/api-test/out-tsc +/temp \ No newline at end of file diff --git a/api-extractor.json b/api-extractor.json new file mode 100644 index 000000000..633d9d237 --- /dev/null +++ b/api-extractor.json @@ -0,0 +1,364 @@ +/** + * Config file for API Extractor. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for + * standard settings to be shared across multiple projects. + * + * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains + * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be + * resolved using NodeJS require(). + * + * SUPPORTED TOKENS: none + * DEFAULT VALUE: "" + */ + // "extends": "./shared/api-extractor-base.json" + // "extends": "my-package/include/api-extractor-base.json" + + /** + * Determines the "" token that can be used with other config file settings. The project folder + * typically contains the tsconfig.json and package.json config files, but the path is user-defined. + * + * The path is resolved relative to the folder of the config file that contains the setting. + * + * The default value for "projectFolder" is the token "", which means the folder is determined by traversing + * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder + * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error + * will be reported. + * + * SUPPORTED TOKENS: + * DEFAULT VALUE: "" + */ + "projectFolder": ".", + + /** + * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor + * analyzes the symbols exported by this module. + * + * The file extension must be ".d.ts" and not ".ts". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + */ + "mainEntryPointFilePath": "/lib/index.d.ts", + + /** + * A list of NPM package names whose exports should be treated as part of this package. + * + * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", + * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part + * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly + * imports library2. To avoid this, we can specify: + * + * "bundledPackages": [ "library2" ], + * + * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been + * local files for library1. + */ + "bundledPackages": [], + + /** + * Determines how the TypeScript compiler engine will be invoked by API Extractor. + */ + "compiler": { + /** + * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * Note: This setting will be ignored if "overrideTsconfig" is used. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/tsconfig.json" + */ + "tsconfigFilePath": "/tsconfig.module.api.json" + /** + * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. + * The object must conform to the TypeScript tsconfig schema: + * + * http://json.schemastore.org/tsconfig + * + * If omitted, then the tsconfig.json file will be read from the "projectFolder". + * + * DEFAULT VALUE: no overrideTsconfig section + */ + // "overrideTsconfig": { + // . . . + // } + /** + * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended + * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when + * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses + * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. + * + * DEFAULT VALUE: false + */ + // "skipLibCheck": true, + }, + + /** + * Configures how the API report file (*.api.md) will be generated. + */ + "apiReport": { + /** + * (REQUIRED) Whether to generate an API report. + */ + "enabled": true + + /** + * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce + * a full file path. + * + * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". + * + * SUPPORTED TOKENS: , + * DEFAULT VALUE: ".api.md" + */ + // "reportFileName": ".api.md", + + /** + * Specifies the folder where the API report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, + * e.g. for an API review. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/etc/" + */ + // "reportFolder": "/etc/", + + /** + * Specifies the folder where the temporary report file is written. The file name portion is determined by + * the "reportFileName" setting. + * + * After the temporary file is written to disk, it is compared with the file in the "reportFolder". + * If they are different, a production build will fail. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/" + */ + // "reportTempFolder": "/temp/" + }, + + /** + * Configures how the doc model file (*.api.json) will be generated. + */ + "docModel": { + /** + * (REQUIRED) Whether to generate a doc model file. + */ + "enabled": true + + /** + * The output path for the doc model file. The file extension should be ".api.json". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/temp/.api.json" + */ + // "apiJsonFilePath": "/temp/.api.json" + }, + + /** + * Configures how the .d.ts rollup file will be generated. + */ + "dtsRollup": { + /** + * (REQUIRED) Whether to generate the .d.ts rollup file. + */ + "enabled": true, + + /** + * Specifies the output path for a .d.ts rollup file to be generated without any trimming. + * This file will include all declarations that are exported by the main entry point. + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "/dist/.d.ts" + */ + "untrimmedFilePath": "/dist/golden-layout/index.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. + * This file will include only declarations that are marked as "@public" or "@beta". + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "betaTrimmedFilePath": "/dist/-beta.d.ts", + + /** + * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. + * This file will include only declarations that are marked as "@public". + * + * If the path is an empty string, then this file will not be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + "publicTrimmedFilePath": "/dist/golden-layout/-public.d.ts" + + /** + * When a declaration is trimmed, by default it will be replaced by a code comment such as + * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the + * declaration completely. + * + * DEFAULT VALUE: false + */ + // "omitTrimmingComments": true + }, + + /** + * Configures how the tsdoc-metadata.json file will be generated. + */ + "tsdocMetadata": { + /** + * Whether to generate the tsdoc-metadata.json file. + * + * DEFAULT VALUE: true + */ + // "enabled": true, + /** + * Specifies where the TSDoc metadata file should be written. + * + * The path is resolved relative to the folder of the config file that contains the setting; to change this, + * prepend a folder token such as "". + * + * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", + * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup + * falls back to "tsdoc-metadata.json" in the package folder. + * + * SUPPORTED TOKENS: , , + * DEFAULT VALUE: "" + */ + // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" + }, + + /** + * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files + * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. + * To use the OS's default newline kind, specify "os". + * + * DEFAULT VALUE: "crlf" + */ + // "newlineKind": "crlf", + + /** + * Configures how API Extractor reports error and warning messages produced during analysis. + * + * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. + */ + "messages": { + /** + * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing + * the input .d.ts files. + * + * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "compilerMessageReporting": { + /** + * Configures the default routing for messages that don't match an explicit rule in this table. + */ + "default": { + /** + * Specifies whether the message should be written to the the tool's output log. Note that + * the "addToApiReportFile" property may supersede this option. + * + * Possible values: "error", "warning", "none" + * + * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail + * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes + * the "--local" option), the warning is displayed but the build will not fail. + * + * DEFAULT VALUE: "warning" + */ + "logLevel": "warning" + + /** + * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), + * then the message will be written inside that file; otherwise, the message is instead logged according to + * the "logLevel" option. + * + * DEFAULT VALUE: false + */ + // "addToApiReportFile": false + } + + // "TS2551": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by API Extractor during its analysis. + * + * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" + * + * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings + */ + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "ae-extra-release-tag": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + /** + * Configures handling of messages reported by the TSDoc parser when analyzing code comments. + * + * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "tsdoc-link-tag-unescaped-text": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + } + } +} diff --git a/api-test/app.ts b/api-test/app.ts new file mode 100644 index 000000000..6be9d1eee --- /dev/null +++ b/api-test/app.ts @@ -0,0 +1,166 @@ +import { Config, GoldenLayout, UserLayoutConfig, UserSerialisableComponentConfig } from "../dist/golden-layout"; +import { BooleanComponent } from './boolean-component'; +import { ColorComponent } from './color-component'; +import { Layout, prefinedLayouts } from './predefined-layouts'; +import { TextComponent } from './text-component'; + +export class App { + private _goldenLayout: GoldenLayout; + private _registerExtraComponentTypesButton; + private _registerExtraComponentTypesButtonClickListener = () => this.handleRegisterExtraComponentTypesButtonClick(); + private _registeredComponentNamesSelect: HTMLSelectElement; + private _registeredComponentNamesSelectChangeListener = () => this.handleRegisteredComponentNamesSelectChange(); + private _addComponentButton: HTMLButtonElement; + private _addComponentButtonClickListener = () => this.handleAddComponentButtonClick(); + private _layoutSelect: HTMLSelectElement; + private _layoutSelectChangeListener = () => this.handleLayoutSelectChange(); + private _loadLayoutButton: HTMLButtonElement; + private _loadLayoutButtonClickListener = () => this.handleLoadLayoutButtonClick(); + private _saveLayout: HTMLButtonElement; + private _saveLayoutClickListener = () => this.handleSaveLayoutClick(); + private _reloadSavedLayout: HTMLButtonElement; + private _reloadSavedLayoutClickListener = () => this.handleReloadSavedLayoutClick(); + + private _allComponentsRegistered = false; + private _savedLayout: Config | undefined; + + constructor() { + const initialConfig = prefinedLayouts.colorComponentCompatible[0].config; + const layoutElement = document.querySelector('#layoutContainer') as HTMLElement; + if (layoutElement === null) { + throw new Error('layoutContainerElement not found'); + } + this._goldenLayout = new GoldenLayout(initialConfig, layoutElement); + this._goldenLayout.registerComponentConstructor(ColorComponent.typeName, ColorComponent); + + const registerExtraComponentTypesButton = document.querySelector('#registerExtraComponentTypesButton') as HTMLButtonElement; + if (registerExtraComponentTypesButton === null) { + throw Error('Could not find RegisterExtraComponentTypesButton'); + } + this._registerExtraComponentTypesButton = registerExtraComponentTypesButton; + this._registerExtraComponentTypesButton.addEventListener('click', this._registerExtraComponentTypesButtonClickListener); + + const registeredComponentNamesSelect = document.querySelector('#registeredComponentTypesSelect') as HTMLSelectElement; + if (registeredComponentNamesSelect === null) { + throw new Error() + } + this._registeredComponentNamesSelect = registeredComponentNamesSelect; + this._registeredComponentNamesSelect.addEventListener('change', this._registeredComponentNamesSelectChangeListener); + + const addComponentButton = document.querySelector('#addComponentButton') as HTMLButtonElement; + if (addComponentButton === null) { + throw Error('Could not find addComponentButton'); + } + this._addComponentButton = addComponentButton; + this._addComponentButton.addEventListener('click', this._addComponentButtonClickListener); + + const layoutSelect = document.querySelector('#layoutSelect') as HTMLSelectElement; + if (layoutSelect === null) { + throw new Error() + } + this._layoutSelect = layoutSelect; + this._layoutSelect.addEventListener('change', this._layoutSelectChangeListener); + + const loadLayoutButton = document.querySelector('#loadLayoutButton') as HTMLButtonElement; + if (loadLayoutButton === null) { + throw Error('Could not find loadLayoutButton'); + } + this._loadLayoutButton = loadLayoutButton; + this._loadLayoutButton.addEventListener('click', this._loadLayoutButtonClickListener); + + const saveLayout = document.querySelector('#saveLayout') as HTMLButtonElement; + if (saveLayout === null) { + throw Error('Could not find saveLayout'); + } + this._saveLayout = saveLayout; + this._saveLayout.addEventListener('click', this._saveLayoutClickListener); + + const reloadSavedLayout = document.querySelector('#reloadSavedLayout') as HTMLButtonElement; + if (reloadSavedLayout === null) { + throw Error('Could not find reloadSavedLayout'); + } + this._reloadSavedLayout = reloadSavedLayout; + this._reloadSavedLayout.disabled = true; + this._reloadSavedLayout.addEventListener('click', this._reloadSavedLayoutClickListener); + } + + start(): void { + this._goldenLayout.init(); + + this.loadRegisteredComponentNamesSelect(); + this.loadLayoutSelect(); + } + + private handleRegisterExtraComponentTypesButtonClick() { + this._goldenLayout.registerComponentConstructor(TextComponent.typeName, TextComponent); + this._goldenLayout.registerComponentConstructor(BooleanComponent.typeName, BooleanComponent); + this._allComponentsRegistered = true; + this.loadRegisteredComponentNamesSelect(); + this.loadLayoutSelect(); + this._registerExtraComponentTypesButton.disabled = true; + } + + private handleRegisteredComponentNamesSelectChange() { + // nothing to do here + } + + private handleAddComponentButtonClick() { + const componentName = this._registeredComponentNamesSelect.value; + const userItemConfig: UserSerialisableComponentConfig = { + componentName, + type: 'component', + } + this._goldenLayout.addItem(userItemConfig, 0) + } + + private handleLayoutSelectChange() { + // nothing to do here + } + + private handleLoadLayoutButtonClick() { + const layoutName = this._layoutSelect.value; + const layouts = this.getAvailableLayouts(); + const selectedLayout = layouts.find((layout) => layout.name === layoutName); + if (selectedLayout === undefined) { + throw new Error('handleLayoutSelectChange'); + } else { + this._goldenLayout.loadLayout(selectedLayout.config); + } + } + + private handleSaveLayoutClick() { + this._savedLayout = this._goldenLayout.saveLayout(); + this._reloadSavedLayout.disabled = false; + } + + private handleReloadSavedLayoutClick() { + if (this._savedLayout === undefined) { + throw new Error('No saved layout'); + } else { + const userLayoutConfig = UserLayoutConfig.fromLayoutConfig(this._savedLayout); + this._goldenLayout.loadLayout(userLayoutConfig); + } + } + + private loadRegisteredComponentNamesSelect() { + this._registeredComponentNamesSelect.options.length = 0; + const names = this._goldenLayout.getRegisteredComponentTypeNames(); + for (const name of names) { + const option = new Option(name); + this._registeredComponentNamesSelect.options.add(option); + } + } + + private getAvailableLayouts(): Layout[] { + return this._allComponentsRegistered ? prefinedLayouts.allComponents : prefinedLayouts.colorComponentCompatible; + } + + private loadLayoutSelect() { + this._layoutSelect.options.length = 0; + const layouts = this.getAvailableLayouts(); + for (const layout of layouts) { + const option = new Option(layout.name); + this._layoutSelect.options.add(option); + } + } +} diff --git a/api-test/boolean-component.ts b/api-test/boolean-component.ts new file mode 100644 index 000000000..e47631fdf --- /dev/null +++ b/api-test/boolean-component.ts @@ -0,0 +1,21 @@ +import { ComponentContainer, JsonValue } from '../dist/golden-layout'; + +export class BooleanComponent { + static readonly typeName = 'boolean'; + + private _inputElement: HTMLInputElement; + + constructor(container: ComponentContainer, state: JsonValue | undefined) { + this._inputElement = document.createElement('input'); + this._inputElement.type = "checkbox"; + this._inputElement.checked = (state as boolean) ?? true; + this._inputElement.style.display = "block"; + container.contentElement.appendChild(this._inputElement); + + container.stateRequestEvent = () => this.handleContainerStateRequestEvent(); + } + + handleContainerStateRequestEvent(): boolean { + return this._inputElement.checked; + } +} \ No newline at end of file diff --git a/api-test/color-component.ts b/api-test/color-component.ts new file mode 100644 index 000000000..711ee9c7e --- /dev/null +++ b/api-test/color-component.ts @@ -0,0 +1,57 @@ +import { ComponentContainer, JsonValue } from '../dist/golden-layout'; + +export class ColorComponent { + static readonly typeName = 'color'; + static readonly undefinedColor = 'MediumVioletRed'; + + private _paraElement: HTMLParagraphElement; + private _inputElement: HTMLInputElement; + + constructor(container: ComponentContainer, state: JsonValue | undefined) { + let color: string; + if (state === undefined) { + color = ColorComponent.undefinedColor; + } else { + if (typeof state !== 'string') { + color = 'IndianRed'; + } else { + color = state; + } + } + + this._paraElement = document.createElement("p"); + this._paraElement.style.textAlign = "left"; + this._paraElement.style.color = color; + const title = container.config.title; + this._paraElement.innerText = (title ?? "unknown") + " component"; + container.contentElement.appendChild(this._paraElement); + + this._inputElement = document.createElement('input'); + this._inputElement.type = "text"; + this._inputElement.value = color; + this._inputElement.style.display = "block"; + + this._inputElement.addEventListener('input', () => this.handleInputChangeEvent()); + container.contentElement.appendChild(this._inputElement); + + container.stateRequestEvent = () => this.handleContainerStateRequestEvent(); + container.beforeDestroyEvent = () => this.handleContainerBeforeDestroyEvent(); + } + + private handleInputChangeEvent() { + this._paraElement.style.color = this._inputElement.value; + } + + private handleContainerStateRequestEvent(): string | undefined { + const color = this._inputElement.value; + if (color === ColorComponent.undefinedColor) { + return undefined; + } else { + return color; + } + } + + private handleContainerBeforeDestroyEvent(): void { + this._inputElement.removeEventListener('change', () => this.handleInputChangeEvent()); + } +} diff --git a/api-test/index.html b/api-test/index.html new file mode 100644 index 000000000..43648a738 --- /dev/null +++ b/api-test/index.html @@ -0,0 +1,30 @@ + + + + + Golden-Layout Demo + + + + +
+
+ +
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ + diff --git a/api-test/main.ts b/api-test/main.ts new file mode 100644 index 000000000..853ea6c19 --- /dev/null +++ b/api-test/main.ts @@ -0,0 +1,22 @@ +import "../src/less/goldenlayout-base.less"; +import "../src/less/themes/goldenlayout-dark-theme.less"; +import { App } from './app'; +import "./test.less"; + +// Run with URL: http://localhost:3000/api-test/dist/ + +declare global { + interface Window { + golderLayoutApiTestApp: App; + } +} + +if (document.readyState !== "loading") run(); +// in case the document is already rendered +else document.addEventListener("DOMContentLoaded", run); + +function run() { + const app = new App(); + window.golderLayoutApiTestApp = app; + app.start(); +} diff --git a/api-test/predefined-layouts.ts b/api-test/predefined-layouts.ts new file mode 100644 index 000000000..e9e71ae65 --- /dev/null +++ b/api-test/predefined-layouts.ts @@ -0,0 +1,455 @@ +import { ItemConfig, UserLayoutConfig, UserSerialisableComponentConfig } from '../dist/golden-layout'; +import { BooleanComponent } from './boolean-component'; +import { ColorComponent } from './color-component'; +import { TextComponent } from './text-component'; + +export interface Layout { + name: string; + config: UserLayoutConfig; +} + +const miniRowConfig: UserLayoutConfig = { + root: { + type: ItemConfig.Type.row, + content: [ + { + type: "component", + title: "Golden", + header: { + show: "top", + }, + isClosable: false, + componentName: ColorComponent.typeName, + width: 30, + componentState: 'gold', + } as UserSerialisableComponentConfig, + { + title: "Layout", + header: { show: "top", popout: false }, + type: "component", + componentName: ColorComponent.typeName, + componentState: undefined, + } as UserSerialisableComponentConfig, + ], + }, +}; + +const miniRowLayout: Layout = { + name: 'miniRow', + config: miniRowConfig, +}; + +const miniStackConfig: UserLayoutConfig = { + root: { + type: ItemConfig.Type.stack, + content: [ + { + type: "component", + title: "Golden", + header: { + show: "top", + }, + isClosable: false, + componentName: ColorComponent.typeName, + width: 30, + componentState: 'white', + } as UserSerialisableComponentConfig, + { + title: "Layout", + header: { show: "top", popout: false }, + type: "component", + componentName: ColorComponent.typeName, + componentState: 'green', + } as UserSerialisableComponentConfig, + ], + }, +}; + +const miniStackLayout: Layout = { + name: 'miniStack', + config: miniStackConfig, +}; + +const standardConfig: UserLayoutConfig = { + root: { + type: "row", + content: [ + { + width: 80, + type: "column", + content: [ + { + title: "Fnts 100", + header: { show: "bottom" }, + type: "component", + componentName: ColorComponent.typeName, + }, + { + type: "row", + content: [ + { + type: "component", + title: "Golden", + header: { show: "right" }, + isClosable: false, + componentName: ColorComponent.typeName, + width: 30, + componentState: { + bg: "golden_layout_spiral.png", + }, + } as UserSerialisableComponentConfig, + { + title: "Layout", + header: { + show: "left", + popout: false, + }, + type: "component", + componentName: ColorComponent.typeName, + componentState: { + bg: "golden_layout_text.png", + }, + } as UserSerialisableComponentConfig, + ], + }, + { + type: "stack", + content: [ + { + type: "component", + title: "Acme, inc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock X", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "LexCorp plc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Y", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "Springshield plc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Z", + }, + } as UserSerialisableComponentConfig, + ], + }, + ], + }, + { + width: 50, + type: "row", + title: "test stack", + content: [ + { + type: "stack", + title: "test row", + content: [ + { + type: "component", + title: "comp 1", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock X", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "comp 2", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Y", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "comp 3", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Z", + }, + } as UserSerialisableComponentConfig, + ], + }, + ], + }, + ], + }, +}; + +const standardLayout: Layout = { + name: 'standard', + config: standardConfig, +}; + +const responsiveConfig: UserLayoutConfig = { + settings: { + responsiveMode: "always", + }, + dimensions: { + minItemWidth: 250, + }, + root: { + type: "row", + content: [ + { + width: 30, + type: "column", + content: [ + { + title: "Fnts 100", + type: "component", + componentName: ColorComponent.typeName, + }, + { + type: "row", + content: [ + { + type: "component", + title: "Golden", + componentName: ColorComponent.typeName, + width: 30, + componentState: { + bg: "golden_layout_spiral.png", + }, + } as UserSerialisableComponentConfig, + ], + }, + { + type: "stack", + content: [ + { + type: "component", + title: "Acme, inc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock X", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "LexCorp plc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Y", + }, + } as UserSerialisableComponentConfig, + { + type: "component", + title: "Springshield plc.", + componentName: ColorComponent.typeName, + componentState: { + companyName: "Stock Z", + }, + } as UserSerialisableComponentConfig, + ], + }, + ], + }, + { + width: 30, + title: "Layout", + type: "component", + componentName: ColorComponent.typeName, + componentState: { bg: "golden_layout_text.png" }, + } as UserSerialisableComponentConfig, + { + width: 20, + type: "component", + title: "Market", + componentName: ColorComponent.typeName, + componentState: { + className: "market-content", + style: [ + ".market-content label {", + " margin-top: 10px", + " display: block", + " text-align: left", + "}", + ".market-content input {", + " width: 250px", + " border: 1px solid red", + "}", + ], + html: [ + '