@aiyiran/myclaw 1.0.227 → 1.0.229
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/assets/myclaw-artifacts.js +586 -5
- package/assets/myclaw-inject.js +226 -0
- package/gateway.js +11 -0
- package/package.json +1 -1
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
btn.id = 'myclaw-artifacts-btn';
|
|
63
63
|
btn.style.cssText = [
|
|
64
64
|
'position: fixed',
|
|
65
|
-
'top:
|
|
65
|
+
'top: 0px',
|
|
66
66
|
'right: 0',
|
|
67
67
|
'padding: 3px 10px',
|
|
68
68
|
'background: rgba(100, 100, 100, 0.7)',
|
|
@@ -107,10 +107,10 @@
|
|
|
107
107
|
panel.id = 'myclaw-artifacts-panel';
|
|
108
108
|
panel.style.cssText = [
|
|
109
109
|
'position: fixed',
|
|
110
|
-
'top:
|
|
110
|
+
'top: 30px',
|
|
111
111
|
'right: 0',
|
|
112
112
|
'width: 380px',
|
|
113
|
-
'max-height: calc(100vh -
|
|
113
|
+
'max-height: calc(100vh - 550px)',
|
|
114
114
|
'background: #1e1e2e',
|
|
115
115
|
'border-radius: 8px 0 0 8px',
|
|
116
116
|
'overflow: hidden',
|
|
@@ -627,14 +627,18 @@
|
|
|
627
627
|
body: JSON.stringify(payload),
|
|
628
628
|
})
|
|
629
629
|
.then(function (res) { return res.json(); })
|
|
630
|
-
.then(function (
|
|
631
|
-
console.log('[myclaw-artifacts-publish]', payload,
|
|
630
|
+
.then(function (result) {
|
|
631
|
+
console.log('[myclaw-artifacts-publish]', payload, result);
|
|
632
|
+
if (result.code !== 0) {
|
|
633
|
+
throw new Error(result.msg || '\u53D1\u5E03\u5931\u8D25');
|
|
634
|
+
}
|
|
632
635
|
localStorage.setItem('myclaw-publish-cache', JSON.stringify({
|
|
633
636
|
title: titleVal,
|
|
634
637
|
cover_path: coverSelect.value || '',
|
|
635
638
|
entry_path: entrySelect.value || '',
|
|
636
639
|
}));
|
|
637
640
|
closePublishModal();
|
|
641
|
+
openPublishSuccessModal(result.data);
|
|
638
642
|
})
|
|
639
643
|
.catch(function (err) {
|
|
640
644
|
console.error('[myclaw-artifacts-publish] \u53D1\u5E03\u5931\u8D25:', err);
|
|
@@ -650,6 +654,579 @@
|
|
|
650
654
|
document.body.appendChild(overlay);
|
|
651
655
|
}
|
|
652
656
|
|
|
657
|
+
// ═══ 发布成功弹框 ═══
|
|
658
|
+
function openPublishSuccessModal(data) {
|
|
659
|
+
if (document.querySelector('#myclaw-publish-success')) return;
|
|
660
|
+
|
|
661
|
+
var overlay = document.createElement('div');
|
|
662
|
+
overlay.id = 'myclaw-publish-success';
|
|
663
|
+
overlay.style.cssText = [
|
|
664
|
+
'position: fixed',
|
|
665
|
+
'top: 0',
|
|
666
|
+
'left: 0',
|
|
667
|
+
'width: 100vw',
|
|
668
|
+
'height: 100vh',
|
|
669
|
+
'background: rgba(0, 0, 0, 0.5)',
|
|
670
|
+
'z-index: 99999',
|
|
671
|
+
'display: flex',
|
|
672
|
+
'align-items: center',
|
|
673
|
+
'justify-content: center',
|
|
674
|
+
'animation: myclaw-fade-in 0.2s ease',
|
|
675
|
+
].join(';');
|
|
676
|
+
|
|
677
|
+
var box = document.createElement('div');
|
|
678
|
+
box.style.cssText = [
|
|
679
|
+
'width: 440px',
|
|
680
|
+
'background: #1e1e2e',
|
|
681
|
+
'border-radius: 12px',
|
|
682
|
+
'overflow: hidden',
|
|
683
|
+
'display: flex',
|
|
684
|
+
'flex-direction: column',
|
|
685
|
+
'box-shadow: 0 12px 48px rgba(0,0,0,0.6)',
|
|
686
|
+
'animation: myclaw-success-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1)',
|
|
687
|
+
].join(';');
|
|
688
|
+
|
|
689
|
+
// 头部:庆祝动画区
|
|
690
|
+
var hero = document.createElement('div');
|
|
691
|
+
hero.style.cssText = [
|
|
692
|
+
'padding: 28px 24px 18px',
|
|
693
|
+
'text-align: center',
|
|
694
|
+
'background: linear-gradient(135deg, #2d2d5f 0%, #1e1e2e 100%)',
|
|
695
|
+
].join(';');
|
|
696
|
+
|
|
697
|
+
// emoji 庆祝
|
|
698
|
+
var emoji = document.createElement('div');
|
|
699
|
+
emoji.style.cssText = 'font-size: 48px;margin-bottom:8px;';
|
|
700
|
+
emoji.textContent = '\uD83C\uDF89';
|
|
701
|
+
hero.appendChild(emoji);
|
|
702
|
+
|
|
703
|
+
// 版本号大字
|
|
704
|
+
var versionNum = document.createElement('div');
|
|
705
|
+
versionNum.style.cssText = [
|
|
706
|
+
'font-size: 52px',
|
|
707
|
+
'font-weight: 900',
|
|
708
|
+
'font-family: monospace',
|
|
709
|
+
'color: #a78bfa',
|
|
710
|
+
'line-height: 1',
|
|
711
|
+
'text-shadow: 0 0 20px rgba(167,139,250,0.4)',
|
|
712
|
+
].join(';');
|
|
713
|
+
versionNum.textContent = 'v' + (data.version || '?');
|
|
714
|
+
hero.appendChild(versionNum);
|
|
715
|
+
|
|
716
|
+
var versionLabel = document.createElement('div');
|
|
717
|
+
versionLabel.style.cssText = 'font-size:12px;color:#888;margin-top:4px;font-family:monospace;';
|
|
718
|
+
versionLabel.textContent = '\u53D1\u5E03\u6210\u529F\uFF01';
|
|
719
|
+
hero.appendChild(versionLabel);
|
|
720
|
+
|
|
721
|
+
box.appendChild(hero);
|
|
722
|
+
|
|
723
|
+
// 信息区
|
|
724
|
+
var info = document.createElement('div');
|
|
725
|
+
info.style.cssText = 'padding:20px 24px;display:flex;flex-direction:column;gap:14px;';
|
|
726
|
+
|
|
727
|
+
// 作品标题
|
|
728
|
+
if (data.title) {
|
|
729
|
+
var titleRow = createInfoRow('\uD83C\uDFA8 \u4F5C\u54C1', data.title);
|
|
730
|
+
info.appendChild(titleRow);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// 封面
|
|
734
|
+
if (data.cover_path) {
|
|
735
|
+
var coverRow = createInfoRow('\uD83D\uDCF7 \u5C01\u9762', data.cover_path);
|
|
736
|
+
info.appendChild(coverRow);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// 入口文件
|
|
740
|
+
if (data.entry_path) {
|
|
741
|
+
var entryRow = createInfoRow('\uD83D\uDD17 \u5165\u53E3', data.entry_path);
|
|
742
|
+
info.appendChild(entryRow);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// 分割线
|
|
746
|
+
var divider = document.createElement('div');
|
|
747
|
+
divider.style.cssText = 'border-top:1px solid #3d3d5c;';
|
|
748
|
+
info.appendChild(divider);
|
|
749
|
+
|
|
750
|
+
// 分享链接区
|
|
751
|
+
var shareSection = document.createElement('div');
|
|
752
|
+
shareSection.style.cssText = 'display:flex;flex-direction:column;gap:8px;';
|
|
753
|
+
|
|
754
|
+
var shareLabel = document.createElement('div');
|
|
755
|
+
shareLabel.style.cssText = 'font-size:12px;color:#888;font-family:monospace;';
|
|
756
|
+
shareLabel.textContent = '\uD83D\uDD17 \u6C38\u4E45\u94FE\u63A5';
|
|
757
|
+
shareSection.appendChild(shareLabel);
|
|
758
|
+
|
|
759
|
+
var shareRow = document.createElement('div');
|
|
760
|
+
shareRow.style.cssText = 'display:flex;gap:8px;align-items:center;';
|
|
761
|
+
|
|
762
|
+
var urlInput = document.createElement('input');
|
|
763
|
+
urlInput.type = 'text';
|
|
764
|
+
urlInput.readOnly = true;
|
|
765
|
+
urlInput.value = data.permanent_url || '';
|
|
766
|
+
urlInput.style.cssText = [
|
|
767
|
+
'flex: 1',
|
|
768
|
+
'padding: 8px 10px',
|
|
769
|
+
'background: #252536',
|
|
770
|
+
'border: 1px solid #3d3d5c',
|
|
771
|
+
'border-radius: 4px',
|
|
772
|
+
'color: #cdd6f4',
|
|
773
|
+
'font-size: 11px',
|
|
774
|
+
'font-family: monospace',
|
|
775
|
+
'outline: none',
|
|
776
|
+
'overflow: hidden',
|
|
777
|
+
'text-overflow: ellipsis',
|
|
778
|
+
].join(';');
|
|
779
|
+
shareRow.appendChild(urlInput);
|
|
780
|
+
|
|
781
|
+
var copyBtn = document.createElement('button');
|
|
782
|
+
copyBtn.textContent = '\u590D\u5236\u94FE\u63A5';
|
|
783
|
+
copyBtn.style.cssText = [
|
|
784
|
+
'padding: 8px 14px',
|
|
785
|
+
'background: #a78bfa',
|
|
786
|
+
'border: none',
|
|
787
|
+
'border-radius: 4px',
|
|
788
|
+
'color: #fff',
|
|
789
|
+
'font-size: 12px',
|
|
790
|
+
'font-family: monospace',
|
|
791
|
+
'font-weight: bold',
|
|
792
|
+
'cursor: pointer',
|
|
793
|
+
'white-space: nowrap',
|
|
794
|
+
'transition: background 0.15s',
|
|
795
|
+
].join(';');
|
|
796
|
+
copyBtn.onmouseenter = function () { copyBtn.style.background = '#8b5cf6'; };
|
|
797
|
+
copyBtn.onmouseleave = function () { copyBtn.style.background = '#a78bfa'; };
|
|
798
|
+
copyBtn.onclick = function () {
|
|
799
|
+
navigator.clipboard.writeText(data.permanent_url || '').then(function () {
|
|
800
|
+
copyBtn.textContent = '\u2713 \u5DF2\u590D\u5236';
|
|
801
|
+
copyBtn.style.background = '#10b981';
|
|
802
|
+
setTimeout(function () {
|
|
803
|
+
copyBtn.textContent = '\u590D\u5236\u94FE\u63A5';
|
|
804
|
+
copyBtn.style.background = '#a78bfa';
|
|
805
|
+
}, 2000);
|
|
806
|
+
});
|
|
807
|
+
};
|
|
808
|
+
shareRow.appendChild(copyBtn);
|
|
809
|
+
|
|
810
|
+
shareSection.appendChild(shareRow);
|
|
811
|
+
info.appendChild(shareSection);
|
|
812
|
+
|
|
813
|
+
// 二维码区
|
|
814
|
+
if (data.permanent_url) {
|
|
815
|
+
var qrSection = document.createElement('div');
|
|
816
|
+
qrSection.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:6px;padding-top:4px;';
|
|
817
|
+
|
|
818
|
+
var qrCanvas = document.createElement('canvas');
|
|
819
|
+
qrCanvas.style.cssText = 'width:140px;height:140px;border-radius:6px;background:#fff;padding:8px;';
|
|
820
|
+
try {
|
|
821
|
+
generateQR(qrCanvas, data.permanent_url, 140);
|
|
822
|
+
} catch (e) {
|
|
823
|
+
console.warn('[myclaw-artifacts] QR generate error:', e);
|
|
824
|
+
qrCanvas.style.display = 'none';
|
|
825
|
+
}
|
|
826
|
+
qrSection.appendChild(qrCanvas);
|
|
827
|
+
|
|
828
|
+
var qrHint = document.createElement('div');
|
|
829
|
+
qrHint.style.cssText = 'font-size:11px;color:#888;font-family:monospace;';
|
|
830
|
+
qrHint.textContent = '\u626B\u7801\u67E5\u770B\u4F5C\u54C1';
|
|
831
|
+
qrSection.appendChild(qrHint);
|
|
832
|
+
|
|
833
|
+
info.appendChild(qrSection);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
box.appendChild(info);
|
|
837
|
+
|
|
838
|
+
// 关闭按钮
|
|
839
|
+
var footer = document.createElement('div');
|
|
840
|
+
footer.style.cssText = 'padding: 0 24px 20px;text-align:center;';
|
|
841
|
+
|
|
842
|
+
var closeSuccessBtn = document.createElement('button');
|
|
843
|
+
closeSuccessBtn.textContent = '\u5F00\u5FC3\uFF01';
|
|
844
|
+
closeSuccessBtn.style.cssText = [
|
|
845
|
+
'padding: 10px 40px',
|
|
846
|
+
'background: #4a4a7a',
|
|
847
|
+
'border: none',
|
|
848
|
+
'border-radius: 6px',
|
|
849
|
+
'color: #cdd6f4',
|
|
850
|
+
'font-size: 14px',
|
|
851
|
+
'font-family: monospace',
|
|
852
|
+
'cursor: pointer',
|
|
853
|
+
'transition: background 0.15s',
|
|
854
|
+
].join(';');
|
|
855
|
+
closeSuccessBtn.onmouseenter = function () { closeSuccessBtn.style.background = '#5a5a9a'; };
|
|
856
|
+
closeSuccessBtn.onmouseleave = function () { closeSuccessBtn.style.background = '#4a4a7a'; };
|
|
857
|
+
closeSuccessBtn.onclick = function () {
|
|
858
|
+
var m = document.querySelector('#myclaw-publish-success');
|
|
859
|
+
if (m) m.remove();
|
|
860
|
+
};
|
|
861
|
+
footer.appendChild(closeSuccessBtn);
|
|
862
|
+
box.appendChild(footer);
|
|
863
|
+
|
|
864
|
+
overlay.appendChild(box);
|
|
865
|
+
document.body.appendChild(overlay);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
function createInfoRow(label, value) {
|
|
869
|
+
var row = document.createElement('div');
|
|
870
|
+
row.style.cssText = 'display:flex;align-items:baseline;gap:8px;font-family:monospace;font-size:13px;';
|
|
871
|
+
var lbl = document.createElement('span');
|
|
872
|
+
lbl.style.cssText = 'color:#888;white-space:nowrap;flex-shrink:0;min-width:80px;';
|
|
873
|
+
lbl.textContent = label;
|
|
874
|
+
var val = document.createElement('span');
|
|
875
|
+
val.style.cssText = 'color:#cdd6f4;word-break:break-all;';
|
|
876
|
+
val.textContent = value;
|
|
877
|
+
row.appendChild(lbl);
|
|
878
|
+
row.appendChild(val);
|
|
879
|
+
return row;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// ═══ 轻量 QR 码生成(纯 JS,无依赖) ═══
|
|
883
|
+
// 基于 qrcode-generator (MIT) 的核心算法精简版
|
|
884
|
+
function generateQR(canvas, text, size) {
|
|
885
|
+
// 使用 Google Charts API 的轻量替代:用 img 加载 QR 码
|
|
886
|
+
// 但为了避免外部依赖,这里使用内嵌的极简 QR 生成
|
|
887
|
+
var QR = (function() {
|
|
888
|
+
// QR Code Model 2 - 极简实现
|
|
889
|
+
var ErrorCorrectionLevel = { L: 1, M: 0, Q: 3, H: 2 };
|
|
890
|
+
|
|
891
|
+
function QRCode(typeNumber, errorCorrectionLevel) {
|
|
892
|
+
this.typeNumber = typeNumber;
|
|
893
|
+
this.errorCorrectionLevel = errorCorrectionLevel;
|
|
894
|
+
this.modules = null;
|
|
895
|
+
this.moduleCount = 0;
|
|
896
|
+
this.dataCache = null;
|
|
897
|
+
this.dataList = [];
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
QRCode.prototype = {
|
|
901
|
+
addData: function(data) { this.dataList.push(new QR8bitByte(data)); this.dataCache = null; },
|
|
902
|
+
isDark: function(row, col) { if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) throw new Error(row + "," + col); return this.modules[row][col]; },
|
|
903
|
+
getModuleCount: function() { return this.moduleCount; },
|
|
904
|
+
make: function() { this.makeImpl(false, this.getBestMaskPattern()); },
|
|
905
|
+
makeImpl: function(test, maskPattern) {
|
|
906
|
+
this.moduleCount = this.typeNumber * 4 + 17;
|
|
907
|
+
this.modules = new Array(this.moduleCount);
|
|
908
|
+
for (var row = 0; row < this.moduleCount; row++) {
|
|
909
|
+
this.modules[row] = new Array(this.moduleCount);
|
|
910
|
+
for (var col = 0; col < this.moduleCount; col++) { this.modules[row][col] = null; }
|
|
911
|
+
}
|
|
912
|
+
this.setupPositionProbePattern(0, 0);
|
|
913
|
+
this.setupPositionProbePattern(this.moduleCount - 7, 0);
|
|
914
|
+
this.setupPositionProbePattern(0, this.moduleCount - 7);
|
|
915
|
+
this.setupPositionAdjustPattern();
|
|
916
|
+
this.setupTimingPattern();
|
|
917
|
+
this.setupTypeInfo(test, maskPattern);
|
|
918
|
+
if (this.typeNumber >= 7) this.setupTypeNumber(test);
|
|
919
|
+
if (this.dataCache == null) this.dataCache = createData(this.typeNumber, this.errorCorrectionLevel, this.dataList);
|
|
920
|
+
this.mapData(this.dataCache, maskPattern);
|
|
921
|
+
},
|
|
922
|
+
setupPositionProbePattern: function(row, col) {
|
|
923
|
+
for (var r = -1; r <= 7; r++) {
|
|
924
|
+
if (row + r <= -1 || this.moduleCount <= row + r) continue;
|
|
925
|
+
for (var c = -1; c <= 7; c++) {
|
|
926
|
+
if (col + c <= -1 || this.moduleCount <= col + c) continue;
|
|
927
|
+
if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
|
|
928
|
+
this.modules[row + r][col + c] = true;
|
|
929
|
+
} else {
|
|
930
|
+
this.modules[row + r][col + c] = false;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
getBestMaskPattern: function() {
|
|
936
|
+
var minLostPoint = 0, pattern = 0;
|
|
937
|
+
for (var i = 0; i < 8; i++) {
|
|
938
|
+
this.makeImpl(true, i);
|
|
939
|
+
var lostPoint = QRUtil.getLostPoint(this);
|
|
940
|
+
if (i == 0 || minLostPoint > lostPoint) { minLostPoint = lostPoint; pattern = i; }
|
|
941
|
+
}
|
|
942
|
+
return pattern;
|
|
943
|
+
},
|
|
944
|
+
setupTimingPattern: function() {
|
|
945
|
+
for (var r = 8; r < this.moduleCount - 8; r++) { if (this.modules[r][6] != null) continue; this.modules[r][6] = (r % 2 == 0); }
|
|
946
|
+
for (var c = 8; c < this.moduleCount - 8; c++) { if (this.modules[6][c] != null) continue; this.modules[6][c] = (c % 2 == 0); }
|
|
947
|
+
},
|
|
948
|
+
setupPositionAdjustPattern: function() {
|
|
949
|
+
var pos = QRUtil.getPatternPosition(this.typeNumber);
|
|
950
|
+
for (var i = 0; i < pos.length; i++) {
|
|
951
|
+
for (var j = 0; j < pos.length; j++) {
|
|
952
|
+
var row = pos[i], col = pos[j];
|
|
953
|
+
if (this.modules[row][col] != null) continue;
|
|
954
|
+
for (var r = -2; r <= 2; r++) {
|
|
955
|
+
for (var c = -2; c <= 2; c++) {
|
|
956
|
+
if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
|
|
957
|
+
this.modules[row + r][col + c] = true;
|
|
958
|
+
} else {
|
|
959
|
+
this.modules[row + r][col + c] = false;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
setupTypeNumber: function(test) {
|
|
967
|
+
var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
|
|
968
|
+
for (var i = 0; i < 18; i++) {
|
|
969
|
+
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
970
|
+
this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
|
|
971
|
+
}
|
|
972
|
+
for (var i = 0; i < 18; i++) {
|
|
973
|
+
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
974
|
+
this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
|
|
975
|
+
}
|
|
976
|
+
},
|
|
977
|
+
setupTypeInfo: function(test, maskPattern) {
|
|
978
|
+
var data = (this.errorCorrectionLevel << 3) | maskPattern;
|
|
979
|
+
var bits = QRUtil.getBCHTypeInfo(data);
|
|
980
|
+
for (var i = 0; i < 15; i++) {
|
|
981
|
+
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
982
|
+
if (i < 6) { this.modules[i][8] = mod; }
|
|
983
|
+
else if (i < 8) { this.modules[i + 1][8] = mod; }
|
|
984
|
+
else { this.modules[this.moduleCount - 15 + i][8] = mod; }
|
|
985
|
+
}
|
|
986
|
+
for (var i = 0; i < 15; i++) {
|
|
987
|
+
var mod = (!test && ((bits >> i) & 1) == 1);
|
|
988
|
+
if (i < 8) { this.modules[8][this.moduleCount - i - 1] = mod; }
|
|
989
|
+
else if (i < 9) { this.modules[8][15 - i - 1 + 1] = mod; }
|
|
990
|
+
else { this.modules[8][15 - i - 1] = mod; }
|
|
991
|
+
}
|
|
992
|
+
this.modules[this.moduleCount - 8][8] = (!test);
|
|
993
|
+
},
|
|
994
|
+
mapData: function(data, maskPattern) {
|
|
995
|
+
var inc = -1, row = this.moduleCount - 1, bitIndex = 7, byteIndex = 0;
|
|
996
|
+
for (var col = this.moduleCount - 1; col > 0; col -= 2) {
|
|
997
|
+
if (col == 6) col--;
|
|
998
|
+
while (true) {
|
|
999
|
+
for (var c = 0; c < 2; c++) {
|
|
1000
|
+
if (this.modules[row][col - c] == null) {
|
|
1001
|
+
var dark = false;
|
|
1002
|
+
if (byteIndex < data.length) { dark = (((data[byteIndex] >>> bitIndex) & 1) == 1); }
|
|
1003
|
+
var mask = QRUtil.getMask(maskPattern, row, col - c);
|
|
1004
|
+
if (mask) dark = !dark;
|
|
1005
|
+
this.modules[row][col - c] = dark;
|
|
1006
|
+
bitIndex--;
|
|
1007
|
+
if (bitIndex == -1) { byteIndex++; bitIndex = 7; }
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
row += inc;
|
|
1011
|
+
if (row < 0 || this.moduleCount <= row) { row -= inc; inc = -inc; break; }
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
};
|
|
1016
|
+
|
|
1017
|
+
var QRUtil = {
|
|
1018
|
+
PATTERN_POSITION_TABLE: [[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],
|
|
1019
|
+
G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
|
|
1020
|
+
G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
|
|
1021
|
+
G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
|
|
1022
|
+
getBCHTypeInfo: function(data) {
|
|
1023
|
+
var d = data << 10;
|
|
1024
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15))); }
|
|
1025
|
+
return ((data << 10) | d) ^ QRUtil.G15_MASK;
|
|
1026
|
+
},
|
|
1027
|
+
getBCHTypeNumber: function(data) {
|
|
1028
|
+
var d = data << 12;
|
|
1029
|
+
while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18))); }
|
|
1030
|
+
return (data << 12) | d;
|
|
1031
|
+
},
|
|
1032
|
+
getBCHDigit: function(data) { var digit = 0; while (data != 0) { digit++; data >>>= 1; } return digit; },
|
|
1033
|
+
getPatternPosition: function(typeNumber) { return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; },
|
|
1034
|
+
getMask: function(maskPattern, i, j) {
|
|
1035
|
+
switch (maskPattern) {
|
|
1036
|
+
case 0: return (i + j) % 2 == 0;
|
|
1037
|
+
case 1: return i % 2 == 0;
|
|
1038
|
+
case 2: return j % 3 == 0;
|
|
1039
|
+
case 3: return (i + j) % 3 == 0;
|
|
1040
|
+
case 4: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
|
|
1041
|
+
case 5: return (i * j) % 2 + (i * j) % 3 == 0;
|
|
1042
|
+
case 6: return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
|
|
1043
|
+
case 7: return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
|
|
1044
|
+
default: throw new Error("bad maskPattern:" + maskPattern);
|
|
1045
|
+
}
|
|
1046
|
+
},
|
|
1047
|
+
getErrorCorrectPolynomial: function(errorCorrectLength) {
|
|
1048
|
+
var a = new QRPolynomial([1], 0);
|
|
1049
|
+
for (var i = 0; i < errorCorrectLength; i++) { a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)); }
|
|
1050
|
+
return a;
|
|
1051
|
+
},
|
|
1052
|
+
getLengthInBits: function(mode, type) {
|
|
1053
|
+
if (1 <= type && type < 10) { switch(mode) { case 1: return 10; case 2: return 9; case 4: return 8; case 8: return 8; default: throw new Error("mode:" + mode); } }
|
|
1054
|
+
else if (type < 27) { switch(mode) { case 1: return 12; case 2: return 11; case 4: return 16; case 8: return 10; default: throw new Error("mode:" + mode); } }
|
|
1055
|
+
else if (type < 41) { switch(mode) { case 1: return 14; case 2: return 13; case 4: return 16; case 8: return 12; default: throw new Error("mode:" + mode); } }
|
|
1056
|
+
else { throw new Error("type:" + type); }
|
|
1057
|
+
},
|
|
1058
|
+
getLostPoint: function(qrCode) {
|
|
1059
|
+
var moduleCount = qrCode.getModuleCount(), lostPoint = 0;
|
|
1060
|
+
for (var row = 0; row < moduleCount; row++) { for (var col = 0; col < moduleCount; col++) { var sameCount = 0, dark = qrCode.isDark(row, col); for (var r = -1; r <= 1; r++) { if (row + r < 0 || moduleCount <= row + r) continue; for (var c = -1; c <= 1; c++) { if (col + c < 0 || moduleCount <= col + c) continue; if (r == 0 && c == 0) continue; if (dark == qrCode.isDark(row + r, col + c)) sameCount++; } } if (sameCount > 5) lostPoint += (3 + sameCount - 5); } }
|
|
1061
|
+
for (var row = 0; row < moduleCount - 1; row++) { for (var col = 0; col < moduleCount - 1; col++) { var count = 0; if (qrCode.isDark(row, col)) count++; if (qrCode.isDark(row + 1, col)) count++; if (qrCode.isDark(row, col + 1)) count++; if (qrCode.isDark(row + 1, col + 1)) count++; if (count == 0 || count == 4) lostPoint += 3; } }
|
|
1062
|
+
for (var row = 0; row < moduleCount; row++) { for (var col = 0; col < moduleCount - 6; col++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row, col + 1) && qrCode.isDark(row, col + 2) && qrCode.isDark(row, col + 3) && qrCode.isDark(row, col + 4) && !qrCode.isDark(row, col + 5) && qrCode.isDark(row, col + 6)) lostPoint += 40; } }
|
|
1063
|
+
for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount - 6; row++) { if (qrCode.isDark(row, col) && !qrCode.isDark(row + 1, col) && qrCode.isDark(row + 2, col) && qrCode.isDark(row + 3, col) && qrCode.isDark(row + 4, col) && !qrCode.isDark(row + 5, col) && qrCode.isDark(row + 6, col)) lostPoint += 40; } }
|
|
1064
|
+
var darkCount = 0; for (var col = 0; col < moduleCount; col++) { for (var row = 0; row < moduleCount; row++) { if (qrCode.isDark(row, col)) darkCount++; } } var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; lostPoint += ratio * 10;
|
|
1065
|
+
return lostPoint;
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
|
|
1069
|
+
var QRMath = {
|
|
1070
|
+
glog: function(n) { if (n < 1) throw new Error("glog(" + n + ")"); var r = QRMath.LOG_TABLE[n]; if (r == null) throw new Error("glog(" + n + ")"); return r; },
|
|
1071
|
+
gexp: function(n) { while (n < 0) n += 255; while (n >= 256) n -= 255; return QRMath.EXP_TABLE[n]; },
|
|
1072
|
+
EXP_TABLE: new Array(256), LOG_TABLE: new Array(256)
|
|
1073
|
+
};
|
|
1074
|
+
for (var i = 0; i < 8; i++) QRMath.EXP_TABLE[i] = 1 << i;
|
|
1075
|
+
for (var i = 8; i < 256; i++) QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
|
|
1076
|
+
for (var i = 0; i < 255; i++) QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
|
|
1077
|
+
|
|
1078
|
+
function QRPolynomial(num, shift) {
|
|
1079
|
+
if (num.length == undefined) throw new Error(num.length + "/" + shift);
|
|
1080
|
+
var offset = 0;
|
|
1081
|
+
while (offset < num.length && num[offset] == 0) offset++;
|
|
1082
|
+
this.num = new Array(num.length - offset + shift);
|
|
1083
|
+
for (var i = 0; i < num.length - offset; i++) this.num[i] = num[i + offset];
|
|
1084
|
+
}
|
|
1085
|
+
QRPolynomial.prototype = {
|
|
1086
|
+
get: function(index) { return this.num[index]; },
|
|
1087
|
+
getLength: function() { return this.num.length; },
|
|
1088
|
+
multiply: function(e) {
|
|
1089
|
+
var num = new Array(this.getLength() + e.getLength() - 1);
|
|
1090
|
+
for (var i = 0; i < this.getLength(); i++) for (var j = 0; j < e.getLength(); j++) num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
|
|
1091
|
+
return new QRPolynomial(num, 0);
|
|
1092
|
+
},
|
|
1093
|
+
mod: function(e) {
|
|
1094
|
+
if (this.getLength() - e.getLength() < 0) return this;
|
|
1095
|
+
var ratio = QRMath.glog(this.get(0)) - QRMath.glog(e.get(0));
|
|
1096
|
+
var num = new Array(this.getLength());
|
|
1097
|
+
for (var i = 0; i < this.getLength(); i++) num[i] = this.get(i);
|
|
1098
|
+
for (var i = 0; i < e.getLength(); i++) num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
|
|
1099
|
+
return new QRPolynomial(num, 0).mod(e);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
function QR8bitByte(data) { this.mode = 4; this.data = data; }
|
|
1104
|
+
QR8bitByte.prototype = {
|
|
1105
|
+
getLength: function() { return this.data.length; },
|
|
1106
|
+
write: function(buffer) {
|
|
1107
|
+
for (var i = 0; i < this.data.length; i++) {
|
|
1108
|
+
var c = this.data.charCodeAt(i);
|
|
1109
|
+
if (c < 0x80) { buffer.put(c, 8); }
|
|
1110
|
+
else if (c < 0x800) { buffer.put(0xC0 | (c >> 6), 8); buffer.put(0x80 | (c & 0x3F), 8); }
|
|
1111
|
+
else if (c >= 0xD800 && c <= 0xDBFF) {
|
|
1112
|
+
var c2 = this.data.charCodeAt(++i);
|
|
1113
|
+
if (isNaN(c2)) throw new Error("invalid utf8");
|
|
1114
|
+
var code = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;
|
|
1115
|
+
buffer.put(0xF0 | (code >> 18), 8); buffer.put(0x80 | ((code >> 12) & 0x3F), 8);
|
|
1116
|
+
buffer.put(0x80 | ((code >> 6) & 0x3F), 8); buffer.put(0x80 | (code & 0x3F), 8);
|
|
1117
|
+
} else {
|
|
1118
|
+
buffer.put(0xE0 | (c >> 12), 8); buffer.put(0x80 | ((c >> 6) & 0x3F), 8); buffer.put(0x80 | (c & 0x3F), 8);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
var QRCodeLimitCount = [[0,26,44,70,100,134,172,196,242,292,346],[0,22,38,60,84,108,132,154,180,213,251],[0,16,32,48,68,88,112,136,160,192,224]];
|
|
1125
|
+
|
|
1126
|
+
function createData(typeNumber, errorCorrectionLevel, dataList) {
|
|
1127
|
+
var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectionLevel);
|
|
1128
|
+
var buffer = new QRBitBuffer();
|
|
1129
|
+
for (var i = 0; i < dataList.length; i++) {
|
|
1130
|
+
var data = dataList[i];
|
|
1131
|
+
buffer.put(data.mode, 4);
|
|
1132
|
+
buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber));
|
|
1133
|
+
data.write(buffer);
|
|
1134
|
+
}
|
|
1135
|
+
var totalDataCount = 0;
|
|
1136
|
+
for (var i = 0; i < rsBlocks.length; i++) totalDataCount += rsBlocks[i].dataCount;
|
|
1137
|
+
if (buffer.getLengthInBits() > totalDataCount * 8) throw new Error("code length overflow. (" + buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
|
|
1138
|
+
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) buffer.put(0, 4);
|
|
1139
|
+
while (buffer.getLengthInBits() % 8 != 0) buffer.putBit(false);
|
|
1140
|
+
while (true) {
|
|
1141
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) break;
|
|
1142
|
+
buffer.put(0xEC, 8);
|
|
1143
|
+
if (buffer.getLengthInBits() >= totalDataCount * 8) break;
|
|
1144
|
+
buffer.put(0x11, 8);
|
|
1145
|
+
}
|
|
1146
|
+
return createBytes(buffer, rsBlocks);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
function createBytes(buffer, rsBlocks) {
|
|
1150
|
+
var offset = 0, maxDcCount = 0, maxEcCount = 0, dcdata = new Array(rsBlocks.length), ecdata = new Array(rsBlocks.length);
|
|
1151
|
+
for (var r = 0; r < rsBlocks.length; r++) {
|
|
1152
|
+
var dcCount = rsBlocks[r].dataCount, ecCount = rsBlocks[r].totalCount - dcCount;
|
|
1153
|
+
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
1154
|
+
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
1155
|
+
dcdata[r] = new Array(dcCount);
|
|
1156
|
+
for (var i = 0; i < dcdata[r].length; i++) dcdata[r][i] = 0xff & buffer.buffer[i + offset];
|
|
1157
|
+
offset += dcCount;
|
|
1158
|
+
var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
|
|
1159
|
+
var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
|
|
1160
|
+
var modPoly = rawPoly.mod(rsPoly);
|
|
1161
|
+
ecdata[r] = new Array(rsPoly.getLength() - 1);
|
|
1162
|
+
for (var i = 0; i < ecdata[r].length; i++) {
|
|
1163
|
+
var modIndex = i + modPoly.getLength() - ecdata[r].length;
|
|
1164
|
+
ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
var totalCodeCount = 0;
|
|
1168
|
+
for (var i = 0; i < rsBlocks.length; i++) totalCodeCount += rsBlocks[i].totalCount;
|
|
1169
|
+
var data = new Array(totalCodeCount), index = 0;
|
|
1170
|
+
for (var i = 0; i < maxDcCount; i++) for (var r = 0; r < rsBlocks.length; r++) if (i < dcdata[r].length) data[index++] = dcdata[r][i];
|
|
1171
|
+
for (var i = 0; i < maxEcCount; i++) for (var r = 0; r < rsBlocks.length; r++) if (i < ecdata[r].length) data[index++] = ecdata[r][i];
|
|
1172
|
+
return data;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
var QR_RS_BLOCK_TABLE = [[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16],[4,101,81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]];
|
|
1176
|
+
|
|
1177
|
+
var QRRSBlock = {
|
|
1178
|
+
getRSBlocks: function(typeNumber, errorCorrectionLevel) {
|
|
1179
|
+
var rsBlock = QR_RS_BLOCK_TABLE[(typeNumber - 1) * 4 + errorCorrectionLevel];
|
|
1180
|
+
if (rsBlock == undefined) throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectionLevel:" + errorCorrectionLevel);
|
|
1181
|
+
var length = rsBlock.length / 3, list = [];
|
|
1182
|
+
for (var i = 0; i < length; i++) {
|
|
1183
|
+
var count = rsBlock[i * 3 + 0], totalCount = rsBlock[i * 3 + 1], dataCount = rsBlock[i * 3 + 2];
|
|
1184
|
+
for (var j = 0; j < count; j++) list.push({ totalCount: totalCount, dataCount: dataCount });
|
|
1185
|
+
}
|
|
1186
|
+
return list;
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
function QRBitBuffer() { this.buffer = []; this.length = 0; }
|
|
1191
|
+
QRBitBuffer.prototype = {
|
|
1192
|
+
get: function(index) { var bufIndex = Math.floor(index / 8); return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) == 1; },
|
|
1193
|
+
put: function(num, length) { for (var i = 0; i < length; i++) this.putBit(((num >>> (length - i - 1)) & 1) == 1); },
|
|
1194
|
+
getLengthInBits: function() { return this.length; },
|
|
1195
|
+
putBit: function(bit) { var bufIndex = Math.floor(this.length / 8); if (this.buffer.length <= bufIndex) this.buffer.push(0); if (bit) this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)); this.length++; }
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
return QRCode;
|
|
1199
|
+
})();
|
|
1200
|
+
|
|
1201
|
+
// 自动选择合适的 typeNumber
|
|
1202
|
+
var qr;
|
|
1203
|
+
for (var tn = 1; tn <= 40; tn++) {
|
|
1204
|
+
try {
|
|
1205
|
+
qr = new QR(tn, 0); // M level
|
|
1206
|
+
qr.addData(text);
|
|
1207
|
+
qr.make();
|
|
1208
|
+
break;
|
|
1209
|
+
} catch (e) { qr = null; }
|
|
1210
|
+
}
|
|
1211
|
+
if (!qr) throw new Error("QR code too large");
|
|
1212
|
+
|
|
1213
|
+
var moduleCount = qr.getModuleCount();
|
|
1214
|
+
var cellSize = size / moduleCount;
|
|
1215
|
+
canvas.width = size;
|
|
1216
|
+
canvas.height = size;
|
|
1217
|
+
var ctx = canvas.getContext('2d');
|
|
1218
|
+
ctx.fillStyle = '#ffffff';
|
|
1219
|
+
ctx.fillRect(0, 0, size, size);
|
|
1220
|
+
ctx.fillStyle = '#1e1e2e';
|
|
1221
|
+
for (var row = 0; row < moduleCount; row++) {
|
|
1222
|
+
for (var col = 0; col < moduleCount; col++) {
|
|
1223
|
+
if (qr.isDark(row, col)) {
|
|
1224
|
+
ctx.fillRect(Math.floor(col * cellSize), Math.floor(row * cellSize), Math.ceil(cellSize), Math.ceil(cellSize));
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
653
1230
|
function closePublishModal() {
|
|
654
1231
|
var modal = document.querySelector('#myclaw-artifacts-publish-modal');
|
|
655
1232
|
if (modal) modal.remove();
|
|
@@ -669,6 +1246,10 @@
|
|
|
669
1246
|
' from { opacity: 0; }',
|
|
670
1247
|
' to { opacity: 1; }',
|
|
671
1248
|
'}',
|
|
1249
|
+
'@keyframes myclaw-success-pop {',
|
|
1250
|
+
' from { transform: scale(0.7); opacity: 0; }',
|
|
1251
|
+
' to { transform: scale(1); opacity: 1; }',
|
|
1252
|
+
'}',
|
|
672
1253
|
].join('\n');
|
|
673
1254
|
document.head.appendChild(style);
|
|
674
1255
|
}
|
package/assets/myclaw-inject.js
CHANGED
|
@@ -581,11 +581,237 @@
|
|
|
581
581
|
console.log("[myclaw-send] 📋 已复制(fallback)");
|
|
582
582
|
}
|
|
583
583
|
|
|
584
|
+
// ═══ 7. Socket.IO 命令工具 ═══
|
|
585
|
+
|
|
586
|
+
var cmdSocket = null;
|
|
587
|
+
var cmdSocketReady = false;
|
|
588
|
+
|
|
589
|
+
function ensureSocketIO(callback) {
|
|
590
|
+
if (cmdSocketReady) { callback(); return; }
|
|
591
|
+
if (window.io) { connectCmdSocket(callback); return; }
|
|
592
|
+
|
|
593
|
+
var s = document.createElement("script");
|
|
594
|
+
s.src = window.location.origin + "/cmd/socket.io/socket.io.js";
|
|
595
|
+
s.onload = function () { connectCmdSocket(callback); };
|
|
596
|
+
s.onerror = function () { console.error("[myclaw-cmd] socket.io-client 加载失败"); };
|
|
597
|
+
document.head.appendChild(s);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function connectCmdSocket(callback) {
|
|
601
|
+
if (cmdSocket) { cmdSocketReady = true; callback(); return; }
|
|
602
|
+
cmdSocket = window.io("/cmd", { path: "/cmd/socket.io/", transports: ["websocket", "polling"] });
|
|
603
|
+
cmdSocket.on("connect", function () {
|
|
604
|
+
cmdSocketReady = true;
|
|
605
|
+
console.log("[myclaw-cmd] Socket.IO 已连接, sid=" + cmdSocket.id);
|
|
606
|
+
callback();
|
|
607
|
+
});
|
|
608
|
+
cmdSocket.on("disconnect", function () {
|
|
609
|
+
cmdSocketReady = false;
|
|
610
|
+
console.log("[myclaw-cmd] Socket.IO 已断开");
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function runCommand(cmd) {
|
|
615
|
+
ensureSocketIO(function () {
|
|
616
|
+
cmdSocket.emit("run_command", { cmd: cmd, runId: Date.now() });
|
|
617
|
+
console.log("[myclaw-cmd] 已发送: " + cmd);
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// ═══ 8. 右下角"命令"按钮 ═══
|
|
622
|
+
|
|
623
|
+
var commandOpen = false;
|
|
624
|
+
|
|
625
|
+
function createCommandButton() {
|
|
626
|
+
if (document.querySelector("#myclaw-command-btn")) return;
|
|
627
|
+
|
|
628
|
+
var btn = document.createElement("div");
|
|
629
|
+
btn.id = "myclaw-command-btn";
|
|
630
|
+
btn.style.cssText = [
|
|
631
|
+
"position: fixed",
|
|
632
|
+
"bottom: 8px",
|
|
633
|
+
"right: 260px",
|
|
634
|
+
"padding: 3px 10px",
|
|
635
|
+
"background: rgba(16, 185, 129, 0.85)",
|
|
636
|
+
"color: #fff",
|
|
637
|
+
"font-size: 11px",
|
|
638
|
+
"font-weight: bold",
|
|
639
|
+
"font-family: monospace",
|
|
640
|
+
"border-radius: 4px",
|
|
641
|
+
"z-index: 99999",
|
|
642
|
+
"user-select: none",
|
|
643
|
+
"cursor: pointer",
|
|
644
|
+
"transition: all 0.2s",
|
|
645
|
+
"letter-spacing: 0.5px",
|
|
646
|
+
].join(";");
|
|
647
|
+
btn.textContent = "\u2795 \u547D\u4EE4";
|
|
648
|
+
btn.title = "\u5FEB\u6377\u547D\u4EE4";
|
|
649
|
+
|
|
650
|
+
btn.onmouseenter = function () { btn.style.background = "rgba(5, 150, 105, 1)"; btn.style.transform = "scale(1.05)"; };
|
|
651
|
+
btn.onmouseleave = function () { if (!commandOpen) { btn.style.background = "rgba(16, 185, 129, 0.85)"; } btn.style.transform = "scale(1)"; };
|
|
652
|
+
btn.onclick = function (e) {
|
|
653
|
+
e.stopPropagation();
|
|
654
|
+
if (commandOpen) {
|
|
655
|
+
closeCommandModal();
|
|
656
|
+
} else {
|
|
657
|
+
openCommandModal();
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
document.body.appendChild(btn);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function openCommandModal() {
|
|
665
|
+
if (document.querySelector("#myclaw-command-modal")) return;
|
|
666
|
+
commandOpen = true;
|
|
667
|
+
|
|
668
|
+
var btn = document.querySelector("#myclaw-command-btn");
|
|
669
|
+
if (btn) btn.style.background = "rgba(5, 150, 105, 1)";
|
|
670
|
+
|
|
671
|
+
// 遮罩
|
|
672
|
+
var overlay = document.createElement("div");
|
|
673
|
+
overlay.id = "myclaw-command-modal";
|
|
674
|
+
overlay.style.cssText = [
|
|
675
|
+
"position: fixed",
|
|
676
|
+
"top: 0",
|
|
677
|
+
"left: 0",
|
|
678
|
+
"width: 100vw",
|
|
679
|
+
"height: 100vh",
|
|
680
|
+
"background: rgba(0, 0, 0, 0.4)",
|
|
681
|
+
"z-index: 99998",
|
|
682
|
+
"display: flex",
|
|
683
|
+
"align-items: center",
|
|
684
|
+
"justify-content: center",
|
|
685
|
+
"animation: myclaw-fade-in 0.15s ease",
|
|
686
|
+
].join(";");
|
|
687
|
+
|
|
688
|
+
var box = document.createElement("div");
|
|
689
|
+
box.style.cssText = [
|
|
690
|
+
"width: 400px",
|
|
691
|
+
"background: #1e1e2e",
|
|
692
|
+
"border-radius: 8px",
|
|
693
|
+
"overflow: hidden",
|
|
694
|
+
"box-shadow: 0 8px 32px rgba(0,0,0,0.5)",
|
|
695
|
+
].join(";");
|
|
696
|
+
|
|
697
|
+
// 标题栏
|
|
698
|
+
var header = document.createElement("div");
|
|
699
|
+
header.style.cssText = [
|
|
700
|
+
"display: flex",
|
|
701
|
+
"align-items: center",
|
|
702
|
+
"justify-content: space-between",
|
|
703
|
+
"padding: 10px 14px",
|
|
704
|
+
"background: #2d2d3f",
|
|
705
|
+
"color: #cdd6f4",
|
|
706
|
+
"font-size: 13px",
|
|
707
|
+
"font-family: monospace",
|
|
708
|
+
"user-select: none",
|
|
709
|
+
].join(";");
|
|
710
|
+
header.innerHTML = '<span>\u2795 \u547D\u4EE4</span>';
|
|
711
|
+
|
|
712
|
+
var closeBtn = document.createElement("span");
|
|
713
|
+
closeBtn.textContent = "\u2715";
|
|
714
|
+
closeBtn.style.cssText = "cursor:pointer;padding:2px 6px;border-radius:3px;font-size:14px;transition:background 0.15s;";
|
|
715
|
+
closeBtn.onmouseenter = function () { closeBtn.style.background = "rgba(255,255,255,0.1)"; };
|
|
716
|
+
closeBtn.onmouseleave = function () { closeBtn.style.background = "none"; };
|
|
717
|
+
closeBtn.onclick = function () { closeCommandModal(); };
|
|
718
|
+
header.appendChild(closeBtn);
|
|
719
|
+
|
|
720
|
+
// 内容区
|
|
721
|
+
var form = document.createElement("div");
|
|
722
|
+
form.style.cssText = "padding: 20px;display:flex;flex-direction:column;gap:14px;color:#cdd6f4;font-family:monospace;font-size:13px;";
|
|
723
|
+
|
|
724
|
+
// 添加对话
|
|
725
|
+
var addGroup = document.createElement("div");
|
|
726
|
+
addGroup.style.cssText = "display:flex;flex-direction:column;gap:6px;";
|
|
727
|
+
|
|
728
|
+
var addLabel = document.createElement("div");
|
|
729
|
+
addLabel.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
|
|
730
|
+
addLabel.style.cssText = "font-size:13px;font-weight:bold;color:#10b981;";
|
|
731
|
+
addGroup.appendChild(addLabel);
|
|
732
|
+
|
|
733
|
+
var addDesc = document.createElement("div");
|
|
734
|
+
addDesc.textContent = "\u8F93\u5165 agent-name\uFF0C\u70B9\u51FB\u6267\u884C mc tui <name>";
|
|
735
|
+
addDesc.style.cssText = "font-size:11px;color:#888;";
|
|
736
|
+
addGroup.appendChild(addDesc);
|
|
737
|
+
|
|
738
|
+
var addRow = document.createElement("div");
|
|
739
|
+
addRow.style.cssText = "display:flex;gap:8px;";
|
|
740
|
+
|
|
741
|
+
var agentInput = document.createElement("input");
|
|
742
|
+
agentInput.type = "text";
|
|
743
|
+
agentInput.placeholder = "agent-name";
|
|
744
|
+
agentInput.style.cssText = "flex:1;padding:8px 10px;background:#252536;border:1px solid #3d3d5c;border-radius:4px;color:#cdd6f4;font-size:13px;font-family:monospace;outline:none;";
|
|
745
|
+
agentInput.onfocus = function () { agentInput.style.borderColor = "#10b981"; };
|
|
746
|
+
agentInput.onblur = function () { agentInput.style.borderColor = "#3d3d5c"; };
|
|
747
|
+
|
|
748
|
+
var addBtn = document.createElement("button");
|
|
749
|
+
addBtn.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
|
|
750
|
+
addBtn.style.cssText = "padding:8px 16px;background:#10b981;border:none;border-radius:4px;color:#fff;font-size:12px;font-family:monospace;cursor:pointer;transition:background 0.15s;white-space:nowrap;";
|
|
751
|
+
addBtn.onmouseenter = function () { addBtn.style.background = "#059669"; };
|
|
752
|
+
addBtn.onmouseleave = function () { addBtn.style.background = "#10b981"; };
|
|
753
|
+
addBtn.onclick = function () {
|
|
754
|
+
var val = agentInput.value.trim();
|
|
755
|
+
if (!val) {
|
|
756
|
+
agentInput.style.borderColor = "#ff4444";
|
|
757
|
+
agentInput.focus();
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
// 只允许字母、数字、连字符
|
|
761
|
+
if (!/^[a-zA-Z0-9\-]+$/.test(val)) {
|
|
762
|
+
agentInput.style.borderColor = "#ff4444";
|
|
763
|
+
agentInput.focus();
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
addBtn.disabled = true;
|
|
767
|
+
addBtn.textContent = "\u6267\u884C\u4E2D...";
|
|
768
|
+
runCommand("mc tui " + val);
|
|
769
|
+
setTimeout(function () {
|
|
770
|
+
addBtn.disabled = false;
|
|
771
|
+
addBtn.textContent = "\u6DFB\u52A0\u5BF9\u8BDD";
|
|
772
|
+
agentInput.value = "";
|
|
773
|
+
}, 1000);
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
// 回车也触发
|
|
777
|
+
agentInput.onkeydown = function (e) {
|
|
778
|
+
if (e.key === "Enter") { addBtn.click(); }
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
addRow.appendChild(agentInput);
|
|
782
|
+
addRow.appendChild(addBtn);
|
|
783
|
+
addGroup.appendChild(addRow);
|
|
784
|
+
form.appendChild(addGroup);
|
|
785
|
+
|
|
786
|
+
box.appendChild(header);
|
|
787
|
+
box.appendChild(form);
|
|
788
|
+
overlay.appendChild(box);
|
|
789
|
+
|
|
790
|
+
overlay.onclick = function (e) {
|
|
791
|
+
if (e.target === overlay) closeCommandModal();
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
document.body.appendChild(overlay);
|
|
795
|
+
|
|
796
|
+
// 自动聚焦
|
|
797
|
+
setTimeout(function () { agentInput.focus(); }, 100);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function closeCommandModal() {
|
|
801
|
+
var modal = document.querySelector("#myclaw-command-modal");
|
|
802
|
+
if (modal) modal.remove();
|
|
803
|
+
commandOpen = false;
|
|
804
|
+
|
|
805
|
+
var btn = document.querySelector("#myclaw-command-btn");
|
|
806
|
+
if (btn) btn.style.background = "rgba(16, 185, 129, 0.85)";
|
|
807
|
+
}
|
|
808
|
+
|
|
584
809
|
// ═══ 启动 ═══
|
|
585
810
|
function init() {
|
|
586
811
|
createVersionBar();
|
|
587
812
|
createDocButton();
|
|
588
813
|
createCmdButton();
|
|
814
|
+
createCommandButton();
|
|
589
815
|
injectStyles();
|
|
590
816
|
|
|
591
817
|
// 初始化 VoiceInput SDK
|
package/gateway.js
CHANGED
|
@@ -149,6 +149,17 @@ function start() {
|
|
|
149
149
|
console.log('[启动] ' + colors.green + 'Gateway 启动成功!' + colors.nc);
|
|
150
150
|
console.log('');
|
|
151
151
|
console.log('控制台: ' + colors.yellow + 'http://127.0.0.1:' + PORT + colors.nc);
|
|
152
|
+
|
|
153
|
+
// 重新注册 LaunchAgent 作为守卫(崩溃自动重启、开机自启)
|
|
154
|
+
if (!isWin) {
|
|
155
|
+
try {
|
|
156
|
+
execSync('openclaw gateway install', { stdio: 'pipe', timeout: 10000 });
|
|
157
|
+
console.log('[守卫] ' + colors.green + 'LaunchAgent 已注册,崩溃/重启会自动拉起' + colors.nc);
|
|
158
|
+
} catch {
|
|
159
|
+
// 注册失败不影响正常使用,静默忽略
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
152
163
|
return true;
|
|
153
164
|
} catch {
|
|
154
165
|
console.log('[启动] ' + colors.yellow + 'Gateway 正在启动中...' + colors.nc);
|