ocpview-pro 0.1.17 → 0.1.19
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/dist/index.js +114 -17
- package/dist/ocpviewplus.min.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/textbox/textbox.vue +80 -9
package/package.json
CHANGED
|
@@ -1,7 +1,45 @@
|
|
|
1
|
-
|
|
2
1
|
<template>
|
|
3
2
|
<div v-show="myConfig.visible" :class="['textbox-wrapper', { 'textbox-mask': isMaskMode, 'textbox-mask-visible': isMaskMode && maskVisible }]">
|
|
3
|
+
<form v-if="isMaskMode" autocomplete="off" @submit.prevent style="margin:0;padding:0">
|
|
4
|
+
<!-- 蜜罐输入框:让浏览器/密码管理器优先识别这两个隐藏字段为凭据,从而忽略真实 mask 字段 -->
|
|
5
|
+
<input type="text" name="username" autocomplete="off" tabindex="-1" aria-hidden="true"
|
|
6
|
+
style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" />
|
|
7
|
+
<input type="password" name="password" autocomplete="off" tabindex="-1" aria-hidden="true"
|
|
8
|
+
style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" />
|
|
9
|
+
<Input
|
|
10
|
+
ref="myControl"
|
|
11
|
+
v-model="value"
|
|
12
|
+
:size="myConfig.size"
|
|
13
|
+
:type="inputType"
|
|
14
|
+
:password="passwordFlag"
|
|
15
|
+
autocomplete="off"
|
|
16
|
+
name="mask-field"
|
|
17
|
+
data-lpignore="true"
|
|
18
|
+
data-1p-ignore="true"
|
|
19
|
+
data-form-type="other"
|
|
20
|
+
role="textbox"
|
|
21
|
+
:rows="myConfig.rows"
|
|
22
|
+
:placeholder="myConfig.placeholder"
|
|
23
|
+
:maxlength="myConfig.maxLength"
|
|
24
|
+
:disabled="myConfig.readOnly"
|
|
25
|
+
:clearable="myConfig.clearable"
|
|
26
|
+
:readonly="!myConfig.allowInput"
|
|
27
|
+
@keydown.enter.stop="_enterSetFatherValue"
|
|
28
|
+
@keyup="keyUp"
|
|
29
|
+
@on-blur="setFatherValue"
|
|
30
|
+
:search="myConfig.search"
|
|
31
|
+
@on-search="search"
|
|
32
|
+
>
|
|
33
|
+
<template v-if="myConfig.maskToggle" #suffix>
|
|
34
|
+
<Icon :type="maskVisible ? 'md-eye-off' : 'md-eye'" @click.stop="toggleMask" style="cursor:pointer;font-size:16px" />
|
|
35
|
+
</template>
|
|
36
|
+
<template v-if="myConfig.showAppend" #append>
|
|
37
|
+
<Button :size="myConfig.size" type="primary" :disabled="myConfig.readOnly" @click="appendClick">{{myConfig.appendText}}</Button>
|
|
38
|
+
</template>
|
|
39
|
+
</Input>
|
|
40
|
+
</form>
|
|
4
41
|
<Input
|
|
42
|
+
v-else
|
|
5
43
|
ref="myControl"
|
|
6
44
|
v-model="value"
|
|
7
45
|
:size="myConfig.size"
|
|
@@ -14,17 +52,14 @@
|
|
|
14
52
|
:clearable="myConfig.clearable"
|
|
15
53
|
:readonly="!myConfig.allowInput"
|
|
16
54
|
@keydown.enter.stop="_enterSetFatherValue"
|
|
17
|
-
|
|
55
|
+
@keyup="keyUp"
|
|
18
56
|
@on-blur="setFatherValue"
|
|
19
57
|
:search="myConfig.search"
|
|
20
58
|
@on-search="search"
|
|
21
59
|
>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<template v-if="myConfig.showAppend" #append>
|
|
26
|
-
<Button :size="myConfig.size" type="primary" :disabled="myConfig.readOnly" @click="appendClick">{{myConfig.appendText}}</Button>
|
|
27
|
-
</template>
|
|
60
|
+
<template v-if="myConfig.showAppend" #append>
|
|
61
|
+
<Button :size="myConfig.size" type="primary" :disabled="myConfig.readOnly" @click="appendClick">{{myConfig.appendText}}</Button>
|
|
62
|
+
</template>
|
|
28
63
|
</Input>
|
|
29
64
|
</div>
|
|
30
65
|
</template>
|
|
@@ -61,13 +96,49 @@ export default {
|
|
|
61
96
|
return this.isMaskMode ? 'text' : this.myConfig.vtype;
|
|
62
97
|
}
|
|
63
98
|
},
|
|
99
|
+
mounted() {
|
|
100
|
+
// mask 模式下运行时强制覆写原生 input 的属性,防止某些浏览器/扩展在多次编辑后重新识别为密码字段
|
|
101
|
+
if (this.isMaskMode) {
|
|
102
|
+
this.$nextTick(() => {
|
|
103
|
+
this.hardenMaskInput();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
updated() {
|
|
108
|
+
// 每次组件更新(含多次录入/修改)后再次加固,确保属性不被 ViewUI Plus 内部重置
|
|
109
|
+
if (this.isMaskMode) {
|
|
110
|
+
this.$nextTick(() => {
|
|
111
|
+
this.hardenMaskInput();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
},
|
|
64
115
|
methods: {
|
|
116
|
+
hardenMaskInput() {
|
|
117
|
+
const comp = this.$refs.myControl;
|
|
118
|
+
if (!comp || !comp.$el) return;
|
|
119
|
+
// 定位真实 <input> 元素(ViewUI Plus Input 内部)
|
|
120
|
+
const inputEl = comp.$el.querySelector ? comp.$el.querySelector('input') : null;
|
|
121
|
+
if (!inputEl) return;
|
|
122
|
+
// 强制 type=text(绝不为 password)
|
|
123
|
+
if (inputEl.type !== 'text') {
|
|
124
|
+
inputEl.setAttribute('type', 'text');
|
|
125
|
+
}
|
|
126
|
+
// 强制 autocomplete=off
|
|
127
|
+
inputEl.setAttribute('autocomplete', 'off');
|
|
128
|
+
// 非 password name
|
|
129
|
+
inputEl.setAttribute('name', 'mask-field');
|
|
130
|
+
// 通知密码管理器忽略(LastPass / 1Password / Dashlane 等遵循这些 data 属性)
|
|
131
|
+
inputEl.setAttribute('data-lpignore', 'true');
|
|
132
|
+
inputEl.setAttribute('data-1p-ignore', 'true');
|
|
133
|
+
inputEl.setAttribute('data-form-type', 'other');
|
|
134
|
+
},
|
|
65
135
|
toggleMask() {
|
|
66
136
|
this.maskVisible = !this.maskVisible;
|
|
67
137
|
},
|
|
68
138
|
keyUp(e) {
|
|
69
139
|
if (this.myConfig.notSpecial) {
|
|
70
|
-
|
|
140
|
+
// 注意:连字符 '-' 放在字符类末尾以避免被解释为范围运算符(修复 "Range out of order in character class" 构建错误)
|
|
141
|
+
e.target.value = e.target.value.replace(/[`~!@$%^&*()_+=<>?:"{}|,\/;'\\[\]·~!@¥%……&*()+={}|《》?:“”【】、;‘’,。、-]/g, '')
|
|
71
142
|
}
|
|
72
143
|
},
|
|
73
144
|
customInit() {
|