@hailin-zheng/editor-core 2.0.4 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index-cjs.js +1085 -129
- package/index-cjs.js.map +1 -1
- package/index.js +1085 -130
- package/index.js.map +1 -1
- package/med_editor/framework/common-util.d.ts +6 -5
- package/med_editor/framework/editor-calendar-vnode.d.ts +2 -0
- package/med_editor/framework/impl/data-element/data-element-barcode.d.ts +5 -1
- package/med_editor/framework/impl/data-element/qrcode.d.ts +93 -0
- package/package.json +3 -2
package/index-cjs.js
CHANGED
@@ -8,6 +8,7 @@ var acor = require('acorn');
|
|
8
8
|
var astring = require('astring');
|
9
9
|
var estraverse = require('estraverse');
|
10
10
|
var bwipjs = require('bwip-js');
|
11
|
+
var JsBarcode = require('jsbarcode');
|
11
12
|
var snabbdom = require('snabbdom');
|
12
13
|
|
13
14
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
@@ -34,6 +35,7 @@ var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
|
|
34
35
|
var acor__namespace = /*#__PURE__*/_interopNamespace(acor);
|
35
36
|
var estraverse__default = /*#__PURE__*/_interopDefaultLegacy(estraverse);
|
36
37
|
var bwipjs__namespace = /*#__PURE__*/_interopNamespace(bwipjs);
|
38
|
+
var JsBarcode__default = /*#__PURE__*/_interopDefaultLegacy(JsBarcode);
|
37
39
|
|
38
40
|
/**
|
39
41
|
* 元素事件
|
@@ -513,7 +515,23 @@ class CommonUtil {
|
|
513
515
|
const { width, height } = rect;
|
514
516
|
const x = 0;
|
515
517
|
const y = 0;
|
516
|
-
const points = [{ x, y, type: 'left-top' }, {
|
518
|
+
const points = [{ x, y, type: 'left-top' }, {
|
519
|
+
x: x + width,
|
520
|
+
y,
|
521
|
+
type: 'right-top'
|
522
|
+
}, { x: x + (Math.floor(width / 2)), y: y, type: 'top-middle' }, {
|
523
|
+
x,
|
524
|
+
y: y + Math.floor(height / 2),
|
525
|
+
type: 'left-middle'
|
526
|
+
}, { x, y: y + height, type: 'left-bottom' }, {
|
527
|
+
x: width,
|
528
|
+
y: Math.floor(height / 2),
|
529
|
+
type: 'right-middle'
|
530
|
+
}, { x: x + width, y: y + height, type: 'right-bottom' }, {
|
531
|
+
x: x + (Math.floor(width / 2)),
|
532
|
+
y: y + height,
|
533
|
+
type: 'bottom-middle'
|
534
|
+
}];
|
517
535
|
for (let i = 0; i < points.length; i++) {
|
518
536
|
const point = points[i];
|
519
537
|
const { x: px, y: py } = point;
|
@@ -524,11 +542,11 @@ class CommonUtil {
|
|
524
542
|
return null;
|
525
543
|
}
|
526
544
|
/**
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
545
|
+
* 整形符合连线要求
|
546
|
+
* @param points
|
547
|
+
* @param width
|
548
|
+
* @param strokeColor
|
549
|
+
*/
|
532
550
|
static resharpPoints(points) {
|
533
551
|
let prevPoint = points[0];
|
534
552
|
const array = [];
|
@@ -650,6 +668,11 @@ class CommonUtil {
|
|
650
668
|
return [item];
|
651
669
|
}
|
652
670
|
}
|
671
|
+
static removeChild(ele) {
|
672
|
+
while (ele.firstChild) {
|
673
|
+
ele.removeChild(ele.firstChild);
|
674
|
+
}
|
675
|
+
}
|
653
676
|
}
|
654
677
|
|
655
678
|
const docOpsMap = new Map();
|
@@ -3435,7 +3458,7 @@ class DocumentRenderObject extends BlockContainerRenderObject {
|
|
3435
3458
|
};
|
3436
3459
|
pageCorner.children?.push(ElementUtil.getStrokeSvgPath(`M ${paddingPos.x - lineWidth} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y - lineWidth}`, "grey", drawLineWidth));
|
3437
3460
|
paddingPos = { x: docWidth - padding.right, y: padding.top };
|
3438
|
-
pageCorner.children?.push(ElementUtil.getStrokeSvgPath(`M ${paddingPos.x + lineWidth} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y
|
3461
|
+
pageCorner.children?.push(ElementUtil.getStrokeSvgPath(`M ${paddingPos.x + lineWidth} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y - lineWidth}`, "grey", drawLineWidth));
|
3439
3462
|
paddingPos = { x: padding.left, y: docHeight - this.padding.bottom };
|
3440
3463
|
pageCorner.children?.push(ElementUtil.getStrokeSvgPath(`M ${paddingPos.x - lineWidth} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y} L ${paddingPos.x} ${paddingPos.y + lineWidth}`, "grey", drawLineWidth));
|
3441
3464
|
paddingPos = { x: docWidth - padding.left, y: docHeight - this.padding.bottom };
|
@@ -3832,7 +3855,7 @@ function drawDecorator(e, r) {
|
|
3832
3855
|
function exportDecoratorHTML(event, r) {
|
3833
3856
|
const canPaint = r.element.isMouseenter || r.element.isFocused;
|
3834
3857
|
if (canPaint && r.element.paintRenders.indexOf(r) === 0) {
|
3835
|
-
const strokeColor =
|
3858
|
+
const strokeColor = '#0050b3';
|
3836
3859
|
const verOffset = 0;
|
3837
3860
|
const renderPosMap = getCurrentParaGroupRenders(r).map(item => ({ pos: getRenderPosToDoc(item), render: item }));
|
3838
3861
|
if (renderPosMap.length > 1) {
|
@@ -9577,6 +9600,858 @@ class ValidateRenderObject extends CommContentBaseRenderObject {
|
|
9577
9600
|
}
|
9578
9601
|
}
|
9579
9602
|
|
9603
|
+
/*
|
9604
|
+
* QR Code generator library (TypeScript)
|
9605
|
+
*
|
9606
|
+
* Copyright (c) Project Nayuki. (MIT License)
|
9607
|
+
* https://www.nayuki.io/page/qr-code-generator-library
|
9608
|
+
*
|
9609
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
9610
|
+
* this software and associated documentation files (the "Software"), to deal in
|
9611
|
+
* the Software without restriction, including without limitation the rights to
|
9612
|
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9613
|
+
* the Software, and to permit persons to whom the Software is furnished to do so,
|
9614
|
+
* subject to the following conditions:
|
9615
|
+
* - The above copyright notice and this permission notice shall be included in
|
9616
|
+
* all copies or substantial portions of the Software.
|
9617
|
+
* - The Software is provided "as is", without warranty of any kind, express or
|
9618
|
+
* implied, including but not limited to the warranties of merchantability,
|
9619
|
+
* fitness for a particular purpose and noninfringement. In no event shall the
|
9620
|
+
* authors or copyright holders be liable for any claim, damages or other
|
9621
|
+
* liability, whether in an action of contract, tort or otherwise, arising from,
|
9622
|
+
* out of or in connection with the Software or the use or other dealings in the
|
9623
|
+
* Software.
|
9624
|
+
*/
|
9625
|
+
var qrcodegen;
|
9626
|
+
(function (qrcodegen) {
|
9627
|
+
/*---- QR Code symbol class ----*/
|
9628
|
+
/*
|
9629
|
+
* A QR Code symbol, which is a type of two-dimension barcode.
|
9630
|
+
* Invented by Denso Wave and described in the ISO/IEC 18004 standard.
|
9631
|
+
* Instances of this class represent an immutable square grid of dark and light cells.
|
9632
|
+
* The class provides static factory functions to create a QR Code from text or binary data.
|
9633
|
+
* The class covers the QR Code Model 2 specification, supporting all versions (sizes)
|
9634
|
+
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
|
9635
|
+
*
|
9636
|
+
* Ways to create a QR Code object:
|
9637
|
+
* - High level: Take the payload data and call QrCode.encodeText() or QrCode.encodeBinary().
|
9638
|
+
* - Mid level: Custom-make the list of segments and call QrCode.encodeSegments().
|
9639
|
+
* - Low level: Custom-make the array of data codeword bytes (including
|
9640
|
+
* segment headers and final padding, excluding error correction codewords),
|
9641
|
+
* supply the appropriate version number, and call the QrCode() constructor.
|
9642
|
+
* (Note that all ways require supplying the desired error correction level.)
|
9643
|
+
*/
|
9644
|
+
class QrCode {
|
9645
|
+
version;
|
9646
|
+
errorCorrectionLevel;
|
9647
|
+
/*-- Static factory functions (high level) --*/
|
9648
|
+
// Returns a QR Code representing the given Unicode text string at the given error correction level.
|
9649
|
+
// As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
|
9650
|
+
// Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
|
9651
|
+
// QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
|
9652
|
+
// ecl argument if it can be done without increasing the version.
|
9653
|
+
static encodeText(text, ecl) {
|
9654
|
+
const segs = qrcodegen.QrSegment.makeSegments(text);
|
9655
|
+
return QrCode.encodeSegments(segs, ecl);
|
9656
|
+
}
|
9657
|
+
// Returns a QR Code representing the given binary data at the given error correction level.
|
9658
|
+
// This function always encodes using the binary segment mode, not any text mode. The maximum number of
|
9659
|
+
// bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
|
9660
|
+
// The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
9661
|
+
static encodeBinary(data, ecl) {
|
9662
|
+
const seg = qrcodegen.QrSegment.makeBytes(data);
|
9663
|
+
return QrCode.encodeSegments([seg], ecl);
|
9664
|
+
}
|
9665
|
+
/*-- Static factory functions (mid level) --*/
|
9666
|
+
// Returns a QR Code representing the given segments with the given encoding parameters.
|
9667
|
+
// The smallest possible QR Code version within the given range is automatically
|
9668
|
+
// chosen for the output. Iff boostEcl is true, then the ECC level of the result
|
9669
|
+
// may be higher than the ecl argument if it can be done without increasing the
|
9670
|
+
// version. The mask number is either between 0 to 7 (inclusive) to force that
|
9671
|
+
// mask, or -1 to automatically choose an appropriate mask (which may be slow).
|
9672
|
+
// This function allows the user to create a custom sequence of segments that switches
|
9673
|
+
// between modes (such as alphanumeric and byte) to encode text in less space.
|
9674
|
+
// This is a mid-level API; the high-level API is encodeText() and encodeBinary().
|
9675
|
+
static encodeSegments(segs, ecl, minVersion = 1, maxVersion = 40, mask = -1, boostEcl = true) {
|
9676
|
+
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION)
|
9677
|
+
|| mask < -1 || mask > 7)
|
9678
|
+
throw new RangeError("Invalid value");
|
9679
|
+
// Find the minimal version number to use
|
9680
|
+
let version;
|
9681
|
+
let dataUsedBits;
|
9682
|
+
for (version = minVersion;; version++) {
|
9683
|
+
const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
9684
|
+
const usedBits = QrSegment.getTotalBits(segs, version);
|
9685
|
+
if (usedBits <= dataCapacityBits) {
|
9686
|
+
dataUsedBits = usedBits;
|
9687
|
+
break; // This version number is found to be suitable
|
9688
|
+
}
|
9689
|
+
if (version >= maxVersion) // All versions in the range could not fit the given data
|
9690
|
+
throw new RangeError("Data too long");
|
9691
|
+
}
|
9692
|
+
// Increase the error correction level while the data still fits in the current version number
|
9693
|
+
for (const newEcl of [QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH]) { // From low to high
|
9694
|
+
if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8)
|
9695
|
+
ecl = newEcl;
|
9696
|
+
}
|
9697
|
+
// Concatenate all segments to create the data bit string
|
9698
|
+
let bb = [];
|
9699
|
+
for (const seg of segs) {
|
9700
|
+
appendBits(seg.mode.modeBits, 4, bb);
|
9701
|
+
appendBits(seg.numChars, seg.mode.numCharCountBits(version), bb);
|
9702
|
+
for (const b of seg.getData())
|
9703
|
+
bb.push(b);
|
9704
|
+
}
|
9705
|
+
assert(bb.length == dataUsedBits);
|
9706
|
+
// Add terminator and pad up to a byte if applicable
|
9707
|
+
const dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
|
9708
|
+
assert(bb.length <= dataCapacityBits);
|
9709
|
+
appendBits(0, Math.min(4, dataCapacityBits - bb.length), bb);
|
9710
|
+
appendBits(0, (8 - bb.length % 8) % 8, bb);
|
9711
|
+
assert(bb.length % 8 == 0);
|
9712
|
+
// Pad with alternating bytes until data capacity is reached
|
9713
|
+
for (let padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
9714
|
+
appendBits(padByte, 8, bb);
|
9715
|
+
// Pack bits into bytes in big endian
|
9716
|
+
let dataCodewords = [];
|
9717
|
+
while (dataCodewords.length * 8 < bb.length)
|
9718
|
+
dataCodewords.push(0);
|
9719
|
+
bb.forEach((b, i) => dataCodewords[i >>> 3] |= b << (7 - (i & 7)));
|
9720
|
+
// Create the QR Code object
|
9721
|
+
return new QrCode(version, ecl, dataCodewords, mask);
|
9722
|
+
}
|
9723
|
+
/*-- Fields --*/
|
9724
|
+
// The width and height of this QR Code, measured in modules, between
|
9725
|
+
// 21 and 177 (inclusive). This is equal to version * 4 + 17.
|
9726
|
+
size;
|
9727
|
+
// The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
|
9728
|
+
// Even if a QR Code is created with automatic masking requested (mask = -1),
|
9729
|
+
// the resulting object still has a mask value between 0 and 7.
|
9730
|
+
mask;
|
9731
|
+
// The modules of this QR Code (false = light, true = dark).
|
9732
|
+
// Immutable after constructor finishes. Accessed through getModule().
|
9733
|
+
modules = [];
|
9734
|
+
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
|
9735
|
+
isFunction = [];
|
9736
|
+
/*-- Constructor (low level) and fields --*/
|
9737
|
+
// Creates a new QR Code with the given version number,
|
9738
|
+
// error correction level, data codeword bytes, and mask number.
|
9739
|
+
// This is a low-level API that most users should not use directly.
|
9740
|
+
// A mid-level API is the encodeSegments() function.
|
9741
|
+
constructor(
|
9742
|
+
// The version number of this QR Code, which is between 1 and 40 (inclusive).
|
9743
|
+
// This determines the size of this barcode.
|
9744
|
+
version,
|
9745
|
+
// The error correction level used in this QR Code.
|
9746
|
+
errorCorrectionLevel, dataCodewords, msk) {
|
9747
|
+
this.version = version;
|
9748
|
+
this.errorCorrectionLevel = errorCorrectionLevel;
|
9749
|
+
// Check scalar arguments
|
9750
|
+
if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)
|
9751
|
+
throw new RangeError("Version value out of range");
|
9752
|
+
if (msk < -1 || msk > 7)
|
9753
|
+
throw new RangeError("Mask value out of range");
|
9754
|
+
this.size = version * 4 + 17;
|
9755
|
+
// Initialize both grids to be size*size arrays of Boolean false
|
9756
|
+
let row = [];
|
9757
|
+
for (let i = 0; i < this.size; i++)
|
9758
|
+
row.push(false);
|
9759
|
+
for (let i = 0; i < this.size; i++) {
|
9760
|
+
this.modules.push(row.slice()); // Initially all light
|
9761
|
+
this.isFunction.push(row.slice());
|
9762
|
+
}
|
9763
|
+
// Compute ECC, draw modules
|
9764
|
+
this.drawFunctionPatterns();
|
9765
|
+
const allCodewords = this.addEccAndInterleave(dataCodewords);
|
9766
|
+
this.drawCodewords(allCodewords);
|
9767
|
+
// Do masking
|
9768
|
+
if (msk == -1) { // Automatically choose best mask
|
9769
|
+
let minPenalty = 1000000000;
|
9770
|
+
for (let i = 0; i < 8; i++) {
|
9771
|
+
this.applyMask(i);
|
9772
|
+
this.drawFormatBits(i);
|
9773
|
+
const penalty = this.getPenaltyScore();
|
9774
|
+
if (penalty < minPenalty) {
|
9775
|
+
msk = i;
|
9776
|
+
minPenalty = penalty;
|
9777
|
+
}
|
9778
|
+
this.applyMask(i); // Undoes the mask due to XOR
|
9779
|
+
}
|
9780
|
+
}
|
9781
|
+
assert(0 <= msk && msk <= 7);
|
9782
|
+
this.mask = msk;
|
9783
|
+
this.applyMask(msk); // Apply the final choice of mask
|
9784
|
+
this.drawFormatBits(msk); // Overwrite old format bits
|
9785
|
+
this.isFunction = [];
|
9786
|
+
}
|
9787
|
+
/*-- Accessor methods --*/
|
9788
|
+
// Returns the color of the module (pixel) at the given coordinates, which is false
|
9789
|
+
// for light or true for dark. The top left corner has the coordinates (x=0, y=0).
|
9790
|
+
// If the given coordinates are out of bounds, then false (light) is returned.
|
9791
|
+
getModule(x, y) {
|
9792
|
+
return 0 <= x && x < this.size && 0 <= y && y < this.size && this.modules[y][x];
|
9793
|
+
}
|
9794
|
+
/*-- Private helper methods for constructor: Drawing function modules --*/
|
9795
|
+
// Reads this object's version field, and draws and marks all function modules.
|
9796
|
+
drawFunctionPatterns() {
|
9797
|
+
// Draw horizontal and vertical timing patterns
|
9798
|
+
for (let i = 0; i < this.size; i++) {
|
9799
|
+
this.setFunctionModule(6, i, i % 2 == 0);
|
9800
|
+
this.setFunctionModule(i, 6, i % 2 == 0);
|
9801
|
+
}
|
9802
|
+
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
|
9803
|
+
this.drawFinderPattern(3, 3);
|
9804
|
+
this.drawFinderPattern(this.size - 4, 3);
|
9805
|
+
this.drawFinderPattern(3, this.size - 4);
|
9806
|
+
// Draw numerous alignment patterns
|
9807
|
+
const alignPatPos = this.getAlignmentPatternPositions();
|
9808
|
+
const numAlign = alignPatPos.length;
|
9809
|
+
for (let i = 0; i < numAlign; i++) {
|
9810
|
+
for (let j = 0; j < numAlign; j++) {
|
9811
|
+
// Don't draw on the three finder corners
|
9812
|
+
if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
|
9813
|
+
this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
|
9814
|
+
}
|
9815
|
+
}
|
9816
|
+
// Draw configuration data
|
9817
|
+
this.drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
|
9818
|
+
this.drawVersion();
|
9819
|
+
}
|
9820
|
+
// Draws two copies of the format bits (with its own error correction code)
|
9821
|
+
// based on the given mask and this object's error correction level field.
|
9822
|
+
drawFormatBits(mask) {
|
9823
|
+
// Calculate error correction code and pack bits
|
9824
|
+
const data = this.errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
|
9825
|
+
let rem = data;
|
9826
|
+
for (let i = 0; i < 10; i++)
|
9827
|
+
rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
|
9828
|
+
const bits = (data << 10 | rem) ^ 0x5412; // uint15
|
9829
|
+
assert(bits >>> 15 == 0);
|
9830
|
+
// Draw first copy
|
9831
|
+
for (let i = 0; i <= 5; i++)
|
9832
|
+
this.setFunctionModule(8, i, getBit(bits, i));
|
9833
|
+
this.setFunctionModule(8, 7, getBit(bits, 6));
|
9834
|
+
this.setFunctionModule(8, 8, getBit(bits, 7));
|
9835
|
+
this.setFunctionModule(7, 8, getBit(bits, 8));
|
9836
|
+
for (let i = 9; i < 15; i++)
|
9837
|
+
this.setFunctionModule(14 - i, 8, getBit(bits, i));
|
9838
|
+
// Draw second copy
|
9839
|
+
for (let i = 0; i < 8; i++)
|
9840
|
+
this.setFunctionModule(this.size - 1 - i, 8, getBit(bits, i));
|
9841
|
+
for (let i = 8; i < 15; i++)
|
9842
|
+
this.setFunctionModule(8, this.size - 15 + i, getBit(bits, i));
|
9843
|
+
this.setFunctionModule(8, this.size - 8, true); // Always dark
|
9844
|
+
}
|
9845
|
+
// Draws two copies of the version bits (with its own error correction code),
|
9846
|
+
// based on this object's version field, iff 7 <= version <= 40.
|
9847
|
+
drawVersion() {
|
9848
|
+
if (this.version < 7)
|
9849
|
+
return;
|
9850
|
+
// Calculate error correction code and pack bits
|
9851
|
+
let rem = this.version; // version is uint6, in the range [7, 40]
|
9852
|
+
for (let i = 0; i < 12; i++)
|
9853
|
+
rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
|
9854
|
+
const bits = this.version << 12 | rem; // uint18
|
9855
|
+
assert(bits >>> 18 == 0);
|
9856
|
+
// Draw two copies
|
9857
|
+
for (let i = 0; i < 18; i++) {
|
9858
|
+
const color = getBit(bits, i);
|
9859
|
+
const a = this.size - 11 + i % 3;
|
9860
|
+
const b = Math.floor(i / 3);
|
9861
|
+
this.setFunctionModule(a, b, color);
|
9862
|
+
this.setFunctionModule(b, a, color);
|
9863
|
+
}
|
9864
|
+
}
|
9865
|
+
// Draws a 9*9 finder pattern including the border separator,
|
9866
|
+
// with the center module at (x, y). Modules can be out of bounds.
|
9867
|
+
drawFinderPattern(x, y) {
|
9868
|
+
for (let dy = -4; dy <= 4; dy++) {
|
9869
|
+
for (let dx = -4; dx <= 4; dx++) {
|
9870
|
+
const dist = Math.max(Math.abs(dx), Math.abs(dy)); // Chebyshev/infinity norm
|
9871
|
+
const xx = x + dx;
|
9872
|
+
const yy = y + dy;
|
9873
|
+
if (0 <= xx && xx < this.size && 0 <= yy && yy < this.size)
|
9874
|
+
this.setFunctionModule(xx, yy, dist != 2 && dist != 4);
|
9875
|
+
}
|
9876
|
+
}
|
9877
|
+
}
|
9878
|
+
// Draws a 5*5 alignment pattern, with the center module
|
9879
|
+
// at (x, y). All modules must be in bounds.
|
9880
|
+
drawAlignmentPattern(x, y) {
|
9881
|
+
for (let dy = -2; dy <= 2; dy++) {
|
9882
|
+
for (let dx = -2; dx <= 2; dx++)
|
9883
|
+
this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
|
9884
|
+
}
|
9885
|
+
}
|
9886
|
+
// Sets the color of a module and marks it as a function module.
|
9887
|
+
// Only used by the constructor. Coordinates must be in bounds.
|
9888
|
+
setFunctionModule(x, y, isDark) {
|
9889
|
+
this.modules[y][x] = isDark;
|
9890
|
+
this.isFunction[y][x] = true;
|
9891
|
+
}
|
9892
|
+
/*-- Private helper methods for constructor: Codewords and masking --*/
|
9893
|
+
// Returns a new byte string representing the given data with the appropriate error correction
|
9894
|
+
// codewords appended to it, based on this object's version and error correction level.
|
9895
|
+
addEccAndInterleave(data) {
|
9896
|
+
const ver = this.version;
|
9897
|
+
const ecl = this.errorCorrectionLevel;
|
9898
|
+
if (data.length != QrCode.getNumDataCodewords(ver, ecl))
|
9899
|
+
throw new RangeError("Invalid argument");
|
9900
|
+
// Calculate parameter numbers
|
9901
|
+
const numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
9902
|
+
const blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver];
|
9903
|
+
const rawCodewords = Math.floor(QrCode.getNumRawDataModules(ver) / 8);
|
9904
|
+
const numShortBlocks = numBlocks - rawCodewords % numBlocks;
|
9905
|
+
const shortBlockLen = Math.floor(rawCodewords / numBlocks);
|
9906
|
+
// Split data into blocks and append ECC to each block
|
9907
|
+
let blocks = [];
|
9908
|
+
const rsDiv = QrCode.reedSolomonComputeDivisor(blockEccLen);
|
9909
|
+
for (let i = 0, k = 0; i < numBlocks; i++) {
|
9910
|
+
let dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
|
9911
|
+
k += dat.length;
|
9912
|
+
const ecc = QrCode.reedSolomonComputeRemainder(dat, rsDiv);
|
9913
|
+
if (i < numShortBlocks)
|
9914
|
+
dat.push(0);
|
9915
|
+
blocks.push(dat.concat(ecc));
|
9916
|
+
}
|
9917
|
+
// Interleave (not concatenate) the bytes from every block into a single sequence
|
9918
|
+
let result = [];
|
9919
|
+
for (let i = 0; i < blocks[0].length; i++) {
|
9920
|
+
blocks.forEach((block, j) => {
|
9921
|
+
// Skip the padding byte in short blocks
|
9922
|
+
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
|
9923
|
+
result.push(block[i]);
|
9924
|
+
});
|
9925
|
+
}
|
9926
|
+
assert(result.length == rawCodewords);
|
9927
|
+
return result;
|
9928
|
+
}
|
9929
|
+
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
|
9930
|
+
// data area of this QR Code. Function modules need to be marked off before this is called.
|
9931
|
+
drawCodewords(data) {
|
9932
|
+
if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8))
|
9933
|
+
throw new RangeError("Invalid argument");
|
9934
|
+
let i = 0; // Bit index into the data
|
9935
|
+
// Do the funny zigzag scan
|
9936
|
+
for (let right = this.size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
|
9937
|
+
if (right == 6)
|
9938
|
+
right = 5;
|
9939
|
+
for (let vert = 0; vert < this.size; vert++) { // Vertical counter
|
9940
|
+
for (let j = 0; j < 2; j++) {
|
9941
|
+
const x = right - j; // Actual x coordinate
|
9942
|
+
const upward = ((right + 1) & 2) == 0;
|
9943
|
+
const y = upward ? this.size - 1 - vert : vert; // Actual y coordinate
|
9944
|
+
if (!this.isFunction[y][x] && i < data.length * 8) {
|
9945
|
+
this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));
|
9946
|
+
i++;
|
9947
|
+
}
|
9948
|
+
// If this QR Code has any remainder bits (0 to 7), they were assigned as
|
9949
|
+
// 0/false/light by the constructor and are left unchanged by this method
|
9950
|
+
}
|
9951
|
+
}
|
9952
|
+
}
|
9953
|
+
assert(i == data.length * 8);
|
9954
|
+
}
|
9955
|
+
// XORs the codeword modules in this QR Code with the given mask pattern.
|
9956
|
+
// The function modules must be marked and the codeword bits must be drawn
|
9957
|
+
// before masking. Due to the arithmetic of XOR, calling applyMask() with
|
9958
|
+
// the same mask value a second time will undo the mask. A final well-formed
|
9959
|
+
// QR Code needs exactly one (not zero, two, etc.) mask applied.
|
9960
|
+
applyMask(mask) {
|
9961
|
+
if (mask < 0 || mask > 7)
|
9962
|
+
throw new RangeError("Mask value out of range");
|
9963
|
+
for (let y = 0; y < this.size; y++) {
|
9964
|
+
for (let x = 0; x < this.size; x++) {
|
9965
|
+
let invert;
|
9966
|
+
switch (mask) {
|
9967
|
+
case 0:
|
9968
|
+
invert = (x + y) % 2 == 0;
|
9969
|
+
break;
|
9970
|
+
case 1:
|
9971
|
+
invert = y % 2 == 0;
|
9972
|
+
break;
|
9973
|
+
case 2:
|
9974
|
+
invert = x % 3 == 0;
|
9975
|
+
break;
|
9976
|
+
case 3:
|
9977
|
+
invert = (x + y) % 3 == 0;
|
9978
|
+
break;
|
9979
|
+
case 4:
|
9980
|
+
invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;
|
9981
|
+
break;
|
9982
|
+
case 5:
|
9983
|
+
invert = x * y % 2 + x * y % 3 == 0;
|
9984
|
+
break;
|
9985
|
+
case 6:
|
9986
|
+
invert = (x * y % 2 + x * y % 3) % 2 == 0;
|
9987
|
+
break;
|
9988
|
+
case 7:
|
9989
|
+
invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
|
9990
|
+
break;
|
9991
|
+
default: throw new Error("Unreachable");
|
9992
|
+
}
|
9993
|
+
if (!this.isFunction[y][x] && invert)
|
9994
|
+
this.modules[y][x] = !this.modules[y][x];
|
9995
|
+
}
|
9996
|
+
}
|
9997
|
+
}
|
9998
|
+
// Calculates and returns the penalty score based on state of this QR Code's current modules.
|
9999
|
+
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
|
10000
|
+
getPenaltyScore() {
|
10001
|
+
let result = 0;
|
10002
|
+
// Adjacent modules in row having same color, and finder-like patterns
|
10003
|
+
for (let y = 0; y < this.size; y++) {
|
10004
|
+
let runColor = false;
|
10005
|
+
let runX = 0;
|
10006
|
+
let runHistory = [0, 0, 0, 0, 0, 0, 0];
|
10007
|
+
for (let x = 0; x < this.size; x++) {
|
10008
|
+
if (this.modules[y][x] == runColor) {
|
10009
|
+
runX++;
|
10010
|
+
if (runX == 5)
|
10011
|
+
result += QrCode.PENALTY_N1;
|
10012
|
+
else if (runX > 5)
|
10013
|
+
result++;
|
10014
|
+
}
|
10015
|
+
else {
|
10016
|
+
this.finderPenaltyAddHistory(runX, runHistory);
|
10017
|
+
if (!runColor)
|
10018
|
+
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
|
10019
|
+
runColor = this.modules[y][x];
|
10020
|
+
runX = 1;
|
10021
|
+
}
|
10022
|
+
}
|
10023
|
+
result += this.finderPenaltyTerminateAndCount(runColor, runX, runHistory) * QrCode.PENALTY_N3;
|
10024
|
+
}
|
10025
|
+
// Adjacent modules in column having same color, and finder-like patterns
|
10026
|
+
for (let x = 0; x < this.size; x++) {
|
10027
|
+
let runColor = false;
|
10028
|
+
let runY = 0;
|
10029
|
+
let runHistory = [0, 0, 0, 0, 0, 0, 0];
|
10030
|
+
for (let y = 0; y < this.size; y++) {
|
10031
|
+
if (this.modules[y][x] == runColor) {
|
10032
|
+
runY++;
|
10033
|
+
if (runY == 5)
|
10034
|
+
result += QrCode.PENALTY_N1;
|
10035
|
+
else if (runY > 5)
|
10036
|
+
result++;
|
10037
|
+
}
|
10038
|
+
else {
|
10039
|
+
this.finderPenaltyAddHistory(runY, runHistory);
|
10040
|
+
if (!runColor)
|
10041
|
+
result += this.finderPenaltyCountPatterns(runHistory) * QrCode.PENALTY_N3;
|
10042
|
+
runColor = this.modules[y][x];
|
10043
|
+
runY = 1;
|
10044
|
+
}
|
10045
|
+
}
|
10046
|
+
result += this.finderPenaltyTerminateAndCount(runColor, runY, runHistory) * QrCode.PENALTY_N3;
|
10047
|
+
}
|
10048
|
+
// 2*2 blocks of modules having same color
|
10049
|
+
for (let y = 0; y < this.size - 1; y++) {
|
10050
|
+
for (let x = 0; x < this.size - 1; x++) {
|
10051
|
+
const color = this.modules[y][x];
|
10052
|
+
if (color == this.modules[y][x + 1] &&
|
10053
|
+
color == this.modules[y + 1][x] &&
|
10054
|
+
color == this.modules[y + 1][x + 1])
|
10055
|
+
result += QrCode.PENALTY_N2;
|
10056
|
+
}
|
10057
|
+
}
|
10058
|
+
// Balance of dark and light modules
|
10059
|
+
let dark = 0;
|
10060
|
+
for (const row of this.modules)
|
10061
|
+
dark = row.reduce((sum, color) => sum + (color ? 1 : 0), dark);
|
10062
|
+
const total = this.size * this.size; // Note that size is odd, so dark/total != 1/2
|
10063
|
+
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
|
10064
|
+
const k = Math.ceil(Math.abs(dark * 20 - total * 10) / total) - 1;
|
10065
|
+
assert(0 <= k && k <= 9);
|
10066
|
+
result += k * QrCode.PENALTY_N4;
|
10067
|
+
assert(0 <= result && result <= 2568888); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
|
10068
|
+
return result;
|
10069
|
+
}
|
10070
|
+
/*-- Private helper functions --*/
|
10071
|
+
// Returns an ascending list of positions of alignment patterns for this version number.
|
10072
|
+
// Each position is in the range [0,177), and are used on both the x and y axes.
|
10073
|
+
// This could be implemented as lookup table of 40 variable-length lists of integers.
|
10074
|
+
getAlignmentPatternPositions() {
|
10075
|
+
if (this.version == 1)
|
10076
|
+
return [];
|
10077
|
+
else {
|
10078
|
+
const numAlign = Math.floor(this.version / 7) + 2;
|
10079
|
+
const step = (this.version == 32) ? 26 :
|
10080
|
+
Math.ceil((this.version * 4 + 4) / (numAlign * 2 - 2)) * 2;
|
10081
|
+
let result = [6];
|
10082
|
+
for (let pos = this.size - 7; result.length < numAlign; pos -= step)
|
10083
|
+
result.splice(1, 0, pos);
|
10084
|
+
return result;
|
10085
|
+
}
|
10086
|
+
}
|
10087
|
+
// Returns the number of data bits that can be stored in a QR Code of the given version number, after
|
10088
|
+
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
|
10089
|
+
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
|
10090
|
+
static getNumRawDataModules(ver) {
|
10091
|
+
if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION)
|
10092
|
+
throw new RangeError("Version number out of range");
|
10093
|
+
let result = (16 * ver + 128) * ver + 64;
|
10094
|
+
if (ver >= 2) {
|
10095
|
+
const numAlign = Math.floor(ver / 7) + 2;
|
10096
|
+
result -= (25 * numAlign - 10) * numAlign - 55;
|
10097
|
+
if (ver >= 7)
|
10098
|
+
result -= 36;
|
10099
|
+
}
|
10100
|
+
assert(208 <= result && result <= 29648);
|
10101
|
+
return result;
|
10102
|
+
}
|
10103
|
+
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
|
10104
|
+
// QR Code of the given version number and error correction level, with remainder bits discarded.
|
10105
|
+
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
|
10106
|
+
static getNumDataCodewords(ver, ecl) {
|
10107
|
+
return Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
|
10108
|
+
QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] *
|
10109
|
+
QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
10110
|
+
}
|
10111
|
+
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
|
10112
|
+
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
10113
|
+
static reedSolomonComputeDivisor(degree) {
|
10114
|
+
if (degree < 1 || degree > 255)
|
10115
|
+
throw new RangeError("Degree out of range");
|
10116
|
+
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
|
10117
|
+
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
|
10118
|
+
let result = [];
|
10119
|
+
for (let i = 0; i < degree - 1; i++)
|
10120
|
+
result.push(0);
|
10121
|
+
result.push(1); // Start off with the monomial x^0
|
10122
|
+
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
|
10123
|
+
// and drop the highest monomial term which is always 1x^degree.
|
10124
|
+
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
|
10125
|
+
let root = 1;
|
10126
|
+
for (let i = 0; i < degree; i++) {
|
10127
|
+
// Multiply the current product by (x - r^i)
|
10128
|
+
for (let j = 0; j < result.length; j++) {
|
10129
|
+
result[j] = QrCode.reedSolomonMultiply(result[j], root);
|
10130
|
+
if (j + 1 < result.length)
|
10131
|
+
result[j] ^= result[j + 1];
|
10132
|
+
}
|
10133
|
+
root = QrCode.reedSolomonMultiply(root, 0x02);
|
10134
|
+
}
|
10135
|
+
return result;
|
10136
|
+
}
|
10137
|
+
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
|
10138
|
+
static reedSolomonComputeRemainder(data, divisor) {
|
10139
|
+
let result = divisor.map(_ => 0);
|
10140
|
+
for (const b of data) { // Polynomial division
|
10141
|
+
const factor = b ^ result.shift();
|
10142
|
+
result.push(0);
|
10143
|
+
divisor.forEach((coef, i) => result[i] ^= QrCode.reedSolomonMultiply(coef, factor));
|
10144
|
+
}
|
10145
|
+
return result;
|
10146
|
+
}
|
10147
|
+
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
|
10148
|
+
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
10149
|
+
static reedSolomonMultiply(x, y) {
|
10150
|
+
if (x >>> 8 != 0 || y >>> 8 != 0)
|
10151
|
+
throw new RangeError("Byte out of range");
|
10152
|
+
// Russian peasant multiplication
|
10153
|
+
let z = 0;
|
10154
|
+
for (let i = 7; i >= 0; i--) {
|
10155
|
+
z = (z << 1) ^ ((z >>> 7) * 0x11D);
|
10156
|
+
z ^= ((y >>> i) & 1) * x;
|
10157
|
+
}
|
10158
|
+
assert(z >>> 8 == 0);
|
10159
|
+
return z;
|
10160
|
+
}
|
10161
|
+
// Can only be called immediately after a light run is added, and
|
10162
|
+
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
|
10163
|
+
finderPenaltyCountPatterns(runHistory) {
|
10164
|
+
const n = runHistory[1];
|
10165
|
+
assert(n <= this.size * 3);
|
10166
|
+
const core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
|
10167
|
+
return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
|
10168
|
+
+ (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
|
10169
|
+
}
|
10170
|
+
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
|
10171
|
+
finderPenaltyTerminateAndCount(currentRunColor, currentRunLength, runHistory) {
|
10172
|
+
if (currentRunColor) { // Terminate dark run
|
10173
|
+
this.finderPenaltyAddHistory(currentRunLength, runHistory);
|
10174
|
+
currentRunLength = 0;
|
10175
|
+
}
|
10176
|
+
currentRunLength += this.size; // Add light border to final run
|
10177
|
+
this.finderPenaltyAddHistory(currentRunLength, runHistory);
|
10178
|
+
return this.finderPenaltyCountPatterns(runHistory);
|
10179
|
+
}
|
10180
|
+
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
|
10181
|
+
finderPenaltyAddHistory(currentRunLength, runHistory) {
|
10182
|
+
if (runHistory[0] == 0)
|
10183
|
+
currentRunLength += this.size; // Add light border to initial run
|
10184
|
+
runHistory.pop();
|
10185
|
+
runHistory.unshift(currentRunLength);
|
10186
|
+
}
|
10187
|
+
/*-- Constants and tables --*/
|
10188
|
+
// The minimum version number supported in the QR Code Model 2 standard.
|
10189
|
+
static MIN_VERSION = 1;
|
10190
|
+
// The maximum version number supported in the QR Code Model 2 standard.
|
10191
|
+
static MAX_VERSION = 40;
|
10192
|
+
// For use in getPenaltyScore(), when evaluating which mask is best.
|
10193
|
+
static PENALTY_N1 = 3;
|
10194
|
+
static PENALTY_N2 = 3;
|
10195
|
+
static PENALTY_N3 = 40;
|
10196
|
+
static PENALTY_N4 = 10;
|
10197
|
+
static ECC_CODEWORDS_PER_BLOCK = [
|
10198
|
+
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
10199
|
+
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
10200
|
+
[-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
10201
|
+
[-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28],
|
10202
|
+
[-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30],
|
10203
|
+
[-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // High
|
10204
|
+
];
|
10205
|
+
static NUM_ERROR_CORRECTION_BLOCKS = [
|
10206
|
+
// Version: (note that index 0 is for padding, and is set to an illegal value)
|
10207
|
+
//0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
|
10208
|
+
[-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25],
|
10209
|
+
[-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49],
|
10210
|
+
[-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68],
|
10211
|
+
[-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81], // High
|
10212
|
+
];
|
10213
|
+
}
|
10214
|
+
qrcodegen.QrCode = QrCode;
|
10215
|
+
// Appends the given number of low-order bits of the given value
|
10216
|
+
// to the given buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
|
10217
|
+
function appendBits(val, len, bb) {
|
10218
|
+
if (len < 0 || len > 31 || val >>> len != 0)
|
10219
|
+
throw new RangeError("Value out of range");
|
10220
|
+
for (let i = len - 1; i >= 0; i--) // Append bit by bit
|
10221
|
+
bb.push((val >>> i) & 1);
|
10222
|
+
}
|
10223
|
+
// Returns true iff the i'th bit of x is set to 1.
|
10224
|
+
function getBit(x, i) {
|
10225
|
+
return ((x >>> i) & 1) != 0;
|
10226
|
+
}
|
10227
|
+
// Throws an exception if the given condition is false.
|
10228
|
+
function assert(cond) {
|
10229
|
+
if (!cond)
|
10230
|
+
throw new Error("Assertion error");
|
10231
|
+
}
|
10232
|
+
/*---- Data segment class ----*/
|
10233
|
+
/*
|
10234
|
+
* A segment of character/binary/control data in a QR Code symbol.
|
10235
|
+
* Instances of this class are immutable.
|
10236
|
+
* The mid-level way to create a segment is to take the payload data
|
10237
|
+
* and call a static factory function such as QrSegment.makeNumeric().
|
10238
|
+
* The low-level way to create a segment is to custom-make the bit buffer
|
10239
|
+
* and call the QrSegment() constructor with appropriate values.
|
10240
|
+
* This segment class imposes no length restrictions, but QR Codes have restrictions.
|
10241
|
+
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
|
10242
|
+
* Any segment longer than this is meaningless for the purpose of generating QR Codes.
|
10243
|
+
*/
|
10244
|
+
class QrSegment {
|
10245
|
+
mode;
|
10246
|
+
numChars;
|
10247
|
+
bitData;
|
10248
|
+
/*-- Static factory functions (mid level) --*/
|
10249
|
+
// Returns a segment representing the given binary data encoded in
|
10250
|
+
// byte mode. All input byte arrays are acceptable. Any text string
|
10251
|
+
// can be converted to UTF-8 bytes and encoded as a byte mode segment.
|
10252
|
+
static makeBytes(data) {
|
10253
|
+
let bb = [];
|
10254
|
+
for (const b of data)
|
10255
|
+
appendBits(b, 8, bb);
|
10256
|
+
return new QrSegment(QrSegment.Mode.BYTE, data.length, bb);
|
10257
|
+
}
|
10258
|
+
// Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
10259
|
+
static makeNumeric(digits) {
|
10260
|
+
if (!QrSegment.isNumeric(digits))
|
10261
|
+
throw new RangeError("String contains non-numeric characters");
|
10262
|
+
let bb = [];
|
10263
|
+
for (let i = 0; i < digits.length;) { // Consume up to 3 digits per iteration
|
10264
|
+
const n = Math.min(digits.length - i, 3);
|
10265
|
+
appendBits(parseInt(digits.substring(i, i + n), 10), n * 3 + 1, bb);
|
10266
|
+
i += n;
|
10267
|
+
}
|
10268
|
+
return new QrSegment(QrSegment.Mode.NUMERIC, digits.length, bb);
|
10269
|
+
}
|
10270
|
+
// Returns a segment representing the given text string encoded in alphanumeric mode.
|
10271
|
+
// The characters allowed are: 0 to 9, A to Z (uppercase only), space,
|
10272
|
+
// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
10273
|
+
static makeAlphanumeric(text) {
|
10274
|
+
if (!QrSegment.isAlphanumeric(text))
|
10275
|
+
throw new RangeError("String contains unencodable characters in alphanumeric mode");
|
10276
|
+
let bb = [];
|
10277
|
+
let i;
|
10278
|
+
for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2
|
10279
|
+
let temp = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
|
10280
|
+
temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
|
10281
|
+
appendBits(temp, 11, bb);
|
10282
|
+
}
|
10283
|
+
if (i < text.length) // 1 character remaining
|
10284
|
+
appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6, bb);
|
10285
|
+
return new QrSegment(QrSegment.Mode.ALPHANUMERIC, text.length, bb);
|
10286
|
+
}
|
10287
|
+
// Returns a new mutable list of zero or more segments to represent the given Unicode text string.
|
10288
|
+
// The result may use various segment modes and switch modes to optimize the length of the bit stream.
|
10289
|
+
static makeSegments(text) {
|
10290
|
+
// Select the most efficient segment encoding automatically
|
10291
|
+
if (text == "")
|
10292
|
+
return [];
|
10293
|
+
else if (QrSegment.isNumeric(text))
|
10294
|
+
return [QrSegment.makeNumeric(text)];
|
10295
|
+
else if (QrSegment.isAlphanumeric(text))
|
10296
|
+
return [QrSegment.makeAlphanumeric(text)];
|
10297
|
+
else
|
10298
|
+
return [QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))];
|
10299
|
+
}
|
10300
|
+
// Returns a segment representing an Extended Channel Interpretation
|
10301
|
+
// (ECI) designator with the given assignment value.
|
10302
|
+
static makeEci(assignVal) {
|
10303
|
+
let bb = [];
|
10304
|
+
if (assignVal < 0)
|
10305
|
+
throw new RangeError("ECI assignment value out of range");
|
10306
|
+
else if (assignVal < (1 << 7))
|
10307
|
+
appendBits(assignVal, 8, bb);
|
10308
|
+
else if (assignVal < (1 << 14)) {
|
10309
|
+
appendBits(0b10, 2, bb);
|
10310
|
+
appendBits(assignVal, 14, bb);
|
10311
|
+
}
|
10312
|
+
else if (assignVal < 1000000) {
|
10313
|
+
appendBits(0b110, 3, bb);
|
10314
|
+
appendBits(assignVal, 21, bb);
|
10315
|
+
}
|
10316
|
+
else
|
10317
|
+
throw new RangeError("ECI assignment value out of range");
|
10318
|
+
return new QrSegment(QrSegment.Mode.ECI, 0, bb);
|
10319
|
+
}
|
10320
|
+
// Tests whether the given string can be encoded as a segment in numeric mode.
|
10321
|
+
// A string is encodable iff each character is in the range 0 to 9.
|
10322
|
+
static isNumeric(text) {
|
10323
|
+
return QrSegment.NUMERIC_REGEX.test(text);
|
10324
|
+
}
|
10325
|
+
// Tests whether the given string can be encoded as a segment in alphanumeric mode.
|
10326
|
+
// A string is encodable iff each character is in the following set: 0 to 9, A to Z
|
10327
|
+
// (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
10328
|
+
static isAlphanumeric(text) {
|
10329
|
+
return QrSegment.ALPHANUMERIC_REGEX.test(text);
|
10330
|
+
}
|
10331
|
+
/*-- Constructor (low level) and fields --*/
|
10332
|
+
// Creates a new QR Code segment with the given attributes and data.
|
10333
|
+
// The character count (numChars) must agree with the mode and the bit buffer length,
|
10334
|
+
// but the constraint isn't checked. The given bit buffer is cloned and stored.
|
10335
|
+
constructor(
|
10336
|
+
// The mode indicator of this segment.
|
10337
|
+
mode,
|
10338
|
+
// The length of this segment's unencoded data. Measured in characters for
|
10339
|
+
// numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
|
10340
|
+
// Always zero or positive. Not the same as the data's bit length.
|
10341
|
+
numChars,
|
10342
|
+
// The data bits of this segment. Accessed through getData().
|
10343
|
+
bitData) {
|
10344
|
+
this.mode = mode;
|
10345
|
+
this.numChars = numChars;
|
10346
|
+
this.bitData = bitData;
|
10347
|
+
if (numChars < 0)
|
10348
|
+
throw new RangeError("Invalid argument");
|
10349
|
+
this.bitData = bitData.slice(); // Make defensive copy
|
10350
|
+
}
|
10351
|
+
/*-- Methods --*/
|
10352
|
+
// Returns a new copy of the data bits of this segment.
|
10353
|
+
getData() {
|
10354
|
+
return this.bitData.slice(); // Make defensive copy
|
10355
|
+
}
|
10356
|
+
// (Package-private) Calculates and returns the number of bits needed to encode the given segments at
|
10357
|
+
// the given version. The result is infinity if a segment has too many characters to fit its length field.
|
10358
|
+
static getTotalBits(segs, version) {
|
10359
|
+
let result = 0;
|
10360
|
+
for (const seg of segs) {
|
10361
|
+
const ccbits = seg.mode.numCharCountBits(version);
|
10362
|
+
if (seg.numChars >= (1 << ccbits))
|
10363
|
+
return Infinity; // The segment's length doesn't fit the field's bit width
|
10364
|
+
result += 4 + ccbits + seg.bitData.length;
|
10365
|
+
}
|
10366
|
+
return result;
|
10367
|
+
}
|
10368
|
+
// Returns a new array of bytes representing the given string encoded in UTF-8.
|
10369
|
+
static toUtf8ByteArray(str) {
|
10370
|
+
str = encodeURI(str);
|
10371
|
+
let result = [];
|
10372
|
+
for (let i = 0; i < str.length; i++) {
|
10373
|
+
if (str.charAt(i) != "%")
|
10374
|
+
result.push(str.charCodeAt(i));
|
10375
|
+
else {
|
10376
|
+
result.push(parseInt(str.substring(i + 1, i + 3), 16));
|
10377
|
+
i += 2;
|
10378
|
+
}
|
10379
|
+
}
|
10380
|
+
return result;
|
10381
|
+
}
|
10382
|
+
/*-- Constants --*/
|
10383
|
+
// Describes precisely all strings that are encodable in numeric mode.
|
10384
|
+
static NUMERIC_REGEX = /^[0-9]*$/;
|
10385
|
+
// Describes precisely all strings that are encodable in alphanumeric mode.
|
10386
|
+
static ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/;
|
10387
|
+
// The set of all legal characters in alphanumeric mode,
|
10388
|
+
// where each character value maps to the index in the string.
|
10389
|
+
static ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
10390
|
+
}
|
10391
|
+
qrcodegen.QrSegment = QrSegment;
|
10392
|
+
})(qrcodegen || (qrcodegen = {}));
|
10393
|
+
/*---- Public helper enumeration ----*/
|
10394
|
+
(function (qrcodegen) {
|
10395
|
+
(function (QrCode) {
|
10396
|
+
/*
|
10397
|
+
* The error correction level in a QR Code symbol. Immutable.
|
10398
|
+
*/
|
10399
|
+
class Ecc {
|
10400
|
+
ordinal;
|
10401
|
+
formatBits;
|
10402
|
+
/*-- Constants --*/
|
10403
|
+
static LOW = new Ecc(0, 1); // The QR Code can tolerate about 7% erroneous codewords
|
10404
|
+
static MEDIUM = new Ecc(1, 0); // The QR Code can tolerate about 15% erroneous codewords
|
10405
|
+
static QUARTILE = new Ecc(2, 3); // The QR Code can tolerate about 25% erroneous codewords
|
10406
|
+
static HIGH = new Ecc(3, 2); // The QR Code can tolerate about 30% erroneous codewords
|
10407
|
+
/*-- Constructor and fields --*/
|
10408
|
+
constructor(
|
10409
|
+
// In the range 0 to 3 (unsigned 2-bit integer).
|
10410
|
+
ordinal,
|
10411
|
+
// (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
|
10412
|
+
formatBits) {
|
10413
|
+
this.ordinal = ordinal;
|
10414
|
+
this.formatBits = formatBits;
|
10415
|
+
}
|
10416
|
+
}
|
10417
|
+
QrCode.Ecc = Ecc;
|
10418
|
+
})(qrcodegen.QrCode || (qrcodegen.QrCode = {}));
|
10419
|
+
})(qrcodegen || (qrcodegen = {}));
|
10420
|
+
/*---- Public helper enumeration ----*/
|
10421
|
+
(function (qrcodegen) {
|
10422
|
+
(function (QrSegment) {
|
10423
|
+
/*
|
10424
|
+
* Describes how a segment's data bits are interpreted. Immutable.
|
10425
|
+
*/
|
10426
|
+
class Mode {
|
10427
|
+
modeBits;
|
10428
|
+
numBitsCharCount;
|
10429
|
+
/*-- Constants --*/
|
10430
|
+
static NUMERIC = new Mode(0x1, [10, 12, 14]);
|
10431
|
+
static ALPHANUMERIC = new Mode(0x2, [9, 11, 13]);
|
10432
|
+
static BYTE = new Mode(0x4, [8, 16, 16]);
|
10433
|
+
static KANJI = new Mode(0x8, [8, 10, 12]);
|
10434
|
+
static ECI = new Mode(0x7, [0, 0, 0]);
|
10435
|
+
/*-- Constructor and fields --*/
|
10436
|
+
constructor(
|
10437
|
+
// The mode indicator bits, which is a uint4 value (range 0 to 15).
|
10438
|
+
modeBits,
|
10439
|
+
// Number of character count bits for three different version ranges.
|
10440
|
+
numBitsCharCount) {
|
10441
|
+
this.modeBits = modeBits;
|
10442
|
+
this.numBitsCharCount = numBitsCharCount;
|
10443
|
+
}
|
10444
|
+
/*-- Method --*/
|
10445
|
+
// (Package-private) Returns the bit width of the character count field for a segment in
|
10446
|
+
// this mode in a QR Code at the given version number. The result is in the range [0, 16].
|
10447
|
+
numCharCountBits(ver) {
|
10448
|
+
return this.numBitsCharCount[Math.floor((ver + 7) / 17)];
|
10449
|
+
}
|
10450
|
+
}
|
10451
|
+
QrSegment.Mode = Mode;
|
10452
|
+
})(qrcodegen.QrSegment || (qrcodegen.QrSegment = {}));
|
10453
|
+
})(qrcodegen || (qrcodegen = {}));
|
10454
|
+
|
9580
10455
|
class DataElementBarcode extends DataElementLeaf {
|
9581
10456
|
resizeable = true;
|
9582
10457
|
barCodeCanvas;
|
@@ -9591,6 +10466,11 @@ class DataElementBarcode extends DataElementLeaf {
|
|
9591
10466
|
this.cache = false;
|
9592
10467
|
});
|
9593
10468
|
}
|
10469
|
+
//伸缩的模式,auto:可以任意伸缩高度和宽度,scale:只能等比例伸缩高度宽度
|
10470
|
+
//resizeMode:'auto'|'scale'='auto';
|
10471
|
+
get resizeMode() {
|
10472
|
+
return this.props.type === 'qrcode';
|
10473
|
+
}
|
9594
10474
|
createRenderObject() {
|
9595
10475
|
const render = new DataElementBarcodeRenderObject(this);
|
9596
10476
|
render.rect.width = this.props.width + 2;
|
@@ -9672,6 +10552,62 @@ class DataElementBarcodeRenderObject extends ResizeLeafRenderObject {
|
|
9672
10552
|
ctxNative.fill();
|
9673
10553
|
ctxNative.restore();
|
9674
10554
|
}
|
10555
|
+
exportHTML(event) {
|
10556
|
+
const t = super.exportHTML(event);
|
10557
|
+
if (this.element.props.type === 'qrcode') {
|
10558
|
+
const QRC = qrcodegen.QrCode;
|
10559
|
+
const qr0 = QRC.encodeText(this.element.props.text, QRC.Ecc.MEDIUM);
|
10560
|
+
t.children = [this.toSvgString(qr0, 2, '#000', '#000')];
|
10561
|
+
}
|
10562
|
+
else {
|
10563
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
10564
|
+
JsBarcode__default["default"](svg, this.element.props.text);
|
10565
|
+
const vNode = snabbdom.toVNode(svg);
|
10566
|
+
t.children = [vNode];
|
10567
|
+
}
|
10568
|
+
return t;
|
10569
|
+
}
|
10570
|
+
toSvgString(qr, border, lightColor, darkColor) {
|
10571
|
+
let parts = [];
|
10572
|
+
for (let y = 0; y < qr.size; y++) {
|
10573
|
+
for (let x = 0; x < qr.size; x++) {
|
10574
|
+
if (qr.getModule(x, y))
|
10575
|
+
parts.push(`M${x + border},${y + border}h1v1h-1z`);
|
10576
|
+
}
|
10577
|
+
}
|
10578
|
+
return {
|
10579
|
+
sel: 'svg',
|
10580
|
+
data: {
|
10581
|
+
ns: 'http://www.w3.org/2000/svg',
|
10582
|
+
attrs: {
|
10583
|
+
viewBox: `0 0 ${qr.size + border * 2} ${qr.size + border * 2}`,
|
10584
|
+
width: this.element.props.width,
|
10585
|
+
height: this.element.props.height,
|
10586
|
+
stroke: 'none'
|
10587
|
+
}
|
10588
|
+
},
|
10589
|
+
children: [{
|
10590
|
+
sel: 'rect',
|
10591
|
+
data: {
|
10592
|
+
ns: 'http://www.w3.org/2000/svg',
|
10593
|
+
attrs: {
|
10594
|
+
width: '100%',
|
10595
|
+
height: '100%',
|
10596
|
+
fill: '#fff'
|
10597
|
+
}
|
10598
|
+
}
|
10599
|
+
}, {
|
10600
|
+
sel: 'path',
|
10601
|
+
data: {
|
10602
|
+
ns: 'http://www.w3.org/2000/svg',
|
10603
|
+
attrs: {
|
10604
|
+
d: parts.join(" "),
|
10605
|
+
fill: '#000'
|
10606
|
+
}
|
10607
|
+
}
|
10608
|
+
}]
|
10609
|
+
};
|
10610
|
+
}
|
9675
10611
|
}
|
9676
10612
|
class DataElementBarcodeFactory extends ElementFactory {
|
9677
10613
|
match(type) {
|
@@ -10366,6 +11302,57 @@ class DataElementListFactory extends DataElementBaseFactory {
|
|
10366
11302
|
}
|
10367
11303
|
}
|
10368
11304
|
|
11305
|
+
class BreakElement extends LeafElement {
|
11306
|
+
textProps;
|
11307
|
+
constructor() {
|
11308
|
+
super('br');
|
11309
|
+
this.textProps = new TextProps();
|
11310
|
+
this.textProps.fontSize = 14;
|
11311
|
+
this.textProps.fontName = '宋体';
|
11312
|
+
this.textProps.color = '#595959';
|
11313
|
+
}
|
11314
|
+
createRenderObject() {
|
11315
|
+
const symbol = new BreakRenderObject(this);
|
11316
|
+
symbol.rect.height = 14;
|
11317
|
+
symbol.rect.width = 7;
|
11318
|
+
return symbol;
|
11319
|
+
}
|
11320
|
+
serialize() {
|
11321
|
+
return {
|
11322
|
+
type: 'br',
|
11323
|
+
props: {}
|
11324
|
+
};
|
11325
|
+
}
|
11326
|
+
clone() {
|
11327
|
+
const clone = new BreakElement();
|
11328
|
+
//clone.renderCtx = this.renderCtx;
|
11329
|
+
return clone;
|
11330
|
+
}
|
11331
|
+
}
|
11332
|
+
class BreakRenderObject extends LeafRenderObject {
|
11333
|
+
render(e) {
|
11334
|
+
const { render, position } = e;
|
11335
|
+
if (render.drawMode === 'print') {
|
11336
|
+
return;
|
11337
|
+
}
|
11338
|
+
render.contentContext.drawText('↓', this.element.textProps, position.x, position.y, 20, this.rect.height);
|
11339
|
+
}
|
11340
|
+
clone() {
|
11341
|
+
const render = new BreakRenderObject(this.element);
|
11342
|
+
render.rect = ElementUtil.cloneRect(this.rect);
|
11343
|
+
return render;
|
11344
|
+
}
|
11345
|
+
}
|
11346
|
+
class BreakFactory extends ElementFactory {
|
11347
|
+
match(type) {
|
11348
|
+
return type === 'br';
|
11349
|
+
}
|
11350
|
+
createElement(data) {
|
11351
|
+
const ele = new BreakElement();
|
11352
|
+
return ele;
|
11353
|
+
}
|
11354
|
+
}
|
11355
|
+
|
10369
11356
|
class DataElementText extends DataElementInlineGroup {
|
10370
11357
|
//props: DataEleBaseTextProps;
|
10371
11358
|
constructor() {
|
@@ -10396,10 +11383,19 @@ class DataElementText extends DataElementInlineGroup {
|
|
10396
11383
|
this.pubOnChange('self');
|
10397
11384
|
this.clearInnerItems();
|
10398
11385
|
if (val) {
|
10399
|
-
const
|
10400
|
-
|
10401
|
-
|
10402
|
-
|
11386
|
+
const items = val.split('<br/>');
|
11387
|
+
if (items.length) {
|
11388
|
+
items.forEach((item, index) => {
|
11389
|
+
const valueText = new TextGroupElement();
|
11390
|
+
this.props.valueTextProps.clone(valueText.props);
|
11391
|
+
valueText.text = item + '';
|
11392
|
+
this.addChild(valueText, this.length - 1);
|
11393
|
+
if (index < items.length - 1) {
|
11394
|
+
const brElement = new BreakElement();
|
11395
|
+
this.addChild(brElement, this.length - 1);
|
11396
|
+
}
|
11397
|
+
});
|
11398
|
+
}
|
10403
11399
|
}
|
10404
11400
|
this.onChangedValidate();
|
10405
11401
|
}
|
@@ -11116,57 +12112,6 @@ class RadioBoxRenderObject extends LeafRenderObject {
|
|
11116
12112
|
}
|
11117
12113
|
}
|
11118
12114
|
|
11119
|
-
class BreakElement extends LeafElement {
|
11120
|
-
textProps;
|
11121
|
-
constructor() {
|
11122
|
-
super('br');
|
11123
|
-
this.textProps = new TextProps();
|
11124
|
-
this.textProps.fontSize = 14;
|
11125
|
-
this.textProps.fontName = '宋体';
|
11126
|
-
this.textProps.color = '#595959';
|
11127
|
-
}
|
11128
|
-
createRenderObject() {
|
11129
|
-
const symbol = new BreakRenderObject(this);
|
11130
|
-
symbol.rect.height = 14;
|
11131
|
-
symbol.rect.width = 7;
|
11132
|
-
return symbol;
|
11133
|
-
}
|
11134
|
-
serialize() {
|
11135
|
-
return {
|
11136
|
-
type: 'br',
|
11137
|
-
props: {}
|
11138
|
-
};
|
11139
|
-
}
|
11140
|
-
clone() {
|
11141
|
-
const clone = new BreakElement();
|
11142
|
-
//clone.renderCtx = this.renderCtx;
|
11143
|
-
return clone;
|
11144
|
-
}
|
11145
|
-
}
|
11146
|
-
class BreakRenderObject extends LeafRenderObject {
|
11147
|
-
render(e) {
|
11148
|
-
const { render, position } = e;
|
11149
|
-
if (render.drawMode === 'print') {
|
11150
|
-
return;
|
11151
|
-
}
|
11152
|
-
render.contentContext.drawText('↓', this.element.textProps, position.x, position.y, 20, this.rect.height);
|
11153
|
-
}
|
11154
|
-
clone() {
|
11155
|
-
const render = new BreakRenderObject(this.element);
|
11156
|
-
render.rect = ElementUtil.cloneRect(this.rect);
|
11157
|
-
return render;
|
11158
|
-
}
|
11159
|
-
}
|
11160
|
-
class BreakFactory extends ElementFactory {
|
11161
|
-
match(type) {
|
11162
|
-
return type === 'br';
|
11163
|
-
}
|
11164
|
-
createElement(data) {
|
11165
|
-
const ele = new BreakElement();
|
11166
|
-
return ele;
|
11167
|
-
}
|
11168
|
-
}
|
11169
|
-
|
11170
12115
|
class ColumnPatchUtil {
|
11171
12116
|
static getPatchPacks(cols, splitCols) {
|
11172
12117
|
const oldLinePointMap = this.getLinePointMap(cols);
|
@@ -15991,7 +16936,7 @@ class DocumentEvent {
|
|
15991
16936
|
//如果单元格中包含图片等可缩放的元素,并且元素的大小超过单元格,则当前图片的某一部分就无法缩放
|
15992
16937
|
if (!this.ismousedown && this.focusedElement && this.focusedRect && this.focusedElement['resizeable']) {
|
15993
16938
|
const relativePos = { x: mousePos.x - this.focusedRect.x, y: mousePos.y - this.focusedRect.y };
|
15994
|
-
|
16939
|
+
let isInCellBorder = CommonUtil.isInPictureResizePoint(this.focusedRect, relativePos, 4);
|
15995
16940
|
if (isInCellBorder) {
|
15996
16941
|
cursorType = ElementUtil.getBorderCursor(isInCellBorder.borderType);
|
15997
16942
|
if (isInCellBorder?.borderType === 'none') {
|
@@ -16593,6 +17538,7 @@ class DocumentEvent {
|
|
16593
17538
|
const mousedownPos = this.edgeRenderInfo.mousedownPos;
|
16594
17539
|
let moveDistanceX = this.currentPos.x - mousedownPos.x;
|
16595
17540
|
let moveDistanceY = this.currentPos.y - mousedownPos.y;
|
17541
|
+
const isScale = imgElement['resizeMode'] === 'scale' || e.shift;
|
16596
17542
|
if (['left-top', 'left-middle', 'left-bottom', 'right-top', 'right-middle', 'right-bottom', 'top-middle', 'bottom-middle'].indexOf(border) >= 0) {
|
16597
17543
|
if (['left-middle', 'right-middle'].indexOf(border) >= 0) {
|
16598
17544
|
moveDistanceY = 0;
|
@@ -16601,7 +17547,7 @@ class DocumentEvent {
|
|
16601
17547
|
moveDistanceX = 0;
|
16602
17548
|
}
|
16603
17549
|
//shift键按比例缩放
|
16604
|
-
if (
|
17550
|
+
if (isScale || ['left-top', 'right-top', 'left-bottom', 'right-bottom'].indexOf(border) >= 0) {
|
16605
17551
|
let scale = 1;
|
16606
17552
|
if (Math.abs(moveDistanceX) > Math.abs(moveDistanceY)) {
|
16607
17553
|
scale = moveDistanceX / imgElement.props.width;
|
@@ -16963,55 +17909,6 @@ class DocumentInput {
|
|
16963
17909
|
onTabKeyEvent = new Subject$1();
|
16964
17910
|
constructor(docCtx) {
|
16965
17911
|
this.docCtx = docCtx;
|
16966
|
-
// const os = ElementUtil.getOSPlatform();
|
16967
|
-
// this.bindInput(node);
|
16968
|
-
// node.addEventListener('keydown', evt => {
|
16969
|
-
// const keyEvent = new KeyboradElementEvent(this.docCtx);
|
16970
|
-
// keyEvent.sourceEvent = evt;
|
16971
|
-
// if (DocumentEvent.invokeEvent('ElementKeyDown', this.docCtx.selectionState.startControl as LeafElement, keyEvent, 'All')) {
|
16972
|
-
// return;
|
16973
|
-
// }
|
16974
|
-
// if (evt.keyCode === 8) {
|
16975
|
-
// this.onBackspaceEvent.next(evt);
|
16976
|
-
// } else if (evt.keyCode === 13 && !evt.shiftKey) {
|
16977
|
-
// this.onEnterEvent.next();
|
16978
|
-
// } else if (evt.keyCode === 37) {
|
16979
|
-
// this.onLeftEvent.next();
|
16980
|
-
// } else if (evt.keyCode === 39) {
|
16981
|
-
// this.onRightEvent.next();
|
16982
|
-
// } else if (evt.keyCode === 38) {
|
16983
|
-
// this.onUpEvent.next();
|
16984
|
-
// } else if (evt.keyCode === 40) {
|
16985
|
-
// this.onDownEvent.next();
|
16986
|
-
// } else if (evt.keyCode === 9) {
|
16987
|
-
// evt.preventDefault();
|
16988
|
-
// this.onTabKeyEvent.next();
|
16989
|
-
// } else if (evt.keyCode === 13 && evt.shiftKey) {
|
16990
|
-
// evt.preventDefault();
|
16991
|
-
// this.onInsertBr.next();
|
16992
|
-
// } else if (evt.keyCode === 46) {
|
16993
|
-
// this.onDeleteEvent.next(evt);
|
16994
|
-
// } else if (evt.ctrlKey && evt.keyCode === 65 && os !== 'Mac') {
|
16995
|
-
// evt.preventDefault();
|
16996
|
-
// this.onSelectAllEvent.next();
|
16997
|
-
// } else if (evt.metaKey && evt.keyCode === 65 && os === 'Mac') {
|
16998
|
-
// evt.preventDefault();
|
16999
|
-
// this.onSelectAllEvent.next();
|
17000
|
-
// } else if (evt.keyCode === 36) {
|
17001
|
-
// this.onHomeEvent.next();
|
17002
|
-
// } else if (evt.keyCode === 35) {
|
17003
|
-
// this.onEndEvent.next();
|
17004
|
-
// }
|
17005
|
-
// });
|
17006
|
-
// node.addEventListener('copy', evt => {
|
17007
|
-
// this.onCopyEvent.next(evt);
|
17008
|
-
// });
|
17009
|
-
// node.addEventListener('paste', evt => {
|
17010
|
-
// this.onPasteEvent.next(evt);
|
17011
|
-
// })
|
17012
|
-
// node.addEventListener('cut', evt => {
|
17013
|
-
// this.onCutEvent.next(evt);
|
17014
|
-
// })
|
17015
17912
|
}
|
17016
17913
|
getEventListener() {
|
17017
17914
|
const os = ElementUtil.getOSPlatform();
|
@@ -18750,6 +19647,18 @@ function printNodes(printNodes, options, printEvent = null) {
|
|
18750
19647
|
}
|
18751
19648
|
printIFrame.onload = () => {
|
18752
19649
|
setTimeout(() => {
|
19650
|
+
printIFrame.contentWindow?.window.matchMedia('print').addListener(function (query) {
|
19651
|
+
if (!query.matches) {
|
19652
|
+
console.log('用户已经打印');
|
19653
|
+
// 执行打印完成后需要执行的代码
|
19654
|
+
}
|
19655
|
+
});
|
19656
|
+
printIFrame.contentWindow?.window.matchMedia('screen').addListener(function (query) {
|
19657
|
+
if (!query.matches) {
|
19658
|
+
console.log('用户已经打印');
|
19659
|
+
// 执行打印完成后需要执行的代码
|
19660
|
+
}
|
19661
|
+
});
|
18753
19662
|
printIFrame.contentWindow?.print();
|
18754
19663
|
printIFrame.parentNode?.removeChild(printIFrame);
|
18755
19664
|
}, 0);
|
@@ -24622,18 +25531,12 @@ class DocumentPrintOffscreenBase {
|
|
24622
25531
|
const docSvgHelper = new DocumentSvg(this.viewOptions, new Map(), this.renderCtx); //.getHTMLVNode(docRenders) as Array<EditorVNodeObject>;
|
24623
25532
|
docSvgHelper.mode = 'print';
|
24624
25533
|
const pageSvgVNodes = docRenders.filter((item, index) => !printRanges || printRanges.indexOf(index) >= 0).map(item => docSvgHelper.getPageSvgVNode(item));
|
24625
|
-
({
|
24626
|
-
sel: 'div#docContent',
|
24627
|
-
data: {},
|
24628
|
-
children: [...pageSvgVNodes]
|
24629
|
-
});
|
24630
25534
|
const patch = init([
|
24631
25535
|
modules.class,
|
24632
25536
|
modules.props,
|
24633
25537
|
modules.attributes,
|
24634
25538
|
modules.style
|
24635
25539
|
]);
|
24636
|
-
new DOMParser();
|
24637
25540
|
const domNodes = pageSvgVNodes.map(item => patch(item)); //.map(item => docParser.parseFromString(item, 'text/html').firstChild) as Array<HTMLElement>;
|
24638
25541
|
return domNodes;
|
24639
25542
|
}
|
@@ -24693,12 +25596,16 @@ class EditorCalendarVNode {
|
|
24693
25596
|
selectedDate;
|
24694
25597
|
currentDate = '';
|
24695
25598
|
onSetValue = new Subject$1();
|
25599
|
+
currTime;
|
25600
|
+
selectedTime;
|
24696
25601
|
constructor() {
|
24697
25602
|
this.currYear = createSignal(new Date().getFullYear());
|
24698
25603
|
//月份赋值是按照索引来的,所以要减1
|
24699
25604
|
this.currMonth = createSignal(new Date().getMonth());
|
24700
25605
|
this.currCalendarMode = createSignal('day');
|
24701
25606
|
this.selectedDate = createSignal(null);
|
25607
|
+
this.currTime = createSignal(null);
|
25608
|
+
this.selectedTime = createSignal(null);
|
24702
25609
|
}
|
24703
25610
|
reset() {
|
24704
25611
|
this.currYear.value = new Date().getFullYear();
|
@@ -24707,6 +25614,8 @@ class EditorCalendarVNode {
|
|
24707
25614
|
this.currCalendarMode.value = 'day';
|
24708
25615
|
this.selectedDate.value = moment__default["default"]().format('YYYY-MM-DD');
|
24709
25616
|
this.currentDate = '';
|
25617
|
+
this.currTime.value = null;
|
25618
|
+
this.selectedTime.value = null;
|
24710
25619
|
}
|
24711
25620
|
render(position, dataValue) {
|
24712
25621
|
if (!this.currentDate && dataValue) {
|
@@ -24718,6 +25627,10 @@ class EditorCalendarVNode {
|
|
24718
25627
|
if (!this.currentDate) {
|
24719
25628
|
this.currentDate = moment__default["default"]().format('YYYY-MM-DD');
|
24720
25629
|
}
|
25630
|
+
if (!this.currTime.value) {
|
25631
|
+
this.currTime.value = moment__default["default"]().format('HH:mm:ss');
|
25632
|
+
this.selectedTime.value = this.currTime.value;
|
25633
|
+
}
|
24721
25634
|
const container = this.renderDropContainer(position);
|
24722
25635
|
let viewNode;
|
24723
25636
|
if (this.currCalendarMode.value === 'day') {
|
@@ -24844,6 +25757,31 @@ class EditorCalendarVNode {
|
|
24844
25757
|
sel: 'div.editor-calendar-footer',
|
24845
25758
|
data: {},
|
24846
25759
|
children: [{
|
25760
|
+
sel: 'div.editor-calendar-footer-left',
|
25761
|
+
data: {},
|
25762
|
+
children: [
|
25763
|
+
{
|
25764
|
+
sel: 'input.editor-calendar-footer-left-time',
|
25765
|
+
data: {
|
25766
|
+
attrs: {
|
25767
|
+
value: this.currTime.value
|
25768
|
+
},
|
25769
|
+
on: {
|
25770
|
+
change: (event) => {
|
25771
|
+
if (moment__default["default"](event.target.value, 'HH:mm:ss').isValid()) {
|
25772
|
+
this.selectedTime = event.target.value;
|
25773
|
+
}
|
25774
|
+
else {
|
25775
|
+
event.target.value = this.currTime.value;
|
25776
|
+
this.currTime.onChange();
|
25777
|
+
}
|
25778
|
+
}
|
25779
|
+
}
|
25780
|
+
}
|
25781
|
+
}
|
25782
|
+
]
|
25783
|
+
},
|
25784
|
+
{
|
24847
25785
|
sel: 'div.editor-calendar-footer-right',
|
24848
25786
|
data: {},
|
24849
25787
|
children: [{
|
@@ -24855,7 +25793,7 @@ class EditorCalendarVNode {
|
|
24855
25793
|
this.onSetValue.next(new Date());
|
24856
25794
|
}
|
24857
25795
|
else {
|
24858
|
-
this.onSetValue.next(moment__default["default"](this.selectedDate.value).toDate());
|
25796
|
+
this.onSetValue.next(moment__default["default"](this.selectedDate.value + ' ' + this.selectedTime.value).toDate());
|
24859
25797
|
}
|
24860
25798
|
}
|
24861
25799
|
}
|
@@ -25898,12 +26836,18 @@ class DocEditor {
|
|
25898
26836
|
*/
|
25899
26837
|
getCurrentDataElement() {
|
25900
26838
|
const selectionState = this.documentSelection.selectionState;
|
25901
|
-
const { startControl } = selectionState;
|
26839
|
+
const { startControl, startOffset } = selectionState;
|
25902
26840
|
if (startControl) {
|
25903
26841
|
if (!ElementUtil.verifyHitable(startControl)) {
|
25904
26842
|
return null;
|
25905
26843
|
}
|
25906
|
-
|
26844
|
+
const dataEle = ElementUtil.getParent(startControl, validateDataEle);
|
26845
|
+
if (IsInSideDataElement(startControl, startOffset)) {
|
26846
|
+
return dataEle;
|
26847
|
+
}
|
26848
|
+
else {
|
26849
|
+
return null;
|
26850
|
+
}
|
25907
26851
|
}
|
25908
26852
|
return null;
|
25909
26853
|
}
|
@@ -26486,7 +27430,7 @@ class DocEditor {
|
|
26486
27430
|
const vNodeFunc = this.renderRoot();
|
26487
27431
|
setActiveEditorContext(null);
|
26488
27432
|
const render = () => {
|
26489
|
-
console.time('patch');
|
27433
|
+
//console.time('patch');
|
26490
27434
|
setActiveEditorContext(this);
|
26491
27435
|
const vNode = vNodeFunc.render();
|
26492
27436
|
setActiveEditorContext(null);
|
@@ -26498,7 +27442,7 @@ class DocEditor {
|
|
26498
27442
|
this.vNodeDocContent = this.nodePatch(this.svgContainer, vNode);
|
26499
27443
|
}
|
26500
27444
|
this.afterNodePatch.next();
|
26501
|
-
console.timeEnd('patch');
|
27445
|
+
//console.timeEnd('patch');
|
26502
27446
|
};
|
26503
27447
|
render();
|
26504
27448
|
this.onShouldRender.subscribe(() => {
|
@@ -26590,8 +27534,10 @@ class DocEditor {
|
|
26590
27534
|
}
|
26591
27535
|
getHtml() {
|
26592
27536
|
const offPrint = new DocumentPrintOffscreen();
|
26593
|
-
offPrint.beforePrint.subscribe(() => {
|
26594
|
-
|
27537
|
+
offPrint.beforePrint.subscribe(() => {
|
27538
|
+
});
|
27539
|
+
offPrint.afterPrint.subscribe(() => {
|
27540
|
+
});
|
26595
27541
|
const html = offPrint.getSvgNodes(this.docCtx.document.paintRenders);
|
26596
27542
|
console.log(html);
|
26597
27543
|
}
|
@@ -26647,6 +27593,9 @@ class DocEditor {
|
|
26647
27593
|
const values = options.filter(item => item.checked).map(item => item.code);
|
26648
27594
|
dataEle.setValue(values);
|
26649
27595
|
editor.setDataElemEndFocus(dataEle);
|
27596
|
+
if (!multiSelect) {
|
27597
|
+
editor.selectionState.clear();
|
27598
|
+
}
|
26650
27599
|
};
|
26651
27600
|
const itemsVNode = options.map(item => {
|
26652
27601
|
const ckbVNode = {
|
@@ -26843,11 +27792,18 @@ const deleteCurrentParagraph = (evt) => {
|
|
26843
27792
|
selectionState.clear();
|
26844
27793
|
const psymbol = ElementUtil.getLastLeafElement(currentElement);
|
26845
27794
|
const nextFocusableEle = ElementUtil.getRecursionNextSiblingElement(psymbol, false, true, viewOptions);
|
27795
|
+
const parentContainer = currentElement.parent;
|
26846
27796
|
if (nextFocusableEle) {
|
26847
|
-
|
27797
|
+
if (nextFocusableEle.parent === parentContainer) {
|
27798
|
+
selectionState.resetRange(nextFocusableEle, 0);
|
27799
|
+
}
|
27800
|
+
else {
|
27801
|
+
selectionState.resetRange(parentContainer, 0);
|
27802
|
+
}
|
26848
27803
|
}
|
26849
27804
|
else {
|
26850
|
-
selectionState.
|
27805
|
+
selectionState.resetRange(parentContainer, 0);
|
27806
|
+
//selectionState.clear();
|
26851
27807
|
}
|
26852
27808
|
currentElement.remove();
|
26853
27809
|
currentElement.destroy();
|