/* * This file is part of DAV-4-TbSync. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; var ui = { getUriFromDirectoryId: function(ownerId) { let directories = MailServices.ab.directories; for (let directory of directories) { if (directory instanceof Components.interfaces.nsIAbDirectory) { if (ownerId.startsWith(directory.dirPrefId)) return directory.URI; } } return null; }, //function to get correct uri of current card for global book as well for mailLists getSelectedUri : function(aUri, aCard) { if (aUri == "moz-abdirectory://?") { //get parent via card owner let ownerId = aCard.directoryId; return dav.ui.getUriFromDirectoryId(ownerId); } else if (MailServices.ab.getDirectory(aUri).isMailList) { //MailList suck, we have to cut the url to get the parent return aUri.substring(0, aUri.lastIndexOf("/")) } else { return aUri; } }, //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //* Functions to handle advanced UI elements of AB //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * updatePref: function(aDocument, icon, toggle = false) { if (toggle) { if (icon.parentNode.meta.includes("PREF")) icon.parentNode.meta = icon.parentNode.meta.filter(e => e != "PREF"); else icon.parentNode.meta.push("PREF"); icon.parentNode.updateFunction (aDocument); } if (icon.parentNode.meta.includes("PREF")) { icon.setAttribute("src", "chrome://dav4tbsync/content/skin/type.pref.png"); } else { icon.setAttribute("src", "chrome://dav4tbsync/content/skin/type.nopref.png"); } }, updateType: function(aDocument, button, newvalue = null) { if (newvalue) { //we declare allowedValues to be non-overlapping -> remove all allowed values and just add the newvalue button.parentNode.meta = button.parentNode.meta.filter(value => -1 == button.allowedValues.indexOf(value)); if (button.allowedValues.includes(newvalue)) { //hardcoded sort order: HOME/WORK always before other types if (["HOME","WORK"].includes(newvalue)) button.parentNode.meta.unshift(newvalue); else button.parentNode.meta.push(newvalue); } button.parentNode.updateFunction (aDocument); } let intersection = button.parentNode.meta.filter(value => -1 !== button.allowedValues.indexOf(value)); let buttonType = (intersection.length > 0) ? intersection[0].toLowerCase() : button.otherIcon; button.setAttribute("image","chrome://dav4tbsync/content/skin/type."+buttonType+"10.png"); }, dragdrop: { handleEvent(event) { //only allow to drag the elements which are valid drag targets if (event.target.getAttribute("dragtarget") != "true") { event.stopPropagation(); return; } let outerbox = event.currentTarget; let richlistitem = outerbox.parentNode; switch (event.type) { case "dragenter": case "dragover": let dropIndex = richlistitem.parentNode.getIndexOfItem(richlistitem); let dragIndex = richlistitem.parentNode.getIndexOfItem(richlistitem.ownerDocument.getElementById(event.dataTransfer.getData("id"))); let centerY = event.currentTarget.clientHeight / 2; let insertBefore = (event.offsetY < centerY); let moveNeeded = !(dropIndex == dragIndex || (dropIndex+1 == dragIndex && !insertBefore) || (dropIndex-1 == dragIndex && insertBefore)); if (moveNeeded) { if (insertBefore) { richlistitem.parentNode.insertBefore(richlistitem.parentNode.getItemAtIndex(dragIndex), richlistitem); } else { richlistitem.parentNode.insertBefore(richlistitem.parentNode.getItemAtIndex(dragIndex), richlistitem.nextSibling); } } event.preventDefault(); break; case "drop": event.preventDefault(); case "dragleave": break; case "dragstart": event.currentTarget.style["background-color"] = "#eeeeee"; event.dataTransfer.setData("id", richlistitem.id); break; case "dragend": event.currentTarget.style["background-color"] = "transparent"; outerbox.updateFunction(outerbox.ownerDocument); break; default: return undefined; } }, }, //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //* Functions to handle multiple email addresses in AB (UI) //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * getNewEmailDetailsRow: function (aWindow, aItemData) { let emailType = "other"; if (aItemData.meta.includes("HOME")) emailType = "home"; else if (aItemData.meta.includes("WORK")) emailType = "work"; //first column let vbox = aWindow.document.createXULElement("vbox"); vbox.setAttribute("class","CardViewText"); vbox.setAttribute("style","margin-right:1ex; margin-bottom:0px;"); let image = aWindow.document.createXULElement("image"); image.setAttribute("width","10"); image.setAttribute("height","10"); image.setAttribute("src", "chrome://dav4tbsync/content/skin/type."+emailType+"10.png"); vbox.appendChild(image); //second column let description = aWindow.document.createXULElement("description"); description.setAttribute("class","plain"); let namespace = aWindow.document.lookupNamespaceURI("html"); let a = aWindow.document.createElementNS(namespace, "a"); a.setAttribute("href", "mailto:" + aItemData.value); a.textContent = aItemData.value; description.appendChild(a); if (aItemData.meta.includes("PREF")) { let pref = aWindow.document.createXULElement("image"); pref.setAttribute("style", "margin-left:1ex;"); pref.setAttribute("width", "11"); pref.setAttribute("height", "10"); pref.setAttribute("src", "chrome://dav4tbsync/content/skin/type.nopref.png"); description.appendChild(pref); } //row let row = aWindow.document.createElement("tr"); let cell1 = aWindow.document.createElement("td"); let cell2 = aWindow.document.createElement("td"); cell2.setAttribute("width","100%"); cell1.appendChild(vbox); cell2.appendChild(description); row.appendChild(cell1); row.appendChild(cell2); return row; }, getNewEmailListItem: function (aDocument, aItemData) { //hbox let outerhbox = aDocument.createXULElement("hbox"); outerhbox.setAttribute("dragtarget", "true"); outerhbox.setAttribute("flex", "1"); outerhbox.setAttribute("align", "center"); outerhbox.setAttribute("style", "padding:0; margin:0"); outerhbox.updateFunction = dav.ui.updateEmails; outerhbox.meta = aItemData.meta; outerhbox.addEventListener("dragenter", dav.ui.dragdrop); outerhbox.addEventListener("dragover", dav.ui.dragdrop); outerhbox.addEventListener("dragleave", dav.ui.dragdrop); outerhbox.addEventListener("dragstart", dav.ui.dragdrop); outerhbox.addEventListener("dragend", dav.ui.dragdrop); outerhbox.addEventListener("drop", dav.ui.dragdrop); outerhbox.style["background-image"] = "url('chrome://dav4tbsync/content/skin/dragdrop.png')"; outerhbox.style["background-position"] = "right"; outerhbox.style["background-repeat"] = "no-repeat"; //button let button = aDocument.createXULElement("button"); button.allowedValues = ["HOME", "WORK"]; button.otherIcon = "other"; button.setAttribute("type", "menu"); button.setAttribute("style", "width: 35px; min-width: 35px; margin: 0; padding:0"); button.appendChild(aDocument.getElementById("DavMenuTemplate").children[0].cloneNode(true)); outerhbox.appendChild(button); //email box let emailbox = aDocument.createXULElement("hbox"); emailbox.setAttribute("flex", "1"); let email = aDocument.createElement("input"); email.setAttribute("style", "width: 240px"); email.setAttribute("value", aItemData.value); email.addEventListener("change", function(e) {dav.ui.updateEmails(aDocument)}); email.addEventListener("keydown", function(e) {if (e.key == "Enter") {e.stopPropagation(); e.preventDefault(); if (e.target.value != "") { dav.ui.addEmailEntry(e.target.ownerDocument); }}}); emailbox.appendChild(email); outerhbox.appendChild(emailbox); //image let image = aDocument.createXULElement("image"); image.setAttribute("width", "11"); image.setAttribute("height", "10"); image.setAttribute("style", "margin:2px 20px 2px 1ex"); image.addEventListener("click", function(e) { dav.ui.updatePref(aDocument, e.target, true); }); outerhbox.appendChild(image); //richlistitem let richlistitem = aDocument.createXULElement("richlistitem"); richlistitem.setAttribute("id", "entry_" + TbSync.generateUUID()); richlistitem.setAttribute("style", "padding:0;margin:0;"); richlistitem.appendChild(outerhbox); return richlistitem; }, getEmailListItemElement: function(item, element) { switch (element) { case "dataContainer": return item.children[0]; case "button": return item.children[0].children[0]; case "email": return item.children[0].children[1].children[0]; case "pref": return item.children[0].children[2]; default: return null; } }, addEmailEntry: function(aDocument) { let list = aDocument.getElementById("X-DAV-EmailAddressList"); let data = {value: "", meta: ["HOME"]}; let item = list.appendChild(dav.ui.getNewEmailListItem(aDocument, data)); list.ensureElementIsVisible(item); dav.ui.updateType(aDocument, dav.ui.getEmailListItemElement(item, "button")); dav.ui.updatePref(aDocument, dav.ui.getEmailListItemElement(item, "pref")); dav.ui.getEmailListItemElement(item, "email").focus(); }, //if any setting changed, we need to update Primary and Secondary Email Fields updateEmails: function(aDocument) { let list = aDocument.getElementById("X-DAV-EmailAddressList"); let emails = []; for (let i=0; i < list.children.length; i++) { let item = list.children[i]; let email = dav.ui.getEmailListItemElement(item, "email").value.trim(); if (email != "") { let json = {}; json.meta = dav.ui.getEmailListItemElement(item, "dataContainer").meta; json.value = email; emails.push(json); } } aDocument.getElementById("X-DAV-JSON-Emails").value = JSON.stringify(emails); //now update all other TB email fields based on the new JSON data let emailData = dav.tools.getEmailsFromJSON(aDocument.getElementById("X-DAV-JSON-Emails").value); for (let field in emailData) { if (emailData.hasOwnProperty(field)) { aDocument.getElementById(field).value = emailData[field].join(", "); } } }, //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * //* Functions to handle multiple phone numbers in AB (UI) //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * getNewPhoneDetailsRow: function (aWindow, aItemData) { let phoneType1 = ""; if (aItemData.meta.includes("HOME")) phoneType1 = "home"; else if (aItemData.meta.includes("WORK")) phoneType1 = "work"; let phoneType2 = ""; if (aItemData.meta.includes("CELL")) phoneType2 = "cell"; else if (aItemData.meta.includes("FAX")) phoneType2 = "fax"; else if (aItemData.meta.includes("PAGER")) phoneType2 = "pager"; else if (aItemData.meta.includes("CAR")) phoneType2 = "car"; else if (aItemData.meta.includes("VIDEO")) phoneType2 = "video"; else if (aItemData.meta.includes("VOICE")) phoneType2 = "voice"; //first column let vbox = aWindow.document.createXULElement("hbox"); vbox.setAttribute("pack","end"); vbox.setAttribute("class","CardViewText"); vbox.setAttribute("style","margin-bottom:0px;"); if (phoneType1) { let image = aWindow.document.createXULElement("image"); image.setAttribute("style","margin-right:1ex;"); image.setAttribute("width","10"); image.setAttribute("height","10"); image.setAttribute("src", "chrome://dav4tbsync/content/skin/type."+phoneType1+"10.png"); vbox.appendChild(image); } if (phoneType2) { let image = aWindow.document.createXULElement("image"); image.setAttribute("style","margin-right:1ex;"); image.setAttribute("width","10"); image.setAttribute("height","10"); image.setAttribute("src", "chrome://dav4tbsync/content/skin/type."+phoneType2+"10.png"); vbox.appendChild(image); } //second column let description = aWindow.document.createXULElement("description"); description.setAttribute("class","plain"); description.setAttribute("style","-moz-user-select: text;"); description.textContent = aItemData.value; if (aItemData.meta.includes("PREF")) { let pref = aWindow.document.createXULElement("image"); pref.setAttribute("style", "margin-left:1ex;"); pref.setAttribute("width", "11"); pref.setAttribute("height", "10"); pref.setAttribute("src", "chrome://dav4tbsync/content/skin/type.nopref.png"); description.appendChild(pref); } //row let row = aWindow.document.createElement("tr"); let cell1 = aWindow.document.createElement("td"); let cell2 = aWindow.document.createElement("td"); cell2.setAttribute("width","100%"); cell1.appendChild(vbox); cell2.appendChild(description); row.appendChild(cell1); row.appendChild(cell2); return row; }, getNewPhoneListItem: function (aDocument, aItemData) { //hbox let outerhbox = aDocument.createXULElement("hbox"); outerhbox.setAttribute("dragtarget", "true"); outerhbox.setAttribute("flex", "1"); outerhbox.setAttribute("align", "center"); outerhbox.setAttribute("style", "padding:0; margin:0"); outerhbox.updateFunction = dav.ui.updatePhoneNumbers; outerhbox.meta = aItemData.meta; outerhbox.addEventListener("dragenter", dav.ui.dragdrop); outerhbox.addEventListener("dragover", dav.ui.dragdrop); outerhbox.addEventListener("dragleave", dav.ui.dragdrop); outerhbox.addEventListener("dragstart", dav.ui.dragdrop); outerhbox.addEventListener("dragend", dav.ui.dragdrop); outerhbox.addEventListener("drop", dav.ui.dragdrop); outerhbox.style["background-image"] = "url('chrome://dav4tbsync/content/skin/dragdrop.png')"; outerhbox.style["background-position"] = "right"; outerhbox.style["background-repeat"] = "no-repeat"; //button1 let button1 = aDocument.createXULElement("button"); button1.allowedValues = ["HOME", "WORK"]; button1.otherIcon = "none"; button1.setAttribute("type", "menu"); button1.setAttribute("style", "width: 35px; min-width: 35px; margin: 0; padding:0"); button1.appendChild(aDocument.getElementById("DavMenuTemplate").children[1].cloneNode(true)); outerhbox.appendChild(button1); //button2 let button2 = aDocument.createXULElement("button"); button2.allowedValues = ["CELL", "FAX", "PAGER", "CAR", "VIDEO", "VOICE"] ; //same order as in getNewPhoneDetailsRow button2.otherIcon = "none"; button2.setAttribute("type", "menu"); button2.setAttribute("class", "plain"); button2.setAttribute("style", "width: 35px; min-width: 35px; margin: 0;"); button2.appendChild(aDocument.getElementById("DavMenuTemplate").children[2].cloneNode(true)); outerhbox.appendChild(button2); //phone box let phonebox = aDocument.createXULElement("hbox"); phonebox.setAttribute("flex", "1"); let phone = aDocument.createElement("input"); phone.setAttribute("style", "width: 205px"); phone.setAttribute("value", aItemData.value); phone.addEventListener("change", function(e) {dav.ui.updatePhoneNumbers(aDocument)}); phone.addEventListener("keydown", function(e) {if (e.key == "Enter") {e.stopPropagation(); e.preventDefault(); if (e.target.value != "") { dav.ui.addPhoneEntry(e.target.ownerDocument); }}}); phonebox.appendChild(phone); outerhbox.appendChild(phonebox); //image let image = aDocument.createXULElement("image"); image.setAttribute("width", "11"); image.setAttribute("height", "10"); image.setAttribute("style", "margin:2px 20px 2px 1ex"); image.addEventListener("click", function(e) { dav.ui.updatePref(aDocument, e.target, true); }); outerhbox.appendChild(image); //richlistitem let richlistitem = aDocument.createXULElement("richlistitem"); richlistitem.setAttribute("id", "entry_" + TbSync.generateUUID()); richlistitem.setAttribute("style", "padding:0;margin:0;"); richlistitem.appendChild(outerhbox); return richlistitem; }, updatePhoneNumbers: function(aDocument) { let list = aDocument.getElementById("X-DAV-PhoneNumberList"); let phones = []; for (let i=0; i < list.children.length; i++) { let item = list.children[i]; let phone = dav.ui.getPhoneListItemElement(item, "phone").value.trim(); if (phone != "") { let json = {}; json.meta = dav.ui.getPhoneListItemElement(item, "dataContainer").meta; json.value = phone; phones.push(json); } } aDocument.getElementById("X-DAV-JSON-Phones").value = JSON.stringify(phones); //now update all other TB number fields based on the new JSON data let phoneData = dav.tools.getPhoneNumbersFromJSON(aDocument.getElementById("X-DAV-JSON-Phones").value); for (let field in phoneData) { if (phoneData.hasOwnProperty(field)) { aDocument.getElementById(field).value = phoneData[field].join(", "); } } }, addPhoneEntry: function(aDocument) { let list = aDocument.getElementById("X-DAV-PhoneNumberList"); let data = {value: "", meta: ["VOICE"]}; let item = list.appendChild(dav.ui.getNewPhoneListItem(aDocument, data)); list.ensureElementIsVisible(item); dav.ui.updateType(aDocument, dav.ui.getPhoneListItemElement(item, "button1")); dav.ui.updateType(aDocument, dav.ui.getPhoneListItemElement(item, "button2")); dav.ui.updatePref(aDocument, dav.ui.getPhoneListItemElement(item, "pref")); dav.ui.getPhoneListItemElement(item, "phone").focus(); }, getPhoneListItemElement: function(item, element) { switch (element) { case "dataContainer": return item.children[0]; case "button1": return item.children[0].children[0]; case "button2": return item.children[0].children[1]; case "phone": return item.children[0].children[2].children[0]; case "pref": return item.children[0].children[3]; default: return null; } }, }