Compare commits

...

24 Commits

Author SHA1 Message Date
Ahmed Bazzara
b335b4883e Merge pull request #9 from qlik-oss/feature/QPE-586-stylelint
[QPE 586] Added stricter stylelint
2019-02-22 13:51:53 +01:00
ahmed-Bazzara
221e2d365c merge conflicts solved 2019-02-22 13:45:19 +01:00
Christopher Lebond
6797f7d561 Merge pull request #13 from qlik-oss/feature/QPE-569-change-eslint-rules
[QPE-569] Fix most of the eslint warnings
2019-02-22 13:21:45 +01:00
Christopher Lebond
f843779b64 Merge pull request #21 from qlik-oss/feature/QPE-474
[QPE-474] replace jquery scroll linking
2019-02-22 13:13:57 +01:00
ahmed-Bazzara
9809587c68 merge conflicts solved 2019-02-22 12:12:00 +01:00
ahmed-Bazzara
808f4df3e3 merge conflicts solved 2019-02-22 12:01:41 +01:00
Christopher Lebond
47b4d1aa5b Merge pull request #15 from qlik-oss/feature/QPE-484
[QPE-484] Edit mode interactions
2019-02-22 11:28:35 +01:00
Christopher Lebond
614d768eea Merge pull request #10 from qlik-oss/QPE-477
[QPE-477] Definition object is Qlik standard
2019-02-22 10:41:36 +01:00
Kristoffer Lind
555000be54 fix rebase issues 2019-02-21 17:49:05 +01:00
Kristoffer Lind
c367f24dd9 replace jquery scroll linking with components (fixing some bugs and getting rid of jquery) 2019-02-21 17:38:51 +01:00
giovanni hanselius
0b3b7b3f57 Merge pull request #19 from qlik-oss/QPE-554
[QPE-554] text alignemt
2019-02-21 17:37:00 +01:00
giovanni hanselius
44b33b4c92 Merge pull request #16 from qlik-oss/feature/QPE-550
[QPE-550] fix excel export
2019-02-21 16:48:34 +01:00
ahmed-Bazzara
24edf1c6f4 values of text alignement property set to have lowercase 2019-02-21 12:02:42 +01:00
ahmed-Bazzara
bcb9d30237 sending the alignment value straight from props instead of numbers 2019-02-19 14:55:50 +01:00
Kristoffer Lind
fa60dd5248 remove unused component 2019-02-19 10:25:14 +01:00
Balazs Gobel
fd653de0e1 Fix most of the eslint warnings 2019-02-19 10:23:24 +01:00
ahmed-Bazzara
ec140efc56 Text alignment property added 2019-02-18 16:42:39 +01:00
Kristoffer Lind
b86806d4cd cleanup tooltips (resulted in whatever header was last hovered to be appended to each column header in xls) 2019-02-14 15:14:23 +01:00
ahmed-Bazzara
db67b864ee edit mode interaction prevented 2019-02-14 13:54:17 +01:00
Kristoffer Lind
c3651a37da Merge branch 'master' into feature/QPE-550 2019-02-14 12:36:55 +01:00
Kristoffer Lind
8b843e028a fix excel export 2019-02-14 11:08:34 +01:00
ahmed-Bazzara
c47b401a1d typo in definiton object 2019-02-12 12:05:01 +01:00
ahmed-Bazzara
3c330465dd Definition object is Qlik standard 2019-02-12 12:03:05 +01:00
Balazs Gobel
f7ceb5c2bf Added stricter stylint rules 2019-02-12 11:24:13 +01:00
24 changed files with 865 additions and 401 deletions

View File

@@ -41,12 +41,12 @@ module.exports = {
"no-cond-assign": ["warn"],
"no-fallthrough": ["warn"],
"no-undef": ["error"],
"no-unused-vars": ["warn"],
"no-use-before-define": ["warn", { "functions": false, "classes": false, "variables": false }],
"no-unused-vars": ["error"],
"no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
"no-useless-escape": ["warn"],
"no-useless-return": ["warn"],
"no-underscore-dangle": ["warn", { "allow": ["_id"] }],
"no-redeclare": ["warn"],
"no-redeclare": ["error"],
"no-restricted-syntax": ["warn"],
"operator-linebreak": ["warn", "before"],
"prefer-promise-reject-errors": ["warn"],
@@ -63,11 +63,11 @@ module.exports = {
"complexity": ["warn"],
"camelcase": ["warn"],
"max-statements": ["off"], // marks the entire functions, a bit too noisy
"sort-vars": ["warn"],
"sort-vars": ["off"], // not much value for the work
"init-declarations": ["off"],
"capitalized-comments": ["off"],
"one-var": ["off"],
"no-var": ["warn"],
"no-var": ["error"],
"no-plusplus": ["warn"],
"vars-on-top": ["off"],
"no-magic-numbers": ["off"], // useful, but also complains for reasonable checks with actual numbers
@@ -80,7 +80,7 @@ module.exports = {
"quote-props": ["off"],
"prefer-template": ["warn"],
"no-lonely-if": ["warn"],
"sort-keys": ["warn"],
"sort-keys": ["off"], // not much value for the work
"no-implicit-coercion": ["warn"],
"no-inline-comments": ["off"],
"spaced-comment": ["warn"],
@@ -107,7 +107,7 @@ module.exports = {
"strict": ["warn"],
"no-ternary": ["off"],
"multiline-ternary": ["off"],
"no-param-reassign": ["warn"],
"no-param-reassign": ["error"],
"prefer-destructuring": ["warn"],
"arrow-parens": ["off"],
"no-array-constructor": ["warn"],

108
package-lock.json generated
View File

@@ -101,6 +101,104 @@
"@babel/types": "^7.0.0"
}
},
"@babel/helper-create-class-features-plugin": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.3.2.tgz",
"integrity": "sha512-tdW8+V8ceh2US4GsYdNVNoohq5uVwOf9k6krjwW4E1lINcHgttnWcNqgdoessn12dAy8QkbezlbQh2nXISNY+A==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-member-expression-to-functions": "^7.0.0",
"@babel/helper-optimise-call-expression": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.2.3"
},
"dependencies": {
"@babel/generator": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.3.tgz",
"integrity": "sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A==",
"dev": true,
"requires": {
"@babel/types": "^7.3.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.11",
"source-map": "^0.5.0",
"trim-right": "^1.0.1"
},
"dependencies": {
"@babel/types": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz",
"integrity": "sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.11",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-replace-supers": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.2.3.tgz",
"integrity": "sha512-GyieIznGUfPXPWu0yLS6U55Mz67AZD9cUk0BfirOWlPrXlBcan9Gz+vHGz+cPfuoweZSnPzPIm67VtQM0OWZbA==",
"dev": true,
"requires": {
"@babel/helper-member-expression-to-functions": "^7.0.0",
"@babel/helper-optimise-call-expression": "^7.0.0",
"@babel/traverse": "^7.2.3",
"@babel/types": "^7.0.0"
}
},
"@babel/parser": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.3.tgz",
"integrity": "sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg==",
"dev": true
},
"@babel/traverse": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz",
"integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/generator": "^7.2.2",
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-split-export-declaration": "^7.0.0",
"@babel/parser": "^7.2.3",
"@babel/types": "^7.2.2",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.10"
},
"dependencies": {
"@babel/types": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.3.tgz",
"integrity": "sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.11",
"to-fast-properties": "^2.0.0"
}
}
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
}
}
},
"@babel/helper-define-map": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz",
@@ -302,6 +400,16 @@
"@babel/plugin-syntax-async-generators": "^7.2.0"
}
},
"@babel/plugin-proposal-class-properties": {
"version": "7.3.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.3.tgz",
"integrity": "sha512-XO9eeU1/UwGPM8L+TjnQCykuVcXqaO5J1bkRPIygqZ/A2L1xVMJ9aZXrY31c0U4H2/LHKL4lbFQLsxktSrc/Ng==",
"dev": true,
"requires": {
"@babel/helper-create-class-features-plugin": "^7.3.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-proposal-json-strings": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz",

View File

@@ -12,10 +12,12 @@
"eslint:fix": "eslint --fix src",
"test": "karma start karma.conf.js",
"test-once": "karma start karma.conf.js --single-run",
"watch": "gulp watch"
"watch": "gulp watch",
"stylelint": "stylelint src/main.less"
},
"devDependencies": {
"@babel/core": "7.1.2",
"@babel/plugin-proposal-class-properties": "7.3.3",
"@babel/plugin-transform-async-to-generator": "7.1.0",
"@babel/polyfill": "7.0.0",
"@babel/preset-env": "7.1.0",

View File

@@ -90,12 +90,17 @@ class DataCell extends React.PureComponent {
if (styleBuilder.hasComments()) {
formattedMeasurementValue = '.';
}
let textAlignment = 'Right';
const textAlignmentProp = styling.options.textAlignment;
if (textAlignmentProp) {
textAlignment = textAlignmentProp;
}
let cellStyle = {
fontFamily: styling.options.fontFamily,
...styleBuilder.getStyle(),
paddingLeft: '4px',
textAlign: 'right'
textAlign: textAlignment
};
const { semaphoreColors } = styling;
@@ -109,7 +114,7 @@ class DataCell extends React.PureComponent {
fontFamily: styling.options.fontFamily,
fontSize: styleBuilder.getStyle().fontSize,
paddingLeft: '4px',
textAlign: 'right'
textAlign: textAlignment
};
}

View File

@@ -2,7 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import StyleBuilder from '../style-builder';
import DataCell from './data-cell.jsx';
import HeaderPadding from './header-padding.jsx';
import RowHeader from './row-header.jsx';
import { injectSeparators } from '../utilities';

View File

@@ -78,7 +78,7 @@ const formatted = {
],
defaultValue: 'Clean',
show (data) {
return data.customfilebool == false;
return !data.customfilebool;
}
},
BodyTextColor: {
@@ -130,7 +130,7 @@ const formatted = {
],
defaultValue: 'Black',
show (data) {
return data.customfilebool == false;
return !data.customfilebool;
}
},
FontFamily: {
@@ -187,6 +187,26 @@ const formatted = {
],
defaultValue: 1
},
textAlignment: {
ref: 'cellTextAlignment',
label: 'Cell Text alignment',
component: 'buttongroup',
options: [
{
value: 'left',
label: 'Left'
},
{
value: 'center',
label: 'Center'
},
{
value: 'right',
label: 'Right'
}
],
defaultValue: 'right'
},
ColumnWidthSlider: {
type: 'number',
component: 'slider',

View File

@@ -27,7 +27,7 @@ const header = {
ref: 'HeaderColorSchema',
type: 'string',
component: 'dropdown',
label: 'BackGround Header Color',
label: 'Background Header Color',
options: [
{
value: 'Clean',

View File

@@ -9,15 +9,16 @@ import pijamaColorLibrary from './pijama-color-library';
const definition = {
component: 'accordion',
items: {
dimensions: {
max: 2,
min: 1,
uses: 'dimensions'
},
measures: {
max: 9,
min: 1,
uses: 'measures'
data: {
items: {
dimensions: {
disabledRef: ''
},
measures: {
disabledRef: ''
}
},
uses: 'data'
},
settings: {
items: {

View File

@@ -25,7 +25,7 @@ const metricSemaphores = {
type: 'string',
defaultValue: '0',
show (data) {
return data.allmetrics == false;
return !data.allmetrics;
}
},
MetricStatus1: {

View File

@@ -1,73 +1,86 @@
import $ from 'jquery';
const isIE = /* @cc_on!@*/false || Boolean(document.documentMode);
const isChrome = Boolean(window.chrome) && Boolean(window.chrome.webstore);
const isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
const isFirefox = typeof InstallTrigger !== 'undefined';
export function enableExcelExport (layout, f) {
let myTitle = '';
let mySubTitle = '';
let myFootNote = '';
if (layout.title.length > 0) {
myTitle += '<p style="font-size:15pt"><b>';
myTitle += layout.title;
myTitle += '</b></p>';
}
if (layout.subtitle.length > 0) {
mySubTitle += '<p style="font-size:11pt">';
mySubTitle += layout.subtitle;
mySubTitle += '</p>';
}
if (layout.footnote.length > 0) {
myFootNote += '<p style="font-size:11pt"><i>Note:</i>';
myFootNote += layout.footnote;
myFootNote += '</p>';
}
$('.icon-xls').on('click', () => {
$('.header-wrapper th').children('.tooltip')
.remove(); // remove some popup effects when exporting
$('.header-wrapper th').children('.icon-xls')
.remove(); // remove the xls icon when exporting
if (isChrome || isSafari) {
const $clonedDiv = $('.data-table').clone(true); // .kpi-table a secas exporta la 1ªcol
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
vEncodeHead += myTitle + mySubTitle + myFootNote;
const vEncode = encodeURIComponent($clonedDiv.html());
let vDecode = `${vEncodeHead + vEncode}</html>`;
$clonedDiv.find('tr.header');
vDecode = vDecode.split('%3E.%3C').join('%3E%3C');
window.open(`data:application/vnd.ms-excel,${vDecode}`);
$.preventDefault();
}
if (isIE) {
let a = '<html><head><meta charset="UTF-8"></head>';
a += myTitle + mySubTitle + myFootNote;
a += f;
a = a.split('>.<').join('><');
a += '</html>';
const w = window.open();
w.document.open();
w.document.write(a);
w.document.close();
w.document.execCommand('SaveAs', true, 'Analysis.xls' || 'c:\TMP');
w.close();
}
if (isFirefox) {
const $clonedDiv = $('.data-table').clone(true);// .kpi-table a secas exporta la 1ªcol
let vEncodeHead = '<html><head><meta charset="UTF-8"></head>';
vEncodeHead += myTitle + mySubTitle + myFootNote;
const vEncode = encodeURIComponent($clonedDiv.html());
let vDecode = `${vEncodeHead + vEncode}</html>`;
$clonedDiv.find('tr.header');
vDecode = vDecode.split('>.<').join('><');
window.open(`data:application/vnd.ms-excel,${vDecode}`);
$.preventDefault();
function removeAllTooltips (node) {
const tooltips = node.querySelectorAll('.tooltip');
[].forEach.call(tooltips, tooltip => {
if (tooltip.parentNode) {
tooltip.parentNode.removeChild(tooltip);
}
});
}
function buildTableHTML (title, subtitle, footnote) {
const titleHTML = `<p style="font-size:15pt"><b>${title}</b></p>`;
const subtitleHTML = `<p style="font-size:11pt">${subtitle}</p>`;
const footnoteHTML = `<p style="font-size:11pt"><i>Note:</i>${footnote}</p>`;
const dataTableClone = document.querySelector('.data-table').cloneNode(true);
removeAllTooltips(dataTableClone);
const tableHTML = `
<html
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40"
>
<head>
<meta charset="UTF-8">
<!--[if gte mso 9]>
<xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>${title || 'Analyze'}</x:Name>
<x:WorksheetOptions>
<x:DisplayGridlines/>
</x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml>
<![endif]-->
</head>
<body>
${titleHTML.length > 0 ? titleHTML : ''}
${subtitleHTML.length > 0 ? subtitleHTML : ''}
${footnoteHTML.length > 0 ? footnoteHTML : ''}
${dataTableClone.outerHTML}
</body>
</html>
`.split('>.<')
.join('><')
.split('>*<')
.join('><');
return tableHTML;
}
function downloadXLS (html) {
const filename = 'analysis.xls';
// IE/Edge
if (window.navigator.msSaveOrOpenBlob) {
const blobObject = new Blob([html]);
return window.navigator.msSaveOrOpenBlob(blobObject, filename);
}
const dataURI = generateDataURI(html);
const link = window.document.createElement('a');
link.href = dataURI;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
return true;
}
function generateDataURI (html) {
const dataType = 'data:application/vnd.ms-excel;base64,';
const data = window.btoa(unescape(encodeURIComponent(html)));
return `${dataType}${data}`;
}
export function exportXLS (title, subtitle, footnote) {
// original was removing icon when starting export, disable and some spinner instead, shouldn't take enough time to warrant either..?
const table = buildTableHTML(title, subtitle, footnote);
downloadXLS(table);
}

View File

@@ -1,13 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';
import { exportXLS } from './excel-export';
// TODO: move interaction logic in here from excel-export.js
class ExportButton extends React.PureComponent {
constructor (props) {
super(props);
this.handleExport = this.handleExport.bind(this);
}
handleExport () {
const { excelExport, general } = this.props;
const { title, subtitle, footnote } = general;
if (excelExport) {
exportXLS(title, subtitle, footnote);
}
}
render () {
const { excelExport } = this.props;
return excelExport === true && (
<input
className="icon-xls"
onClick={this.handleExport}
src="/Extensions/qlik-smart-pivot/Excel.png"
type="image"
/>
@@ -20,7 +34,8 @@ ExportButton.defaultProps = {
};
ExportButton.propTypes = {
excelExport: PropTypes.bool
excelExport: PropTypes.bool,
general: PropTypes.shape({}).isRequired
};
export default ExportButton;

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ExportButton from '../export-button.jsx';
const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimension, styling }) => {
const ExportColumnHeader = ({ baseCSS, general, title, allowExcelExport, hasSecondDimension, styling }) => {
const rowSpan = hasSecondDimension ? 2 : 1;
const style = {
...baseCSS,
@@ -19,7 +19,10 @@ const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimensi
rowSpan={rowSpan}
style={style}
>
<ExportButton excelExport={allowExcelExport} />
<ExportButton
excelExport={allowExcelExport}
general={general}
/>
{title}
</th>
);
@@ -28,6 +31,7 @@ const ExportColumnHeader = ({ baseCSS, title, allowExcelExport, hasSecondDimensi
ExportColumnHeader.propTypes = {
allowExcelExport: PropTypes.bool.isRequired,
baseCSS: PropTypes.shape({}).isRequired,
general: PropTypes.shape({}).isRequired,
hasSecondDimension: PropTypes.bool.isRequired,
styling: PropTypes.shape({
headerOptions: PropTypes.shape({

View File

@@ -29,6 +29,7 @@ const HeadersTable = ({ data, general, qlik, styling }) => {
<ExportColumnHeader
allowExcelExport={general.allowExcelExport}
baseCSS={baseCSS}
general={general}
hasSecondDimension={hasSecondDimension}
styling={styling}
title={dimension1[0].name}

View File

@@ -12,6 +12,18 @@ export default {
'$timeout',
function () { }
],
data: {
dimensions: {
max: 2,
min: 1,
uses: 'dimensions'
},
measures: {
max: 9,
min: 1,
uses: 'measures'
}
},
definition,
initialProperties: {
qHyperCubeDef: {

View File

@@ -255,7 +255,10 @@ async function initializeTransformed ({ $element, layout, component }) {
allowFilteringByClick: layout.filteroncellclick,
cellSuffix: getCellSuffix(layout.columnwidthslider), // TOOD: move to matrix cells or is it headers.measurements?
errorMessage: layout.errormessage,
maxLoops
footnote: layout.footnote,
maxLoops,
subtitle: layout.subtitle,
title: layout.title
},
selection: {
dimensionSelectionCounts: dimensionsInformation.map(dimensionInfo => dimensionInfo.qStateCounts.qSelected)
@@ -279,7 +282,8 @@ async function initializeTransformed ({ $element, layout, component }) {
backgroundColorOdd: colors[`vColLib${layout.ColorSchemaP}`],
color: layout.BodyTextColorSchema,
fontFamily: layout.FontFamily,
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersize)
fontSizeAdjustment: getFontSizeAdjustment(layout.lettersize),
textAlignment: layout.cellTextAlignment
},
semaphoreColors: {
fieldsToApplyTo: {

View File

@@ -0,0 +1,2 @@
export { default as LinkedScrollWrapper } from './linked-scroll-wrapper.jsx';
export { default as LinkedScrollSection } from './linked-scroll-section.jsx';

View File

@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import { LinkedScrollContext } from './linked-scroll-wrapper.jsx';
class LinkedScrollSection extends React.PureComponent {
static contextType = LinkedScrollContext;
componentDidMount () {
const { link } = this.context;
link(this);
}
componentWillUnmount () {
const { unlink } = this.context;
unlink(this);
}
render () {
const { children } = this.props;
return children;
}
}
LinkedScrollSection.propTypes = {
children: PropTypes.any
};
export default LinkedScrollSection;

View File

@@ -0,0 +1,82 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
export const LinkedScrollContext = React.createContext();
class LinkedScrollWrapper extends React.PureComponent {
constructor (props) {
super(props);
this.linkComponent = this.linkComponent.bind(this);
this.unlinkComponent = this.unlinkComponent.bind(this);
this.handleScroll = this.handleScroll.bind(this);
this.scrollElements = [];
this.linkActions = {
link: this.linkComponent,
unlink: this.unlinkComponent
};
}
linkComponent (component) {
// eslint-disable-next-line react/no-find-dom-node
const node = ReactDOM.findDOMNode(component);
const element = {
component,
node
};
this.scrollElements.push(element);
node.onscroll = this.handleScroll.bind(this, element);
}
unlinkComponent (component) {
const componentIndex = this.scrollElements.map(element => element.component).indexOf(component);
if (componentIndex !== -1) {
this.scrollElements.removeAt(componentIndex);
// eslint-disable-next-line react/no-find-dom-node
const node = ReactDOM.findDOMNode(component);
node.onscroll = null;
}
}
handleScroll (element) {
window.requestAnimationFrame(() => {
this.sync(element);
});
}
sync (scrollElement) {
this.scrollElements.forEach(element => {
if (scrollElement === element) {
return;
}
element.node.onscroll = null;
if (element.component.props.linkHorizontal) {
element.node.scrollLeft = scrollElement.node.scrollLeft;
}
if (element.component.props.linkVertical) {
element.node.scrollTop = scrollElement.node.scrollTop;
}
window.requestAnimationFrame(() => {
element.node.onscroll = this.handleScroll.bind(this, element);
});
});
}
render () {
const { children } = this.props;
return (
<LinkedScrollContext.Provider value={this.linkActions}>
{children}
</LinkedScrollContext.Provider>
);
}
}
LinkedScrollWrapper.propTypes = {
children: PropTypes.any
};
export default LinkedScrollWrapper;

View File

@@ -1,215 +1,284 @@
/* eslint-disable */
.qv-object-qlik-smart-pivot {
@TableBorder: 1px solid #d3d3d3;
@KpiTableWidth: 230px;
._cell(@Width: 50px) {
min-width: @Width!important;
max-width: @Width!important;
cursor: pointer;
line-height: 1em!important;
.edit-mode {
pointer-events: none;
}
div.qv-object-content-container {
overflow-x: scroll;
overflow-y: hidden;
z-index: 110;
}
._cell(@Width: 50px) {
min-width: @Width !important;
max-width: @Width !important;
cursor: pointer;
line-height: 1em !important;
}
.icon-xls {
text-align: left;
}
div.qv-object-content-container {
z-index: 110;
}
button {
width: 100%;
}
.icon-xls {
text-align: left;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: auto;
border-left: @TableBorder;
border-right: @TableBorder;
border-top: @TableBorder;
}
button {
width: 100%;
}
td, th {
border: 1px solid #ffffff;
padding: 5px;
border-collapse: collapse;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
cursor: default;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: auto;
border-left: @TableBorder;
border-right: @TableBorder;
border-top: @TableBorder;
}
.empty {
width: 3%;
background: #ffffff;
min-width: 4px !important;
max-width: 4px !important;
}
td,
th {
border: 1px solid #fff;
padding: 5px;
border-collapse: collapse;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
cursor: default;
}
th.main-kpi {
text-align: center;
vertical-align: middle;
border-bottom: @TableBorder;
}
.empty {
width: 3%;
background: #fff;
min-width: 4px !important;
max-width: 4px !important;
}
.numeric {
text-align: right;
}
/*This is for wrap text in headers*/
.wrapclass25 {
width: 100%;
height: 25px;
white-space: pre-line;
overflow: hidden;
display: block;
}
th.main-kpi {
text-align: center;
vertical-align: middle;
border-bottom: @TableBorder;
}
.wrapclass45 {
width: 100%;
height: 45px;
white-space: pre-line;
overflow: hidden;
display: block;
}
.numeric {
text-align: right;
}
.wrapclass70 {
width: 100%;
height: 70px;
white-space: pre-line;
overflow: hidden;
display: inline-block;
vertical-align: middle;
line-height: 20px;
}
/* This is for wrap text in headers */
.wrapclass25 {
width: 100%;
height: 25px;
white-space: pre-line;
overflow: hidden;
display: block;
}
.wrapclassEmpty {
width: 100%;
}
/*******************/
/* Medium column size*/
/*******************/
.grid-cells { ._cell(70px); }
.grid-cells2 { ._cell(70px); }
.grid-cells-small { ._cell(52px); }
.grid-cells2-small { ._cell(52px); }
/*******************/
/* Small column size*/
/*******************/
.grid-cells-s { ._cell(67px); }
.grid-cells2-s { ._cell(67px); }
.grid-cells-small-s { ._cell(52px); }
.grid-cells2-small-s { ._cell(52px); }
/*******************/
/* large column size*/
/*******************/
.grid-cells-l { ._cell(82px); }
.grid-cells2-l { ._cell(82px); }
.grid-cells-small-l { ._cell(66px); }
.grid-cells2-small-l { ._cell(66px); }
.wrapclass45 {
width: 100%;
height: 45px;
white-space: pre-line;
overflow: hidden;
display: block;
}
/*END OF GRID CELLS*/
/*First Column*/
.fdim-cells {
min-width: 230px !Important;
max-width: 230px !Important;
cursor: pointer;
background-color: white;
}
.wrapclass70 {
width: 100%;
height: 70px;
white-space: pre-line;
overflow: hidden;
display: inline-block;
vertical-align: middle;
line-height: 20px;
}
.fdim-cells:hover {
/*cursor: default;*/
background-color: #808080 !important;
color: #ffffff;
}
.wrapclassEmpty {
width: 100%;
}
tbody tr:hover {
cursor: default;
background-color: #808080 !important;
color: #ffffff;
}
/* ***************** */
.grid-cells-header {
padding: 0px;
}
/* Medium column size */
.grid-cells-title {
min-width: 522px;
}
/* ***************** */
.grid-cells:before {
content: "\00a0";
}
.grid-cells {
._cell(70px);
}
.grid-cells2 {
._cell(70px);
}
.grid-cells-small {
._cell(52px);
}
.grid-cells2-small {
._cell(52px);
}
/* ***************** */
/* Small column size */
/* ***************** */
.grid-cells-s {
._cell(67px);
}
.grid-cells2-s {
._cell(67px);
}
.grid-cells-small-s {
._cell(52px);
}
.grid-cells2-small-s {
._cell(52px);
}
/* ***************** */
/* large column size */
/* ***************** */
.grid-cells-l {
._cell(82px);
}
.grid-cells2-l {
._cell(82px);
}
.grid-cells-small-l {
._cell(66px);
}
.grid-cells2-small-l {
._cell(66px);
}
/* END OF GRID CELLS */
/* First Column */
.fdim-cells {
min-width: 230px !Important;
max-width: 230px !Important;
cursor: pointer;
background-color: #fff;
}
.fdim-cells:hover {
background-color: #808080 !important;
color: #fff;
}
tbody tr:hover {
cursor: default;
background-color: #808080 !important;
color: #fff;
}
.grid-cells-header {
padding: 0;
}
.grid-cells-title {
min-width: 522px;
}
.grid-cells::before {
content: "\00a0";
}
.grid {
height: 50px;
width: 350px;
height: 50px;
width: 350px;
}
/* popups for headers */
.header-wrapper {
position: absolute;
top: 0;
z-index: 1;
position: absolute;
top: 0;
z-index: 1;
}
/*popups for headers*/
.tooltip {
position: fixed !important;
color: RGB(70,70,70);
background-color: RGB(245,239,207);
text-align: center;
border: groove;
position: fixed !important;
color: rgb(70, 70, 70);
background-color: rgb(245, 239, 207);
text-align: center;
border: groove;
}
/*end popups*/
.row-wrapper {
position: absolute;
top: 97px;
height: calc(~"100% - 97px");
overflow-x: hidden;
overflow-y: scroll;
padding: 0;
margin-top: 0;
height: calc(~"100% - 97px");
padding: 0;
margin-top: 0;
}
.kpi-table .fdim-cells, .data-table td {
line-height: 1em!important;
.kpi-table .fdim-cells,
.data-table td {
line-height: 1em !important;
}
.data-table .fdim-cells {
display: none;
display: none;
}
.kpi-table {
width: @KpiTableWidth !important;
overflow: hidden !important;
display: table;
height: 100%;
margin: 0;
padding: 0;
z-index: 100;
position: absolute;
top: 0;
left: 0;
border-right: 1px solid white;
box-shadow: 4px 2px 8px #e1e1e1;
}
width: @KpiTableWidth !important;
overflow: hidden !important;
height: 100%;
margin: 0;
padding: 0;
position: absolute;
top: 0;
left: 0;
border-right: 1px solid #fff;
box-shadow: 4px 2px 8px #e1e1e1;
.kpi-table .row-wrapper {
overflow: hidden;
.row-wrapper {
height: calc(~"100% - 97px");
overflow: scroll;
position: absolute;
padding: 0;
margin-top: 0;
}
}
.data-table {
width: 272px !important;
float: left;
display: table;
height: 100%;
z-index: 90;
position: absolute;
margin-left: @KpiTableWidth + 13px;
-ms-overflow-style: none;
height: 100%;
width: calc(100% - 243px);
position: absolute;
margin-left: @KpiTableWidth + 13px;
.header-wrapper {
overflow: scroll;
width: 100%;
}
.row-wrapper {
height: calc(~"100% - 97px");
width: 100%;
overflow: scroll;
padding: 0;
margin-top: 0;
}
}
// hide scrollbars
.kpi-table .header-wrapper,
.kpi-table .row-wrapper,
.data-table .header-wrapper,
.data-table .row-wrapper {
-ms-overflow-style: none; // IE 10+
-moz-overflow: -moz-scrollbars-none; // Firefox
&::-webkit-scrollbar {
display: none; // Safari and Chrome
}
}
}

View File

@@ -13,7 +13,7 @@ export function ApplyPreMask (mask, value) { // aqui
case '+#,##0':
return (addSeparators(value, ',', '.', 0));
default:
return (ApplyMask(mask.substring(0, mask.indexOf(';')), value));
return (applyMask(mask.substring(0, mask.indexOf(';')), value));
}
} else {
const vMyValue = value * -1;
@@ -30,46 +30,47 @@ export function ApplyPreMask (mask, value) { // aqui
case '-#,##0':
return (`(${addSeparators(vMyValue, ',', '.', 0)})`);
default:
return (`(${ApplyMask(vMyMask, vMyValue)})`);
return (`(${applyMask(vMyMask, vMyValue)})`);
}
}
} else {
return (ApplyMask(mask, value));
return (applyMask(mask, value));
}
}
function ApplyMask (mask, value) {
if (!mask || isNaN(Number(value))) {
return value; // return as it is.
function applyMask (originalMask, originalValue) {
if (!originalMask || isNaN(Number(originalValue))) {
return originalValue;
}
let isNegative, result, decimal, group, posLeadZero, posTrailZero, posSeparator,
part, szSep, integer,
// find prefix/suffix
len = mask.length,
start = mask.search(/[0-9\-\+#]/),
prefix = start > 0 ? mask.substring(0, start) : '',
// reverse string: not an ideal method if there are surrogate pairs
str = mask.split('').reverse()
.join(''),
end = str.search(/[0-9\-\+#]/),
offset = len - end,
substr = mask.substring(offset, offset + 1),
indx = offset + ((substr === '.' || (substr === ',')) ? 1 : 0),
suffix = end > 0 ? mask.substring(indx, len) : '';
let isNegative;
let result;
let integer;
// find prefix/suffix
let len = originalMask.length;
const start = originalMask.search(/[0-9\-\+#]/);
const prefix = start > 0 ? originalMask.substring(0, start) : '';
// reverse string: not an ideal method if there are surrogate pairs
let str = originalMask.split('')
.reverse()
.join('');
const end = str.search(/[0-9\-\+#]/);
let offset = len - end;
const substr = originalMask.substring(offset, offset + 1);
let index = offset + ((substr === '.' || (substr === ',')) ? 1 : 0);
const suffix = end > 0 ? originalMask.substring(index, len) : '';
// mask with prefix & suffix removed
mask = mask.substring(start, indx);
let mask = originalMask.substring(start, index);
// convert any string to number according to formation sign.
value = mask.charAt(0) === '-' ? -value : Number(value);
let value = mask.charAt(0) === '-' ? -originalValue : Number(originalValue);
isNegative = value < 0 ? value = -value : 0; // process only abs(), and turn on flag.
// search for separator for grp & decimal, anything not digit, not +/- sign, not #.
result = mask.match(/[^\d\-\+#]/g);
decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
const decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
const group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
// split the decimal for the format string if any.
mask = mask.split(decimal);
@@ -78,16 +79,16 @@ function ApplyMask (mask, value) {
value = String(Number(value)); // convert number to string to trim off *all* trailing decimal zero(es)
// fill back any trailing zero according to format
posTrailZero = mask[1] && mask[1].lastIndexOf('0'); // look for last zero in format
part = value.split('.');
const posTrailZero = mask[1] && mask[1].lastIndexOf('0'); // look for last zero in format
const part = value.split('.');
// integer will get !part[1]
if (!part[1] || (part[1] && part[1].length <= posTrailZero)) {
value = (Number(value)).toFixed(posTrailZero + 1);
}
szSep = mask[0].split(group); // look for separator
const szSep = mask[0].split(group); // look for separator
mask[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
posLeadZero = mask[0] && mask[0].indexOf('0');
const posLeadZero = mask[0] && mask[0].indexOf('0');
if (posLeadZero > -1) {
while (part[0].length < (mask[0].length - posLeadZero)) {
part[0] = `0${part[0]}`;
@@ -101,17 +102,17 @@ function ApplyMask (mask, value) {
// process the first group separator from decimal (.) only, the rest ignore.
// get the length of the last slice of split result.
posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
const posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
if (posSeparator) {
integer = value[0];
str = '';
offset = integer.length % posSeparator;
len = integer.length;
for (indx = 0; indx < len; indx++) {
str += integer.charAt(indx); // ie6 only support charAt for sz.
for (index = 0; index < len; index++) {
str += integer.charAt(index); // ie6 only support charAt for sz.
// -posSeparator so that won't trail separator on full length
// jshint -W018
if (!((indx - offset + 1) % posSeparator) && indx < len - posSeparator) {
if (!((index - offset + 1) % posSeparator) && index < len - posSeparator) {
str += group;
}
}

View File

@@ -1,9 +1,10 @@
import $ from 'jquery';
import $ from 'jquery'; // eslint-disable-line id-length
import initializeStore from './store';
import React from 'react';
import ReactDOM from 'react-dom';
import HeadersTable from './headers-table/index.jsx';
import DataTable from './data-table/index.jsx';
import { LinkedScrollWrapper, LinkedScrollSection } from './linked-scroll';
export default async function paint ($element, layout, component) {
const state = await initializeStore({
@@ -11,55 +12,52 @@ export default async function paint ($element, layout, component) {
component,
layout
});
const editmodeClass = component.inAnalysisState() ? '' : 'edit-mode';
const jsx = (
<React.Fragment>
<div className="kpi-table">
<LinkedScrollWrapper>
<div className={`kpi-table ${editmodeClass}`}>
<HeadersTable
data={state.data}
general={state.general}
qlik={component}
styling={state.styling}
/>
<DataTable
data={state.data}
general={state.general}
qlik={component}
renderData={false}
styling={state.styling}
/>
<LinkedScrollSection linkVertical>
<DataTable
data={state.data}
general={state.general}
qlik={component}
renderData={false}
styling={state.styling}
/>
</LinkedScrollSection>
</div>
<div className="data-table">
<HeadersTable
data={state.data}
general={state.general}
qlik={component}
styling={state.styling}
/>
<DataTable
data={state.data}
general={state.general}
qlik={component}
styling={state.styling}
/>
<div className={`data-table ${editmodeClass}`}>
<LinkedScrollSection linkHorizontal>
<HeadersTable
data={state.data}
general={state.general}
qlik={component}
styling={state.styling}
/>
</LinkedScrollSection>
<LinkedScrollSection
linkHorizontal
linkVertical
>
<DataTable
data={state.data}
general={state.general}
qlik={component}
styling={state.styling}
/>
</LinkedScrollSection>
</div>
</React.Fragment>
</LinkedScrollWrapper>
);
ReactDOM.render(jsx, $element[0]);
// TODO: skipped the following as they weren't blockers for letting react handle rendering,
// they are however the only reason we still depend on jQuery and should be removed as part of unnecessary dependencies issue
$(`[tid="${layout.qInfo.qId}"] .data-table .row-wrapper`).on('scroll', function () {
$(`[tid="${layout.qInfo.qId}"] .kpi-table .row-wrapper`).scrollTop($(this).scrollTop());
});
// freeze first column
$(`[tid="${layout.qInfo.qId}"] .qv-object-content-container`).on('scroll', (t) => {
$(`[tid="${layout.qInfo.qId}"] .kpi-table`).css('left', `${Math.round(t.target.scrollLeft)}px`);
});
// TODO: fixing tooltips has a seperate issue, make sure to remove this as part of that issue
$(`[tid="${layout.qInfo.qId}"] .header-wrapper th`).hover(function () {
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(500)
@@ -82,8 +80,4 @@ export default async function paint ($element, layout, component) {
$(`[tid="${layout.qInfo.qId}"] .tooltip`).delay(0)
.hide(0);
});
// TODO: excel export is broken in most browsers, fixing it has an issue of it's own (leaving it disabled for now)
// import { enableExcelExport } from './excel-export';
// enableExcelExport(layout, html);
}

View File

@@ -9,17 +9,19 @@ export function distinctArray (array) {
.map(entry => JSON.parse(entry));
}
export function addSeparators (nStr, thousandsSep, decimalSep, numDecimals) {
let x1;
nStr = nStr.toFixed(numDecimals);
const x = nStr.split('.');
x1 = x[0];
const x2 = x.length > 1 ? decimalSep + x[1] : '';
const rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, `$1${thousandsSep}$2`);
export function addSeparators (number, thousandSeparator, decimalSeparator, numberOfDecimals) {
const numberString = number.toFixed(numberOfDecimals);
const numberStringParts = numberString.split('.');
let [
wholeNumber,
decimal
] = numberStringParts;
decimal = numberStringParts.length > 1 ? decimalSeparator + decimal : '';
const regexCheckForThousand = /(\d+)(\d{3})/;
while (regexCheckForThousand.test(wholeNumber)) {
wholeNumber = wholeNumber.replace(regexCheckForThousand, `$1${thousandSeparator}$2`);
}
return x1 + x2;
return wholeNumber + decimal;
}
export function Deferred () {

View File

@@ -1,35 +1,129 @@
"use strict";
module.exports = {
rules: {
"at-rule-no-unknown": true,
"block-no-empty": true,
"color-no-invalid-hex": true,
"comment-no-empty": true,
"declaration-block-no-duplicate-properties": [
true,
'rules': {
'at-rule-empty-line-before': [
'always',
{
ignore: ["consecutive-duplicates-with-different-values"]
except: [
'blockless-after-same-name-blockless',
'first-nested'
],
ignore: ['after-comment']
}
],
"declaration-block-no-shorthand-property-overrides": true,
"font-family-no-duplicate-names": true,
"font-family-no-missing-generic-family-keyword": true,
"function-calc-no-unspaced-operator": true,
"function-linear-gradient-no-nonstandard-direction": true,
"keyframe-declaration-no-important": true,
"media-feature-name-no-unknown": true,
"no-descending-specificity": true,
"no-duplicate-at-import-rules": true,
"no-duplicate-selectors": true,
"no-empty-source": true,
"no-extra-semicolons": true,
"no-invalid-double-slash-comments": true,
"property-no-unknown": true,
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-element-no-unknown": true,
"selector-type-no-unknown": true,
"string-no-newline": true,
"unit-no-unknown": true
'at-rule-name-case': 'lower',
'at-rule-name-space-after': 'always-single-line',
'at-rule-semicolon-newline-after': 'always',
'block-closing-brace-empty-line-before': 'never',
'block-closing-brace-newline-after': 'always',
'block-closing-brace-newline-before': 'always-multi-line',
'block-closing-brace-space-before': 'always-single-line',
'block-opening-brace-newline-after': 'always-multi-line',
'block-opening-brace-space-after': 'always-single-line',
'block-opening-brace-space-before': 'always',
'color-hex-case': 'lower',
'color-hex-length': 'short',
'color-named': 'never',
'comment-empty-line-before': [
'always',
{
except: ['first-nested'],
ignore: ['stylelint-commands']
}
],
'comment-whitespace-inside': 'always',
'custom-property-empty-line-before': [
'always',
{
except: [
'after-custom-property',
'first-nested'
],
ignore: [
'after-comment',
'inside-single-line-block'
]
}
],
'declaration-bang-space-after': 'never',
'declaration-bang-space-before': 'always',
'declaration-block-semicolon-newline-after': 'always-multi-line',
'declaration-block-semicolon-space-after': 'always-single-line',
'declaration-block-semicolon-space-before': 'never',
'declaration-block-single-line-max-declarations': 1,
'declaration-block-trailing-semicolon': 'always',
'declaration-colon-newline-after': 'always-multi-line',
'declaration-colon-space-after': 'always-single-line',
'declaration-colon-space-before': 'never',
'declaration-empty-line-before': [
'always',
{
except: [
'after-declaration',
'first-nested'
],
ignore: [
'after-comment',
'inside-single-line-block'
]
}
],
'declaration-no-important': [
true,
{
severity: 'warning'
}
],
'function-comma-newline-after': 'always-multi-line',
'function-comma-space-after': 'always-single-line',
'function-comma-space-before': 'never',
'function-max-empty-lines': 0,
'function-name-case': 'lower',
'function-parentheses-newline-inside': 'always-multi-line',
'function-parentheses-space-inside': 'never-single-line',
'function-whitespace-after': 'always',
'indentation': 2,
'length-zero-no-unit': true,
'max-empty-lines': 1,
'max-nesting-depth': 3,
'media-feature-colon-space-after': 'always',
'media-feature-colon-space-before': 'never',
'media-feature-name-case': 'lower',
'media-feature-parentheses-space-inside': 'never',
'media-feature-range-operator-space-after': 'always',
'media-feature-range-operator-space-before': 'always',
'media-query-list-comma-newline-after': 'always-multi-line',
'media-query-list-comma-space-after': 'always-single-line',
'media-query-list-comma-space-before': 'never',
'no-extra-semicolons': true,
'no-missing-end-of-source-newline': true,
'number-leading-zero': 'always',
'number-no-trailing-zeros': true,
'property-case': 'lower',
'rule-empty-line-before': [
'always-multi-line',
{
except: ['first-nested'],
ignore: ['after-comment']
}
],
'selector-attribute-brackets-space-inside': 'never',
'selector-attribute-operator-space-after': 'never',
'selector-attribute-operator-space-before': 'never',
'selector-combinator-space-after': 'always',
'selector-combinator-space-before': 'always',
'selector-descendant-combinator-no-non-space': true,
'selector-list-comma-newline-after': 'always',
'selector-list-comma-space-before': 'never',
'selector-max-empty-lines': 0,
'selector-pseudo-class-case': 'lower',
'selector-pseudo-class-parentheses-space-inside': 'never',
'selector-pseudo-element-case': 'lower',
'selector-pseudo-element-colon-notation': 'double',
'selector-type-case': 'lower',
'unit-case': 'lower',
'value-list-comma-newline-after': 'always-multi-line',
'value-list-comma-space-after': 'always-single-line',
'value-list-comma-space-before': 'never',
'value-list-max-empty-lines': 0
}
};

View File

@@ -6,23 +6,16 @@ console.log('Webpack mode:', settings.mode); // eslint-disable-line no-console
const config = {
devtool: 'source-map',
entry: [
'./src/index.js'
],
mode: settings.mode,
output: {
path: settings.buildDestination,
filename: settings.name + '.js',
libraryTarget: 'amd'
},
entry: ['./src/index.js'],
externals: {
jquery: {
amd: 'jquery',
commonjs: 'jquery',
commonjs2: 'jquery',
root: '_'
},
}
},
mode: settings.mode,
// TODO: breaks core-js for some reason
// resolve: {
// extensions: ['js', 'jsx']
@@ -31,20 +24,23 @@ const config = {
rules: [
{
enforce: 'pre',
test: /\.(js|jsx)$/,
exclude: /(node_modules|Library)/,
loader: 'eslint-loader',
options: {
failOnError: true
}
},
test: /\.(js|jsx)$/
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
plugins: ['@babel/plugin-transform-async-to-generator'],
plugins: [
'@babel/plugin-transform-async-to-generator',
'@babel/plugin-proposal-class-properties'
],
presets: [
'@babel/preset-env',
'@babel/preset-react'
@@ -54,23 +50,34 @@ const config = {
},
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
use: [
'style-loader',
'css-loader',
'less-loader'
]
}
]
},
output: {
filename: `${settings.name}.js`,
libraryTarget: 'amd',
path: settings.buildDestination
},
plugins: [
new CopyWebpackPlugin([
'assets/' + settings.name + '.qext',
'assets/' + settings.name + '.png',
`assets/${settings.name}.qext`,
`assets/${settings.name}.png`,
'assets/wbfolder.wbl',
'resources/Excel.png',
// TODO: remove entries below this line
'resources/Accounts.csv',
'resources/Accounts2.csv',
'resources/QlikLook.csv',
'resources/Excel.png',
'resources/QlikLook.csv'
], {}),
new StyleLintPlugin()
new StyleLintPlugin({
files: '**/*.less'
})
]
};