/* * Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved. */ /* * This is an extension and not part of the main GoJS library. * Note that the API for this class may change with any version, even point releases. * If you intend to use an extension in production, you should copy the code to your own source directory. * Extensions can be found in the GoJS kit under the extensions or extensionsTS folders. * See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information. */ import * as go from '../release/go-module.js'; // A "ScrollingTable" Panel // This also defines an "AutoRepeatButton" Panel, // which is used by the scrollbar in the "ScrollingTable" Panel. // This defines a custom "Button" that automatically repeats its click // action when the user holds down the mouse. // The first optional argument may be a number indicating the number of milliseconds // to wait between calls to the click function. Default is 50. // The second optional argument may be a number indicating the number of milliseconds // to delay before starting calls to the click function. Default is 500. // Example: // $("AutoRepeatButton", 150, // slower than the default 50 milliseconds between calls // { // click: function(e, button) { doSomething(button.part); } // }, // $(go.Shape, "Circle", { width: 8, height: 8 }) // ) go.GraphObject.defineBuilder('AutoRepeatButton', function(args) { const repeat = go.GraphObject.takeBuilderArgument(args, 50, function(x) { return typeof x === "number"; }); const delay = go.GraphObject.takeBuilderArgument(args, 500, function(x) { return typeof x === "number"; }); const $ = go.GraphObject.make; // some internal helper functions for auto-repeating function delayClicking(e: go.InputEvent, obj: any) { endClicking(e, obj); if (obj.click) { obj._timer = setTimeout(function() { repeatClicking(e, obj); }, delay); // wait milliseconds before starting clicks } } function repeatClicking(e: go.InputEvent, obj: any) { if (obj._timer) clearTimeout(obj._timer); if (obj.click) { obj._timer = setTimeout(function() { if (obj.click) { (obj.click)(e, obj); repeatClicking(e, obj); } }, repeat); // milliseconds between clicks } } function endClicking(e: go.InputEvent, obj: any) { if (obj._timer) { clearTimeout(obj._timer); obj._timer = undefined; } } return $('Button', { actionDown: delayClicking, actionUp: endClicking }); }); // Create a scrolling Table Panel, whose name is given as the optional first argument. // If not given the name defaults to "TABLE". // Example use: // $("ScrollingTable", "TABLE", // new go.Binding("TABLE.itemArray", "someArrayProperty"), // ...) // Note that if you have more than one of these in a Part, // you'll want to make sure each one has a unique name. go.GraphObject.defineBuilder('ScrollingTable', function(args) { const $ = go.GraphObject.make; const tablename = go.GraphObject.takeBuilderArgument(args, 'TABLE'); // an internal helper function for actually performing a scrolling operation function incrTableIndex(obj: go.GraphObject, i: number) { const diagram = obj.diagram; if (!obj.panel || !obj.panel.panel || !obj.panel.panel.panel) return; const table = obj.panel.panel.panel.findObject(tablename) as go.Panel; if (i === +Infinity || i === -Infinity) { // page up or down const tabh = table.actualBounds.height; const rowh = table.elt(table.topIndex).actualBounds.height; // assume each row has same height? if (i === +Infinity) { i = Math.max(1, Math.ceil(tabh / rowh) - 1); } else { i = -Math.max(1, Math.ceil(tabh / rowh) - 1); } } let idx = table.topIndex + i; if (idx < 0) idx = 0; else if (idx >= table.rowCount - 1) idx = table.rowCount - 1; if (table.topIndex !== idx) { if (diagram !== null) diagram.startTransaction('scroll'); table.topIndex = idx; const node = table.part; // may need to reroute links if the table contains any ports if (node instanceof go.Node) node.invalidateConnectedLinks(); updateScrollBar(table); if (diagram !== null) diagram.commitTransaction('scroll'); } } function updateScrollBar(table: go.Panel) { if (table.panel === null) return; const bar = table.panel.elt(1) as go.Node; // the scrollbar is a sibling of the table if (!bar) return; const idx = table.topIndex; const up = bar.findObject('UP'); if (up) up.opacity = (idx > 0) ? 1.0 : 0.3; const down = bar.findObject('DOWN'); if (down) down.opacity = (idx < table.rowCount - 1) ? 1.0 : 0.3; const tabh = bar.actualBounds.height; let rowh = table.elt(idx).actualBounds.height; // ?? assume each row has same height? if (rowh === 0 && idx < table.rowCount - 2) rowh = table.elt(idx + 1).actualBounds.height; const numVisibleRows = Math.max(1, Math.ceil(tabh / rowh) - 1); const needed = idx > 0 || idx + numVisibleRows <= table.rowCount; bar.opacity = needed ? 1.0 : 0.5; } return $(go.Panel, 'Table', { _updateScrollBar: updateScrollBar }, // this actually holds the item elements $(go.Panel, 'Table', { name: tablename, column: 0, stretch: go.GraphObject.Fill, background: 'whitesmoke', rowSizing: go.RowColumnDefinition.None, defaultAlignment: go.Spot.Top }), // this is the scrollbar $(go.RowColumnDefinition, { column: 1, sizing: go.RowColumnDefinition.None }), $(go.Panel, 'Table', { column: 1, stretch: go.GraphObject.Vertical, background: '#DDDDDD' }, // the scroll up button $('AutoRepeatButton', { name: 'UP', row: 0, alignment: go.Spot.Top, 'ButtonBorder.figure': 'Rectangle', 'ButtonBorder.fill': 'lightgray', click: function(e: go.InputEvent, obj: go.GraphObject) { incrTableIndex(obj, -1); } }, $(go.Shape, 'TriangleUp', { stroke: null, desiredSize: new go.Size(6, 6) })), // (someday implement a thumb here and support dragging to scroll) // the scroll down button $('AutoRepeatButton', { name: 'DOWN', row: 2, alignment: go.Spot.Bottom, 'ButtonBorder.figure': 'Rectangle', 'ButtonBorder.fill': 'lightgray', click: function(e: go.InputEvent, obj: go.GraphObject) { incrTableIndex(obj, +1); } }, $(go.Shape, 'TriangleDown', { stroke: null, desiredSize: new go.Size(6, 6) })) ) ); });