1document.addEventListener('e8::beforeInit', function (e) { 2 const registerComponent = e?.detail?.registerComponent ?? (() => console.error('Function \'registerComponent\' not found')); 3 4 const config = { 5 id: 'login-form', 6 template: ` 7<div v-if="$root.vars.object" class="login-form__container"> 8 <div class="login-form__subcontainer"> 9 10 <e8-form-input 11 v-model="$root.vars.object.login" 12 internal-id="login" 13 autocomplete="username" 14 :placeholder="t('login_form.login_placeholder')" 15 class="field-login-form-login" 16 :title="t('login_form.login_label')" 17 :label="t('login_form.login_label')" 18 ref="login" 19 tabindex="1" 20 ></e8-form-input> 21 22 <e8-form-password 23 v-model="$root.vars.object.password" 24 internal-id="password" 25 autocomplete="current-password" 26 :placeholder="t('login_form.password_placeholder')" 27 class="field-login-form-password" 28 :title="t('login_form.password_label')" 29 :label="t('login_form.password_label')" 30 ref="password" 31 :show-reveal-button="true" 32 tabindex="2" 33 > 34 </e8-form-password> 35 36 <template v-if="isMobileApp"> 37 <div class="btn-group login-form__button-group" role="group"> 38 <e8-button class="login-form__button" @click="onSubmit" 39 :disabled="sending" 40 :loading="sending" 41 tabindex="4" 42 :pill="false" 43 > 44 {{ t('login_form.action_sign_in') }} 45 </e8-button> 46 47 <e8-button class="login-form__qr-button" @click="signInWithQr" 48 :disabled="sending" 49 tabindex="-1" 50 :pill="false" 51 > 52 <e8-icon name="qrcode"></e8-icon> 53 </e8-button> 54 </div> 55 </template> 56 57 <template v-else> 58 <e8-form-checkbox 59 v-model="$root.vars.object.rememberMe" 60 internal-id="rememberMe" 61 class="field-login-form-rememberme" 62 :label="t('login_form.remember_me_checkbox')" 63 tabindex="3" 64 ></e8-form-checkbox> 65 66 <e8-button class="login-form__button" @click="onSubmit" 67 :disabled="sending" 68 :loading="sending" 69 tabindex="4" 70 :pill="false" 71 > 72 {{ t('login_form.action_sign_in') }} 73 </e8-button> 74 </template> 75 76 <div class="login-form__forgot-password-link-container"> 77 <e8-link 78 class="login-form__link" 79 href="javascript:;" 80 @click="onForgotClick" 81 tabindex="5" 82 > 83 {{ t('login_form.action_forgot_password') }} 84 </e8-link> 85 </div> 86 </div> 87</div>`, 88 }; 89 90 const definition = { 91 data() { 92 return { 93 sending: false, 94 }; 95 }, 96 computed: { 97 isMock() { 98 return !!this.$root.vars.isMock; 99 }, 100 isMobileApp() { 101 return this.$root.isMobileApp(); 102 }, 103 }, 104 methods: { 105 async validateAttrs() { 106 let isValid = true; 107 108 const promises = [ 109 this.$refs.login.validate().then((value) => { 110 if (!value) { 111 isValid = false; 112 } 113 }), 114 this.$refs.password.validate().then((value) => { 115 if (!value) { 116 isValid = false; 117 } 118 }), 119 ]; 120 121 await Promise.all(promises); 122 123 return isValid; 124 }, 125 async onSubmit() { 126 if (this.isMock || this.sending) { 127 return; 128 } 129 130 this.sending = true; 131 const isValid = await this.validateAttrs(); 132 133 if (!isValid) { 134 this.sending = false;
135 return; 136 } 137 138 this.$root.$notify.closeAll(); 139 140 const body = new FormData(); 141 body.append('login', this.$root.vars.object.login); 142 body.append('password', this.$root.vars.object.password); 143 body.append('rememberMe', (this.$root.vars.object.rememberMe || this.isMobileApp) ? 1 : 0); 144 145 try { 146 const response = await fetch( 147 window.location.href, 148 { body, method: 'POST', headers: { 'X-Requested-With': 'fetch' } }, 149 ); 150 151 if (response.redirected) { 152 window.location.href = response.url; 153 return; 154 } 155 156 if (response.ok) { 157 const result = await response.json(); 158 if (result.redirect) { 159 window.location.href = result.redirect; 160 return; 161 } 162 163 if (result.success) { 164 return; 165 } 166 167 throw new Error(result.message || `${response.status} ${response.statusText}`); 168 } else { 169 throw new Error(`${response.status} ${response.statusText}`); 170 } 171 } catch (e) { 172 console.error(e); 173 this.$root.$notify.danger(e?.message); 174 } finally { 175 this.sending = false; 176 } 177 }, 178 onForgotClick() { 179 if (this.isMock) { 180 return; 181 } 182 183 window.location.href = '/user/forgot'; 184 }, 185 t(...args) { 186 return this.$root.$t(...args); 187 }, 188 signInWithQr() { 189 this.sending = true; 190 this.$root.$mediaDevices.scanQrCode() 191 .then((result) => { 192 if (!result) { 193 this.sending = false; 194 return; 195 } 196 197 try { 198 const url = new URL(result); 199 const urlParams = new URLSearchParams(window.location.search); 200 urlParams.set('token', url.searchParams.get('token')); 201 window.location.search = urlParams.toString(); 202 } catch (e) { 203 const urlParams = new URLSearchParams(window.location.search); 204 urlParams.set('token', String(result)); 205 window.location.search = urlParams.toString(); 206 } 207 }) 208 .catch(() => { 209 this.sending = false; 210 }); 211 }, 212 setMock() { 213 if (this.isMock) { 214 this.$nextTick(() => { 215 this.$refs.login?.validate(); 216 this.$refs.password?.validate(); 217 }); 218 } 219 }, 220 }, 221 watch: { 222 isMock: { 223 handler: 'setMock', 224 immediate: true, 225 }, 226 }, 227 }; 228 229 registerComponent(config, definition); 230});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.