From 0dc2b16041bf3c774723b00b440369357931c15b Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Mon, 12 Jul 2021 15:51:27 -0400 Subject: some formatting changes --- src/client/views/collections/schemaView/CollectionSchemaView.scss | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/client/views/collections/schemaView/CollectionSchemaView.scss b/src/client/views/collections/schemaView/CollectionSchemaView.scss index b57fee0e4..0662eabaf 100644 --- a/src/client/views/collections/schemaView/CollectionSchemaView.scss +++ b/src/client/views/collections/schemaView/CollectionSchemaView.scss @@ -134,6 +134,13 @@ min-height: 30px; border: 0 !important; } + .rt-tr:nth-of-type(even) { + direction: ltr; + flex: 0 1 auto; + min-height: 30px; + border: 0 !important; + background-color: lightgray; + } .rt-tr { width: 100%; min-height: 30px; -- cgit v1.2.3-70-g09d2 From b5494be46ea1e02b85d24d9405f0d9c60ba2b0f1 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Sat, 17 Jul 2021 15:34:46 -0400 Subject: some styling changes --- .../views/collections/collectionSchema/CollectionSchemaView.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss index 0662eabaf..e866ec079 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaView.scss +++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.scss @@ -134,12 +134,12 @@ min-height: 30px; border: 0 !important; } - .rt-tr:nth-of-type(even) { + .rt-tr-group:nth-of-type(even) { direction: ltr; flex: 0 1 auto; min-height: 30px; border: 0 !important; - background-color: lightgray; + background-color: red; } .rt-tr { width: 100%; -- cgit v1.2.3-70-g09d2 From 6330a8adc6e85bfa5e0b24016e5d76d85bc07e41 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Wed, 21 Jul 2021 08:56:39 -0400 Subject: fixed date formatting --- .../collectionSchema/CollectionSchemaCells.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index f75179cea..a8d901f4d 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -351,13 +351,16 @@ export class CollectionSchemaDateCell extends CollectionSchemaCell { //} } + // If the cell is not clicked on, render the date normally. Otherwise, render a date picker. render() { - return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : - this.handleChange(date)} - onChange={date => this.handleChange(date)} - />; + return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : +
+ this.handleChange(date)} + onChange={date => this.handleChange(date)} + /> +
} } -- cgit v1.2.3-70-g09d2 From 02c5628bdaf43100a6e40baab781342bc27df464 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Wed, 21 Jul 2021 12:46:13 -0400 Subject: fixed the fact that text, number, and boolean were ignoring input types when accepting input --- .../collectionSchema/CollectionSchemaCells.tsx | 114 +++++++++++++-------- 1 file changed, 69 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index a8d901f4d..8b7fb9be8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -214,6 +214,55 @@ export class CollectionSchemaCell extends React.Component { positions.pop(); } } + + // handles input procedures for string cells + let stringInput = (value: string, retVal: boolean): void => { + let valueSansQuotes = value; + if (this._isEditing) { + const vsqLength = valueSansQuotes.length; + // get rid of outer quotes + valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, + valueSansQuotes.charAt(vsqLength - 1) == "\"" ? vsqLength - 1 : vsqLength); + } + let inputAsString = '"'; + // escape any quotes in the string + for (const i of valueSansQuotes) { + if (i == '"') { + inputAsString += '\\"'; + } else { + inputAsString += i; + } + } + // add a closing quote + inputAsString += '"'; + //two options here: we can strip off outer quotes or we can figure out what's going on with the script + const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + } + + // handles input procedure for number cells + let numberInput = (value: string, retVal: boolean): void => { + const inputscript = value.substring(value.startsWith("=") ? 1 : 0); + // if commas are not stripped, the parser only considers the numbers after the last comma + let inputSansCommas = ""; + for (let s of inputscript) { + if (!(s == ",")) { + inputSansCommas += s; + } + } + const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = value.length !== value.length || value.length - 2 !== value.length + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + } + + // handles input procedure for boolean cells + let boolInput = (value: string, retVal: boolean): void => { + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = value.length !== value.length || value.length - 2 !== value.length + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + } + const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined"; return (
{ } // check if the input is a boolean let inputIsBool: boolean = value == "false" || value == "true"; - // what to do in the case - if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { - // if it's not a number, it's a string, and should be processed as such - // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically - // after each edit - let valueSansQuotes = value; - if (this._isEditing) { - const vsqLength = valueSansQuotes.length; - // get rid of outer quotes - valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, - valueSansQuotes.charAt(vsqLength - 1) == "\"" ? vsqLength - 1 : vsqLength); - } - let inputAsString = '"'; - // escape any quotes in the string - for (const i of valueSansQuotes) { - if (i == '"') { - inputAsString += '\\"'; - } else { - inputAsString += i; - } - } - // add a closing quote - inputAsString += '"'; - //two options here: we can strip off outer quotes or we can figure out what's going on with the script - const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - // handle numbers and expressions - } else if (inputIsNum || value.startsWith("=")) { - //TODO: make accept numbers - const inputscript = value.substring(value.startsWith("=") ? 1 : 0); - // if commas are not stripped, the parser only considers the numbers after the last comma - let inputSansCommas = ""; - for (let s of inputscript) { - if (!(s == ",")) { - inputSansCommas += s; - } + + if (type == undefined) { + // what to do in the case + if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { + // if it's not a number, it's a string, and should be processed as such + // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically + // after each edit + stringInput(value, retVal); + // handle numbers and expressions + } else if (inputIsNum || value.startsWith("=")) { + numberInput(value, retVal); + // handle booleans + } else if (inputIsBool) { + boolInput(value, retVal); } - const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - // handle booleans - } else if (inputIsBool) { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + } else if (type == "string") { + stringInput(value, retVal); + } else if (type == "number" && inputIsNum) { + numberInput(value, retVal); + } else if (type == "boolean" && inputIsBool) { + boolInput(value, retVal); } } if (retVal) { -- cgit v1.2.3-70-g09d2 From ee0e2c6c53db65c5524b67ed09369cc0e0e6f173 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Wed, 21 Jul 2021 16:10:04 -0400 Subject: Fixed minor bugs --- .../collectionSchema/CollectionSchemaCells.tsx | 27 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index 8b7fb9be8..f7dfaaeb4 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -300,8 +300,16 @@ export class CollectionSchemaCell extends React.Component { inputIsNum = false; } } + + let contentsAreNum = true; + for (let s of contents) { + if (isNaN(parseInt(s)) && !(s == ".") && !(s == ",")) { + contentsAreNum = false; + } + } // check if the input is a boolean let inputIsBool: boolean = value == "false" || value == "true"; + let contentsAreBool: boolean = contents == "false" || contents == "true"; if (type == undefined) { // what to do in the case @@ -317,12 +325,23 @@ export class CollectionSchemaCell extends React.Component { } else if (inputIsBool) { boolInput(value, retVal); } + // if the cell type is a string } else if (type == "string") { stringInput(value, retVal); - } else if (type == "number" && inputIsNum) { - numberInput(value, retVal); - } else if (type == "boolean" && inputIsBool) { - boolInput(value, retVal); + // if the cell type is a number + } else if (type == "number") { + if (inputIsNum) { + numberInput(value, retVal); + } else if (!contentsAreNum) { + stringInput("", retVal); + } + // if the cell type is a boolean + } else if (type == "boolean") { + if (inputIsBool) { + boolInput(value, retVal); + } else if (!contentsAreBool) { + stringInput("", retVal); + } } } if (retVal) { -- cgit v1.2.3-70-g09d2 From 0b6a18bc445825ecf69f57b49b002ed5c8a13902 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Mon, 26 Jul 2021 16:39:06 -0400 Subject: comments --- src/fields/Doc.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index bd0ba3ad7..e51eb44db 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1251,6 +1251,7 @@ export namespace Doc { if (typeof resolved === "object" && !(resolved instanceof Array)) { output = convertObject(resolved, excludeEmptyObjects, title, appendToExisting?.targetDoc); } else { + // give the proper types to the data extracted from the JSON const result = toField(resolved, excludeEmptyObjects); if (appendToExisting) { (output = appendToExisting.targetDoc)[appendToExisting.fieldKey || defaultKey] = result; -- cgit v1.2.3-70-g09d2 From b3fde759b304f6401595f4e43bb00cc6fa65c915 Mon Sep 17 00:00:00 2001 From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com> Date: Thu, 29 Jul 2021 17:50:15 -0400 Subject: added message to empty tab screen --- src/client/goldenLayout.js | 3056 ++++++++++---------- src/client/views/MainView.scss | 30 +- .../views/collections/CollectionDockingView.scss | 23 + 3 files changed, 1574 insertions(+), 1535 deletions(-) (limited to 'src') diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index 9cfea7f3f..7fca8d9d5 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -82,16 +82,16 @@ return target; }; - /** - * This is based on Paul Irish's shim, but looks quite odd in comparison. Why? - * Because - * a) it shouldn't affect the global requestAnimationFrame function - * b) it shouldn't pass on the time that has passed - * - * @param {Function} fn - * - * @returns {void} - */ + /** + * This is based on Paul Irish's shim, but looks quite odd in comparison. Why? + * Because + * a) it shouldn't affect the global requestAnimationFrame function + * b) it shouldn't pass on the time that has passed + * + * @param {Function} fn + * + * @returns {void} + */ lm.utils.animFrame = function (fn) { return (window.requestAnimationFrame || window.webkitRequestAnimationFrame || @@ -178,16 +178,16 @@ .replace('.', ''); }; - /** - * A basic XSS filter. It is ultimately up to the - * implementing developer to make sure their particular - * applications and usecases are save from cross site scripting attacks - * - * @param {String} input - * @param {Boolean} keepTags - * - * @returns {String} filtered input - */ + /** + * A basic XSS filter. It is ultimately up to the + * implementing developer to make sure their particular + * applications and usecases are save from cross site scripting attacks + * + * @param {String} input + * @param {Boolean} keepTags + * + * @returns {String} filtered input + */ lm.utils.filterXss = function (input, keepTags) { var output = input @@ -206,41 +206,41 @@ } }; - /** - * Removes html tags from a string - * - * @param {String} input - * - * @returns {String} input without tags - */ + /** + * Removes html tags from a string + * + * @param {String} input + * + * @returns {String} input without tags + */ lm.utils.stripTags = function (input) { return $.trim(input.replace(/(<([^>]+)>)/ig, '')); }; - /** - * A generic and very fast EventEmitter - * implementation. On top of emitting the - * actual event it emits an - * - * lm.utils.EventEmitter.ALL_EVENT - * - * event for every event triggered. This allows - * to hook into it and proxy events forwards - * - * @constructor - */ + /** + * A generic and very fast EventEmitter + * implementation. On top of emitting the + * actual event it emits an + * + * lm.utils.EventEmitter.ALL_EVENT + * + * event for every event triggered. This allows + * to hook into it and proxy events forwards + * + * @constructor + */ lm.utils.EventEmitter = function () { this._mSubscriptions = {}; this._mSubscriptions[lm.utils.EventEmitter.ALL_EVENT] = []; - /** - * Listen for events - * - * @param {String} sEvent The name of the event to listen to - * @param {Function} fCallback The callback to execute when the event occurs - * @param {[Object]} oContext The value of the this pointer within the callback function - * - * @returns {void} - */ + /** + * Listen for events + * + * @param {String} sEvent The name of the event to listen to + * @param {Function} fCallback The callback to execute when the event occurs + * @param {[Object]} oContext The value of the this pointer within the callback function + * + * @returns {void} + */ this.on = function (sEvent, fCallback, oContext) { if (!lm.utils.isFunction(fCallback)) { throw new Error('Tried to listen to event ' + sEvent + ' with non-function callback ' + fCallback); @@ -253,14 +253,14 @@ this._mSubscriptions[sEvent].push({ fn: fCallback, ctx: oContext }); }; - /** - * Emit an event and notify listeners - * - * @param {String} sEvent The name of the event - * @param {Mixed} various additional arguments that will be passed to the listener - * - * @returns {void} - */ + /** + * Emit an event and notify listeners + * + * @param {String} sEvent The name of the event + * @param {Mixed} various additional arguments that will be passed to the listener + * + * @returns {void} + */ this.emit = function (sEvent) { var i, ctx, args; @@ -286,15 +286,15 @@ } }; - /** - * Removes a listener for an event, or all listeners if no callback and context is provided. - * - * @param {String} sEvent The name of the event - * @param {Function} fCallback The previously registered callback method (optional) - * @param {Object} oContext The previously registered context (optional) - * - * @returns {void} - */ + /** + * Removes a listener for an event, or all listeners if no callback and context is provided. + * + * @param {String} sEvent The name of the event + * @param {Function} fCallback The previously registered callback method (optional) + * @param {Object} oContext The previously registered context (optional) + * + * @returns {void} + */ this.unbind = function (sEvent, fCallback, oContext) { if (!this._mSubscriptions[sEvent]) { throw new Error('No subscribtions to unsubscribe for event ' + sEvent); @@ -318,28 +318,28 @@ } }; - /** - * Alias for unbind - */ + /** + * Alias for unbind + */ this.off = this.unbind; - /** - * Alias for emit - */ + /** + * Alias for emit + */ this.trigger = this.emit; }; - /** - * The name of the event that's triggered for every other event - * - * usage - * - * myEmitter.on( lm.utils.EventEmitter.ALL_EVENT, function( eventName, argsArray ){ - * //do stuff - * }); - * - * @type {String} - */ + /** + * The name of the event that's triggered for every other event + * + * usage + * + * myEmitter.on( lm.utils.EventEmitter.ALL_EVENT, function( eventName, argsArray ){ + * //do stuff + * }); + * + * @type {String} + */ lm.utils.EventEmitter.ALL_EVENT = '__all'; lm.utils.DragListener = function (eElement, nButtonCode) { lm.utils.EventEmitter.call(this); @@ -349,14 +349,14 @@ this._eBody = $(document.body); this._nButtonCode = nButtonCode || 0; - /** - * The delay after which to start the drag in milliseconds - */ + /** + * The delay after which to start the drag in milliseconds + */ this._nDelay = 200; - /** - * The distance the mouse needs to be moved to qualify as a drag - */ + /** + * The distance the mouse needs to be moved to qualify as a drag + */ this._nDistance = 10;//TODO - works better with delay only this._nX = 0; @@ -459,16 +459,16 @@ }; } }); - /** - * The main class that will be exposed as GoldenLayout. - * - * @public - * @constructor - * @param {GoldenLayout config} config - * @param {[DOM element container]} container Can be a jQuery selector string or a Dom element. Defaults to body - * - * @returns {VOID} - */ + /** + * The main class that will be exposed as GoldenLayout. + * + * @public + * @constructor + * @param {GoldenLayout config} config + * @param {[DOM element container]} container Can be a jQuery selector string or a Dom element. Defaults to body + * + * @returns {VOID} + */ lm.LayoutManager = function (config, container) { if (!$ || typeof $.noConflict !== 'function') { @@ -521,59 +521,59 @@ }; }; - /** - * Hook that allows to access private classes - */ + /** + * Hook that allows to access private classes + */ lm.LayoutManager.__lm = lm; - /** - * Takes a GoldenLayout configuration object and - * replaces its keys and values recursively with - * one letter codes - * - * @static - * @public - * @param {Object} config A GoldenLayout config object - * - * @returns {Object} minified config - */ + /** + * Takes a GoldenLayout configuration object and + * replaces its keys and values recursively with + * one letter codes + * + * @static + * @public + * @param {Object} config A GoldenLayout config object + * + * @returns {Object} minified config + */ lm.LayoutManager.minifyConfig = function (config) { return (new lm.utils.ConfigMinifier()).minifyConfig(config); }; - /** - * Takes a configuration Object that was previously minified - * using minifyConfig and returns its original version - * - * @static - * @public - * @param {Object} minifiedConfig - * - * @returns {Object} the original configuration - */ + /** + * Takes a configuration Object that was previously minified + * using minifyConfig and returns its original version + * + * @static + * @public + * @param {Object} minifiedConfig + * + * @returns {Object} the original configuration + */ lm.LayoutManager.unminifyConfig = function (config) { return (new lm.utils.ConfigMinifier()).unminifyConfig(config); }; lm.utils.copy(lm.LayoutManager.prototype, { - /** - * Register a component with the layout manager. If a configuration node - * of type component is reached it will look up componentName and create the - * associated component - * - * { - * type: "component", - * componentName: "EquityNewsFeed", - * componentState: { "feedTopic": "us-bluechips" } - * } - * - * @public - * @param {String} name - * @param {Function} constructor - * - * @returns {void} - */ + /** + * Register a component with the layout manager. If a configuration node + * of type component is reached it will look up componentName and create the + * associated component + * + * { + * type: "component", + * componentName: "EquityNewsFeed", + * componentState: { "feedTopic": "us-bluechips" } + * } + * + * @public + * @param {String} name + * @param {Function} constructor + * + * @returns {void} + */ registerComponent: function (name, constructor) { if (typeof constructor !== 'function') { throw new Error('Please register a constructor function'); @@ -586,12 +586,12 @@ this._components[name] = constructor; }, - /** - * Creates a layout configuration object based on the the current state - * - * @public - * @returns {Object} GoldenLayout configuration - */ + /** + * Creates a layout configuration object based on the the current state + * + * @public + * @returns {Object} GoldenLayout configuration + */ toConfig: function (root) { var config, next, i; @@ -603,18 +603,18 @@ throw new Error('Root must be a ContentItem'); } - /* - * settings & labels - */ + /* + * settings & labels + */ config = { settings: lm.utils.copy({}, this.config.settings), dimensions: lm.utils.copy({}, this.config.dimensions), labels: lm.utils.copy({}, this.config.labels) }; - /* - * Content - */ + /* + * Content + */ config.content = []; next = function (configNode, item) { var key, i; @@ -641,30 +641,30 @@ next(config, this.root); } - /* - * Retrieve config for subwindows - */ + /* + * Retrieve config for subwindows + */ this._$reconcilePopoutWindows(); config.openPopouts = []; for (i = 0; i < this.openPopouts.length; i++) { config.openPopouts.push(this.openPopouts[i].toConfig()); } - /* - * Add maximised item - */ + /* + * Add maximised item + */ config.maximisedItemId = this._maximisedItem ? '__glMaximised' : null; return config; }, - /** - * Returns a previously registered component - * - * @public - * @param {String} name The name used - * - * @returns {Function} - */ + /** + * Returns a previously registered component + * + * @public + * @param {String} name The name used + * + * @returns {Function} + */ getComponent: function (name) { if (this._components[name] === undefined) { throw new lm.errors.ConfigurationError('Unknown component "' + name + '"'); @@ -673,44 +673,44 @@ return this._components[name]; }, - /** - * Creates the actual layout. Must be called after all initial components - * are registered. Recurses through the configuration and sets up - * the item tree. - * - * If called before the document is ready it adds itself as a listener - * to the document.ready event - * - * @public - * - * @returns {void} - */ + /** + * Creates the actual layout. Must be called after all initial components + * are registered. Recurses through the configuration and sets up + * the item tree. + * + * If called before the document is ready it adds itself as a listener + * to the document.ready event + * + * @public + * + * @returns {void} + */ init: function () { - /** - * Create the popout windows straight away. If popouts are blocked - * an error is thrown on the same 'thread' rather than a timeout and can - * be caught. This also prevents any further initilisation from taking place. - */ + /** + * Create the popout windows straight away. If popouts are blocked + * an error is thrown on the same 'thread' rather than a timeout and can + * be caught. This also prevents any further initilisation from taking place. + */ if (this._subWindowsCreated === false) { this._createSubWindows(); this._subWindowsCreated = true; } - /** - * If the document isn't ready yet, wait for it. - */ + /** + * If the document isn't ready yet, wait for it. + */ if (document.readyState === 'loading' || document.body === null) { $(document).ready(lm.utils.fnBind(this.init, this)); return; } - /** - * If this is a subwindow, wait a few milliseconds for the original - * page's js calls to be executed, then replace the bodies content - * with GoldenLayout - */ + /** + * If this is a subwindow, wait a few milliseconds for the original + * page's js calls to be executed, then replace the bodies content + * with GoldenLayout + */ if (this.isSubWindow === true && this._creationTimeoutPassed === false) { setTimeout(lm.utils.fnBind(this.init, this), 7); this._creationTimeoutPassed = true; @@ -732,15 +732,15 @@ this.emit('initialised'); }, - /** - * Updates the layout managers size - * - * @public - * @param {[int]} width height in pixels - * @param {[int]} height width in pixels - * - * @returns {void} - */ + /** + * Updates the layout managers size + * + * @public + * @param {[int]} width height in pixels + * @param {[int]} height width in pixels + * + * @returns {void} + */ updateSize: function (width, height) { if (arguments.length === 2) { this.width = width; @@ -763,13 +763,13 @@ } }, - /** - * Destroys the LayoutManager instance itself as well as every ContentItem - * within it. After this is called nothing should be left of the LayoutManager. - * - * @public - * @returns {void} - */ + /** + * Destroys the LayoutManager instance itself as well as every ContentItem + * within it. After this is called nothing should be left of the LayoutManager. + * + * @public + * @returns {void} + */ destroy: function () { if (this.isInitialised === false) { return; @@ -793,16 +793,16 @@ this._dragSources = []; }, - /** - * Recursively creates new item tree structures based on a provided - * ItemConfiguration object - * - * @public - * @param {Object} config ItemConfig - * @param {[ContentItem]} parent The item the newly created item should be a child of - * - * @returns {lm.items.ContentItem} - */ + /** + * Recursively creates new item tree structures based on a provided + * ItemConfiguration object + * + * @public + * @param {Object} config ItemConfig + * @param {[ContentItem]} parent The item the newly created item should be a child of + * + * @returns {lm.items.ContentItem} + */ createContentItem: function (config, parent) { var typeErrorMsg, contentItem; @@ -823,9 +823,9 @@ } - /** - * We add an additional stack around every component that's not within a stack anyways. - */ + /** + * We add an additional stack around every component that's not within a stack anyways. + */ if ( // If this is a component config.type === 'component' && @@ -851,17 +851,17 @@ return contentItem; }, - /** - * Creates a popout window with the specified content and dimensions - * - * @param {Object|lm.itemsAbstractContentItem} configOrContentItem - * @param {[Object]} dimensions A map with width, height, left and top - * @param {[String]} parentId the id of the element this item will be appended to - * when popIn is called - * @param {[Number]} indexInParent The position of this item within its parent element + /** + * Creates a popout window with the specified content and dimensions + * + * @param {Object|lm.itemsAbstractContentItem} configOrContentItem + * @param {[Object]} dimensions A map with width, height, left and top + * @param {[String]} parentId the id of the element this item will be appended to + * when popIn is called + * @param {[Number]} indexInParent The position of this item within its parent element - * @returns {lm.controls.BrowserPopout} - */ + * @returns {lm.controls.BrowserPopout} + */ createPopout: function (configOrContentItem, dimensions, parentId, indexInParent) { var config = configOrContentItem, isItem = configOrContentItem instanceof lm.items.AbstractContentItem, @@ -879,14 +879,14 @@ config = this.toConfig(configOrContentItem).content; parentId = lm.utils.getUniqueId(); - /** - * If the item is the only component within a stack or for some - * other reason the only child of its parent the parent will be destroyed - * when the child is removed. - * - * In order to support this we move up the tree until we find something - * that will remain after the item is being popped out - */ + /** + * If the item is the only component within a stack or for some + * other reason the only child of its parent the parent will be destroyed + * when the child is removed. + * + * In order to support this we move up the tree until we find something + * that will remain after the item is being popped out + */ parent = configOrContentItem.parent; child = configOrContentItem; while (parent.contentItems.length === 1 && !parent.isRoot) { @@ -946,16 +946,16 @@ return browserPopout; }, - /** - * Attaches DragListener to any given DOM element - * and turns it into a way of creating new ContentItems - * by 'dragging' the DOM element into the layout - * - * @param {jQuery DOM element} element - * @param {Object|Function} itemConfig for the new item to be created, or a function which will provide it - * - * @returns {void} - */ + /** + * Attaches DragListener to any given DOM element + * and turns it into a way of creating new ContentItems + * by 'dragging' the DOM element into the layout + * + * @param {jQuery DOM element} element + * @param {Object|Function} itemConfig for the new item to be created, or a function which will provide it + * + * @returns {void} + */ createDragSource: function (element, itemConfig) { this.config.settings.constrainDragToContainer = false; var dragSource = new lm.controls.DragSource($(element), itemConfig, this); @@ -964,17 +964,17 @@ return dragSource; }, - /** - * Programmatically selects an item. This deselects - * the currently selected item, selects the specified item - * and emits a selectionChanged event - * - * @param {lm.item.AbstractContentItem} item# - * @param {[Boolean]} _$silent Wheather to notify the item of its selection - * @event selectionChanged - * - * @returns {VOID} - */ + /** + * Programmatically selects an item. This deselects + * the currently selected item, selects the specified item + * and emits a selectionChanged event + * + * @param {lm.item.AbstractContentItem} item# + * @param {[Boolean]} _$silent Wheather to notify the item of its selection + * @event selectionChanged + * + * @returns {VOID} + */ selectItem: function (item, _$silent) { if (this.config.settings.selectionEnabled !== true) { @@ -998,9 +998,9 @@ this.emit('selectionChanged', item); }, - /************************* - * PACKAGE PRIVATE - *************************/ + /************************* + * PACKAGE PRIVATE + *************************/ _$maximiseItem: function (contentItem) { if (this._maximisedItem !== null) { this._$minimiseItem(this._maximisedItem); @@ -1028,20 +1028,20 @@ this.emit('stateChanged'); }, - /** - * This method is used to get around sandboxed iframe restrictions. - * If 'allow-top-navigation' is not specified in the iframe's 'sandbox' attribute - * (as is the case with codepens) the parent window is forbidden from calling certain - * methods on the child, such as window.close() or setting document.location.href. - * - * This prevented GoldenLayout popouts from popping in in codepens. The fix is to call - * _$closeWindow on the child window's gl instance which (after a timeout to disconnect - * the invoking method from the close call) closes itself. - * - * @packagePrivate - * - * @returns {void} - */ + /** + * This method is used to get around sandboxed iframe restrictions. + * If 'allow-top-navigation' is not specified in the iframe's 'sandbox' attribute + * (as is the case with codepens) the parent window is forbidden from calling certain + * methods on the child, such as window.close() or setting document.location.href. + * + * This prevented GoldenLayout popouts from popping in in codepens. The fix is to call + * _$closeWindow on the child window's gl instance which (after a timeout to disconnect + * the invoking method from the close call) closes itself. + * + * @packagePrivate + * + * @returns {void} + */ _$closeWindow: function () { window.setTimeout(function () { window.close(); @@ -1088,13 +1088,13 @@ var i, area, allContentItems = this._getAllContentItems(); this._itemAreas = []; - /** - * If the last item is dragged out, highlight the entire container size to - * allow to re-drop it. allContentItems[ 0 ] === this.root at this point - * - * Don't include root into the possible drop areas though otherwise since it - * will used for every gap in the layout, e.g. splitters - */ + /** + * If the last item is dragged out, highlight the entire container size to + * allow to re-drop it. allContentItems[ 0 ] === this.root at this point + * + * Don't include root into the possible drop areas though otherwise since it + * will used for every gap in the layout, e.g. splitters + */ if (allContentItems.length === 1) { this._itemAreas.push(this.root._$getArea()); return; @@ -1124,18 +1124,18 @@ } }, - /** - * Takes a contentItem or a configuration and optionally a parent - * item and returns an initialised instance of the contentItem. - * If the contentItem is a function, it is first called - * - * @packagePrivate - * - * @param {lm.items.AbtractContentItem|Object|Function} contentItemOrConfig - * @param {lm.items.AbtractContentItem} parent Only necessary when passing in config - * - * @returns {lm.items.AbtractContentItem} - */ + /** + * Takes a contentItem or a configuration and optionally a parent + * item and returns an initialised instance of the contentItem. + * If the contentItem is a function, it is first called + * + * @packagePrivate + * + * @param {lm.items.AbtractContentItem|Object|Function} contentItemOrConfig + * @param {lm.items.AbtractContentItem} parent Only necessary when passing in config + * + * @returns {lm.items.AbtractContentItem} + */ _$normalizeContentItem: function (contentItemOrConfig, parent) { if (!contentItemOrConfig) { throw new Error('No content item defined'); @@ -1158,15 +1158,15 @@ } }, - /** - * Iterates through the array of open popout windows and removes the ones - * that are effectively closed. This is necessary due to the lack of reliably - * listening for window.close / unload events in a cross browser compatible fashion. - * - * @packagePrivate - * - * @returns {void} - */ + /** + * Iterates through the array of open popout windows and removes the ones + * that are effectively closed. This is necessary due to the lack of reliably + * listening for window.close / unload events in a cross browser compatible fashion. + * + * @packagePrivate + * + * @returns {void} + */ _$reconcilePopoutWindows: function () { var openPopouts = [], i; @@ -1185,17 +1185,17 @@ }, - /*************************** - * PRIVATE - ***************************/ - /** - * Returns a flattened array of all content items, - * regardles of level or type - * - * @private - * - * @returns {void} - */ + /*************************** + * PRIVATE + ***************************/ + /** + * Returns a flattened array of all content items, + * regardles of level or type + * + * @private + * + * @returns {void} + */ _getAllContentItems: function () { var allContentItems = []; @@ -1214,13 +1214,13 @@ return allContentItems; }, - /** - * Binds to DOM/BOM events on init - * - * @private - * - * @returns {void} - */ + /** + * Binds to DOM/BOM events on init + * + * @private + * + * @returns {void} + */ _bindEvents: function () { if (this._isFullPage) { $(window).resize(this._resizeFunction); @@ -1228,27 +1228,27 @@ $(window).on('unload beforeunload', this._unloadFunction); }, - /** - * Debounces resize events - * - * @private - * - * @returns {void} - */ + /** + * Debounces resize events + * + * @private + * + * @returns {void} + */ _onResize: function () { clearTimeout(this._resizeTimeoutId); this._resizeTimeoutId = setTimeout(lm.utils.fnBind(this.updateSize, this), 100); }, - /** - * Extends the default config with the user specific settings and applies - * derivations. Please note that there's a seperate method (AbstractContentItem._extendItemNode) - * that deals with the extension of item configs - * - * @param {Object} config - * @static - * @returns {Object} config - */ + /** + * Extends the default config with the user specific settings and applies + * derivations. Please note that there's a seperate method (AbstractContentItem._extendItemNode) + * that deals with the extension of item configs + * + * @param {Object} config + * @static + * @returns {Object} config + */ _createConfig: function (config) { var windowConfigKey = lm.utils.getQueryStringParam('gl-window'); @@ -1283,14 +1283,14 @@ return config; }, - /** - * This is executed when GoldenLayout detects that it is run - * within a previously opened popout window. - * - * @private - * - * @returns {void} - */ + /** + * This is executed when GoldenLayout detects that it is run + * within a previously opened popout window. + * + * @private + * + * @returns {void} + */ _adjustToWindowMode: function () { var popInButton = $('
' + '
' + @@ -1310,26 +1310,26 @@ .css('visibility', 'visible') .append(popInButton); - /* - * This seems a bit pointless, but actually causes a reflow/re-evaluation getting around - * slickgrid's "Cannot find stylesheet." bug in chrome - */ + /* + * This seems a bit pointless, but actually causes a reflow/re-evaluation getting around + * slickgrid's "Cannot find stylesheet." bug in chrome + */ var x = document.body.offsetHeight; // jshint ignore:line - /* - * Expose this instance on the window object - * to allow the opening window to interact with - * it - */ + /* + * Expose this instance on the window object + * to allow the opening window to interact with + * it + */ window.__glInstance = this; }, - /** - * Creates Subwindows (if there are any). Throws an error - * if popouts are blocked. - * - * @returns {void} - */ + /** + * Creates Subwindows (if there are any). Throws an error + * if popouts are blocked. + * + * @returns {void} + */ _createSubWindows: function () { var i, popout; @@ -1345,13 +1345,13 @@ } }, - /** - * Determines what element the layout will be created in - * - * @private - * - * @returns {void} - */ + /** + * Determines what element the layout will be created in + * + * @private + * + * @returns {void} + */ _setContainer: function () { var container = $(this.container || 'body'); @@ -1377,13 +1377,13 @@ this.container = container; }, - /** - * Kicks of the initial, recursive creation chain - * - * @param {Object} config GoldenLayout Config - * - * @returns {void} - */ + /** + * Kicks of the initial, recursive creation chain + * + * @param {Object} config GoldenLayout Config + * + * @returns {void} + */ _create: function (config) { var errorMsg; @@ -1410,12 +1410,12 @@ } }, - /** - * Called when the window is closed or the user navigates away - * from the page - * - * @returns {void} - */ + /** + * Called when the window is closed or the user navigates away + * from the page + * + * @returns {void} + */ _onUnload: function () { if (this.config.settings.closePopoutsOnUnload === true) { for (var i = 0; i < this.openPopouts.length; i++) { @@ -1424,11 +1424,11 @@ } }, - /** - * Adjusts the number of columns to be lower to fit the screen and still maintain minItemWidth. - * - * @returns {void} - */ + /** + * Adjusts the number of columns to be lower to fit the screen and still maintain minItemWidth. + * + * @returns {void} + */ _adjustColumnsResponsive: function () { // If there is no min width set, or not content items, do nothing. @@ -1470,21 +1470,21 @@ this._updatingColumnsResponsive = false; }, - /** - * Determines if responsive layout should be used. - * - * @returns {bool} - True if responsive layout should be used; otherwise false. - */ + /** + * Determines if responsive layout should be used. + * + * @returns {bool} - True if responsive layout should be used; otherwise false. + */ _useResponsiveLayout: function () { return this.config.settings && (this.config.settings.responsiveMode == 'always' || (this.config.settings.responsiveMode == 'onload' && this._firstLoad)); }, - /** - * Adds all children of a node to another container recursively. - * @param {object} container - Container to add child content items to. - * @param {object} node - Node to search for content items. - * @returns {void} - */ + /** + * Adds all children of a node to another container recursively. + * @param {object} container - Container to add child content items to. + * @param {object} node - Node to search for content items. + * @returns {void} + */ _addChildContentItemsToContainer: function (container, node) { if (node.type === 'stack') { node.contentItems.forEach(function (item) { @@ -1499,10 +1499,10 @@ } }, - /** - * Finds all the stack containers. - * @returns {array} - The found stack containers. - */ + /** + * Finds all the stack containers. + * @returns {array} - The found stack containers. + */ _findAllStackContainers: function () { var stackContainers = []; this._findAllStackContainersRecursive(stackContainers, this.root); @@ -1510,14 +1510,14 @@ return stackContainers; }, - /** - * Finds all the stack containers. - * - * @param {array} - Set of containers to populate. - * @param {object} - Current node to process. - * - * @returns {void} - */ + /** + * Finds all the stack containers. + * + * @param {array} - Set of containers to populate. + * @param {object} - Current node to process. + * + * @returns {void} + */ _findAllStackContainersRecursive: function (stackContainers, node) { node.contentItems.forEach(lm.utils.fnBind(function (item) { if (item.type == 'stack') { @@ -1530,9 +1530,9 @@ } }); - /** - * Expose the Layoutmanager as the single entrypoint using UMD - */ + /** + * Expose the Layoutmanager as the single entrypoint using UMD + */ (function () { /* global define */ if (typeof define === 'function' && define.amd) { @@ -1583,7 +1583,7 @@ close: 'close', maximise: 'maximise', minimise: 'minimise', - popout: 'open in new window', + popout: 'new tab', popin: 'pop in', tabDropdown: 'additional tabs' } @@ -1611,36 +1611,36 @@ lm.utils.copy(lm.container.ItemContainer.prototype, { - /** - * Get the inner DOM element the container's content - * is intended to live in - * - * @returns {DOM element} - */ + /** + * Get the inner DOM element the container's content + * is intended to live in + * + * @returns {DOM element} + */ getElement: function () { return this._contentElement; }, - /** - * Hide the container. Notifies the containers content first - * and then hides the DOM node. If the container is already hidden - * this should have no effect - * - * @returns {void} - */ + /** + * Hide the container. Notifies the containers content first + * and then hides the DOM node. If the container is already hidden + * this should have no effect + * + * @returns {void} + */ hide: function () { this.emit('hide'); this.isHidden = true; this._element.hide(); }, - /** - * Shows a previously hidden container. Notifies the - * containers content first and then shows the DOM element. - * If the container is already visible this has no effect. - * - * @returns {void} - */ + /** + * Shows a previously hidden container. Notifies the + * containers content first and then shows the DOM element. + * If the container is already visible this has no effect. + * + * @returns {void} + */ show: function () { this.emit('show'); this.isHidden = false; @@ -1651,19 +1651,19 @@ } }, - /** - * Set the size from within the container. Traverses up - * the item tree until it finds a row or column element - * and resizes its items accordingly. - * - * If this container isn't a descendant of a row or column - * it returns false - * @todo Rework!!! - * @param {Number} width The new width in pixel - * @param {Number} height The new height in pixel - * - * @returns {Boolean} resizeSuccesful - */ + /** + * Set the size from within the container. Traverses up + * the item tree until it finds a row or column element + * and resizes its items accordingly. + * + * If this container isn't a descendant of a row or column + * it returns false + * @todo Rework!!! + * @param {Number} width The new width in pixel + * @param {Number} height The new height in pixel + * + * @returns {Boolean} resizeSuccesful + */ setSize: function (width, height) { var rowOrColumn = this.parent, rowOrColumnChild = this, @@ -1679,9 +1679,9 @@ rowOrColumn = rowOrColumn.parent; - /** - * No row or column has been found - */ + /** + * No row or column has been found + */ if (rowOrColumn.isRoot) { return false; } @@ -1707,13 +1707,13 @@ return true; }, - /** - * Closes the container if it is closable. Can be called by - * both the component within at as well as the contentItem containing - * it. Emits a close event before the container itself is closed. - * - * @returns {void} - */ + /** + * Closes the container if it is closable. Can be called by + * both the component within at as well as the contentItem containing + * it. Emits a close event before the container itself is closed. + * + * @returns {void} + */ close: function () { if (this._config.isClosable) { this.emit('close'); @@ -1721,55 +1721,55 @@ } }, - /** - * Returns the current state object - * - * @returns {Object} state - */ + /** + * Returns the current state object + * + * @returns {Object} state + */ getState: function () { return this._config.componentState; }, - /** - * Merges the provided state into the current one - * - * @param {Object} state - * - * @returns {void} - */ + /** + * Merges the provided state into the current one + * + * @param {Object} state + * + * @returns {void} + */ extendState: function (state) { this.setState($.extend(true, this.getState(), state)); }, - /** - * Notifies the layout manager of a stateupdate - * - * @param {serialisable} state - */ + /** + * Notifies the layout manager of a stateupdate + * + * @param {serialisable} state + */ setState: function (state) { this._config.componentState = state; this.parent.emitBubblingEvent('stateChanged'); }, - /** - * Set's the components title - * - * @param {String} title - */ + /** + * Set's the components title + * + * @param {String} title + */ setTitle: function (title) { this.parent.setTitle(title); }, - /** - * Set's the containers size. Called by the container's component. - * To set the size programmatically from within the container please - * use the public setSize method - * - * @param {[Int]} width in px - * @param {[Int]} height in px - * - * @returns {void} - */ + /** + * Set's the containers size. Called by the container's component. + * To set the size programmatically from within the container please + * use the public setSize method + * + * @param {[Int]} width in px + * @param {[Int]} height in px + * + * @returns {void} + */ _$setSize: function (width, height) { if (width !== this.width || height !== this.height) { this.width = width; @@ -1784,22 +1784,22 @@ } }); - /** - * Pops a content item out into a new browser window. - * This is achieved by - * - * - Creating a new configuration with the content item as root element - * - Serializing and minifying the configuration - * - Opening the current window's URL with the configuration as a GET parameter - * - GoldenLayout when opened in the new window will look for the GET parameter - * and use it instead of the provided configuration - * - * @param {Object} config GoldenLayout item config - * @param {Object} dimensions A map with width, height, top and left - * @param {String} parentId The id of the element the item will be appended to on popIn - * @param {Number} indexInParent The position of this element within its parent - * @param {lm.LayoutManager} layoutManager - */ + /** + * Pops a content item out into a new browser window. + * This is achieved by + * + * - Creating a new configuration with the content item as root element + * - Serializing and minifying the configuration + * - Opening the current window's URL with the configuration as a GET parameter + * - GoldenLayout when opened in the new window will look for the GET parameter + * and use it instead of the provided configuration + * + * @param {Object} config GoldenLayout item config + * @param {Object} dimensions A map with width, height, top and left + * @param {String} parentId The id of the element the item will be appended to on popIn + * @param {Number} indexInParent The position of this element within its parent + * @param {lm.LayoutManager} layoutManager + */ lm.controls.BrowserPopout = function (config, dimensions, parentId, indexInParent, layoutManager) { lm.utils.EventEmitter.call(this); this.isInitialised = false; @@ -1853,10 +1853,10 @@ } }, - /** - * Returns the popped out item to its original position. If the original - * parent isn't available anymore it falls back to the layout's topmost element - */ + /** + * Returns the popped out item to its original position. If the original + * parent isn't available anymore it falls back to the layout's topmost element + */ popIn: function () { var childConfig, parentItem, @@ -1864,22 +1864,22 @@ if (this._parentId) { - /* - * The $.extend call seems a bit pointless, but it's crucial to - * copy the config returned by this.getGlInstance().toConfig() - * onto a new object. Internet Explorer keeps the references - * to objects on the child window, resulting in the following error - * once the child window is closed: - * - * The callee (server [not server application]) is not available and disappeared - */ + /* + * The $.extend call seems a bit pointless, but it's crucial to + * copy the config returned by this.getGlInstance().toConfig() + * onto a new object. Internet Explorer keeps the references + * to objects on the child window, resulting in the following error + * once the child window is closed: + * + * The callee (server [not server application]) is not available and disappeared + */ childConfig = $.extend(true, {}, this.getGlInstance().toConfig()).content[0]; parentItem = this._layoutManager.root.getItemsById(this._parentId)[0]; - /* - * Fallback if parentItem is not available. Either add it to the topmost - * item or make it the topmost item if the layout is empty - */ + /* + * Fallback if parentItem is not available. Either add it to the topmost + * item or make it the topmost item if the layout is empty + */ if (!parentItem) { if (this._layoutManager.root.contentItems.length > 0) { parentItem = this._layoutManager.root.contentItems[0]; @@ -1894,28 +1894,28 @@ this.close(); }, - /** - * Creates the URL and window parameter - * and opens a new window - * - * @private - * - * @returns {void} - */ + /** + * Creates the URL and window parameter + * and opens a new window + * + * @private + * + * @returns {void} + */ _createWindow: function () { var checkReadyInterval, url = this._createUrl(), - /** - * Bogus title to prevent re-usage of existing window with the - * same title. The actual title will be set by the new window's - * GoldenLayout instance if it detects that it is in subWindowMode - */ + /** + * Bogus title to prevent re-usage of existing window with the + * same title. The actual title will be set by the new window's + * GoldenLayout instance if it detects that it is in subWindowMode + */ title = Math.floor(Math.random() * 1000000).toString(36), - /** - * The options as used in the window.open string - */ + /** + * The options as used in the window.open string + */ options = this._serializeWindowOptions({ width: this._dimensions.width, height: this._dimensions.height, @@ -1946,12 +1946,12 @@ .on('load', lm.utils.fnBind(this._positionWindow, this)) .on('unload beforeunload', lm.utils.fnBind(this._onClose, this)); - /** - * Polling the childwindow to find out if GoldenLayout has been initialised - * doesn't seem optimal, but the alternatives - adding a callback to the parent - * window or raising an event on the window object - both would introduce knowledge - * about the parent to the child window which we'd rather avoid - */ + /** + * Polling the childwindow to find out if GoldenLayout has been initialised + * doesn't seem optimal, but the alternatives - adding a callback to the parent + * window or raising an event on the window object - both would introduce knowledge + * about the parent to the child window which we'd rather avoid + */ checkReadyInterval = setInterval(lm.utils.fnBind(function () { if (this._popoutWindow.__glInstance && this._popoutWindow.__glInstance.isInitialised) { this._onInitialised(); @@ -1960,13 +1960,13 @@ }, this), 10); }, - /** - * Serialises a map of key:values to a window options string - * - * @param {Object} windowOptions - * - * @returns {String} serialised window options - */ + /** + * Serialises a map of key:values to a window options string + * + * @param {Object} windowOptions + * + * @returns {String} serialised window options + */ _serializeWindowOptions: function (windowOptions) { var windowOptionsString = [], key; @@ -1977,12 +1977,12 @@ return windowOptionsString.join(','); }, - /** - * Creates the URL for the new window, including the - * config GET parameter - * - * @returns {String} URL - */ + /** + * Creates the URL for the new window, including the + * config GET parameter + * + * @returns {String} URL + */ _createUrl: function () { var config = { content: this._config }, storageKey = 'gl-window-config-' + lm.utils.getUniqueId(), @@ -2008,57 +2008,57 @@ } }, - /** - * Move the newly created window roughly to - * where the component used to be. - * - * @private - * - * @returns {void} - */ + /** + * Move the newly created window roughly to + * where the component used to be. + * + * @private + * + * @returns {void} + */ _positionWindow: function () { this._popoutWindow.moveTo(this._dimensions.left, this._dimensions.top); this._popoutWindow.focus(); }, - /** - * Callback when the new window is opened and the GoldenLayout instance - * within it is initialised - * - * @returns {void} - */ + /** + * Callback when the new window is opened and the GoldenLayout instance + * within it is initialised + * + * @returns {void} + */ _onInitialised: function () { this.isInitialised = true; this.getGlInstance().on('popIn', this.popIn, this); this.emit('initialised'); }, - /** - * Invoked 50ms after the window unload event - * - * @private - * - * @returns {void} - */ + /** + * Invoked 50ms after the window unload event + * + * @private + * + * @returns {void} + */ _onClose: function () { setTimeout(lm.utils.fnBind(this.emit, this, ['closed']), 50); } }); - /** - * This class creates a temporary container - * for the component whilst it is being dragged - * and handles drag events - * - * @constructor - * @private - * - * @param {Number} x The initial x position - * @param {Number} y The initial y position - * @param {lm.utils.DragListener} dragListener - * @param {lm.LayoutManager} layoutManager - * @param {lm.item.AbstractContentItem} contentItem - * @param {lm.item.AbstractContentItem} originalParent - */ + /** + * This class creates a temporary container + * for the component whilst it is being dragged + * and handles drag events + * + * @constructor + * @private + * + * @param {Number} x The initial x position + * @param {Number} y The initial y position + * @param {lm.utils.DragListener} dragListener + * @param {lm.LayoutManager} layoutManager + * @param {lm.item.AbstractContentItem} contentItem + * @param {lm.item.AbstractContentItem} originalParent + */ lm.controls.DragProxy = function (x, y, dragListener, layoutManager, contentItem, originalParent) { lm.utils.EventEmitter.call(this); @@ -2120,19 +2120,19 @@ lm.utils.copy(lm.controls.DragProxy.prototype, { - /** - * Callback on every mouseMove event during a drag. Determines if the drag is - * still within the valid drag area and calls the layoutManager to highlight the - * current drop area - * - * @param {Number} offsetX The difference from the original x position in px - * @param {Number} offsetY The difference from the original y position in px - * @param {jQuery DOM event} event - * - * @private - * - * @returns {void} - */ + /** + * Callback on every mouseMove event during a drag. Determines if the drag is + * still within the valid drag area and calls the layoutManager to highlight the + * current drop area + * + * @param {Number} offsetX The difference from the original x position in px + * @param {Number} offsetY The difference from the original y position in px + * @param {jQuery DOM event} event + * + * @private + * + * @returns {void} + */ _onDrag: function (offsetX, offsetY, event) { event = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0] : event; @@ -2148,16 +2148,16 @@ this._setDropPosition(x, y); }, - /** - * Sets the target position, highlighting the appropriate area - * - * @param {Number} x The x position in px - * @param {Number} y The y position in px - * - * @private - * - * @returns {void} - */ + /** + * Sets the target position, highlighting the appropriate area + * + * @param {Number} x The x position in px + * @param {Number} y The y position in px + * + * @private + * + * @returns {void} + */ _setDropPosition: function (x, y) { this.element.css({ left: x, top: y }); this._area = this._layoutManager._$getArea(x, y); @@ -2168,43 +2168,43 @@ } }, - /** - * Callback when the drag has finished. Determines the drop area - * and adds the child to it - * - * @private - * - * @returns {void} - */ + /** + * Callback when the drag has finished. Determines the drop area + * and adds the child to it + * + * @private + * + * @returns {void} + */ _onDrop: function () { this._layoutManager.dropTargetIndicator.hide(); - /* - * Valid drop area found - */ + /* + * Valid drop area found + */ if (this._area !== null) { this._area.contentItem._$onDrop(this._contentItem, this._area); - /** - * No valid drop area available at present, but one has been found before. - * Use it - */ + /** + * No valid drop area available at present, but one has been found before. + * Use it + */ } else if (this._lastValidArea !== null) { this._lastValidArea.contentItem._$onDrop(this._contentItem, this._lastValidArea); - /** - * No valid drop area found during the duration of the drag. Return - * content item to its original position if a original parent is provided. - * (Which is not the case if the drag had been initiated by createDragSource) - */ + /** + * No valid drop area found during the duration of the drag. Return + * content item to its original position if a original parent is provided. + * (Which is not the case if the drag had been initiated by createDragSource) + */ } else if (this._originalParent) { this._originalParent.addChild(this._contentItem); - /** - * The drag didn't ultimately end up with adding the content item to - * any container. In order to ensure clean up happens, destroy the - * content item. - */ + /** + * The drag didn't ultimately end up with adding the content item to + * any container. In order to ensure clean up happens, destroy the + * content item. + */ } else { this._contentItem._$destroy(); } @@ -2215,18 +2215,18 @@ this._layoutManager.emit('itemDropped', this._contentItem); }, - /** - * Removes the item from its original position within the tree - * - * @private - * - * @returns {void} - */ + /** + * Removes the item from its original position within the tree + * + * @private + * + * @returns {void} + */ _updateTree: function () { - /** - * parent is null if the drag had been initiated by a external drag source - */ + /** + * parent is null if the drag had been initiated by a external drag source + */ if (this._contentItem.parent) { this._contentItem.parent.removeChild(this._contentItem, true); } @@ -2234,13 +2234,13 @@ this._contentItem._$setParent(this); }, - /** - * Updates the Drag Proxie's dimensions - * - * @private - * - * @returns {void} - */ + /** + * Updates the Drag Proxie's dimensions + * + * @private + * + * @returns {void} + */ _setDimensions: function () { var dimensions = this._layoutManager.config.dimensions, width = dimensions.dragProxyWidth, @@ -2259,16 +2259,16 @@ } }); - /** - * Allows for any DOM item to create a component on drag - * start tobe dragged into the Layout - * - * @param {jQuery element} element - * @param {Object} itemConfig the configuration for the contentItem that will be created - * @param {LayoutManager} layoutManager - * - * @constructor - */ + /** + * Allows for any DOM item to create a component on drag + * start tobe dragged into the Layout + * + * @param {jQuery element} element + * @param {Object} itemConfig the configuration for the contentItem that will be created + * @param {LayoutManager} layoutManager + * + * @constructor + */ lm.controls.DragSource = function (element, itemConfig, layoutManager) { this._element = element; this._itemConfig = itemConfig; @@ -2280,11 +2280,11 @@ lm.utils.copy(lm.controls.DragSource.prototype, { - /** - * Called initially and after every drag - * - * @returns {void} - */ + /** + * Called initially and after every drag + * + * @returns {void} + */ _createDragListener: function () { if (this._dragListener !== null) { this._dragListener.destroy(); @@ -2306,14 +2306,14 @@ } }, - /** - * Callback for the DragListener's dragStart event - * - * @param {int} x the x position of the mouse on dragStart - * @param {int} y the x position of the mouse on dragStart - * - * @returns {void} - */ + /** + * Callback for the DragListener's dragStart event + * + * @param {int} x the x position of the mouse on dragStart + * @param {int} y the x position of the mouse on dragStart + * + * @returns {void} + */ _onDragStart: function (x, y) { var itemConfig = this._itemConfig; if (lm.utils.isFunction(itemConfig)) { @@ -2355,12 +2355,12 @@ this.element.hide(); } }); - /** - * This class represents a header above a Stack ContentItem. - * - * @param {lm.LayoutManager} layoutManager - * @param {lm.item.AbstractContentItem} parent - */ + /** + * This class represents a header above a Stack ContentItem. + * + * @param {lm.LayoutManager} layoutManager + * @param {lm.item.AbstractContentItem} parent + */ lm.controls.Header = function (layoutManager, parent) { lm.utils.EventEmitter.call(this); @@ -2400,14 +2400,14 @@ lm.utils.copy(lm.controls.Header.prototype, { - /** - * Creates a new tab and associates it with a contentItem - * - * @param {lm.item.AbstractContentItem} contentItem - * @param {Integer} index The position of the tab - * - * @returns {void} - */ + /** + * Creates a new tab and associates it with a contentItem + * + * @param {lm.item.AbstractContentItem} contentItem + * @param {Integer} index The position of the tab + * + * @returns {void} + */ createTab: function (contentItem, index) { var tab, i; @@ -2441,13 +2441,13 @@ this._updateTabSizes(); }, - /** - * Finds a tab based on the contentItem its associated with and removes it. - * - * @param {lm.item.AbstractContentItem} contentItem - * - * @returns {void} - */ + /** + * Finds a tab based on the contentItem its associated with and removes it. + * + * @param {lm.item.AbstractContentItem} contentItem + * + * @returns {void} + */ removeTab: function (contentItem) { for (var i = 0; i < this.tabs.length; i++) { if (this.tabs[i].contentItem === contentItem) { @@ -2460,11 +2460,11 @@ throw new Error('contentItem is not controlled by this header'); }, - /** - * The programmatical equivalent of clicking a Tab. - * - * @param {lm.item.AbstractContentItem} contentItem - */ + /** + * The programmatical equivalent of clicking a Tab. + * + * @param {lm.item.AbstractContentItem} contentItem + */ setActiveContentItem: function (contentItem) { var i, j, isActive, activeTab; @@ -2478,10 +2478,10 @@ } if (this.layoutManager.config.settings.reorderOnTabMenuClick) { - /** - * If the tab selected was in the dropdown, move everything down one to make way for this one to be the first. - * This will make sure the most used tabs stay visible. - */ + /** + * If the tab selected was in the dropdown, move everything down one to make way for this one to be the first. + * This will make sure the most used tabs stay visible. + */ if (this._lastVisibleTabIndex !== -1 && this.parent.config.activeItemIndex > this._lastVisibleTabIndex) { activeTab = this.tabs[this.parent.config.activeItemIndex]; for (j = this.parent.config.activeItemIndex; j > 0; j--) { @@ -2496,13 +2496,13 @@ this.parent.emitBubblingEvent('stateChanged'); }, - /** - * Programmatically operate with header position. - * - * @param {string} position one of ('top','left','right','bottom') to set or empty to get it. - * - * @returns {string} previous header position - */ + /** + * Programmatically operate with header position. + * + * @param {string} position one of ('top','left','right','bottom') to set or empty to get it. + * + * @returns {string} previous header position + */ position: function (position) { var previous = this.parent._header.show; if (previous && !this.parent._side) @@ -2514,14 +2514,14 @@ return previous; }, - /** - * Programmatically set closability. - * - * @package private - * @param {Boolean} isClosable Whether to enable/disable closability. - * - * @returns {Boolean} Whether the action was successful - */ + /** + * Programmatically set closability. + * + * @package private + * @param {Boolean} isClosable Whether to enable/disable closability. + * + * @returns {Boolean} Whether the action was successful + */ _$setClosable: function (isClosable) { if (this.closeButton && this._isClosable()) { this.closeButton.element[isClosable ? "show" : "hide"](); @@ -2531,13 +2531,13 @@ return false; }, - /** - * Destroys the entire header - * - * @package private - * - * @returns {void} - */ + /** + * Destroys the entire header + * + * @package private + * + * @returns {void} + */ _$destroy: function () { this.emit('destroy', this); @@ -2548,20 +2548,20 @@ this.element.remove(); }, - /** - * get settings from header - * - * @returns {string} when exists - */ + /** + * get settings from header + * + * @returns {string} when exists + */ _getHeaderSetting: function (name) { if (name in this.parent._header) return this.parent._header[name]; }, - /** - * Creates the popout, maximise and close buttons in the header's top right corner - * - * @returns {void} - */ + /** + * Creates the popout, maximise and close buttons in the header's top right corner + * + * @returns {void} + */ _createControls: function () { var closeStack, popout, @@ -2573,26 +2573,26 @@ tabDropdownLabel, showTabDropdown; - /** - * Dropdown to show additional tabs. - */ + /** + * Dropdown to show additional tabs. + */ showTabDropdown = lm.utils.fnBind(this._showAdditionalTabsDropdown, this); tabDropdownLabel = this.layoutManager.config.labels.tabDropdown; this.tabDropdownButton = new lm.controls.HeaderButton(this, tabDropdownLabel, 'lm_tabdropdown', showTabDropdown); this.tabDropdownButton.element.hide(); - /** - * Popout control to launch component in new window. - */ + /** + * Popout control to launch component in new window. + */ if (this._getHeaderSetting('popout')) { popout = lm.utils.fnBind(this._onPopoutClick, this); label = this._getHeaderSetting('popout'); new lm.controls.HeaderButton(this, label, 'lm_popout', popout); } - /** - * Maximise control - set the component to the full size of the layout - */ + /** + * Maximise control - set the component to the full size of the layout + */ if (this._getHeaderSetting('maximise')) { maximise = lm.utils.fnBind(this.parent.toggleMaximise, this.parent); maximiseLabel = this._getHeaderSetting('maximise'); @@ -2608,9 +2608,9 @@ }); } - /** - * Close button - */ + /** + * Close button + */ if (this._isClosable()) { closeStack = lm.utils.fnBind(this.parent.remove, this.parent); label = this._getHeaderSetting('close'); @@ -2618,30 +2618,30 @@ } }, - /** - * Shows drop down for additional tabs when there are too many to display. - * - * @returns {void} - */ + /** + * Shows drop down for additional tabs when there are too many to display. + * + * @returns {void} + */ _showAdditionalTabsDropdown: function () { this.tabDropdownContainer.show(); }, - /** - * Hides drop down for additional tabs when there are too many to display. - * - * @returns {void} - */ + /** + * Hides drop down for additional tabs when there are too many to display. + * + * @returns {void} + */ _hideAdditionalTabsDropdown: function (e) { this.tabDropdownContainer.hide(); }, - /** - * Checks whether the header is closable based on the parent config and - * the global config. - * - * @returns {Boolean} Whether the header is closable. - */ + /** + * Checks whether the header is closable based on the parent config and + * the global config. + * + * @returns {Boolean} Whether the header is closable. + */ _isClosable: function () { return this.parent.config.isClosable && this.layoutManager.config.settings.showCloseIcon; }, @@ -2655,24 +2655,24 @@ }, - /** - * Invoked when the header's background is clicked (not it's tabs or controls) - * - * @param {jQuery DOM event} event - * - * @returns {void} - */ + /** + * Invoked when the header's background is clicked (not it's tabs or controls) + * + * @param {jQuery DOM event} event + * + * @returns {void} + */ _onHeaderClick: function (event) { if (event.target === this.element[0]) { this.parent.select(); } }, - /** - * Pushes the tabs to the tab dropdown if the available space is not sufficient - * - * @returns {void} - */ + /** + * Pushes the tabs to the tab dropdown if the available space is not sufficient + * + * @returns {void} + */ _updateTabSizes: function (showTabMenu) { if (this.tabs.length === 0) { return; @@ -2835,14 +2835,14 @@ } }); - /** - * Represents an individual tab within a Stack's header - * - * @param {lm.controls.Header} header - * @param {lm.items.AbstractContentItem} contentItem - * - * @constructor - */ + /** + * Represents an individual tab within a Stack's header + * + * @param {lm.controls.Header} header + * @param {lm.items.AbstractContentItem} contentItem + * + * @constructor + */ lm.controls.Tab = function (header, contentItem) { this.header = header; this.contentItem = contentItem; @@ -2888,37 +2888,37 @@ } }; - /** - * The tab's html template - * - * @type {String} - */ + /** + * The tab's html template + * + * @type {String} + */ lm.controls.Tab._template = '
  • ' + '
    ' + '
  • '; lm.utils.copy(lm.controls.Tab.prototype, { - /** - * Sets the tab's title to the provided string and sets - * its title attribute to a pure text representation (without - * html tags) of the same string. - * - * @public - * @param {String} title can contain html - */ + /** + * Sets the tab's title to the provided string and sets + * its title attribute to a pure text representation (without + * html tags) of the same string. + * + * @public + * @param {String} title can contain html + */ setTitle: function (title) { this.element.attr('title', lm.utils.stripTags(title)); this.titleElement.html(title); }, - /** - * Sets this tab's active state. To programmatically - * switch tabs, use header.setActiveContentItem( item ) instead. - * - * @public - * @param {Boolean} isActive - */ + /** + * Sets this tab's active state. To programmatically + * switch tabs, use header.setActiveContentItem( item ) instead. + * + * @public + * @param {Boolean} isActive + */ setActive: function (isActive) { if (isActive === this.isActive) { return; @@ -2932,12 +2932,12 @@ } }, - /** - * Destroys the tab - * - * @private - * @returns {void} - */ + /** + * Destroys the tab + * + * @private + * @returns {void} + */ _$destroy: function () { this._layoutManager.emit('tabDestroyed', this); this.element.off('mousedown touchstart', this._onTabClickFn); @@ -2950,15 +2950,15 @@ this.element.remove(); }, - /** - * Callback for the DragListener - * - * @param {Number} x The tabs absolute x position - * @param {Number} y The tabs absolute y position - * - * @private - * @returns {void} - */ + /** + * Callback for the DragListener + * + * @param {Number} x The tabs absolute x position + * @param {Number} y The tabs absolute y position + * + * @private + * @returns {void} + */ _onDragStart: function (x, y) { if (this.contentItem.parent.isMaximised === true) { this.contentItem.parent.toggleMaximise(); @@ -2973,14 +2973,14 @@ ); }, - /** - * Callback when the tab is clicked - * - * @param {jQuery DOM event} event - * - * @private - * @returns {void} - */ + /** + * Callback when the tab is clicked + * + * @param {jQuery DOM event} event + * + * @private + * @returns {void} + */ _onTabClick: function (event) { // left mouse button or tap if (event.button === 0 || event.type === 'touchstart') { @@ -2995,30 +2995,30 @@ } }, - /** - * Callback when the tab's close button is - * clicked - * - * @param {jQuery DOM event} event - * - * @private - * @returns {void} - */ + /** + * Callback when the tab's close button is + * clicked + * + * @param {jQuery DOM event} event + * + * @private + * @returns {void} + */ _onCloseClick: function (event) { event.stopPropagation(); this.header.parent.removeChild(this.contentItem); }, - /** - * Callback to capture tab close button mousedown - * to prevent tab from activating. - * - * @param (jQuery DOM event) event - * - * @private - * @returns {void} - */ + /** + * Callback to capture tab close button mousedown + * to prevent tab from activating. + * + * @param (jQuery DOM event) event + * + * @private + * @returns {void} + */ _onCloseMousedown: function (event) { event.stopPropagation(); } @@ -3040,9 +3040,9 @@ }, transitionElements: function (fromElement, toElement) { - /** - * TODO - This is not quite as cool as expected. Review. - */ + /** + * TODO - This is not quite as cool as expected. Review. + */ return; this._toElement = toElement; this._animationStartTime = lm.utils.now(); @@ -3096,27 +3096,27 @@ lm.errors.ConfigurationError.prototype = new Error(); - /** - * This is the baseclass that all content items inherit from. - * Most methods provide a subset of what the sub-classes do. - * - * It also provides a number of functions for tree traversal - * - * @param {lm.LayoutManager} layoutManager - * @param {item node configuration} config - * @param {lm.item} parent - * - * @event stateChanged - * @event beforeItemDestroyed - * @event itemDestroyed - * @event itemCreated - * @event componentCreated - * @event rowCreated - * @event columnCreated - * @event stackCreated - * - * @constructor - */ + /** + * This is the baseclass that all content items inherit from. + * Most methods provide a subset of what the sub-classes do. + * + * It also provides a number of functions for tree traversal + * + * @param {lm.LayoutManager} layoutManager + * @param {item node configuration} config + * @param {lm.item} parent + * + * @event stateChanged + * @event beforeItemDestroyed + * @event itemDestroyed + * @event itemCreated + * @event componentCreated + * @event rowCreated + * @event columnCreated + * @event stackCreated + * + * @constructor + */ lm.items.AbstractContentItem = function (layoutManager, config, parent) { lm.utils.EventEmitter.call(this); @@ -3146,26 +3146,26 @@ lm.utils.copy(lm.items.AbstractContentItem.prototype, { - /** - * Set the size of the component and its children, called recursively - * - * @abstract - * @returns void - */ + /** + * Set the size of the component and its children, called recursively + * + * @abstract + * @returns void + */ setSize: function () { throw new Error('Abstract Method'); }, - /** - * Calls a method recursively downwards on the tree - * - * @param {String} functionName the name of the function to be called - * @param {[Array]}functionArguments optional arguments that are passed to every function - * @param {[bool]} bottomUp Call methods from bottom to top, defaults to false - * @param {[bool]} skipSelf Don't invoke the method on the class that calls it, defaults to false - * - * @returns {void} - */ + /** + * Calls a method recursively downwards on the tree + * + * @param {String} functionName the name of the function to be called + * @param {[Array]}functionArguments optional arguments that are passed to every function + * @param {[bool]} bottomUp Call methods from bottom to top, defaults to false + * @param {[bool]} skipSelf Don't invoke the method on the class that calls it, defaults to false + * + * @returns {void} + */ callDownwards: function (functionName, functionArguments, bottomUp, skipSelf) { var i; @@ -3180,53 +3180,53 @@ } }, - /** - * Removes a child node (and its children) from the tree - * - * @param {lm.items.ContentItem} contentItem - * - * @returns {void} - */ + /** + * Removes a child node (and its children) from the tree + * + * @param {lm.items.ContentItem} contentItem + * + * @returns {void} + */ removeChild: function (contentItem, keepChild) { - /* - * Get the position of the item that's to be removed within all content items this node contains - */ + /* + * Get the position of the item that's to be removed within all content items this node contains + */ var index = lm.utils.indexOf(contentItem, this.contentItems); - /* - * Make sure the content item to be removed is actually a child of this item - */ + /* + * Make sure the content item to be removed is actually a child of this item + */ if (index === -1) { throw new Error('Can\'t remove child item. Unknown content item'); } - /** - * Call ._$destroy on the content item. This also calls ._$destroy on all its children - */ + /** + * Call ._$destroy on the content item. This also calls ._$destroy on all its children + */ if (keepChild !== true) { this.contentItems[index]._$destroy(); } - /** - * Remove the content item from this nodes array of children - */ + /** + * Remove the content item from this nodes array of children + */ this.contentItems.splice(index, 1); - /** - * Remove the item from the configuration - */ + /** + * Remove the item from the configuration + */ this.config.content.splice(index, 1); - /** - * If this node still contains other content items, adjust their size - */ + /** + * If this node still contains other content items, adjust their size + */ if (this.contentItems.length > 0) { this.callDownwards('setSize'); - /** - * If this was the last content item, remove this node as well - */ + /** + * If this was the last content item, remove this node as well + */ } else if (!(this instanceof lm.items.Root) && this.config.isClosable === true) { const stack = this; const rowOrCol = stack.parent; @@ -3244,14 +3244,14 @@ } }, - /** - * Sets up the tree structure for the newly added child - * The responsibility for the actual DOM manipulations lies - * with the concrete item - * - * @param {lm.items.AbstractContentItem} contentItem - * @param {[Int]} index If omitted item will be appended - */ + /** + * Sets up the tree structure for the newly added child + * The responsibility for the actual DOM manipulations lies + * with the concrete item + * + * @param {lm.items.AbstractContentItem} contentItem + * @param {[Int]} index If omitted item will be appended + */ addChild: function (contentItem, index) { if (index === undefined) { index = this.contentItems.length; @@ -3271,15 +3271,15 @@ } }, - /** - * Replaces oldChild with newChild. This used to use jQuery.replaceWith... which for - * some reason removes all event listeners, so isn't really an option. - * - * @param {lm.item.AbstractContentItem} oldChild - * @param {lm.item.AbstractContentItem} newChild - * - * @returns {void} - */ + /** + * Replaces oldChild with newChild. This used to use jQuery.replaceWith... which for + * some reason removes all event listeners, so isn't really an option. + * + * @param {lm.item.AbstractContentItem} oldChild + * @param {lm.item.AbstractContentItem} newChild + * + * @returns {void} + */ replaceChild: function (oldChild, newChild, _$destroyOldChild) { newChild = this.layoutManager._$normalizeContentItem(newChild); @@ -3293,23 +3293,23 @@ parentNode.replaceChild(newChild.element[0], oldChild.element[0]); - /* - * Optionally destroy the old content item - */ + /* + * Optionally destroy the old content item + */ if (_$destroyOldChild === true) { oldChild.parent = null; oldChild._$destroy(); } - /* - * Wire the new contentItem into the tree - */ + /* + * Wire the new contentItem into the tree + */ this.contentItems[index] = newChild; newChild.parent = this; - /* - * Update tab reference - */ + /* + * Update tab reference + */ if (this.isStack) { this.header.tabs[index].contentItem = newChild; } @@ -3322,33 +3322,33 @@ this.callDownwards('setSize'); }, - /** - * Convenience method. - * Shorthand for this.parent.removeChild( this ) - * - * @returns {void} - */ + /** + * Convenience method. + * Shorthand for this.parent.removeChild( this ) + * + * @returns {void} + */ remove: function () { this.parent.removeChild(this); }, - /** - * Removes the component from the layout and creates a new - * browser window with the component and its children inside - * - * @returns {lm.controls.BrowserPopout} - */ + /** + * Removes the component from the layout and creates a new + * browser window with the component and its children inside + * + * @returns {lm.controls.BrowserPopout} + */ popout: function () { var browserPopout = this.layoutManager.createPopout(this); this.emitBubblingEvent('stateChanged'); return browserPopout; }, - /** - * Maximises the Item or minimises it if it is already maximised - * - * @returns {void} - */ + /** + * Maximises the Item or minimises it if it is already maximised + * + * @returns {void} + */ toggleMaximise: function (e) { e && e.preventDefault(); if (this.isMaximised === true) { @@ -3361,11 +3361,11 @@ this.emitBubblingEvent('stateChanged'); }, - /** - * Selects the item if it is not already selected - * - * @returns {void} - */ + /** + * Selects the item if it is not already selected + * + * @returns {void} + */ select: function () { if (this.layoutManager.selectedItem !== this) { this.layoutManager.selectItem(this, true); @@ -3373,11 +3373,11 @@ } }, - /** - * De-selects the item if it is selected - * - * @returns {void} - */ + /** + * De-selects the item if it is selected + * + * @returns {void} + */ deselect: function () { if (this.layoutManager.selectedItem === this) { this.layoutManager.selectedItem = null; @@ -3385,28 +3385,28 @@ } }, - /** - * Set this component's title - * - * @public - * @param {String} title - * - * @returns {void} - */ + /** + * Set this component's title + * + * @public + * @param {String} title + * + * @returns {void} + */ setTitle: function (title) { this.config.title = title; this.emit('titleChanged', title); this.emit('stateChanged'); }, - /** - * Checks whether a provided id is present - * - * @public - * @param {String} id - * - * @returns {Boolean} isPresent - */ + /** + * Checks whether a provided id is present + * + * @public + * @param {String} id + * + * @returns {Boolean} isPresent + */ hasId: function (id) { if (!this.config.id) { return false; @@ -3417,15 +3417,15 @@ } }, - /** - * Adds an id. Adds it as a string if the component doesn't - * have an id yet or creates/uses an array - * - * @public - * @param {String} id - * - * @returns {void} - */ + /** + * Adds an id. Adds it as a string if the component doesn't + * have an id yet or creates/uses an array + * + * @public + * @param {String} id + * + * @returns {void} + */ addId: function (id) { if (this.hasId(id)) { return; @@ -3440,15 +3440,15 @@ } }, - /** - * Removes an existing id. Throws an error - * if the id is not present - * - * @public - * @param {String} id - * - * @returns {void} - */ + /** + * Removes an existing id. Throws an error + * if the id is not present + * + * @public + * @param {String} id + * + * @returns {void} + */ removeId: function (id) { if (!this.hasId(id)) { throw new Error('Id not found'); @@ -3462,9 +3462,9 @@ } }, - /**************************************** - * SELECTOR - ****************************************/ + /**************************************** + * SELECTOR + ****************************************/ getItemsByFilter: function (filter) { var result = [], next = function (contentItem) { @@ -3508,9 +3508,9 @@ return instances; }, - /**************************************** - * PACKAGE PRIVATE - ****************************************/ + /**************************************** + * PACKAGE PRIVATE + ****************************************/ _$getItemsByProperty: function (key, value) { return this.getItemsByFilter(function (item) { return item[key] === value; @@ -3555,11 +3555,11 @@ } }, - /** - * Destroys this item ands its children - * - * @returns {void} - */ + /** + * Destroys this item ands its children + * + * @returns {void} + */ _$destroy: function () { this.emitBubblingEvent('beforeItemDestroyed'); this.callDownwards('_$destroy', [], true, true); @@ -3567,17 +3567,17 @@ this.emitBubblingEvent('itemDestroyed'); }, - /** - * Returns the area the component currently occupies in the format - * - * { - * x1: int - * xy: int - * y1: int - * y2: int - * contentItem: contentItem - * } - */ + /** + * Returns the area the component currently occupies in the format + * + * { + * x1: int + * xy: int + * y1: int + * y2: int + * contentItem: contentItem + * } + */ _$getArea: function (element) { element = element || this.element; @@ -3595,17 +3595,17 @@ }; }, - /** - * The tree of content items is created in two steps: First all content items are instantiated, - * then init is called recursively from top to bottem. This is the basic init function, - * it can be used, extended or overwritten by the content items - * - * Its behaviour depends on the content item - * - * @package private - * - * @returns {void} - */ + /** + * The tree of content items is created in two steps: First all content items are instantiated, + * then init is called recursively from top to bottem. This is the basic init function, + * it can be used, extended or overwritten by the content items + * + * Its behaviour depends on the content item + * + * @package private + * + * @returns {void} + */ _$init: function () { var i; this.setSize(); @@ -3619,26 +3619,26 @@ this.emitBubblingEvent(this.type + 'Created'); }, - /** - * Emit an event that bubbles up the item tree. - * - * @param {String} name The name of the event - * - * @returns {void} - */ + /** + * Emit an event that bubbles up the item tree. + * + * @param {String} name The name of the event + * + * @returns {void} + */ emitBubblingEvent: function (name) { var event = new lm.utils.BubblingEvent(name, this); this.emit(name, event); }, - /** - * Private method, creates all content items for this node at initialisation time - * PLEASE NOTE, please see addChild for adding contentItems add runtime - * @private - * @param {configuration item node} config - * - * @returns {void} - */ + /** + * Private method, creates all content items for this node at initialisation time + * PLEASE NOTE, please see addChild for adding contentItems add runtime + * @private + * @param {configuration item node} config + * + * @returns {void} + */ _createContentItems: function (config) { var oContentItem, i; @@ -3652,13 +3652,13 @@ } }, - /** - * Extends an item configuration node with default settings - * @private - * @param {configuration item node} config - * - * @returns {configuration item node} extended config - */ + /** + * Extends an item configuration node with default settings + * @private + * @param {configuration item node} config + * + * @returns {configuration item node} extended config + */ _extendItemNode: function (config) { for (var key in lm.config.itemDefaultConfig) { @@ -3670,26 +3670,26 @@ return config; }, - /** - * Called for every event on the item tree. Decides whether the event is a bubbling - * event and propagates it to its parent - * - * @param {String} name the name of the event - * @param {lm.utils.BubblingEvent} event - * - * @returns {void} - */ + /** + * Called for every event on the item tree. Decides whether the event is a bubbling + * event and propagates it to its parent + * + * @param {String} name the name of the event + * @param {lm.utils.BubblingEvent} event + * + * @returns {void} + */ _propagateEvent: function (name, event) { if (event instanceof lm.utils.BubblingEvent && event.isPropagationStopped === false && this.isInitialised === true) { - /** - * In some cases (e.g. if an element is created from a DragSource) it - * doesn't have a parent and is not below root. If that's the case - * propagate the bubbling event from the top level of the substree directly - * to the layoutManager - */ + /** + * In some cases (e.g. if an element is created from a DragSource) it + * doesn't have a parent and is not below root. If that's the case + * propagate the bubbling event from the top level of the substree directly + * to the layoutManager + */ if (this.isRoot === false && this.parent) { this.parent.emit.apply(this.parent, Array.prototype.slice.call(arguments, 0)); } else { @@ -3698,16 +3698,16 @@ } }, - /** - * All raw events bubble up to the root element. Some events that - * are propagated to - and emitted by - the layoutManager however are - * only string-based, batched and sanitized to make them more usable - * - * @param {String} name the name of the event - * - * @private - * @returns {void} - */ + /** + * All raw events bubble up to the root element. Some events that + * are propagated to - and emitted by - the layoutManager however are + * only string-based, batched and sanitized to make them more usable + * + * @param {String} name the name of the event + * + * @private + * @returns {void} + */ _scheduleEventPropagationToLayoutManager: function (name, event) { if (lm.utils.indexOf(name, this._throttledEvents) === -1) { this.layoutManager.emit(name, event.origin); @@ -3720,25 +3720,25 @@ }, - /** - * Callback for events scheduled by _scheduleEventPropagationToLayoutManager - * - * @param {String} name the name of the event - * - * @private - * @returns {void} - */ + /** + * Callback for events scheduled by _scheduleEventPropagationToLayoutManager + * + * @param {String} name the name of the event + * + * @private + * @returns {void} + */ _propagateEventToLayoutManager: function (name, event) { this._pendingEventPropagations[name] = false; this.layoutManager.emit(name, event); } }); - /** - * @param {[type]} layoutManager [description] - * @param {[type]} config [description] - * @param {[type]} parent [description] - */ + /** + * @param {[type]} layoutManager [description] + * @param {[type]} config [description] + * @param {[type]} parent [description] + */ lm.items.Component = function (layoutManager, config, parent) { lm.items.AbstractContentItem.call(this, layoutManager, config, parent); @@ -3798,11 +3798,11 @@ lm.items.AbstractContentItem.prototype._$destroy.call(this); }, - /** - * Dragging onto a component directly is not an option - * - * @returns null - */ + /** + * Dragging onto a component directly is not an option + * + * @returns null + */ _$getArea: function () { return null; } @@ -3841,9 +3841,9 @@ this.element.width(width); this.element.height(height); - /* - * Root can be empty - */ + /* + * Root can be empty + */ if (this.contentItems[0]) { this.contentItems[0].element.width(width); this.contentItems[0].element.height(height); @@ -3917,18 +3917,18 @@ lm.utils.copy(lm.items.RowOrColumn.prototype, { - /** - * Add a new contentItem to the Row or Column - * - * @param {lm.item.AbstractContentItem} contentItem - * @param {[int]} index The position of the new item within the Row or Column. - * If no index is provided the item will be added to the end - * @param {[bool]} _$suspendResize If true the items won't be resized. This will leave the item in - * an inconsistent state and is only intended to be used if multiple - * children need to be added in one go and resize is called afterwards - * - * @returns {void} - */ + /** + * Add a new contentItem to the Row or Column + * + * @param {lm.item.AbstractContentItem} contentItem + * @param {[int]} index The position of the new item within the Row or Column. + * If no index is provided the item will be added to the end + * @param {[bool]} _$suspendResize If true the items won't be resized. This will leave the item in + * an inconsistent state and is only intended to be used if multiple + * children need to be added in one go and resize is called afterwards + * + * @returns {void} + */ addChild: function (contentItem, index, _$suspendResize) { var newItemSize, itemSize, i, splitterElement; @@ -3986,14 +3986,14 @@ }, - /** - * Removes a child of this element - * - * @param {lm.items.AbstractContentItem} contentItem - * @param {boolean} keepChild If true the child will be removed, but not destroyed - * - * @returns {void} - */ + /** + * Removes a child of this element + * + * @param {lm.items.AbstractContentItem} contentItem + * @param {boolean} keepChild If true the child will be removed, but not destroyed + * + * @returns {void} + */ removeChild: function (contentItem, keepChild) { var removedItemSize = contentItem.config[this._dimension], index = lm.utils.indexOf(contentItem, this.contentItems), @@ -4005,10 +4005,10 @@ throw new Error('Can\'t remove child. ContentItem is not child of this Row or Column'); } - /** - * Remove the splitter before the item or after if the item happens - * to be the first in the row/column - */ + /** + * Remove the splitter before the item or after if the item happens + * to be the first in the row/column + */ if (this._splitter[splitterIndex]) { this._splitter[splitterIndex]._$destroy(); this._splitter.splice(splitterIndex, 1); @@ -4019,9 +4019,9 @@ if (this.contentItems[i].config.fixed) fixedItemSize += this.contentItems[i].config[this._dimension]; } - /** - * Allocate the space that the removed item occupied to the remaining items - */ + /** + * Allocate the space that the removed item occupied to the remaining items + */ for (i = 0; i < this.contentItems.length; i++) { if (this.contentItems[i].config.fixed) ; @@ -4044,14 +4044,14 @@ } }, - /** - * Replaces a child of this Row or Column with another contentItem - * - * @param {lm.items.AbstractContentItem} oldChild - * @param {lm.items.AbstractContentItem} newChild - * - * @returns {void} - */ + /** + * Replaces a child of this Row or Column with another contentItem + * + * @param {lm.items.AbstractContentItem} oldChild + * @param {lm.items.AbstractContentItem} newChild + * + * @returns {void} + */ replaceChild: function (oldChild, newChild) { var size = oldChild.config[this._dimension]; lm.items.AbstractContentItem.prototype.replaceChild.call(this, oldChild, newChild); @@ -4060,11 +4060,11 @@ this.emitBubblingEvent('stateChanged'); }, - /** - * Called whenever the dimensions of this item or one of its parents change - * - * @returns {void} - */ + /** + * Called whenever the dimensions of this item or one of its parents change + * + * @returns {void} + */ setSize: function () { if (this.contentItems.length > 0) { this._calculateRelativeSizes(); @@ -4074,15 +4074,15 @@ this.emit('resize'); }, - /** - * Invoked recursively by the layout manager. AbstractContentItem.init appends - * the contentItem's DOM elements to the container, RowOrColumn init adds splitters - * in between them - * - * @package private - * @override AbstractContentItem._$init - * @returns {void} - */ + /** + * Invoked recursively by the layout manager. AbstractContentItem.init appends + * the contentItem's DOM elements to the container, RowOrColumn init adds splitters + * in between them + * + * @package private + * @override AbstractContentItem._$init + * @returns {void} + */ _$init: function () { if (this.isInitialised === true) return; @@ -4095,15 +4095,15 @@ } }, - /** - * Turns the relative sizes calculated by _calculateRelativeSizes into - * absolute pixel values and applies them to the children's DOM elements - * - * Assigns additional pixels to counteract Math.floor - * - * @private - * @returns {void} - */ + /** + * Turns the relative sizes calculated by _calculateRelativeSizes into + * absolute pixel values and applies them to the children's DOM elements + * + * Assigns additional pixels to counteract Math.floor + * + * @private + * @returns {void} + */ _setAbsoluteSizes: function () { var i, sizeData = this._calculateAbsoluteSizes(); @@ -4123,10 +4123,10 @@ } }, - /** - * Calculates the absolute sizes of all of the children of this Item. - * @returns {object} - Set with absolute sizes and additional pixels. - */ + /** + * Calculates the absolute sizes of all of the children of this Item. + * @returns {object} - Set with absolute sizes and additional pixels. + */ _calculateAbsoluteSizes: function () { var i, totalSplitterSize = (this.contentItems.length - 1) * this._splitterSize, @@ -4164,27 +4164,27 @@ }; }, - /** - * Calculates the relative sizes of all children of this Item. The logic - * is as follows: - * - * - Add up the total size of all items that have a configured size - * - * - If the total == 100 (check for floating point errors) - * Excellent, job done - * - * - If the total is > 100, - * set the size of items without set dimensions to 1/3 and add this to the total - * set the size off all items so that the total is hundred relative to their original size - * - * - If the total is < 100 - * If there are items without set dimensions, distribute the remainder to 100 evenly between them - * If there are no items without set dimensions, increase all items sizes relative to - * their original size so that they add up to 100 - * - * @private - * @returns {void} - */ + /** + * Calculates the relative sizes of all children of this Item. The logic + * is as follows: + * + * - Add up the total size of all items that have a configured size + * + * - If the total == 100 (check for floating point errors) + * Excellent, job done + * + * - If the total is > 100, + * set the size of items without set dimensions to 1/3 and add this to the total + * set the size off all items so that the total is hundred relative to their original size + * + * - If the total is < 100 + * If there are items without set dimensions, distribute the remainder to 100 evenly between them + * If there are no items without set dimensions, increase all items sizes relative to + * their original size so that they add up to 100 + * + * @private + * @returns {void} + */ _calculateRelativeSizes: function () { var i, @@ -4200,17 +4200,17 @@ } } - /** - * Everything adds up to hundred, all good :-) - */ + /** + * Everything adds up to hundred, all good :-) + */ if (Math.round(total) === 100) { this._respectMinItemWidth(); return; } - /** - * Allocate the remaining size to the items without a set dimension - */ + /** + * Allocate the remaining size to the items without a set dimension + */ if (Math.round(total) < 100 && itemsWithoutSetDimension.length > 0) { for (i = 0; i < itemsWithoutSetDimension.length; i++) { itemsWithoutSetDimension[i].config[dimension] = (100 - total) / itemsWithoutSetDimension.length; @@ -4219,12 +4219,12 @@ return; } - /** - * If the total is > 100, but there are also items without a set dimension left, assing 50 - * as their dimension and add it to the total - * - * This will be reset in the next step - */ + /** + * If the total is > 100, but there are also items without a set dimension left, assing 50 + * as their dimension and add it to the total + * + * This will be reset in the next step + */ if (Math.round(total) > 100) { for (i = 0; i < itemsWithoutSetDimension.length; i++) { itemsWithoutSetDimension[i].config[dimension] = 50; @@ -4232,9 +4232,9 @@ } } - /** - * Set every items size relative to 100 relative to its size to total - */ + /** + * Set every items size relative to 100 relative to its size to total + */ for (i = 0; i < this.contentItems.length; i++) { this.contentItems[i].config[dimension] = (this.contentItems[i].config[dimension] / total) * 100; } @@ -4242,10 +4242,10 @@ this._respectMinItemWidth(); }, - /** - * Adjusts the column widths to respect the dimensions minItemWidth if set. - * @returns {} - */ + /** + * Adjusts the column widths to respect the dimensions minItemWidth if set. + * @returns {} + */ _respectMinItemWidth: function () { var minItemWidth = this.layoutManager.config.dimensions ? (this.layoutManager.config.dimensions.minItemWidth || 0) : 0, sizeData = null, @@ -4266,9 +4266,9 @@ sizeData = this._calculateAbsoluteSizes(); - /** - * Figure out how much we are under the min item size total and how much room we have to use. - */ + /** + * Figure out how much we are under the min item size total and how much room we have to use. + */ for (var i = 0; i < this.contentItems.length; i++) { contentItem = this.contentItems[i]; @@ -4288,16 +4288,16 @@ allEntries.push(entry); } - /** - * If there is nothing under min, or there is not enough over to make up the difference, do nothing. - */ + /** + * If there is nothing under min, or there is not enough over to make up the difference, do nothing. + */ if (totalUnderMin === 0 || totalUnderMin > totalOverMin) { return; } - /** - * Evenly reduce all columns that are over the min item width to make up the difference. - */ + /** + * Evenly reduce all columns that are over the min item width to make up the difference. + */ reducePercent = totalUnderMin / totalOverMin; remainingWidth = totalUnderMin; for (i = 0; i < entriesOverMin.length; i++) { @@ -4307,31 +4307,31 @@ entry.width -= reducedWidth; } - /** - * Take anything remaining from the last item. - */ + /** + * Take anything remaining from the last item. + */ if (remainingWidth !== 0) { allEntries[allEntries.length - 1].width -= remainingWidth; } - /** - * Set every items size relative to 100 relative to its size to total - */ + /** + * Set every items size relative to 100 relative to its size to total + */ for (i = 0; i < this.contentItems.length; i++) { this.contentItems[i].config.width = (allEntries[i].width / sizeData.totalWidth) * 100; } }, - /** - * Instantiates a new lm.controls.Splitter, binds events to it and adds - * it to the array of splitters at the position specified as the index argument - * - * What it doesn't do though is append the splitter to the DOM - * - * @param {Int} index The position of the splitter - * - * @returns {lm.controls.Splitter} - */ + /** + * Instantiates a new lm.controls.Splitter, binds events to it and adds + * it to the array of splitters at the position specified as the index argument + * + * What it doesn't do though is append the splitter to the DOM + * + * @param {Int} index The position of the splitter + * + * @returns {lm.controls.Splitter} + */ _createSplitter: function (index) { var splitter; splitter = new lm.controls.Splitter(this._isColumn, this._splitterSize, this._splitterGrabSize); @@ -4342,16 +4342,16 @@ return splitter; }, - /** - * Locates the instance of lm.controls.Splitter in the array of - * registered splitters and returns a map containing the contentItem - * before and after the splitters, both of which are affected if the - * splitter is moved - * - * @param {lm.controls.Splitter} splitter - * - * @returns {Object} A map of contentItems that the splitter affects - */ + /** + * Locates the instance of lm.controls.Splitter in the array of + * registered splitters and returns a map containing the contentItem + * before and after the splitters, both of which are affected if the + * splitter is moved + * + * @param {lm.controls.Splitter} splitter + * + * @returns {Object} A map of contentItems that the splitter affects + */ _getItemsForSplitter: function (splitter) { var index = lm.utils.indexOf(splitter, this._splitter); @@ -4361,11 +4361,11 @@ }; }, - /** - * Gets the minimum dimensions for the given item configuration array - * @param item - * @private - */ + /** + * Gets the minimum dimensions for the given item configuration array + * @param item + * @private + */ _getMinimumDimensions: function (arr) { var minWidth = 0, minHeight = 0; @@ -4377,14 +4377,14 @@ return { horizontal: minWidth, vertical: minHeight }; }, - /** - * Invoked when a splitter's dragListener fires dragStart. Calculates the splitters - * movement area once (so that it doesn't need calculating on every mousemove event) - * - * @param {lm.controls.Splitter} splitter - * - * @returns {void} - */ + /** + * Invoked when a splitter's dragListener fires dragStart. Calculates the splitters + * movement area once (so that it doesn't need calculating on every mousemove event) + * + * @param {lm.controls.Splitter} splitter + * + * @returns {void} + */ _onSplitterDragStart: function (splitter) { var items = this._getItemsForSplitter(splitter), minSize = this.layoutManager.config.dimensions[this._isColumn ? 'minItemHeight' : 'minItemWidth']; @@ -4400,16 +4400,16 @@ this._splitterMaxPosition = items.after.element[this._dimension]() - (afterMinSize || minSize); }, - /** - * Invoked when a splitter's DragListener fires drag. Updates the splitters DOM position, - * but not the sizes of the elements the splitter controls in order to minimize resize events - * - * @param {lm.controls.Splitter} splitter - * @param {Int} offsetX Relative pixel values to the splitters original position. Can be negative - * @param {Int} offsetY Relative pixel values to the splitters original position. Can be negative - * - * @returns {void} - */ + /** + * Invoked when a splitter's DragListener fires drag. Updates the splitters DOM position, + * but not the sizes of the elements the splitter controls in order to minimize resize events + * + * @param {lm.controls.Splitter} splitter + * @param {Int} offsetX Relative pixel values to the splitters original position. Can be negative + * @param {Int} offsetY Relative pixel values to the splitters original position. Can be negative + * + * @returns {void} + */ _onSplitterDrag: function (splitter, offsetX, offsetY) { var offset = this._isColumn ? offsetY : offsetX; @@ -4419,15 +4419,15 @@ } }, - /** - * Invoked when a splitter's DragListener fires dragStop. Resets the splitters DOM position, - * and applies the new sizes to the elements before and after the splitter and their children - * on the next animation frame - * - * @param {lm.controls.Splitter} splitter - * - * @returns {void} - */ + /** + * Invoked when a splitter's DragListener fires dragStop. Resets the splitters DOM position, + * and applies the new sizes to the elements before and after the splitter and their children + * on the next animation frame + * + * @param {lm.controls.Splitter} splitter + * + * @returns {void} + */ _onSplitterDragStop: function (splitter) { var items = this._getItemsForSplitter(splitter), @@ -4451,7 +4451,7 @@ lm.items.Stack = function (layoutManager, config, parent) { lm.items.AbstractContentItem.call(this, layoutManager, config, parent); - this.element = $('
    '); + this.element = $('

    Click to create a new tab

    '); this._activeContentItem = null; var cfg = layoutManager.config; this._header = { // defaults' reconstruction from old configuration style @@ -4575,13 +4575,13 @@ this.emitBubblingEvent('stateChanged'); }, - /** - * Validates that the stack is still closable or not. If a stack is able - * to close, but has a non closable component added to it, the stack is no - * longer closable until all components are closable. - * - * @returns {void} - */ + /** + * Validates that the stack is still closable or not. If a stack is able + * to close, but has a non closable component added to it, the stack is no + * longer closable until all components are closable. + * + * @returns {void} + */ _$validateClosability: function () { var contentItem, isClosable, @@ -4607,51 +4607,51 @@ }, - /** - * Ok, this one is going to be the tricky one: The user has dropped {contentItem} onto this stack. - * - * It was dropped on either the stacks header or the top, right, bottom or left bit of the content area - * (which one of those is stored in this._dropSegment). Now, if the user has dropped on the header the case - * is relatively clear: We add the item to the existing stack... job done (might be good to have - * tab reordering at some point, but lets not sweat it right now) - * - * If the item was dropped on the content part things are a bit more complicated. If it was dropped on either the - * top or bottom region we need to create a new column and place the items accordingly. - * Unless, of course if the stack is already within a column... in which case we want - * to add the newly created item to the existing column... - * either prepend or append it, depending on wether its top or bottom. - * - * Same thing for rows and left / right drop segments... so in total there are 9 things that can potentially happen - * (left, top, right, bottom) * is child of the right parent (row, column) + header drop - * - * @param {lm.item} contentItem - * - * @returns {void} - */ + /** + * Ok, this one is going to be the tricky one: The user has dropped {contentItem} onto this stack. + * + * It was dropped on either the stacks header or the top, right, bottom or left bit of the content area + * (which one of those is stored in this._dropSegment). Now, if the user has dropped on the header the case + * is relatively clear: We add the item to the existing stack... job done (might be good to have + * tab reordering at some point, but lets not sweat it right now) + * + * If the item was dropped on the content part things are a bit more complicated. If it was dropped on either the + * top or bottom region we need to create a new column and place the items accordingly. + * Unless, of course if the stack is already within a column... in which case we want + * to add the newly created item to the existing column... + * either prepend or append it, depending on wether its top or bottom. + * + * Same thing for rows and left / right drop segments... so in total there are 9 things that can potentially happen + * (left, top, right, bottom) * is child of the right parent (row, column) + header drop + * + * @param {lm.item} contentItem + * + * @returns {void} + */ _$onDrop: function (contentItem) { - /* - * The item was dropped on the header area. Just add it as a child of this stack and - * get the hell out of this logic - */ + /* + * The item was dropped on the header area. Just add it as a child of this stack and + * get the hell out of this logic + */ if (this._dropSegment === 'header') { this._resetHeaderDropZone(); this.addChild(contentItem, this._dropIndex); return; } - /* - * The stack is empty. Let's just add the element. - */ + /* + * The stack is empty. Let's just add the element. + */ if (this._dropSegment === 'body') { this.addChild(contentItem); return; } - /* - * The item was dropped on the top-, left-, bottom- or right- part of the content. Let's - * aggregate some conditions to make the if statements later on more readable - */ + /* + * The item was dropped on the top-, left-, bottom- or right- part of the content. Let's + * aggregate some conditions to make the if statements later on more readable + */ var isVertical = this._dropSegment === 'top' || this._dropSegment === 'bottom', isHorizontal = this._dropSegment === 'left' || this._dropSegment === 'right', insertBefore = this._dropSegment === 'top' || this._dropSegment === 'left', @@ -4662,9 +4662,9 @@ stack, rowOrColumn; - /* - * The content item can be either a component or a stack. If it is a component, wrap it into a stack - */ + /* + * The content item can be either a component or a stack. If it is a component, wrap it into a stack + */ if (contentItem.isComponent) { stack = this.layoutManager.createContentItem({ type: 'stack', @@ -4675,20 +4675,20 @@ contentItem = stack; } - /* - * If the item is dropped on top or bottom of a column or left and right of a row, it's already - * layd out in the correct way. Just add it as a child - */ + /* + * If the item is dropped on top or bottom of a column or left and right of a row, it's already + * layd out in the correct way. Just add it as a child + */ if (hasCorrectParent) { index = lm.utils.indexOf(this, this.parent.contentItems); this.parent.addChild(contentItem, insertBefore ? index : index + 1, true); this.config[dimension] *= 0.5; contentItem.config[dimension] = this.config[dimension]; this.parent.callDownwards('setSize'); - /* - * This handles items that are dropped on top or bottom of a row or left / right of a column. We need - * to create the appropriate contentItem for them to live in - */ + /* + * This handles items that are dropped on top or bottom of a row or left / right of a column. We need + * to create the appropriate contentItem for them to live in + */ } else { type = isVertical ? 'column' : 'row'; rowOrColumn = this.layoutManager.createContentItem({ type: type }, this); @@ -4703,15 +4703,15 @@ } }, - /** - * If the user hovers above the header part of the stack, indicate drop positions for tabs. - * otherwise indicate which segment of the body the dragged item would be dropped on - * - * @param {Int} x Absolute Screen X - * @param {Int} y Absolute Screen Y - * - * @returns {void} - */ + /** + * If the user hovers above the header part of the stack, indicate drop positions for tabs. + * otherwise indicate which segment of the body the dragged item would be dropped on + * + * @param {Int} x Absolute Screen X + * @param {Int} y Absolute Screen Y + * + * @returns {void} + */ _$highlightDropZone: function (x, y) { var segment, area; @@ -4761,17 +4761,17 @@ } }; - /** - * If this Stack is a parent to rows, columns or other stacks only its - * header is a valid dropzone. - */ + /** + * If this Stack is a parent to rows, columns or other stacks only its + * header is a valid dropzone. + */ if (this._activeContentItem && this._activeContentItem.isComponent === false) { return headerArea; } - /** - * Highlight the entire body if the stack is empty - */ + /** + * Highlight the entire body if the stack is empty + */ if (this.contentItems.length === 0) { this._contentAreaDimensions.body = { @@ -4971,13 +4971,13 @@ lm.utils.BubblingEvent.prototype.stopPropagation = function () { this.isPropagationStopped = true; }; - /** - * Minifies and unminifies configs by replacing frequent keys - * and values with one letter substitutes. Config options must - * retain array position/index, add new options at the end. - * - * @constructor - */ + /** + * Minifies and unminifies configs by replacing frequent keys + * and values with one letter substitutes. Config options must + * retain array position/index, add new options at the end. + * + * @constructor + */ lm.utils.ConfigMinifier = function () { this._keys = [ 'settings', @@ -5031,160 +5031,160 @@ 'close', 'maximise', 'minimise', - 'open in new window' + 'new tab' ]; }; lm.utils.copy(lm.utils.ConfigMinifier.prototype, { - /** - * Takes a GoldenLayout configuration object and - * replaces its keys and values recursively with - * one letter counterparts - * - * @param {Object} config A GoldenLayout config object - * - * @returns {Object} minified config - */ + /** + * Takes a GoldenLayout configuration object and + * replaces its keys and values recursively with + * one letter counterparts + * + * @param {Object} config A GoldenLayout config object + * + * @returns {Object} minified config + */ minifyConfig: function (config) { var min = {}; this._nextLevel(config, min, '_min'); return min; }, - /** - * Takes a configuration Object that was previously minified - * using minifyConfig and returns its original version - * - * @param {Object} minifiedConfig - * - * @returns {Object} the original configuration - */ + /** + * Takes a configuration Object that was previously minified + * using minifyConfig and returns its original version + * + * @param {Object} minifiedConfig + * + * @returns {Object} the original configuration + */ unminifyConfig: function (minifiedConfig) { var orig = {}; this._nextLevel(minifiedConfig, orig, '_max'); return orig; }, - /** - * Recursive function, called for every level of the config structure - * - * @param {Array|Object} orig - * @param {Array|Object} min - * @param {String} translationFn - * - * @returns {void} - */ + /** + * Recursive function, called for every level of the config structure + * + * @param {Array|Object} orig + * @param {Array|Object} min + * @param {String} translationFn + * + * @returns {void} + */ _nextLevel: function (from, to, translationFn) { var key, minKey; for (key in from) { - /** - * For in returns array indices as keys, so let's cast them to numbers - */ + /** + * For in returns array indices as keys, so let's cast them to numbers + */ if (from instanceof Array) key = parseInt(key, 10); - /** - * In case something has extended Object prototypes - */ + /** + * In case something has extended Object prototypes + */ if (!from.hasOwnProperty(key)) continue; - /** - * Translate the key to a one letter substitute - */ + /** + * Translate the key to a one letter substitute + */ minKey = this[translationFn](key, this._keys); - /** - * For Arrays and Objects, create a new Array/Object - * on the minified object and recurse into it - */ + /** + * For Arrays and Objects, create a new Array/Object + * on the minified object and recurse into it + */ if (typeof from[key] === 'object') { to[minKey] = from[key] instanceof Array ? [] : {}; this._nextLevel(from[key], to[minKey], translationFn); - /** - * For primitive values (Strings, Numbers, Boolean etc.) - * minify the value - */ + /** + * For primitive values (Strings, Numbers, Boolean etc.) + * minify the value + */ } else { to[minKey] = this[translationFn](from[key], this._values); } } }, - /** - * Minifies value based on a dictionary - * - * @param {String|Boolean} value - * @param {Array} dictionary - * - * @returns {String} The minified version - */ + /** + * Minifies value based on a dictionary + * + * @param {String|Boolean} value + * @param {Array} dictionary + * + * @returns {String} The minified version + */ _min: function (value, dictionary) { - /** - * If a value actually is a single character, prefix it - * with ___ to avoid mistaking it for a minification code - */ + /** + * If a value actually is a single character, prefix it + * with ___ to avoid mistaking it for a minification code + */ if (typeof value === 'string' && value.length === 1) { return '___' + value; } var index = lm.utils.indexOf(value, dictionary); - /** - * value not found in the dictionary, return it unmodified - */ + /** + * value not found in the dictionary, return it unmodified + */ if (index === -1) { return value; - /** - * value found in dictionary, return its base36 counterpart - */ + /** + * value found in dictionary, return its base36 counterpart + */ } else { return index.toString(36); } }, _max: function (value, dictionary) { - /** - * value is a single character. Assume that it's a translation - * and return the original value from the dictionary - */ + /** + * value is a single character. Assume that it's a translation + * and return the original value from the dictionary + */ if (typeof value === 'string' && value.length === 1) { return dictionary[parseInt(value, 36)]; } - /** - * value originally was a single character and was prefixed with ___ - * to avoid mistaking it for a translation. Remove the prefix - * and return the original character - */ + /** + * value originally was a single character and was prefixed with ___ + * to avoid mistaking it for a translation. Remove the prefix + * and return the original character + */ if (typeof value === 'string' && value.substr(0, 3) === '___') { return value[3]; } - /** - * value was not minified - */ + /** + * value was not minified + */ return value; } }); - /** - * An EventEmitter singleton that propagates events - * across multiple windows. This is a little bit trickier since - * windows are allowed to open childWindows in their own right - * - * This means that we deal with a tree of windows. Hence the rules for event propagation are: - * - * - Propagate events from this layout to both parents and children - * - Propagate events from parent to this and children - * - Propagate events from children to the other children (but not the emitting one) and the parent - * - * @constructor - * - * @param {lm.LayoutManager} layoutManager - */ + /** + * An EventEmitter singleton that propagates events + * across multiple windows. This is a little bit trickier since + * windows are allowed to open childWindows in their own right + * + * This means that we deal with a tree of windows. Hence the rules for event propagation are: + * + * - Propagate events from this layout to both parents and children + * - Propagate events from parent to this and children + * - Propagate events from children to the other children (but not the emitting one) and the parent + * + * @constructor + * + * @param {lm.LayoutManager} layoutManager + */ lm.utils.EventHub = function (layoutManager) { lm.utils.EventEmitter.call(this); this._layoutManager = layoutManager; @@ -5195,15 +5195,15 @@ $(window).on('gl_child_event', this._boundOnEventFromChild); }; - /** - * Called on every event emitted on this eventHub, regardles of origin. - * - * @private - * - * @param {Mixed} - * - * @returns {void} - */ + /** + * Called on every event emitted on this eventHub, regardles of origin. + * + * @private + * + * @param {Mixed} + * + * @returns {void} + */ lm.utils.EventHub.prototype._onEventFromThis = function () { var args = Array.prototype.slice.call(arguments); @@ -5217,40 +5217,40 @@ this._childEventSource = null; }; - /** - * Called by the parent layout. - * - * @param {Array} args Event name + arguments - * - * @returns {void} - */ + /** + * Called by the parent layout. + * + * @param {Array} args Event name + arguments + * + * @returns {void} + */ lm.utils.EventHub.prototype._$onEventFromParent = function (args) { this._dontPropagateToParent = args[0]; this.emit.apply(this, args); }; - /** - * Callback for child events raised on the window - * - * @param {DOMEvent} event - * @private - * - * @returns {void} - */ + /** + * Callback for child events raised on the window + * + * @param {DOMEvent} event + * @private + * + * @returns {void} + */ lm.utils.EventHub.prototype._onEventFromChild = function (event) { this._childEventSource = event.originalEvent.__gl; this.emit.apply(this, event.originalEvent.__glArgs); }; - /** - * Propagates the event to the parent by emitting - * it on the parent's DOM window - * - * @param {Array} args Event name + arguments - * @private - * - * @returns {void} - */ + /** + * Propagates the event to the parent by emitting + * it on the parent's DOM window + * + * @param {Array} args Event name + arguments + * @private + * + * @returns {void} + */ lm.utils.EventHub.prototype._propagateToParent = function (args) { var event, eventName = 'gl_child_event'; @@ -5274,14 +5274,14 @@ } }; - /** - * Propagate events to children - * - * @param {Array} args Event name + arguments - * @private - * - * @returns {void} - */ + /** + * Propagate events to children + * + * @param {Array} args Event name + arguments + * @private + * + * @returns {void} + */ lm.utils.EventHub.prototype._propagateToChildren = function (args) { var childGl, i; @@ -5295,25 +5295,25 @@ }; - /** - * Destroys the EventHub - * - * @public - * @returns {void} - */ + /** + * Destroys the EventHub + * + * @public + * @returns {void} + */ lm.utils.EventHub.prototype.destroy = function () { $(window).off('gl_child_event', this._boundOnEventFromChild); }; - /** - * A specialised GoldenLayout component that binds GoldenLayout container - * lifecycle events to react components - * - * @constructor - * - * @param {lm.container.ItemContainer} container - * @param {Object} state state is not required for react components - */ + /** + * A specialised GoldenLayout component that binds GoldenLayout container + * lifecycle events to react components + * + * @constructor + * + * @param {lm.container.ItemContainer} container + * @param {Object} state state is not required for react components + */ lm.utils.ReactComponentHandler = function (container, state) { this._reactComponent = null; this._originalComponentWillUpdate = null; @@ -5326,15 +5326,15 @@ lm.utils.copy(lm.utils.ReactComponentHandler.prototype, { - /** - * Creates the react class and component and hydrates it with - * the initial state - if one is present - * - * By default, react's getInitialState will be used - * - * @private - * @returns {void} - */ + /** + * Creates the react class and component and hydrates it with + * the initial state - if one is present + * + * By default, react's getInitialState will be used + * + * @private + * @returns {void} + */ _render: function () { this._reactComponent = ReactDOM.render(this._getReactComponent(), this._container.getElement()[0]); this._originalComponentWillUpdate = this._reactComponent.componentWillUpdate || function () { @@ -5345,36 +5345,36 @@ } }, - /** - * Removes the component from the DOM and thus invokes React's unmount lifecycle - * - * @private - * @returns {void} - */ + /** + * Removes the component from the DOM and thus invokes React's unmount lifecycle + * + * @private + * @returns {void} + */ _destroy: function () { ReactDOM.unmountComponentAtNode(this._container.getElement()[0]); this._container.off('open', this._render, this); this._container.off('destroy', this._destroy, this); }, - /** - * Hooks into React's state management and applies the componentstate - * to GoldenLayout - * - * @private - * @returns {void} - */ + /** + * Hooks into React's state management and applies the componentstate + * to GoldenLayout + * + * @private + * @returns {void} + */ _onUpdate: function (nextProps, nextState) { this._container.setState(nextState); this._originalComponentWillUpdate.call(this._reactComponent, nextProps, nextState); }, - /** - * Retrieves the react class from GoldenLayout's registry - * - * @private - * @returns {React.Class} - */ + /** + * Retrieves the react class from GoldenLayout's registry + * + * @private + * @returns {React.Class} + */ _getReactClass: function () { var componentName = this._container._config.component; var reactClass; @@ -5393,12 +5393,12 @@ return reactClass; }, - /** - * Copies and extends the properties array and returns the React element - * - * @private - * @returns {React.Element} - */ + /** + * Copies and extends the properties array and returns the React element + * + * @private + * @returns {React.Element} + */ _getReactComponent: function () { var defaultProps = { glEventHub: this._container.layoutManager.eventHub, diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss index 07ca0257c..08bcd55ae 100644 --- a/src/client/views/MainView.scss +++ b/src/client/views/MainView.scss @@ -63,6 +63,10 @@ .mainView-container { color: $dark-gray; + .lm_goldenlayout { + background: $medium-gray; + } + .lm_title { background: $light-gray; color: $dark-gray; @@ -153,7 +157,8 @@ cursor: auto; } -.mainView-innerContent, .mainView-innerContent-dark { +.mainView-innerContent, +.mainView-innerContent-dark { display: contents; flex-direction: row; position: relative; @@ -175,44 +180,52 @@ position: absolute; z-index: 2; background-color: $medium-gray; + .editable-title { background-color: $light-gray; } } } + .mainView-libraryHandle { background-color: $light-gray; } -.mainView-innerContent-dark -{ + +.mainView-innerContent-dark { .propertiesView { background-color: #252525; + input { background-color: $medium-gray; } - .propertiesView-sharingTable - { + + .propertiesView-sharingTable { background-color: $medium-gray; } + .editable-title { background-color: $medium-gray; } + .propertiesView-field { background-color: $medium-gray; } } + .mainView-propertiesDragger, .mainView-libraryHandle { background: #353535; } } + .mainView-container-dark { .contextMenu-cont { background: $medium-gray; color: $white; + input::placeholder { - color:$white; + color: $white; } } } @@ -432,6 +445,7 @@ right: unset !important; left: 0 !important; } + .lm_close_tab { padding: 0; width: 15px !important; @@ -443,7 +457,9 @@ right: unset !important; left: 0 !important; } -.lm_tab, .lm_tab_active { + +.lm_tab, +.lm_tab_active { display: flex !important; padding-right: 0 !important; } \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss index a054f0ae1..d1b8b2df0 100644 --- a/src/client/views/collections/CollectionDockingView.scss +++ b/src/client/views/collections/CollectionDockingView.scss @@ -55,6 +55,29 @@ display: inline; } +.empty-tabs-message { + position: absolute; + width: 100%; + z-index: 1; + top: 50%; + z-index: 1; + text-align: center; + font-size: 18; + color: $dark-gray; + + img { + position: relative; + top: -1px; + margin: 0 5px; + } +} + +.lm_header, +.lm_items { + z-index: 2; + position: relative; +} + .collectiondockingview-container { width: 100%; height: 100%; -- cgit v1.2.3-70-g09d2 From 02336134cff5f5789380bf5950864f4b95583cf6 Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Mon, 16 Aug 2021 16:09:13 -0400 Subject: commented column code --- .../collectionSchema/CollectionSchemaMovableColumn.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx index 456c38c68..2df95ffd8 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaMovableColumn.tsx @@ -21,27 +21,38 @@ export interface MovableColumnProps { ScreenToLocalTransform: () => Transform; } export class MovableColumn extends React.Component { + // The header of the column private _header?: React.RefObject = React.createRef(); + // The container of the function that is responsible for moving the column over to a new plac private _colDropDisposer?: DragManager.DragDropDisposer; + // initial column position private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 }; + // sensitivity to being dragged, in pixels private _sensitivity: number = 16; + // Column reference ID private _dragRef: React.RefObject = React.createRef(); onPointerEnter = (e: React.PointerEvent): void => { + // if the column is left-clicked and it is being dragged if (e.buttons === 1 && SnappingManager.GetIsDragging()) { this._header!.current!.className = "collectionSchema-col-wrapper"; document.addEventListener("pointermove", this.onDragMove, true); } } + onPointerLeave = (e: React.PointerEvent): void => { this._header!.current!.className = "collectionSchema-col-wrapper"; document.removeEventListener("pointermove", this.onDragMove, true); !e.buttons && document.removeEventListener("pointermove", this.onPointerMove); } + onDragMove = (e: PointerEvent): void => { + // only take into account the horizonal direction when a column is dragged const x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY); const rect = this._header!.current!.getBoundingClientRect(); + // Now store the point at the top center of the column when it was in its original position const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top); + // to be compared with its new horizontal position const before = x[0] < bounds[0]; this._header!.current!.className = "collectionSchema-col-wrapper"; if (before) this._header!.current!.className += " col-before"; @@ -58,11 +69,15 @@ export class MovableColumn extends React.Component { colDrop = (e: Event, de: DragManager.DropEvent) => { document.removeEventListener("pointermove", this.onDragMove, true); + // we only care about whether the column is shifted to the side const x = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y); + // get the dimensions of the smallest rectangle that bounds the header const rect = this._header!.current!.getBoundingClientRect(); const bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left + ((rect.right - rect.left) / 2), rect.top); + // get whether the column was dragged before or after where it is now const before = x[0] < bounds[0]; const colDragData = de.complete.columnDragData; + // if there is colDragData, which happen when the drag is complete, reorder the columns according to the established variables if (colDragData) { e.stopPropagation(); this.props.reorderColumns(colDragData.colKey, this.props.columnValue, before, this.props.allColumns); @@ -85,8 +100,10 @@ export class MovableColumn extends React.Component { document.removeEventListener("pointermove", onRowMove); document.removeEventListener('pointerup', onRowUp); }; + // if the left mouse button is the one being held if (e.buttons === 1) { const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y); + // If the movemnt of the drag exceeds the sensitivity value if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) { document.removeEventListener("pointermove", this.onPointerMove); e.stopPropagation(); @@ -105,6 +122,7 @@ export class MovableColumn extends React.Component { onPointerDown = (e: React.PointerEvent, ref: React.RefObject) => { this._dragRef = ref; const [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX, e.clientY); + // If the cell thing dragged is not being edited if (!(e.target as any)?.tagName.includes("INPUT")) { this._startDragPosition = { x: dx, y: dy }; document.addEventListener("pointermove", this.onPointerMove); -- cgit v1.2.3-70-g09d2 From 9031708067ee16d7b7e6b2689f45ee54ea5f1e4a Mon Sep 17 00:00:00 2001 From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com> Date: Tue, 17 Aug 2021 14:14:26 -0400 Subject: Added empty tabs message todo: create buttons for recent tabs when all tabs in a dashboard are closed --- src/client/documents/Documents.ts | 2 +- src/client/goldenLayout.js | 8 +++++++- src/client/views/MainView.tsx | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 48886aa3b..47e0377df 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -269,7 +269,7 @@ export class DocumentOptions { linearViewIsExpanded?: boolean; // is linear view expanded useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox border?: string; //for searchbox - hoverBackgroundColor?: string; // background color of a label when hovered + hoverBackgroundColor?: string; // background color of a label when hovered } export namespace Docs { diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js index db94cce3d..896237e1d 100644 --- a/src/client/goldenLayout.js +++ b/src/client/goldenLayout.js @@ -2355,6 +2355,7 @@ this.element.hide(); } }); + /** * This class represents a header above a Stack ContentItem. * @@ -2362,6 +2363,7 @@ * @param {lm.item.AbstractContentItem} parent */ lm.controls.Header = function (layoutManager, parent) { + lm.utils.EventEmitter.call(this); this.layoutManager = layoutManager; @@ -4449,7 +4451,11 @@ lm.items.Stack = function (layoutManager, config, parent) { lm.items.AbstractContentItem.call(this, layoutManager, config, parent); - this.element = $('

    Click to create a new tab

    '); + this.element = $( + '
    ' + + '

    Click to create a new tab

    ' + + '
    ' + ); this._activeContentItem = null; var cfg = layoutManager.config; this._header = { // defaults' reconstruction from old configuration style diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b0b8d7f41..ba8f2a4c8 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -448,6 +448,7 @@ export class MainView extends React.Component {
    ; } + expandFlyout = action((button: Doc) => { this._flyoutWidth = (this._flyoutWidth || 250); this._sidebarContent.proto = button.target as any; -- cgit v1.2.3-70-g09d2 From 53019659c2335906ac9e42d755548ea35dfc0365 Mon Sep 17 00:00:00 2001 From: dinhanhtruong <70963346+dinhanhtruong@users.noreply.github.com> Date: Tue, 17 Aug 2021 15:05:09 -0400 Subject: Fixed linking relationship misattribution fixed bug where link relationships were stored as link descriptions --- src/client/views/linking/LinkEditor.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index f74b422d3..9d0938a6e 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -70,7 +70,7 @@ export class LinkEditor extends React.Component { } onDown = () => this.setDescripValue(this.description); - onRelationshipDown = () => this.setRelationshipValue(this.description); + onRelationshipDown = () => this.setRelationshipValue(this.relationship); @action handleChange = (e: React.ChangeEvent) => { this.description = e.target.value; } @@ -149,35 +149,35 @@ export class LinkEditor extends React.Component {
    this.changeFollowBehavior("default")}> Default -
    +
    this.changeFollowBehavior("add:left")}> Always open in new left pane -
    +
    this.changeFollowBehavior("add:right")}> Always open in new right pane -
    +
    this.changeFollowBehavior("replace:right")}> Always replace right tab -
    +
    this.changeFollowBehavior("replace:left")}> Always replace left tab -
    +
    this.changeFollowBehavior("fullScreen")}> Always open full screen -
    +
    this.changeFollowBehavior("add")}> Always open in a new tab -
    +
    this.changeFollowBehavior("replace")}> Replace Tab -
    + {this.props.linkDoc.linksToAnnotation ?
    this.changeFollowBehavior("openExternal")}> -- cgit v1.2.3-70-g09d2 From c5e96c72fcf149b9bcfe5f7f7a9c714de1d5fd9a Mon Sep 17 00:00:00 2001 From: 0x85FB9C51 <77808164+0x85FB9C51@users.noreply.github.com> Date: Wed, 25 Aug 2021 16:58:57 -0400 Subject: added comment, fixed path issue --- .../collectionSchema/CollectionSchemaCells.tsx | 239 +++++++++++---------- .../collectionSchema/CollectionSchemaHeaders.tsx | 2 +- 2 files changed, 126 insertions(+), 115 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx index f7dfaaeb4..c8638dd12 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx @@ -26,7 +26,7 @@ import { SnappingManager } from "../../../util/SnappingManager"; import { undoBatch } from "../../../util/UndoManager"; import '../../../views/DocumentDecorations.scss'; import { EditableView } from "../../EditableView"; -import { MAX_ROW_HEIGHT } from '../../globalCssVariables.scss'; +import { MAX_ROW_HEIGHT } from '../../../../client/views/globalCssVariables.scss'; import { DocumentIconContainer } from "../../nodes/DocumentIcon"; import { OverlayView } from "../../OverlayView"; import "./CollectionSchemaView.scss"; @@ -38,27 +38,35 @@ export interface CellProps { row: number; col: number; rowProps: CellInfo; + // currently unused CollectionView: Opt; + // currently unused ContainingCollection: Opt; Document: Doc; + // column name fieldKey: string; + // currently unused renderDepth: number; + // called when a button is pressed on the node itself addDocTab: (document: Doc, where: string) => boolean; pinToPres: (document: Doc) => void; moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean; isFocused: boolean; changeFocusedCellByIndex: (row: number, col: number) => void; + // set whether the cell is in the isEditing mode setIsEditing: (isEditing: boolean) => void; isEditable: boolean; setPreviewDoc: (doc: Doc) => void; setComputed: (script: string, doc: Doc, field: string, row: number, col: number) => boolean; getField: (row: number, col?: number) => void; + // currnetly unused showDoc: (doc: Doc | undefined, dataDoc?: any, screenX?: number, screenY?: number) => void; } @observer export class CollectionSchemaCell extends React.Component { + // return a field key that is corrected for whether it COMMENT public static resolvedFieldKey(column: string, rowDoc: Doc) { const fieldKey = column; if (fieldKey.startsWith("*")) { @@ -72,7 +80,9 @@ export class CollectionSchemaCell extends React.Component { @observable protected _isEditing: boolean = false; protected _focusRef = React.createRef(); protected _rowDoc = this.props.rowProps.original; + // Gets the serialized data in proto form of the base proto that this document's proto inherits from protected _rowDataDoc = Doc.GetProto(this.props.rowProps.original); + // methods for dragging and dropping protected _dropDisposer?: DragManager.DragDropDisposer; @observable contents: string = ""; @@ -81,6 +91,7 @@ export class CollectionSchemaCell extends React.Component { @action onKeyDown = (e: KeyboardEvent): void => { + // If a cell is editable and clicked, hitting enter shoudl allow the user to edit it if (this.props.isFocused && this.props.isEditable && e.keyCode === KeyCodes.ENTER) { document.removeEventListener("keydown", this.onKeyDown); this._isEditing = true; @@ -90,7 +101,11 @@ export class CollectionSchemaCell extends React.Component { @action isEditingCallback = (isEditing: boolean): void => { + // a general method that takes a boolean that determines whether the cell should be in + // is-editing mode + // remove the event listener if it's there document.removeEventListener("keydown", this.onKeyDown); + // it's not already in is-editing mode, re-add the event listener isEditing && document.addEventListener("keydown", this.onKeyDown); this._isEditing = isEditing; this.props.setIsEditing(isEditing); @@ -99,12 +114,16 @@ export class CollectionSchemaCell extends React.Component { @action onPointerDown = async (e: React.PointerEvent): Promise => { + // pan to the cell this.onItemDown(e); + // focus on it this.props.changeFocusedCellByIndex(this.props.row, this.props.col); this.props.setPreviewDoc(this.props.rowProps.original); + // console.log("click cell"); let url: string; if (url = StrCast(this.props.rowProps.row.href)) { + // opens up the the doc in a new window, blurring the old one try { new URL(url); const temp = window.open(url)!; @@ -119,18 +138,25 @@ export class CollectionSchemaCell extends React.Component { @undoBatch applyToDoc = (doc: Doc, row: number, col: number, run: (args?: { [name: string]: any }) => any) => { + // apply a specified change to the cell const res = run({ this: doc, $r: row, $c: col, $: (r: number = 0, c: number = 0) => this.props.getField(r + row, c + col) }); if (!res.success) return false; + // change what is rendered to this new changed cell content doc[this.renderFieldKey] = res.result; return true; + // return whether the change was successful } private drop = (e: Event, de: DragManager.DropEvent) => { + // if the drag has data at its completion if (de.complete.docDragData) { + // if only one doc was dragged if (de.complete.docDragData.draggedDocuments.length === 1) { + // update the renderFieldKey this._rowDataDoc[this.renderFieldKey] = de.complete.docDragData.draggedDocuments[0]; } else { + // create schema document reflecting the new column arrangement const coll = Docs.Create.SchemaDocument([new SchemaHeaderField("title", "#f1efeb")], de.complete.docDragData.draggedDocuments, {}); this._rowDataDoc[this.renderFieldKey] = coll; } @@ -139,7 +165,9 @@ export class CollectionSchemaCell extends React.Component { } protected dropRef = (ele: HTMLElement | null) => { + // if the drop disposer is not undefined, run its function this._dropDisposer?.(); + // if ele is not null, give ele a non-undefined drop disposer ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this))); } @@ -163,33 +191,46 @@ export class CollectionSchemaCell extends React.Component { return {contents ? contents?.valueOf() : "undefined"}; } - @computed get renderFieldKey() { return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); } + @computed get renderFieldKey() { + // gets the resolved field key of this cell + return CollectionSchemaCell.resolvedFieldKey(this.props.rowProps.column.id!, this.props.rowProps.original); + } + onItemDown = async (e: React.PointerEvent) => { + // if the document is a document used to change UI for search results in schema view if (this.props.Document._searchDoc) { const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc); const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null); + // Jump to the this document DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext, undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc)); } } + renderCellWithType(type: string | undefined) { const dragRef: React.RefObject = React.createRef(); + // the column const fieldKey = this.renderFieldKey; + // the exact cell const field = this._rowDoc[fieldKey]; const onPointerEnter = (e: React.PointerEvent): void => { + // e.buttons === 1 means the left moue pointer is down if (e.buttons === 1 && SnappingManager.GetIsDragging() && (type === "document" || type === undefined)) { dragRef.current!.className = "collectionSchemaView-cellContainer doc-drag-over"; } }; const onPointerLeave = (e: React.PointerEvent): void => { + // change the class name to indicate that the cell is no longer being dragged dragRef.current!.className = "collectionSchemaView-cellContainer"; }; let contents = Field.toString(field as Field); + // display 2 hyphens instead of a blank box for empty cells contents = contents === "" ? "--" : contents; + // classname reflects the tatus of the cell let className = "collectionSchemaView-cellWrapper"; if (this._isEditing) className += " editing"; if (this.props.isFocused && this.props.isEditable) className += " focused"; @@ -197,72 +238,27 @@ export class CollectionSchemaCell extends React.Component { const positions = []; if (StrCast(this.props.Document._searchString).toLowerCase() !== "") { + // term is ...promise pending... if the field is a Promise, otherwise it is the cell's contents let term = (field instanceof Promise) ? "...promise pending..." : contents.toLowerCase(); const search = StrCast(this.props.Document._searchString).toLowerCase(); let start = term.indexOf(search); let tally = 0; + // if search is found in term if (start !== -1) { positions.push(start); } + // if search is found in term, continue finding all instances of search in term while (start < contents?.length && start !== -1) { term = term.slice(start + search.length + 1); tally += start + search.length + 1; start = term.indexOf(search); positions.push(tally + start); } + // remove the last position if (positions.length > 1) { positions.pop(); } } - - // handles input procedures for string cells - let stringInput = (value: string, retVal: boolean): void => { - let valueSansQuotes = value; - if (this._isEditing) { - const vsqLength = valueSansQuotes.length; - // get rid of outer quotes - valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, - valueSansQuotes.charAt(vsqLength - 1) == "\"" ? vsqLength - 1 : vsqLength); - } - let inputAsString = '"'; - // escape any quotes in the string - for (const i of valueSansQuotes) { - if (i == '"') { - inputAsString += '\\"'; - } else { - inputAsString += i; - } - } - // add a closing quote - inputAsString += '"'; - //two options here: we can strip off outer quotes or we can figure out what's going on with the script - const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - } - - // handles input procedure for number cells - let numberInput = (value: string, retVal: boolean): void => { - const inputscript = value.substring(value.startsWith("=") ? 1 : 0); - // if commas are not stripped, the parser only considers the numbers after the last comma - let inputSansCommas = ""; - for (let s of inputscript) { - if (!(s == ",")) { - inputSansCommas += s; - } - } - const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - } - - // handles input procedure for boolean cells - let boolInput = (value: string, retVal: boolean): void => { - const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); - const changeMade = value.length !== value.length || value.length - 2 !== value.length - script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); - } - const placeholder = type === "number" ? "0" : contents === "" ? "--" : "undefined"; return (
    { } else { // check if the input is a number let inputIsNum = true; - for (let s of value) { - if (isNaN(parseInt(s)) && !(s == ".") && !(s == ",")) { + for (const s of value) { + if (isNaN(parseInt(s)) && !(s === ".") && !(s === ",")) { inputIsNum = false; } } - - let contentsAreNum = true; - for (let s of contents) { - if (isNaN(parseInt(s)) && !(s == ".") && !(s == ",")) { - contentsAreNum = false; - } - } // check if the input is a boolean - let inputIsBool: boolean = value == "false" || value == "true"; - let contentsAreBool: boolean = contents == "false" || contents == "true"; - - if (type == undefined) { - // what to do in the case - if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { - // if it's not a number, it's a string, and should be processed as such - // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically - // after each edit - stringInput(value, retVal); - // handle numbers and expressions - } else if (inputIsNum || value.startsWith("=")) { - numberInput(value, retVal); - // handle booleans - } else if (inputIsBool) { - boolInput(value, retVal); + const inputIsBool: boolean = value === "false" || value === "true"; + // what to do in the case + if (!inputIsNum && !inputIsBool && !value.startsWith("=")) { + // if it's not a number, it's a string, and should be processed as such + // strips the string of quotes when it is edited to prevent quotes form being added to the text automatically + // after each edit + let valueSansQuotes = value; + if (this._isEditing) { + const vsqLength = valueSansQuotes.length; + // get rid of outer quotes + valueSansQuotes = valueSansQuotes.substring(value.startsWith("\"") ? 1 : 0, + valueSansQuotes.charAt(vsqLength - 1) === "\"" ? vsqLength - 1 : vsqLength); } - // if the cell type is a string - } else if (type == "string") { - stringInput(value, retVal); - // if the cell type is a number - } else if (type == "number") { - if (inputIsNum) { - numberInput(value, retVal); - } else if (!contentsAreNum) { - stringInput("", retVal); + let inputAsString = '"'; + // escape any quotes in the string + for (const i of valueSansQuotes) { + if (i === '"') { + inputAsString += '\\"'; + } else { + inputAsString += i; + } } - // if the cell type is a boolean - } else if (type == "boolean") { - if (inputIsBool) { - boolInput(value, retVal); - } else if (!contentsAreBool) { - stringInput("", retVal); + // add a closing quote + inputAsString += '"'; + //two options here: we can strip off outer quotes or we can figure out what's going on with the script + const script = CompileScript(inputAsString, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = inputAsString.length !== value.length || inputAsString.length - 2 !== value.length; + // change it if a change is made, otherwise, just compile using the old cell conetnts + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + // handle numbers and expressions + } else if (inputIsNum || value.startsWith("=")) { + //TODO: make accept numbers + const inputscript = value.substring(value.startsWith("=") ? 1 : 0); + // if commas are not stripped, the parser only considers the numbers after the last comma + let inputSansCommas = ""; + for (const s of inputscript) { + if (!(s === ",")) { + inputSansCommas += s; + } } + const script = CompileScript(inputSansCommas, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = value.length !== value.length || value.length - 2 !== value.length; + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); + // handle booleans + } else if (inputIsBool) { + const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); + const changeMade = value.length !== value.length || value.length - 2 !== value.length; + script.compiled && (retVal = this.applyToDoc(changeMade ? this._rowDoc : this._rowDataDoc, this.props.row, this.props.col, script.run)); } } if (retVal) { @@ -351,6 +354,7 @@ export class CollectionSchemaCell extends React.Component { return retVal; })} OnFillDown={async (value: string) => { + // computes all of the value preceded by := const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } }); script.compiled && DocListCast(this.props.Document[this.props.fieldKey]). forEach((doc, i) => value.startsWith(":=") ? @@ -381,7 +385,10 @@ export class CollectionSchemaStringCell extends CollectionSchemaCell { render() @observer export class CollectionSchemaDateCell extends CollectionSchemaCell { - @computed get _date(): Opt { return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; } + @computed get _date(): Opt { + // if the cell is a date field, cast then contents to a date. Otherrwwise, make the contents undefined. + return this._rowDoc[this.renderFieldKey] instanceof DateField ? DateCast(this._rowDoc[this.renderFieldKey]) : undefined; + } @action handleChange = (date: any) => { @@ -394,16 +401,13 @@ export class CollectionSchemaDateCell extends CollectionSchemaCell { //} } - // If the cell is not clicked on, render the date normally. Otherwise, render a date picker. render() { - return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : -
    - this.handleChange(date)} - onChange={date => this.handleChange(date)} - /> -
    + return !this.props.isFocused ? {this._date ? Field.toString(this._date as Field) : "--"} : + this.handleChange(date)} + onChange={date => this.handleChange(date)} + />; } } @@ -423,8 +427,9 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { typecheck: true, transformer: DocumentIconContainer.getTransformer() }); - + // compile the script const results = script.compiled && script.run(); + // if the script was compiled and run if (results && results.success) { this._rowDoc[this.renderFieldKey] = results.result; return true; @@ -442,6 +447,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { @action isEditingCallback = (isEditing: boolean): void => { + // the isEditingCallback from a general CollectionSchemaCell document.removeEventListener("keydown", this.onKeyDown); isEditing && document.addEventListener("keydown", this.onKeyDown); this._isEditing = isEditing; @@ -450,6 +456,7 @@ export class CollectionSchemaDocCell extends CollectionSchemaCell { } render() { + // if there's a doc, render it return !this._doc ? this.renderCellWithType("document") :
    Cast(doc[Doc.LayoutFieldKey(doc)], ImageField, null)?.url).filter(url => url).map(url => this.choosePath(url)); // access the primary layout data of the alternate documents const paths = field ? [this.choosePath(field.url), ...altpaths] : altpaths; + // If there is a path, follow it; otherwise, follow a link to a default image icon const url = paths.length ? paths : [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")]; - const aspect = Doc.NativeAspect(this._rowDoc); - let width = Math.min(75, this.props.rowProps.width); - const height = Math.min(75, width / aspect); - width = height * aspect; + const aspect = Doc.NativeAspect(this._rowDoc); // aspect ratio + let width = Math.min(75, this.props.rowProps.width); // get a with that is no smaller than 75px + const height = Math.min(75, width / aspect); // get a height either proportional to that or 75 px + width = height * aspect; // increase the width of the image if necessary to maintain proportionality const reference = React.createRef(); return
    @@ -523,13 +531,13 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { @computed get _field() { return this._rowDoc[this.renderFieldKey]; } @computed get _optionsList() { return this._field as List; } - @observable private _opened = false; + @observable private _opened = false; // whether the list is opened @observable private _text = "select an item"; - @observable private _selectedNum = 0; + @observable private _selectedNum = 0; // the index of the list item selected @action onSetValue = (value: string) => { - // change if its a document + // change if it's a document this._optionsList[this._selectedNum] = this._text = value; (this._field as List).splice(this._selectedNum, 1, value); @@ -537,6 +545,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { @action onSelected = (element: string, index: number) => { + // if an item is selected, the private variables should update to reflect this this._text = element; this._selectedNum = index; } @@ -550,6 +559,7 @@ export class CollectionSchemaListCell extends CollectionSchemaCell { const link = false; const reference = React.createRef(); + // if the list is not opened, don't display it; otherwise, do. if (this._optionsList?.length) { const options = !this._opened ? (null) :
    @@ -617,6 +627,7 @@ export class CollectionSchemaCheckboxCell extends CollectionSchemaCell { @observer export class CollectionSchemaButtons extends CollectionSchemaCell { + // the navigation buttons for schema view when it is used for search. render() { return !this.props.Document._searchDoc || ![DocumentType.PDF, DocumentType.RTF].includes(StrCast(this._rowDoc.type) as DocumentType) ? <> :
    @@ -628,4 +639,4 @@ export class CollectionSchemaButtons extends CollectionSchemaCell {
    ; } -} \ No newline at end of file +} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index b2115b22e..2da9409f2 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -25,6 +25,7 @@ export interface AddColumnHeaderProps { @observer export class CollectionSchemaAddColumnHeader extends React.Component { + // the button that allows the user to add a column render() { return ( @@ -32,7 +33,6 @@ export class CollectionSchemaAddColumnHeader extends React.Component Date: Thu, 14 Oct 2021 12:16:17 -0400 Subject: fixed comparison box error. --- src/client/views/nodes/ComparisonBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index b1aada158..0f962f95c 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -90,7 +90,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent { var whichDoc = Cast(this.dataDoc[which], Doc, null); //if (whichDoc?.type === DocumentType.MARKER) - const targetDoc = Cast(whichDoc.annotationOn, Doc, null) ?? whichDoc; + const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc; return whichDoc ? <> { -- cgit v1.2.3-70-g09d2 From 93bc6d3fbfa35c7f47b7000e0ea36d9ab81d7eba Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 14 Oct 2021 15:33:41 -0400 Subject: fixed document resizing. --- src/client/views/DocumentDecorations.tsx | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index bd9c3509b..17a81149c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -318,8 +318,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P const doc = Document(docView.rootDoc); const nwidth = docView.nativeWidth; const nheight = docView.nativeHeight; - const width = (doc._width || 0); - let height = (doc._height || (nheight / nwidth * width)); + const docheight = doc._height || 0; + const docwidth = doc._width || 0; + const width = docwidth; + let height = (docheight || (nheight / nwidth * width)); height = !height || isNaN(height) ? 20 : height; const scale = docView.props.ScreenToLocalTransform().Scale; const modifyNativeDim = (e.ctrlKey || doc.forceReflow) && doc.nativeDimModifiable; @@ -332,17 +334,18 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P else dW = dH * nwidth / nheight; } } - const actualdW = Math.max(width + (dW * scale), 20); - const actualdH = Math.max(height + (dH * scale), 20); - doc.x = (doc.x || 0) + dX * (actualdW - width); - doc.y = (doc.y || 0) + dY * (actualdH - height); + let actualdW = Math.max(width + (dW * scale), 20); + let actualdH = Math.max(height + (dH * scale), 20); const fixedAspect = (nwidth && nheight); if (fixedAspect) { if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !modifyNativeDim)) || dragRight) { if (dragRight && modifyNativeDim) { doc._nativeWidth = actualdW / (doc._width || 1) * Doc.NativeWidth(doc); } else { - if (!doc._fitWidth) doc._height = nheight / nwidth * actualdW; + if (!doc._fitWidth) { + actualdH = nheight / nwidth * actualdW; + doc._height = actualdH; + } else if (!modifyNativeDim || dragBotRight) doc._height = actualdH; } doc._width = actualdW; @@ -353,10 +356,16 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P doc._nativeHeight = actualdH / (doc._height || 1) * Doc.NativeHeight(doc); doc._autoHeight = false; } else { - if (!doc._fitWidth) doc._width = nwidth / nheight * actualdH; + if (!doc._fitWidth) { + actualdW = nwidth / nheight * actualdH; + doc._width = actualdW; + } else if (!modifyNativeDim || dragBotRight) doc._width = actualdW; } - if (!modifyNativeDim) doc._height = Math.min(nheight / nwidth * NumCast(doc._width), actualdH); + if (!modifyNativeDim) { + actualdH = Math.min(nheight / nwidth * NumCast(doc._width), actualdH); + doc._height = actualdH; + } else doc._height = actualdH; } } else { @@ -364,6 +373,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P dW && (doc._width = actualdW); dH && (doc._autoHeight = false); } + doc.x = (doc.x || 0) + dX * (actualdW - docwidth); + doc.y = (doc.y || 0) + dY * (actualdH - docheight); doc._lastModified = new DateField(); } const val = this._dragHeights.get(docView.layoutDoc); -- cgit v1.2.3-70-g09d2 From b08232def0a7533cc7dbc7db8d3153e72a3ff2d5 Mon Sep 17 00:00:00 2001 From: Aubrey Li Date: Thu, 14 Oct 2021 15:50:54 -0400 Subject: dashboard treeview freeze --- src/client/util/CurrentUserUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 3c32c2359..9d06ad8a3 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -810,7 +810,7 @@ export class CurrentUserUtils { const newDashboard = ScriptField.MakeScript(`createNewDashboard(Doc.UserDoc())`); const newDashboardButton: Doc = Docs.Create.FontIconDocument({ onClick: newDashboard, _forceActive: true, toolTip: "Create new dashboard", _stayInCollection: true, _hideContextMenu: true, title: "new dashboard", btnType: ButtonType.ClickButton, _width: 30, _height: 30, buttonText: "New trail", icon: "plus", system: true }); doc.myDashboards = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, + title: "My Dashboards", _showTitle: "title", _height: 400, childHideLinkButton: true, freezeChildren: "remove|add", treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, ignoreClick: true, buttonMenu: true, buttonMenuDoc: newDashboardButton, _lockedPosition: true, boxShadow: "0 0", childDontRegisterViews: true, targetDropAction: "same", treeViewType: "fileSystem", isFolder: true, system: true, @@ -1328,6 +1328,7 @@ export class CurrentUserUtils { Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); doc.savedFilters = new List(); doc.filterDocCount = 0; + doc.freezeChildren = "remove|add"; this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates this.setupImportSidebar(doc); // sets up the import sidebar -- cgit v1.2.3-70-g09d2 From bdf0befa2b5eff79c2729254c2d053afe18b1646 Mon Sep 17 00:00:00 2001 From: bobzel Date: Sat, 16 Oct 2021 01:58:15 -0400 Subject: fixed warnings/errors & redirection to /home --- src/client/views/collections/TreeView.tsx | 12 ++++++------ .../collections/collectionSchema/CollectionSchemaHeaders.tsx | 4 ++-- src/client/views/linking/LinkEditor.tsx | 4 ++-- src/client/views/nodes/ComparisonBox.tsx | 2 +- src/server/server_Initialization.ts | 2 ++ 5 files changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a3da0e0e4..7f2128230 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -820,7 +820,7 @@ export class TreeView extends React.Component { childDocs: Doc[], treeView: CollectionTreeView, parentTreeView: CollectionTreeView | TreeView | undefined, - conainerCollection: Doc, + containerCollection: Doc, dataDoc: Doc | undefined, parentCollectionDoc: Doc | undefined, containerPrevSibling: Doc | undefined, @@ -846,16 +846,16 @@ export class TreeView extends React.Component { unobserveHeight: (ref: any) => void, contextMenuItems: ({ script: ScriptField, filter: ScriptField, label: string, icon: string }[]) ) { - const viewSpecScript = Cast(conainerCollection.viewSpecScript, ScriptField); + const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField); if (viewSpecScript) { childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result); } - const docs = TreeView.sortDocs(childDocs, StrCast(conainerCollection.treeViewSortCriterion)); + const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion)); const rowWidth = () => panelWidth() - treeBulletWidth(); const treeViewRefs = new Map(); return docs.filter(child => child instanceof Doc).map((child, i) => { - const pair = Doc.GetLayoutDataDocPair(conainerCollection, dataDoc, child); + const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child); if (!pair.layout || pair.data instanceof Promise) { return (null); } @@ -883,7 +883,7 @@ export class TreeView extends React.Component { return treeViewRefs.set(child, r ? r : undefined)} document={pair.layout} dataDoc={pair.data} - containerCollection={conainerCollection} + containerCollection={containerCollection} prevSibling={docs[i]} treeView={treeView} indentDocument={indent} @@ -891,7 +891,7 @@ export class TreeView extends React.Component { onCheckedClick={onCheckedClick} onChildClick={onChildClick} renderDepth={renderDepth} - removeDoc={StrCast(conainerCollection.freezeChildren).includes("remove") ? undefined : remove} + removeDoc={StrCast(containerCollection.freezeChildren).includes("remove") ? undefined : remove} addDocument={addDocument} styleProvider={styleProvider} panelWidth={rowWidth} diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx index 074074bc5..1306b79cb 100644 --- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx @@ -395,8 +395,8 @@ export class KeysDropdown extends React.Component { this.closeResultsVisibility = "none"; } for (let i = 0; i < (filters?.length ?? 0) - 1; i++) { - if (filters![i] === this.props.col.heading && keyOptions.includes(filters![i].split(":")[1]) === false) { - keyOptions.push(filters![i + 1]); + if (filters[i] === this.props.col.heading && keyOptions.includes(filters[i].split(":")[1]) === false) { + keyOptions.push(filters[i + 1]); } } const options = keyOptions.map(key => { diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index 5b5c3cd01..db331bb75 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -54,9 +54,9 @@ export class LinkEditor extends React.Component { linkRelationshipList.push(value); linkRelationshipSizes.push(1); const randColor = "rgb(" + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + "," + Math.floor(Math.random() * 255) + ")"; - linkColorList.push(randColor) + linkColorList.push(randColor); // if the relationship is already in the list AND the new rel is different from the prev rel, update the rel sizes - } else if (linkRelationshipList && value != prevRelationship) { + } else if (linkRelationshipList && value !== prevRelationship) { const index = linkRelationshipList.indexOf(value); //increment size of new relationship size if (index !== -1 && index < linkRelationshipSizes.length) { diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index 0f962f95c..750213e67 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -88,7 +88,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent; }; const displayDoc = (which: string) => { - var whichDoc = Cast(this.dataDoc[which], Doc, null); + const whichDoc = Cast(this.dataDoc[which], Doc, null); //if (whichDoc?.type === DocumentType.MARKER) const targetDoc = Cast(whichDoc?.annotationOn, Doc, null) ?? whichDoc; return whichDoc ? <> diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 0f4a067fc..00a801e03 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -37,6 +37,8 @@ export let resolvedServerUrl: string; export default async function InitializeServer(routeSetter: RouteSetter) { const app = buildWithMiddleware(express()); + // Root route of express app + app.get("/", (req, res) => res.redirect("/home")); app.use(express.static(publicDirectory, { setHeaders: res => res.setHeader("Access-Control-Allow-Origin", "*") -- cgit v1.2.3-70-g09d2