Signed-off-by: Christopher Ng <chrng8@gmail.com> Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>tags/v23.0.0beta1
display: grid; | display: grid; | ||||
align-items: center; | align-items: center; | ||||
input { | |||||
grid-area: 1 / 1; | |||||
height: 34px; | |||||
width: 100%; | |||||
margin: 3px 3px 3px 0; | |||||
padding: 7px 6px; | |||||
cursor: text; | |||||
font-family: var(--font-face); | |||||
border: 1px solid var(--color-border-dark); | |||||
border-radius: var(--border-radius); | |||||
background-color: var(--color-main-background); | |||||
color: var(--color-main-text); | |||||
} | |||||
input { | |||||
grid-area: 1 / 1; | |||||
width: 100%; | |||||
height: 34px; | |||||
margin: 3px 3px 3px 0; | |||||
padding: 7px 6px; | |||||
color: var(--color-main-text); | |||||
border: 1px solid var(--color-border-dark); | |||||
border-radius: var(--border-radius); | |||||
background-color: var(--color-main-background); | |||||
font-family: var(--font-face); | |||||
cursor: text; | |||||
} | |||||
.displayname__actions-container { | .displayname__actions-container { | ||||
grid-area: 1 / 1; | grid-area: 1 / 1; |
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
section { | |||||
padding: 10px 10px; | |||||
section { | |||||
padding: 10px 10px; | |||||
&::v-deep button:disabled { | |||||
cursor: default; | |||||
} | |||||
&::v-deep button:disabled { | |||||
cursor: default; | |||||
} | } | ||||
} | } | ||||
</style> | </style> |
display: grid; | display: grid; | ||||
align-items: center; | align-items: center; | ||||
input { | |||||
grid-area: 1 / 1; | |||||
height: 34px; | |||||
width: 100%; | |||||
margin: 3px 3px 3px 0; | |||||
padding: 7px 6px; | |||||
cursor: text; | |||||
font-family: var(--font-face); | |||||
border: 1px solid var(--color-border-dark); | |||||
border-radius: var(--border-radius); | |||||
background-color: var(--color-main-background); | |||||
color: var(--color-main-text); | |||||
} | |||||
.email__actions-container { | |||||
grid-area: 1 / 1; | |||||
justify-self: flex-end; | |||||
height: 30px; | |||||
input { | |||||
grid-area: 1 / 1; | |||||
width: 100%; | |||||
height: 34px; | |||||
margin: 3px 3px 3px 0; | |||||
padding: 7px 6px; | |||||
color: var(--color-main-text); | |||||
border: 1px solid var(--color-border-dark); | |||||
border-radius: var(--border-radius); | |||||
background-color: var(--color-main-background); | |||||
font-family: var(--font-face); | |||||
cursor: text; | |||||
} | |||||
.email__actions-container { | .email__actions-container { | ||||
grid-area: 1 / 1; | grid-area: 1 / 1; |
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
section { | |||||
padding: 10px 10px; | |||||
section { | |||||
padding: 10px 10px; | |||||
&::v-deep button:disabled { | |||||
cursor: default; | |||||
} | |||||
&::v-deep button:disabled { | |||||
cursor: default; | |||||
} | } | ||||
} | } | ||||
</style> | </style> |
name="language" | name="language" | ||||
:placeholder="t('settings', 'Language')" | :placeholder="t('settings', 'Language')" | ||||
required | required | ||||
@input="onLanguageChange"> | |||||
@change="onLanguageChange"> | |||||
<option v-for="commonLanguage in commonLanguages" | <option v-for="commonLanguage in commonLanguages" | ||||
:key="commonLanguage.code" | :key="commonLanguage.code" | ||||
:selected="language.code === commonLanguage.code" | :selected="language.code === commonLanguage.code" | ||||
import { showError } from '@nextcloud/dialogs' | import { showError } from '@nextcloud/dialogs' | ||||
import { saveLanguage } from '../../../service/PersonalInfo/LanguageService' | import { saveLanguage } from '../../../service/PersonalInfo/LanguageService' | ||||
import { validateLanguage } from '../../../utils/validate' | |||||
export default { | export default { | ||||
name: 'Language', | name: 'Language', | ||||
const language = this.constructLanguage(e.target.value) | const language = this.constructLanguage(e.target.value) | ||||
this.$emit('update:language', language) | this.$emit('update:language', language) | ||||
if (this.$refs.language?.checkValidity()) { | |||||
if (validateLanguage(language)) { | |||||
await this.updateLanguage(language) | await this.updateLanguage(language) | ||||
} | } | ||||
}, | }, | ||||
.language { | .language { | ||||
display: grid; | display: grid; | ||||
select { | |||||
width: 100%; | |||||
height: 34px; | |||||
margin: 3px 3px 3px 0; | |||||
padding: 6px 16px; | |||||
color: var(--color-main-text); | |||||
border: 1px solid var(--color-border-dark); | |||||
border-radius: var(--border-radius); | |||||
background: var(--icon-triangle-s-000) no-repeat right 4px center; | |||||
font-family: var(--font-face); | |||||
appearance: none; | |||||
cursor: pointer; | |||||
} | |||||
a { | a { | ||||
color: var(--color-main-text); | |||||
text-decoration: none; | |||||
width: max-content; | width: max-content; | ||||
} | } | ||||
} | } |
--> | --> | ||||
<template> | <template> | ||||
<form | |||||
ref="form" | |||||
class="section" | |||||
@submit.stop.prevent="() => {}"> | |||||
<section> | |||||
<HeaderBar | <HeaderBar | ||||
:account-property="accountProperty" | :account-property="accountProperty" | ||||
label-for="language" | label-for="language" | ||||
:is-valid-form="isValidForm" /> | |||||
:is-valid-section="isValidSection" /> | |||||
<template v-if="isEditable"> | <template v-if="isEditable"> | ||||
<Language | <Language | ||||
:common-languages="commonLanguages" | :common-languages="commonLanguages" | ||||
:other-languages="otherLanguages" | :other-languages="otherLanguages" | ||||
:language.sync="language" | |||||
@update:language="onUpdateLanguage" /> | |||||
:language.sync="language" /> | |||||
</template> | </template> | ||||
<span v-else> | <span v-else> | ||||
{{ t('settings', 'No language set') }} | {{ t('settings', 'No language set') }} | ||||
</span> | </span> | ||||
</form> | |||||
</section> | |||||
</template> | </template> | ||||
<script> | <script> | ||||
import HeaderBar from '../shared/HeaderBar' | import HeaderBar from '../shared/HeaderBar' | ||||
import { SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants' | import { SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants' | ||||
import { validateLanguage } from '../../../utils/validate' | |||||
const { languages: { activeLanguage, commonLanguages, otherLanguages } } = loadState('settings', 'personalInfoParameters', {}) | const { languages: { activeLanguage, commonLanguages, otherLanguages } } = loadState('settings', 'personalInfoParameters', {}) | ||||
data() { | data() { | ||||
return { | return { | ||||
accountProperty: SETTING_PROPERTY_READABLE_ENUM.LANGUAGE, | accountProperty: SETTING_PROPERTY_READABLE_ENUM.LANGUAGE, | ||||
isValidForm: true, | |||||
commonLanguages, | commonLanguages, | ||||
otherLanguages, | otherLanguages, | ||||
language: activeLanguage, | language: activeLanguage, | ||||
isEditable() { | isEditable() { | ||||
return Boolean(this.language) | return Boolean(this.language) | ||||
}, | }, | ||||
}, | |||||
mounted() { | |||||
this.$nextTick(() => this.updateFormValidity()) | |||||
}, | |||||
methods: { | |||||
onUpdateLanguage() { | |||||
this.$nextTick(() => this.updateFormValidity()) | |||||
}, | |||||
updateFormValidity() { | |||||
this.isValidForm = this.$refs.form?.checkValidity() | |||||
isValidSection() { | |||||
return validateLanguage(this.language) | |||||
}, | }, | ||||
}, | }, | ||||
} | } | ||||
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
form::v-deep button { | |||||
&:disabled { | |||||
section { | |||||
padding: 10px 10px; | |||||
&::v-deep button:disabled { | |||||
cursor: default; | cursor: default; | ||||
} | } | ||||
} | } |
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
h3 { | h3 { | ||||
display: inline-flex; | |||||
width: 100%; | |||||
margin: 12px 0 0 0; | |||||
display: inline-flex; | |||||
width: 100%; | |||||
margin: 12px 0 0 0; | |||||
font-size: 16px; | font-size: 16px; | ||||
color: var(--color-text-light); | |||||
color: var(--color-text-light); | |||||
&.setting-property { | |||||
height: 38px; | |||||
} | |||||
label { | label { | ||||
cursor: pointer; | cursor: pointer; | ||||
} | } | ||||
} | } | ||||
h3.setting-property { | |||||
width: 100%; | |||||
min-height: 38px; | |||||
display: inline-flex; | |||||
position: relative; | |||||
flex-wrap: nowrap; | |||||
justify-content: flex-start; | |||||
} | |||||
.federation-control { | .federation-control { | ||||
margin: -12px 0 0 8px; | margin: -12px 0 0 8px; | ||||
} | } |
* | * | ||||
*/ | */ | ||||
/* | |||||
* Frontend validators, less strict than backend validators | |||||
* | |||||
* TODO add nice validation errors for Profile page settings modal | |||||
*/ | |||||
import { VALIDATE_EMAIL_REGEX } from '../constants/AccountPropertyConstants' | import { VALIDATE_EMAIL_REGEX } from '../constants/AccountPropertyConstants' | ||||
/** | /** | ||||
&& input.length <= 320 | && input.length <= 320 | ||||
&& encodeURIComponent(input).replace(/%../g, 'x').length <= 320 | && encodeURIComponent(input).replace(/%../g, 'x').length <= 320 | ||||
} | } | ||||
/** | |||||
* Validate the language input | |||||
* | |||||
* @param {string} input the input | |||||
* @returns {boolean} | |||||
*/ | |||||
export function validateLanguage(input) { | |||||
return input.code !== '' | |||||
&& input.name | |||||
} |