github.com/soulteary/pocket-bookcase@v0.0.0-20240428065142-0b5a9a0fc98a/internal/view/assets/js/component/dialog.js (about) 1 var template = ` 2 <div v-if="visible" class="custom-dialog-overlay" @keyup.esc="handleEscPressed"> 3 <div class="custom-dialog"> 4 <p class="custom-dialog-header">{{title}}</p> 5 <div class="custom-dialog-body"> 6 <slot> 7 <p class="custom-dialog-content">{{content}}</p> 8 <template v-for="(field,index) in formFields"> 9 <label v-if="showLabel && field.type !== 'check'">{{field.label}} :</label> 10 <textarea v-if="field.type === 'area'" 11 :style="{gridColumnEnd: showLabel ? null : 'span 2'}" 12 :placeholder="field.label" 13 :tabindex="index+1" 14 ref="input" 15 v-model="field.value" 16 @focus="$event.target.select()" 17 @keyup="handleInput(index)"> 18 </textarea> 19 <label v-else-if="field.type === 'check'" class="checkbox-field"> 20 <input type="checkbox" 21 v-model="field.value" 22 :tabindex="index+1">{{field.label}} 23 </label> 24 <input v-else 25 :style="{gridColumnEnd: showLabel ? null : 'span 2'}" 26 :type="fieldType(field)" 27 :placeholder="field.label" 28 :tabindex="index+1" 29 ref="input" 30 v-model="field.value" 31 @focus="$event.target.select()" 32 @keyup="handleInput(index)" 33 @keyup.enter="handleInputEnter(index)"> 34 <button :ref="'suggestion-'+index" 35 v-if="field.suggestion" 36 @click="handleInputEnter(index)" 37 class="suggestion">{{field.suggestion}}</button> 38 </template> 39 </slot> 40 </div> 41 <div class="custom-dialog-footer"> 42 <i v-if="loading" class="fas fa-fw fa-spinner fa-spin"></i> 43 <slot v-else name="custom-footer"> 44 <a v-if="secondText" 45 :tabindex="btnTabIndex+1" 46 @click="handleSecondClick" 47 @keyup.enter="handleSecondClick" 48 class="custom-dialog-button">{{secondText}} 49 </a> 50 <a :tabindex="btnTabIndex" 51 ref="mainButton" 52 @click="handleMainClick" 53 @keyup.enter="handleMainClick" 54 class="custom-dialog-button main">{{mainText}} 55 </a> 56 </slot> 57 </div> 58 </div> 59 </div>`; 60 61 export default { 62 template: template, 63 props: { 64 title: String, 65 loading: Boolean, 66 visible: Boolean, 67 content: { 68 type: String, 69 default: "", 70 }, 71 fields: { 72 type: Array, 73 default() { 74 return []; 75 }, 76 }, 77 showLabel: { 78 type: Boolean, 79 default: false, 80 }, 81 mainText: { 82 type: String, 83 default: "OK", 84 }, 85 secondText: String, 86 mainClick: { 87 type: Function, 88 default() { 89 this.visible = false; 90 }, 91 }, 92 secondClick: { 93 type: Function, 94 default() { 95 this.visible = false; 96 }, 97 }, 98 escPressed: { 99 type: Function, 100 default() { 101 this.visible = false; 102 }, 103 }, 104 }, 105 data() { 106 return { 107 formFields: [], 108 }; 109 }, 110 computed: { 111 btnTabIndex() { 112 return this.fields.length + 1; 113 }, 114 }, 115 watch: { 116 fields: { 117 immediate: true, 118 handler() { 119 this.formFields = this.fields.map((field) => { 120 if (typeof field === "string") 121 return { 122 name: field, 123 label: field, 124 value: "", 125 type: "text", 126 dictionary: [], 127 separator: " ", 128 suggestion: undefined, 129 }; 130 131 if (typeof field === "object") 132 return { 133 name: field.name || "", 134 label: field.label || "", 135 value: field.value || "", 136 type: field.type || "text", 137 dictionary: 138 field.dictionary instanceof Array ? field.dictionary : [], 139 separator: field.separator || " ", 140 suggestion: undefined, 141 }; 142 }); 143 }, 144 }, 145 "fields.length"() { 146 this.focus(); 147 }, 148 visible: { 149 immediate: true, 150 handler() { 151 this.focus(); 152 }, 153 }, 154 }, 155 methods: { 156 fieldType(f) { 157 var type = f.type || "text"; 158 if (type !== "text" && type !== "password") return "text"; 159 else return type; 160 }, 161 handleMainClick() { 162 var data = {}; 163 this.formFields.forEach((field) => { 164 var value = field.value; 165 if (field.type === "number") value = parseInt(value, 10) || 0; 166 else if (field.type === "float") value = parseFloat(value) || 0.0; 167 else if (field.type === "check") value = Boolean(value); 168 data[field.name] = value; 169 }); 170 171 this.mainClick(data); 172 }, 173 handleSecondClick() { 174 this.secondClick(); 175 }, 176 handleEscPressed() { 177 this.escPressed(); 178 }, 179 handleInput(index) { 180 // Create initial variable 181 var field = this.formFields[index], 182 dictionary = field.dictionary; 183 184 // Make sure dictionary is not empty 185 if (dictionary.length === 0) return; 186 187 // Fetch suggestion from dictionary 188 var words = field.value.split(field.separator), 189 lastWord = words[words.length - 1].toLowerCase(), 190 suggestion; 191 192 if (lastWord !== "") { 193 suggestion = dictionary.find((word) => { 194 return word.toLowerCase().startsWith(lastWord); 195 }); 196 } 197 198 this.formFields[index].suggestion = suggestion; 199 200 // Make sure suggestion exist 201 if (suggestion == null) return; 202 203 // Display suggestion 204 this.$nextTick(() => { 205 var input = this.$refs.input[index], 206 suggestionNode = this.$refs["suggestion-" + index][0], 207 inputRect = input.getBoundingClientRect(); 208 209 suggestionNode.style.top = inputRect.bottom - 1 + "px"; 210 suggestionNode.style.left = inputRect.left + "px"; 211 }); 212 }, 213 handleInputEnter(index) { 214 var suggestion = this.formFields[index].suggestion; 215 216 if (suggestion == null) { 217 this.handleMainClick(); 218 return; 219 } 220 221 var separator = this.formFields[index].separator, 222 words = this.formFields[index].value.split(separator); 223 224 words.pop(); 225 words.push(suggestion); 226 227 this.formFields[index].value = words.join(separator) + separator; 228 this.formFields[index].suggestion = undefined; 229 // Focus input again after suggestion is accepted 230 this.$refs.input[index].focus(); 231 }, 232 focus() { 233 this.$nextTick(() => { 234 if (!this.visible) return; 235 236 var fields = this.$refs.input, 237 otherInput = this.$el.querySelectorAll("input"), 238 button = this.$refs.mainButton; 239 240 if (fields && fields.length > 0) { 241 this.$refs.input[0].focus(); 242 this.$refs.input[0].select(); 243 } else if (otherInput && otherInput.length > 0) { 244 otherInput[0].focus(); 245 otherInput[0].select(); 246 } else if (button) { 247 button.focus(); 248 } 249 }); 250 }, 251 }, 252 };