/*
* RCMCardDAV - CardDAV plugin for Roundcube webmail
*
* Copyright (C) 2011-2022 Benjamin Schieder <rcmcarddav@wegwerf.anderdonau.de>,
* Michael Stilkerich <ms@mike2k.de>
*
* This file is part of RCMCardDAV.
*
* RCMCardDAV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* RCMCardDAV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RCMCardDAV. If not, see <https://www.gnu.org/licenses/>.
*/
/* global $, rcmail, rcube_webmail, rcube_treelist_widget, UI, parent */
window.rcmail && rcmail.addEventListener('init', function (evt) {
if (rcmail.env.task !== 'settings') {
return
}
if (rcmail.env.action === 'plugin.carddav') {
if (rcmail.gui_objects.addressbookslist) {
// eslint-disable-next-line new-cap
rcmail.addressbooks_list = new rcube_treelist_widget(rcmail.gui_objects.addressbookslist, {
selectable: true,
tabexit: false,
parent_focus: true,
id_prefix: 'rcmli'
})
rcmail.addressbooks_list.addEventListener('select', function (node) { rcmail.carddav_AbListSelect(node) })
}
rcmail.register_command(
'plugin.carddav-AbToggleActive',
function (abookid, active) { rcmail.carddav_AbToggleActive(abookid, active) },
true
)
// don't show the Add account button if disabled by the admin
if (!rcmail.env.carddav_forbidCustomAddressbooks) {
rcmail.register_command('plugin.carddav-AccAdd', function () { rcmail.carddav_AccAdd() }, true)
}
rcmail.register_command('plugin.carddav-AccRm', function () { rcmail.carddav_AccRm() }, false)
rcmail.register_command('plugin.carddav-AccRedisc', function () { rcmail.carddav_AccRedisc() }, false)
rcmail.register_command('plugin.carddav-AbSync', function () { rcmail.carddav_AbSync('AbSync') }, false)
rcmail.register_command('plugin.carddav-AbClrCache', function () { rcmail.carddav_AbSync('AbClrCache') }, false)
} else if (rcmail.env.action === 'plugin.carddav.AbDetails') {
rcmail.register_command(
'plugin.carddav-AbSave',
function () { rcmail.carddav_AccAbSave('addressbookdetails', 'plugin.carddav.AbSave') },
true // enable
)
} else if (rcmail.env.action === 'plugin.carddav.AccDetails') {
const action = $('input[name="accountid"]').val() === 'new' ? 'plugin.carddav.AccAdd' : 'plugin.carddav.AccSave'
rcmail.register_command(
'plugin.carddav-AccSave',
function () { rcmail.carddav_AccAbSave('accountdetails', action) },
true // enable
)
}
})
// handler when a row (account/addressbook) of the list is selected
rcube_webmail.prototype.carddav_AbListSelect = function (node) {
const id = node.id
let url
this.enable_command('plugin.carddav-AccRm', false)
this.enable_command('plugin.carddav-AccRedisc', false)
this.enable_command('plugin.carddav-AbSync', false)
this.enable_command('plugin.carddav-AbClrCache', false)
if (id.startsWith('_acc')) {
// Account
url = '&_action=plugin.carddav.AccDetails&accountid=' + id.substr(4)
this.enable_command('plugin.carddav-AccRm', !node.classes.includes('preset'))
this.enable_command('plugin.carddav-AccRedisc', true)
} else if (id.startsWith('_abook')) {
// Addressbook
url = '&_action=plugin.carddav.AbDetails&abookid=' + id.substr(6)
this.enable_command('plugin.carddav-AbSync', true)
this.enable_command('plugin.carddav-AbClrCache', true)
} else {
// unexpected id
return
}
const win = this.get_frame_window(this.env.contentframe)
if (win) {
this.env.frame_lock = this.set_busy(true, 'loading')
win.location.href = this.env.comm_path + '&_framed=1' + url
}
}
// handler invoked when the toggle-active checkbox for an addressbook is changed
rcube_webmail.prototype.carddav_AbToggleActive = function (abookid, active) {
if (abookid) {
const lock = this.display_message('', 'loading')
this.http_post('plugin.carddav.AbToggleActive', { abookid, active: (active ? '1' : '0') }, lock)
}
}
// resets state of addressbook active checkbox (e.g. on error), invoked from the backend
rcube_webmail.prototype.carddav_AbResetActive = function (abook, active) {
const row = rcmail.addressbooks_list.get_item('_abook' + abook, true)
if (row) {
$('input[name="_active[]"]', row).first().prop('checked', active)
}
}
// invoked when the Save button in the account or addressbook detail view is pressed
rcube_webmail.prototype.carddav_AccAbSave = function (formname, action) {
if (!document.forms[formname].reportValidity()) {
return
}
const lock = this.display_message('', 'loading')
const formDataTuples = $('form[name="' + formname + '"]').serializeArray()
const formData = {}
for (const tuple of formDataTuples) {
formData[tuple.name] = tuple.value
}
this.http_post(action, formData, lock)
}
/**
* Updates the fields of a form shown in the content frame and related elements in the addressbook list.
*
* This function is invoked both from the content frame (e.g., AbSave) as well as the main frame (e.g. AbSync) and must
* handle both cases.
*
* @param {Object} formData The data fields to update in the form and the addressbooks list.
*/
rcube_webmail.prototype.carddav_UpdateForm = function (formData) {
const win = this.is_framed() ? window : this.get_frame_window(this.env.contentframe)
for (const fieldKey in formData) {
const fieldType = formData[fieldKey][0]
const fieldValue = formData[fieldKey][1]
const inputSelectorByName = 'input[name="' + fieldKey + '"]'
let node, nodeUpdate, listAccSel
switch (fieldType) {
case 'text':
case 'timestr':
case 'password':
$(inputSelectorByName, win.document).val(fieldValue)
break
case 'radio':
$(inputSelectorByName + '[value="' + fieldValue + '"]', win.document).prop('checked', true)
break
case 'datetime':
case 'plain':
$('span#rcmcrd_plain_' + fieldKey, win.document).text(fieldValue)
break
// this is a special case to update an element given by a CSS selector in the parent document, i.e. update the
// name in the addressbook list.
case 'parent':
listAccSel = '#rcmli' + fieldKey
node = $(listAccSel + ' > a', win.parent.document)
// For some reason, the toggle active checkbox of the node doesn't work anymore after using the
// treelist.update() function. What can be observed is that the list select handler is called upon clicking the
// checkbox and before the ToggleActive handler is called, the ToggleActive handler will then be skipped because
// the list select handler sets the rcmail object busy. The select handler is normally not called when clicking
// the checkbox, and I haven't figured out so far why the behavior is different after treelist.update().
// Therefore, we only carry out the change if necessary.
if (node.children('span').text() !== fieldValue) {
node.children('span').text(fieldValue)
nodeUpdate = { html: node.prop('outerHTML') }
win.parent.window.rcmail.addressbooks_list.update(fieldKey, nodeUpdate, true)
// fixup the checkboxes (note: this is elastic-specific)
if (typeof UI === 'object' && typeof UI.pretty_checkbox === 'function') {
$(listAccSel + ' input[type="checkbox"]', parent.document).each(function () { UI.pretty_checkbox(this) })
}
}
break
}
}
}
// invoked from the backend to insert new accounts or addressbooks in the list
// records is an array of arrays, of which each has the members:
// [0]: object id
// [1]: li HTML code
// [2]: parent id (null for accounts, account id for addressbooks)
//
// If selectId is specified as an array of object type (acc or abook) and object id, the so specified item is selected
rcube_webmail.prototype.carddav_InsertListElem = function (records, selectId) {
for (const record of records) {
const [id, newLi, accountId] = record
let type, classes
let domIdParent = null
if (accountId === undefined) {
type = 'acc'
classes = ['account']
} else {
type = 'abook'
classes = ['addressbook']
domIdParent = '_acc' + accountId
}
const domId = '_' + type + id
parent.window.rcmail.addressbooks_list.insert(
{ id: domId, html: newLi, classes },
domIdParent,
true
)
// fixup the checkboxes (note: this is elastic-specific)
if (typeof UI === 'object' && typeof UI.pretty_checkbox === 'function') {
$('#rcmli' + domId + ' input[type="checkbox"]', parent.document).each(function () { UI.pretty_checkbox(this) })
}
}
if (selectId !== undefined) {
const [type, id] = selectId
const domId = '_' + type + id
parent.window.rcmail.addressbooks_list.select(domId)
}
}
// this is called when the Add Account button is clicked
rcube_webmail.prototype.carddav_AccAdd = function () {
const win = this.get_frame_window(this.env.contentframe)
if (win) {
this.env.frame_lock = this.set_busy(true, 'loading')
win.location.href = this.env.comm_path + '&_framed=1&_action=plugin.carddav.AccDetails&accountid=new&_nav=hide'
}
}
// this is called when the Delete Account button is clicked
rcube_webmail.prototype.carddav_AccRm = function () {
const selectedNode = rcmail.addressbooks_list.get_selection()
if (selectedNode.startsWith('_acc')) {
const accountid = selectedNode.substr(4)
const lock = this.display_message('', 'loading')
this.http_post('plugin.carddav.AccRm', { accountid }, lock)
}
}
// this is called when the Rediscover Account button is clicked
rcube_webmail.prototype.carddav_AccRedisc = function () {
const selectedNode = rcmail.addressbooks_list.get_selection()
if (selectedNode.startsWith('_acc')) {
const accountid = selectedNode.substr(4)
const lock = this.display_message('', 'loading')
this.http_post('plugin.carddav.AccRedisc', { accountid }, lock)
}
}
// invoked from the backend to remove accounts or addressbooks from the addressbook list
rcube_webmail.prototype.carddav_RemoveListElem = function (accountId, abookIds) {
if (abookIds === undefined) {
// remove the entire account
const domIdAcc = '_acc' + accountId
parent.window.rcmail.addressbooks_list.remove(domIdAcc)
} else {
// remove only the given abooks
for (const abookId of abookIds) {
const domIdAbook = '_abook' + abookId
parent.window.rcmail.addressbooks_list.remove(domIdAbook)
}
}
// if the selected node was removed in the process, set the content frame to the blank page
const selectedNode = rcmail.addressbooks_list.get_selection()
if (selectedNode && rcmail.addressbooks_list.get_node(selectedNode) === undefined) {
const win = this.get_frame_window(this.env.contentframe)
if (win) {
win.location.href = this.env.blankpage
}
}
}
// this is called when the Resync addressbook button is hit
// synctype: AbSync, AbClrCache
rcube_webmail.prototype.carddav_AbSync = function (synctype) {
const selectedNode = rcmail.addressbooks_list.get_selection()
if (selectedNode.startsWith('_abook')) {
const abookid = selectedNode.substr(6)
const lock = this.display_message(rcmail.get_label(synctype + '_msg_inprogress', 'carddav'), 'loading')
this.http_post('plugin.carddav.AbSync', { abookid, synctype }, lock)
}
}
// vim: ts=2:sw=2:expandtab:fenc=utf8:ff=unix:tw=120