Skip to content

Commit

Permalink
Add property-defined actions
Browse files Browse the repository at this point in the history
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
  • Loading branch information
skjnldsv committed Jan 30, 2019
1 parent 7af5d37 commit 7a4cc3c
Show file tree
Hide file tree
Showing 12 changed files with 76 additions and 15 deletions.
12 changes: 9 additions & 3 deletions css/Properties/Properties.scss
Expand Up @@ -142,7 +142,9 @@ $property-value-max-width: 250px;

// show ext & delete button on full row hover
&:hover &__ext,
&:hover &__delete {
&:hover &__delete,
&:hover &__actions:not(.action-item--multiple),
&:hover &__actions.action-item--multiple .icon-more {
opacity: .5;
}

Expand All @@ -157,14 +159,17 @@ $property-value-max-width: 250px;
&:active {
opacity: .7;
// still show the delete button for keyboard accessibility
~ .property__delete {
~ .property__delete,
~ .property__actions:not(.action-item--multiple),
~ .property__actions.action-item--multiple .icon-more {
opacity: .5;
}
}
}

// Delete property button
&__delete {
&__delete,
&__actions {
position: absolute;
top: 0;
left: 100%;
Expand All @@ -174,6 +179,7 @@ $property-value-max-width: 250px;
border: 0;
background-color: transparent;
opacity: 0;
z-index: 10;
&:hover,
&:active,
&:focus {
Expand Down
4 changes: 4 additions & 0 deletions css/icons.scss
Expand Up @@ -35,3 +35,7 @@
.icon-eye-white {
@include icon-color('eye', 'contacts', $color-white, 1);
}

.icon-up {
@include icon-color('up', 'contacts', $color-black, 1);
}
3 changes: 3 additions & 0 deletions img/up.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/components/ContactDetails.vue
Expand Up @@ -95,9 +95,11 @@
<section v-else class="contact-details">
<!-- properties iteration -->
<!-- using contact.key in the key and index as key to avoid conflicts between similar data and exact key -->
<!-- passing the debounceUpdateContact so that the contact-property component contains the function
and allow us to use it on the rfcProps since the scope is forwarded to the actions -->
<contact-property v-for="(property, index) in sortedProperties" :key="`${index}-${contact.key}-${property.name}`" :index="index"
:sorted-properties="sortedProperties" :property="property" :contact="contact"
@updatedcontact="debounceUpdateContact" />
:update-contact="debounceUpdateContact" @updatedcontact="debounceUpdateContact" />

<!-- addressbook change select - no last property because class is not applied here,
empty property because this is a required prop on regular property-select. But since
Expand Down
12 changes: 11 additions & 1 deletion src/components/ContactDetails/ContactDetailsProperty.vue
Expand Up @@ -61,6 +61,14 @@ export default {
contact: {
type: Contact,
default: null
},
/**
* This is needed so that we can update
* the contact within the rfcProps actions
*/
updateContact: {
type: Function,
default: () => {}
}
},
Expand Down Expand Up @@ -139,7 +147,9 @@ export default {
* @returns {Object}
*/
propModel() {
return this.properties[this.propName]
// passing this to properties to allow us to scope the properties object
// this make possible defining actions there
return this.properties(this)[this.propName]
},
/**
Expand Down
3 changes: 1 addition & 2 deletions src/components/Properties/PropertyMultipleText.vue
Expand Up @@ -48,8 +48,7 @@
class="property__value" type="text" @input="updateValue">

<!-- delete the prop -->
<button v-if="!isReadOnly" :title="t('contacts', 'Delete')" class="property__delete icon-delete"
@click="deleteProperty" />
<action :actions="actions" class="property__actions" />
</div>

<!-- force order based on model -->
Expand Down
3 changes: 2 additions & 1 deletion src/main.js
Expand Up @@ -27,7 +27,7 @@ import { sync } from 'vuex-router-sync'
import { generateFilePath } from 'nextcloud-server/dist/router'

/** GLOBAL COMPONENTS AND DIRECTIVE */
import { AppNavigation, DatetimePicker, Multiselect, PopoverMenu } from 'nextcloud-vue'
import { Action, AppNavigation, DatetimePicker, Multiselect, PopoverMenu } from 'nextcloud-vue'
import ClickOutside from 'vue-click-outside'
import { VTooltip } from 'v-tooltip'
import VueClipboard from 'vue-clipboard2'
Expand All @@ -43,6 +43,7 @@ __webpack_nonce__ = btoa(OC.requestToken)
// eslint-disable-next-line
__webpack_public_path__ = generateFilePath('contacts', '', 'js/')

Vue.component('Action', Action)
Vue.component('AppNavigation', AppNavigation)
Vue.component('DatetimePicker', DatetimePicker)
Vue.component('Multiselect', Multiselect)
Expand Down
11 changes: 11 additions & 0 deletions src/mixins/PropertyMixin.js
Expand Up @@ -76,6 +76,17 @@ export default {
}
},

computed: {
actions() {
const del = {
text: t('contacts', 'Delete'),
icon: 'icon-delete',
action: this.deleteProperty
}
return [del, ...this.propModel.actions ? this.propModel.actions : []]
}
},

watch: {
/**
* Since we're updating a local data based on the value prop,
Expand Down
23 changes: 20 additions & 3 deletions src/models/rfcProps.js
Expand Up @@ -21,7 +21,17 @@
*/
import { VCardTime } from 'ical.js'

const properties = {
const copyNtoFN = ({ contact, updateContact }) => () => {
if (contact.vCard.hasProperty('n')) {
// Stevenson;John;Philip,Paul;Dr.;Jr.,M.D.,A.C.P.
// -> John Stevenson
const n = contact.vCard.getFirstPropertyValue('n')
contact.fullName = n.slice(0, 2).reverse().join(' ')
updateContact()
}
}

const properties = component => ({
nickname: {
readableName: t('contacts', 'Nickname'),
icon: 'icon-user'
Expand All @@ -39,7 +49,14 @@ const properties = {
defaultValue: {
value: ['', '', '', '', '']
},
icon: 'icon-user'
icon: 'icon-user',
actions: [
{
text: t('contacts', 'Copy to full name'),
icon: 'icon-up',
action: copyNtoFN(component)
}
]
},
note: {
readableName: t('contacts', 'Notes'),
Expand Down Expand Up @@ -266,7 +283,7 @@ const properties = {
{ id: 'O', name: t('contacts', 'Other') }
]
}
}
})

const fieldOrder = [
'org',
Expand Down
4 changes: 4 additions & 0 deletions src/services/checks/missingFN.js
Expand Up @@ -29,6 +29,10 @@ export default {
run: contact => {
return !contact.vCard.hasProperty('fn') // No FN
|| contact.vCard.getFirstPropertyValue('fn') === '' // Empty FN
|| ( // we don't want to fix newly created contacts
contact.dav // Existing contact
&& contact.vCard.getFirstPropertyValue('fn') === t('contacts', 'New contact') // AND Unchanged FN
)
},
fix: contact => {
if (contact.vCard.hasProperty('n')) {
Expand Down
4 changes: 4 additions & 0 deletions src/store/contacts.js
Expand Up @@ -285,6 +285,10 @@ const actions = {
* @returns {Promise}
*/
async updateContact(context, contact) {

// Checking contact validity 🙈
validate(contact)

let vData = ICAL.stringify(contact.vCard.jCal)

// if no dav key, contact does not exists on server
Expand Down

0 comments on commit 7a4cc3c

Please sign in to comment.