mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
feat: remove sense legacy build path (#1244)
This commit is contained in:
@@ -22,7 +22,6 @@ Options:
|
|||||||
--output Destination directory [string] [default: "<name>-ext"]
|
--output Destination directory [string] [default: "<name>-ext"]
|
||||||
--minify Minify and uglify code [boolean] [default: true]
|
--minify Minify and uglify code [boolean] [default: true]
|
||||||
--sourcemap Generate sourcemaps [boolean] [default: false]
|
--sourcemap Generate sourcemaps [boolean] [default: false]
|
||||||
--legacy Generate legacy extension [boolean] [default: false]
|
|
||||||
-h, --help Show help [boolean]
|
-h, --help Show help [boolean]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -123,21 +122,3 @@ example:
|
|||||||
"supernova": true
|
"supernova": true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `"supernova": true` attribute should not be added when building with the
|
|
||||||
--legacy option below.
|
|
||||||
|
|
||||||
### Legacy
|
|
||||||
|
|
||||||
Qlik Sense before 2020 does not support nebula supernova natively, so a special
|
|
||||||
build path is needed for visualizations to load properly in the client.
|
|
||||||
For this purpose, use the --legacy option.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nebula sense --legacy
|
|
||||||
```
|
|
||||||
|
|
||||||
You can find that the generated `QEXT` file does not include `supernova: true`.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
For old Qlik Sense, not all features of extension are presented.
|
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const fs = require('fs-extra');
|
|
||||||
|
|
||||||
const rollup = require('rollup');
|
|
||||||
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
|
||||||
const common = require('@rollup/plugin-commonjs');
|
|
||||||
const replace = require('@rollup/plugin-replace');
|
|
||||||
const babel = require('@rollup/plugin-babel');
|
|
||||||
const terser = require('@rollup/plugin-terser');
|
|
||||||
|
|
||||||
async function build(argv) {
|
|
||||||
const cwd = process.cwd();
|
|
||||||
|
|
||||||
const supernovaPkg = require(path.resolve(cwd, 'package.json')); // eslint-disable-line
|
|
||||||
|
|
||||||
let extName = supernovaPkg.name.split('/').reverse()[0];
|
|
||||||
|
|
||||||
const { main } = supernovaPkg;
|
|
||||||
|
|
||||||
if (extName === main) {
|
|
||||||
extName = extName.replace(/\.js$/, '-ext.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetDir = argv.output !== '<name>-ext' ? argv.output : `${extName}-ext`;
|
|
||||||
const qextLegacyTargetDir = path.resolve(cwd, targetDir);
|
|
||||||
const qextFileName = path.resolve(qextLegacyTargetDir, `${extName}.qext`);
|
|
||||||
const qextFileNameJs = qextFileName.replace(/\.qext$/, '.js');
|
|
||||||
|
|
||||||
const extDefinition = argv.ext ? path.resolve(argv.ext) : '';
|
|
||||||
|
|
||||||
const relativeMainFile = `./${main.replace(/\.js$/, '')}`;
|
|
||||||
|
|
||||||
async function moveSnBundle() {
|
|
||||||
const code = await fs.readFile(path.resolve(cwd, main), { encoding: 'utf8' });
|
|
||||||
const replacedCode = code.replace(/@nebula.js\/stardust/g, '../nlib/@nebula.js/stardust/dist/stardust');
|
|
||||||
|
|
||||||
await fs.outputFile(path.resolve(qextLegacyTargetDir, main), replacedCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function moveResources() {
|
|
||||||
await fs.copy(
|
|
||||||
path.resolve(path.dirname(require.resolve('@nebula.js/stardust')), 'dist'),
|
|
||||||
path.resolve(qextLegacyTargetDir, 'nlib/@nebula.js/stardust/dist')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createQextFiles() {
|
|
||||||
const qext = supernovaPkg.qext || {};
|
|
||||||
if (argv.meta) {
|
|
||||||
const meta = require(path.resolve(cwd, argv.meta)); // eslint-disable-line
|
|
||||||
Object.assign(qext, meta);
|
|
||||||
}
|
|
||||||
const contents = {
|
|
||||||
name: qext.name || extName,
|
|
||||||
version: supernovaPkg.version,
|
|
||||||
description: supernovaPkg.description,
|
|
||||||
author: supernovaPkg.author,
|
|
||||||
icon: qext.icon || 'extension',
|
|
||||||
preview: qext.preview,
|
|
||||||
type: 'visualization',
|
|
||||||
};
|
|
||||||
|
|
||||||
await fs.writeFile(qextFileName, JSON.stringify(contents, null, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wrapIt() {
|
|
||||||
const bundle = await rollup.rollup({
|
|
||||||
input: path.resolve(__dirname, '../src/legacy/sn-ext.js'),
|
|
||||||
external: ['translator', 'qlik', './nlib/@nebula.js/stardust/dist/stardust', relativeMainFile],
|
|
||||||
plugins: [
|
|
||||||
replace({
|
|
||||||
__SN_DEF__: `${relativeMainFile}`,
|
|
||||||
__EXT_DEF__: `${extDefinition.replace(/\\/g, '/')}`,
|
|
||||||
preventAssignment: true,
|
|
||||||
}),
|
|
||||||
nodeResolve(),
|
|
||||||
common(),
|
|
||||||
babel({
|
|
||||||
babelHelpers: 'bundled',
|
|
||||||
babelrc: false,
|
|
||||||
exclude: [/node_modules/],
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@babel/preset-env',
|
|
||||||
{
|
|
||||||
modules: false,
|
|
||||||
targets: {
|
|
||||||
browsers: ['chrome 62'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
argv.minify &&
|
|
||||||
terser({
|
|
||||||
output: {
|
|
||||||
comments: /@license|@preserve|Copyright|license/,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
await bundle.write({
|
|
||||||
file: qextFileNameJs,
|
|
||||||
format: 'amd',
|
|
||||||
sourcemap: argv.sourcemap,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await moveSnBundle();
|
|
||||||
await moveResources();
|
|
||||||
await wrapIt();
|
|
||||||
await createQextFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = build;
|
|
||||||
@@ -27,12 +27,6 @@ const options = {
|
|||||||
default: false,
|
default: false,
|
||||||
desc: 'Generate sourcemaps',
|
desc: 'Generate sourcemaps',
|
||||||
},
|
},
|
||||||
legacy: {
|
|
||||||
type: 'boolean',
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
desc: 'Generate legacy extension',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = (yargs) => yargs.options(options);
|
module.exports = (yargs) => yargs.options(options);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
const buildLegacy = require('./build-legacy');
|
|
||||||
const build = require('./build');
|
const build = require('./build');
|
||||||
|
|
||||||
function sense(argv) {
|
function sense(argv) {
|
||||||
if (argv.legacy) {
|
if (argv.legacy) {
|
||||||
return buildLegacy(argv);
|
console.error('Legacy sense-build support removed in 4.0, it is not required for sense compatability.');
|
||||||
|
process.exit(1);
|
||||||
}
|
}
|
||||||
return build(argv);
|
return build(argv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
import createSelections from '../selections';
|
|
||||||
|
|
||||||
describe('supernova-wrapper', () => {
|
|
||||||
describe('selections', () => {
|
|
||||||
let selectionsApi;
|
|
||||||
let selectionsApiActivateMock;
|
|
||||||
let selectionsApiDeactivateMock;
|
|
||||||
|
|
||||||
let backendApi;
|
|
||||||
let backendApiBeganSelectionMock;
|
|
||||||
let backendApiEndSelectionMock;
|
|
||||||
let backendApiResetSelectionMock;
|
|
||||||
let backendApiSwitchModalSelectionMock;
|
|
||||||
|
|
||||||
let selections;
|
|
||||||
let selectionsEmitMock;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
selectionsApiActivateMock = jest.fn();
|
|
||||||
selectionsApiDeactivateMock = jest.fn();
|
|
||||||
|
|
||||||
backendApiBeganSelectionMock = jest.fn();
|
|
||||||
backendApiEndSelectionMock = jest.fn();
|
|
||||||
backendApiResetSelectionMock = jest.fn();
|
|
||||||
backendApiSwitchModalSelectionMock = jest.fn();
|
|
||||||
|
|
||||||
selectionsEmitMock = jest.fn();
|
|
||||||
|
|
||||||
selectionsApi = {
|
|
||||||
activated: selectionsApiActivateMock,
|
|
||||||
deactivated: selectionsApiDeactivateMock,
|
|
||||||
};
|
|
||||||
backendApi = {
|
|
||||||
beginSelections: backendApiBeganSelectionMock,
|
|
||||||
endSelections: backendApiEndSelectionMock,
|
|
||||||
model: {
|
|
||||||
resetMadeSelections: backendApiResetSelectionMock,
|
|
||||||
app: {
|
|
||||||
switchModalSelection: backendApiSwitchModalSelectionMock,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
selections = createSelections({ selectionsApi, backendApi });
|
|
||||||
selections.emit = selectionsEmitMock;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should `begin`', () => {
|
|
||||||
selections.begin();
|
|
||||||
expect(selectionsApi.activated).toHaveBeenCalledWith(true);
|
|
||||||
expect(backendApi.beginSelections).toHaveBeenCalledWith();
|
|
||||||
expect(selections.emit).toHaveBeenCalledWith('activated');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should `begin` with paths', () => {
|
|
||||||
const paths = ['hypercubePath', 'otherHypercubePath'];
|
|
||||||
selections.begin(paths);
|
|
||||||
expect(selectionsApi.activated).toHaveBeenCalledWith(true);
|
|
||||||
expect(backendApi.beginSelections).toHaveBeenCalledTimes(0);
|
|
||||||
expect(backendApi.model.app.switchModalSelection).toHaveBeenCalledWith(backendApi.model, paths);
|
|
||||||
expect(selections.emit).toHaveBeenCalledWith('activated');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
const x = {};
|
|
||||||
|
|
||||||
export default x;
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
const INTERACTION_STATES = {
|
|
||||||
STATIC: 0,
|
|
||||||
ANALYSIS: 1,
|
|
||||||
EDIT: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
function showTooltip(options) {
|
|
||||||
if (options.tooltips) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return options.interactionState === INTERACTION_STATES.ANALYSIS && options.tooltips !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function permissions(options, backendApi) {
|
|
||||||
const p = [];
|
|
||||||
if (showTooltip(options)) {
|
|
||||||
p.push('passive');
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
options.interactionState === INTERACTION_STATES.ANALYSIS &&
|
|
||||||
options.tooltips !== false &&
|
|
||||||
options.limitedInteraction !== true
|
|
||||||
) {
|
|
||||||
p.push('interact');
|
|
||||||
}
|
|
||||||
if (!backendApi.isSnapshot) {
|
|
||||||
if (options.selections !== false) {
|
|
||||||
p.push('select');
|
|
||||||
}
|
|
||||||
p.push('fetch');
|
|
||||||
}
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default permissions;
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/* eslint no-param-reassign: 0 */
|
|
||||||
import EventEmitter from 'node-event-emitter';
|
|
||||||
|
|
||||||
export default (scope) => {
|
|
||||||
const mixin = (obj) => {
|
|
||||||
Object.keys(EventEmitter.prototype).forEach((key) => {
|
|
||||||
obj[key] = EventEmitter.prototype[key];
|
|
||||||
});
|
|
||||||
EventEmitter.init(obj);
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO one and only one
|
|
||||||
|
|
||||||
const selectionAPI = {
|
|
||||||
begin(paths) {
|
|
||||||
const suppressBeginSelections = true;
|
|
||||||
scope.selectionsApi.activated(suppressBeginSelections);
|
|
||||||
if (paths) {
|
|
||||||
scope.backendApi.model.app.switchModalSelection(scope.backendApi.model, paths);
|
|
||||||
} else {
|
|
||||||
scope.backendApi.beginSelections();
|
|
||||||
}
|
|
||||||
selectionAPI.emit('activated');
|
|
||||||
},
|
|
||||||
clear() {
|
|
||||||
scope.backendApi.model.resetMadeSelections();
|
|
||||||
},
|
|
||||||
confirm() {
|
|
||||||
scope.selectionsApi.confirm();
|
|
||||||
},
|
|
||||||
cancel() {
|
|
||||||
scope.selectionsApi.cancel();
|
|
||||||
},
|
|
||||||
select(s) {
|
|
||||||
if (!scope.selectionsApi.active) {
|
|
||||||
scope.backendApi.beginSelections();
|
|
||||||
}
|
|
||||||
scope.backendApi.model[s.method](...s.params).then((qSuccess) => {
|
|
||||||
if (!qSuccess) {
|
|
||||||
scope.selectionsApi.selectionsMade = false;
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
scope.selectionsApi.selectionsMade = s.method !== 'resetMadeSelections';
|
|
||||||
},
|
|
||||||
isActive() {
|
|
||||||
return scope.selectionsApi.active;
|
|
||||||
},
|
|
||||||
isModal() {
|
|
||||||
return scope.backendApi.model === (scope.backendApi.model.app && scope.backendApi.model.app.modalSelectionObject);
|
|
||||||
},
|
|
||||||
refreshToolbar() {
|
|
||||||
scope.selectionsApi.refreshToolbar();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
mixin(selectionAPI);
|
|
||||||
|
|
||||||
scope.selectionsApi.confirm = () => {
|
|
||||||
scope.backendApi.endSelections(true).then(() => {
|
|
||||||
scope.selectionsApi.deactivated();
|
|
||||||
selectionAPI.emit('confirmed');
|
|
||||||
selectionAPI.emit('deactivated');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.selectionsApi.clear = () => {
|
|
||||||
scope.backendApi.clearSelections();
|
|
||||||
scope.selectionsApi.selectionsMade = false;
|
|
||||||
selectionAPI.emit('cleared');
|
|
||||||
};
|
|
||||||
|
|
||||||
scope.selectionsApi.cancel = () => {
|
|
||||||
scope.backendApi.endSelections(false);
|
|
||||||
scope.selectionsApi.deactivated();
|
|
||||||
selectionAPI.emit('canceled');
|
|
||||||
selectionAPI.emit('deactivated');
|
|
||||||
};
|
|
||||||
|
|
||||||
return selectionAPI;
|
|
||||||
};
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
/* eslint no-underscore-dangle: 0 */
|
|
||||||
/* eslint import/no-unresolved: 0 */
|
|
||||||
/* eslint import/extensions: 0 */
|
|
||||||
|
|
||||||
// Sense dependencies
|
|
||||||
import qlik from 'qlik';
|
|
||||||
import senseTranslator from 'translator';
|
|
||||||
|
|
||||||
// injected
|
|
||||||
import snDefinition from '__SN_DEF__';
|
|
||||||
import extDefinition from '__EXT_DEF__';
|
|
||||||
import emptyExtDefinition from './empty-ext';
|
|
||||||
|
|
||||||
// lib dependencies
|
|
||||||
import { __DO_NOT_USE__ } from './nlib/@nebula.js/stardust/dist/stardust';
|
|
||||||
|
|
||||||
// wrapper code
|
|
||||||
import permissions from './permissions';
|
|
||||||
import selectionsApi from './selections';
|
|
||||||
|
|
||||||
const { generator: supernova, theme: themeFn, locale: localeFn } = __DO_NOT_USE__;
|
|
||||||
|
|
||||||
// ------- locale ---------
|
|
||||||
// use nebula locale API to ensure all viz get the same API regardless
|
|
||||||
// if consumed in Sense or outside
|
|
||||||
const loc = localeFn({
|
|
||||||
initial: senseTranslator.language,
|
|
||||||
});
|
|
||||||
const translator = {
|
|
||||||
...loc.translator,
|
|
||||||
// wrap get() for this API in order to prefer strings provided by Sense
|
|
||||||
get(str, args) {
|
|
||||||
const s = senseTranslator.get(str, args);
|
|
||||||
if (s === str) {
|
|
||||||
return loc.translator.get(str, args);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// ------------------------
|
|
||||||
|
|
||||||
// Galaxy is usually provided by @nebula.js/nucleus when a viz is instantiated.
|
|
||||||
// Since nucleus is not being used in Sense yet, this interface MUST be provided explicitly here
|
|
||||||
// and it MUST have the same interface as the one provided by nucleus.
|
|
||||||
const galaxy = {
|
|
||||||
deviceType: 'auto',
|
|
||||||
translator,
|
|
||||||
flags: {
|
|
||||||
isEnabled: () => false,
|
|
||||||
},
|
|
||||||
anything: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const ALLOWED_OPTIONS = ['viewState', 'direction', 'renderer'];
|
|
||||||
function limitOptions(newOptions, oldOptions) {
|
|
||||||
const op = {};
|
|
||||||
let opChanged = false;
|
|
||||||
Object.keys(newOptions).forEach((key) => {
|
|
||||||
if (ALLOWED_OPTIONS.indexOf(key) === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
op[key] = newOptions[key];
|
|
||||||
if (oldOptions[key] !== newOptions[key]) {
|
|
||||||
opChanged = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (opChanged) {
|
|
||||||
return op;
|
|
||||||
}
|
|
||||||
return oldOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createActions(actions) {
|
|
||||||
return actions.map((a) => {
|
|
||||||
const senseItem = {
|
|
||||||
isIcon: true,
|
|
||||||
buttonClass: 'sel-toolbar-icon-toggle',
|
|
||||||
isActive() {
|
|
||||||
return a.active;
|
|
||||||
},
|
|
||||||
isDisabled() {
|
|
||||||
return a.disabled;
|
|
||||||
},
|
|
||||||
action() {
|
|
||||||
a.action();
|
|
||||||
},
|
|
||||||
getSvgIcon() {
|
|
||||||
const icon = a.getSvgIconShape();
|
|
||||||
const { viewBox = '0 0 16 16' } = icon;
|
|
||||||
const shapes = icon.shapes
|
|
||||||
.map(
|
|
||||||
({ type, attrs }) =>
|
|
||||||
`<${type} ${Object.keys(attrs)
|
|
||||||
.map((k) => `${k}="${attrs[k]}"`)
|
|
||||||
.join(' ')}/>`
|
|
||||||
)
|
|
||||||
.join('');
|
|
||||||
return `<i style="display:inline-block;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.2em;text-rendering:optimizeLegibility;web-kit-font-smoothing:antialiased;moz-osx-font-smoothing:grayscale"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="${viewBox}" fill="currentColor">${shapes}</svg></i>`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
Object.defineProperties(senseItem, {
|
|
||||||
name: {
|
|
||||||
get: () => a.label,
|
|
||||||
},
|
|
||||||
hidden: {
|
|
||||||
get: () => a.hidden,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return senseItem;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTheme(ref) {
|
|
||||||
return qlik
|
|
||||||
.currApp(ref)
|
|
||||||
.theme.getApplied()
|
|
||||||
.then((qTheme) => {
|
|
||||||
if (ref.nTheme.externalAPI.name() !== qTheme.id) {
|
|
||||||
ref.nTheme.internalAPI.setTheme(qTheme.properties, qTheme.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============= EXTENSON =====================================================
|
|
||||||
|
|
||||||
const snGenerator = supernova(snDefinition, galaxy);
|
|
||||||
const ext =
|
|
||||||
typeof extDefinition === 'function'
|
|
||||||
? extDefinition({ translator })
|
|
||||||
: extDefinition || snGenerator.definition.ext || emptyExtDefinition || {};
|
|
||||||
let data;
|
|
||||||
|
|
||||||
if (snGenerator.qae.data.targets[0]) {
|
|
||||||
const d = snGenerator.qae.data.targets[0];
|
|
||||||
// supernova uses the convention of 'added' instead of 'add' since the
|
|
||||||
// method is called after the dimension/measures has been added to the hypercube.
|
|
||||||
// we therefore need to map supernova callbacks to the ones supported in Sense
|
|
||||||
const map = (v) => ({
|
|
||||||
...v,
|
|
||||||
add: v.added,
|
|
||||||
remove: v.removed,
|
|
||||||
replace: v.replaced,
|
|
||||||
move: v.moved,
|
|
||||||
});
|
|
||||||
|
|
||||||
data = {};
|
|
||||||
if (d.dimensions) {
|
|
||||||
data.dimensions = map(d.dimensions);
|
|
||||||
}
|
|
||||||
if (d.measures) {
|
|
||||||
data.measures = map(d.measures);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const X = {
|
|
||||||
// overridable properties
|
|
||||||
definition: {
|
|
||||||
type: 'items',
|
|
||||||
component: 'accordion',
|
|
||||||
items: {
|
|
||||||
data: data
|
|
||||||
? {
|
|
||||||
uses: 'data',
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
sorting: data
|
|
||||||
? {
|
|
||||||
uses: 'sorting',
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
settings: {
|
|
||||||
uses: 'settings',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data,
|
|
||||||
// -- defaults for the following are injected in default-extension.js --
|
|
||||||
// support
|
|
||||||
// importProperties,
|
|
||||||
// exportProperties,
|
|
||||||
// ----
|
|
||||||
getSelectionToolbar() {
|
|
||||||
return [
|
|
||||||
...this.senseItems,
|
|
||||||
{
|
|
||||||
name: 'Tooltip.clearSelection',
|
|
||||||
tid: 'selection-toolbar.clear',
|
|
||||||
isIcon: true,
|
|
||||||
buttonClass: 'clear',
|
|
||||||
iconClass: 'lui-icon lui-icon--clear-selections',
|
|
||||||
action: function action() {
|
|
||||||
this.selectionsApi.clear();
|
|
||||||
},
|
|
||||||
isDisabled: function isDisabled() {
|
|
||||||
return !this.selectionsApi.selectionsMade;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
// override with user config
|
|
||||||
...ext,
|
|
||||||
|
|
||||||
// =============================================
|
|
||||||
// non-overridable properties
|
|
||||||
initialProperties: snGenerator.qae.properties.initial,
|
|
||||||
template: '<div style="height: 100%;position: relative"></div>',
|
|
||||||
mounted($element) {
|
|
||||||
const element = $element[0].children[0];
|
|
||||||
const selectionAPI = selectionsApi(this.$scope);
|
|
||||||
const sn = snGenerator.create({
|
|
||||||
model: this.backendApi.model,
|
|
||||||
app: this.backendApi.model.session.app,
|
|
||||||
selections: selectionAPI,
|
|
||||||
explicitResize: true,
|
|
||||||
});
|
|
||||||
this.sn = sn;
|
|
||||||
this.snComponent = sn.component;
|
|
||||||
this.snComponent.created();
|
|
||||||
this.snComponent.mounted(element);
|
|
||||||
this.senseItems = [];
|
|
||||||
const { senseItems } = this;
|
|
||||||
this.snComponent.observeActions((actions) => {
|
|
||||||
senseItems.length = 0;
|
|
||||||
senseItems.push(...createActions(actions));
|
|
||||||
this.$scope.selectionsApi.refreshToolbar();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.nTheme = themeFn();
|
|
||||||
|
|
||||||
this.initiatedTheme = updateTheme(this);
|
|
||||||
},
|
|
||||||
suppressOnPaint: () => false,
|
|
||||||
paint() {
|
|
||||||
const perms = permissions(this.options, this.backendApi);
|
|
||||||
const constraints = {
|
|
||||||
passive: perms.indexOf('passive') === -1 || undefined,
|
|
||||||
active: perms.indexOf('interact') === -1 || undefined,
|
|
||||||
select: perms.indexOf('select') === -1 || undefined,
|
|
||||||
edit: perms.indexOf('edit') === -1 || undefined,
|
|
||||||
};
|
|
||||||
const opts = limitOptions(this.options, this.snComponent.context.options);
|
|
||||||
this._pureLayout = this.backendApi.model.pureLayout || this.backendApi.model.layout;
|
|
||||||
return this.initiatedTheme.then(() => {
|
|
||||||
updateTheme(this);
|
|
||||||
return this.snComponent.render({
|
|
||||||
layout: this.backendApi.model.pureLayout || this.backendApi.model.layout,
|
|
||||||
context: {
|
|
||||||
appLayout: {
|
|
||||||
qLocaleInfo: this.backendApi.localeInfo,
|
|
||||||
},
|
|
||||||
constraints,
|
|
||||||
theme: this.nTheme.externalAPI,
|
|
||||||
},
|
|
||||||
options: opts,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
resize() {
|
|
||||||
if (this._pureLayout !== this.backendApi.model.pureLayout) {
|
|
||||||
return this.paint();
|
|
||||||
}
|
|
||||||
const opts = limitOptions(this.options, this.snComponent.context.options);
|
|
||||||
this.snComponent.context.options = opts;
|
|
||||||
return this.snComponent.resize();
|
|
||||||
},
|
|
||||||
setInteractionState() {
|
|
||||||
this.paint();
|
|
||||||
},
|
|
||||||
setSnapshotData(layout) {
|
|
||||||
return this.snComponent.setSnapshotData(layout);
|
|
||||||
},
|
|
||||||
onContextMenu(menu, event) {
|
|
||||||
return this.snComponent.onContextMenu(menu, event);
|
|
||||||
},
|
|
||||||
getViewState() {
|
|
||||||
const ref = this.snComponent.getImperativeHandle();
|
|
||||||
if (ref && typeof ref.getViewState === 'function') {
|
|
||||||
return ref.getViewState();
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
destroy() {
|
|
||||||
this.sn.destroy();
|
|
||||||
if (this.snComponent) {
|
|
||||||
this.snComponent.willUnmount();
|
|
||||||
this.snComponent.destroy();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default X;
|
|
||||||
Reference in New Issue
Block a user