Browse Source

Merge branch 'v2' into 'master'

V2

Merge v2 to master. Final 2.0.0

See merge request !1
tags/v2.0.4
Christoph Haas 4 years ago
parent
commit
c2f26697fb
24 changed files with 1587 additions and 1561 deletions
  1. +18
    -0
      .idea/contactimporter.iml
  2. +6
    -0
      .idea/vcs.xml
  3. +63
    -139
      build.xml
  4. +8
    -10
      config.php
  5. +22
    -22
      js/ABOUT.js
  6. +19
    -11
      js/data/ResponseHandler.js
  7. +14
    -16
      js/dialogs/ImportContentPanel.js
  8. +358
    -269
      js/dialogs/ImportPanel.js
  9. +172
    -103
      js/plugin.contactimporter.js
  10. +136
    -0
      js/ui/ContextMenu.js
  11. +6
    -4
      manifest.xml
  12. +5
    -0
      php/.gitignore
  13. +5
    -0
      php/composer.json
  14. +72
    -0
      php/download.php
  15. +612
    -265
      php/module.contact.php
  16. +24
    -11
      php/plugin.contactimporter.php
  17. +18
    -16
      php/upload.php
  18. +0
    -690
      php/vcf/class.vCard.php
  19. +29
    -5
      resources/css/contactimporter-main.css
  20. BIN
      resources/images/download.png
  21. BIN
      resources/images/download.xcf
  22. BIN
      resources/images/import_icon.png
  23. BIN
      resources/images/upload.png
  24. BIN
      resources/images/upload.xcf

+ 18
- 0
.idea/contactimporter.iml View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library name="PHARS">
<CLASSES>
<root url="phar://$MODULE_DIR$/php/composer.phar" />
</CLASSES>
<SOURCES>
<root url="phar://$MODULE_DIR$/php/composer.phar" />
</SOURCES>
</library>
</orderEntry>
</component>
</module>

+ 6
- 0
.idea/vcs.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

+ 63
- 139
build.xml View File

@@ -1,18 +1,15 @@
<project default="all">
<!--############# CONFIGURE ALL PROPERTIES FOR THE REPLACER HERE ################-->
<property name="plugin_version" value="1.0.3"/>
<!-- EOC -->
<property name="root-folder" value="${basedir}/../"/>
<property name="tools-folder" value="${root-folder}/TOOLS/"/>
<property name="target-folder" value="${root-folder}/DEPLOY/plugins"/>
<property environment="env"/>
<property name="root-folder" value="${basedir}/../../"/>
<property name="tools-folder" value="${root-folder}/tools/"/>
<property name="target-folder" value="${root-folder}/deploy/plugins"/>
<property name="server-folder" value="${root-folder}/server"/>

<import file="${tools-folder}/antutil.xml"/>

<typedef file="${tools-folder}/antlib.xml">
<classpath>
<pathelement location="${tools-folder}/tools.jar"/>
<pathelement location="${tools-folder}/lib/compiler.jar"/>
</classpath>
</typedef>

@@ -21,30 +18,8 @@
<pathelement location="${tools-folder}/lib/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<!-- os checks for xmllint... -->
<condition property="isWindows" value="true">
<os family="windows" />
</condition>
<!-- define nicknames for libraries -->
<property name="yui-compressor" location="${tools-folder}/lib/yuicompressor-2.4.2.jar" />
<property name="yui-compressor-ant-task" location="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" />

<!-- adds libraries to the classpath -->
<path id="yui.classpath">
<pathelement location="${yui-compressor}" />
<pathelement location="${yui-compressor-ant-task}" />
</path>

<!-- define tasks -->
<taskdef name="yui-compressor" classname="net.noha.tools.ant.yuicompressor.tasks.YuiCompressorTask">
<classpath refid="yui.classpath" />
</taskdef>

<!-- Determine plugin name -->
<var name="plugin" unset="true"/>
<basename file="${basedir}" property="plugin"/>

<!-- The Plugin distribution files -->
@@ -54,8 +29,7 @@

<!-- The Plugin CSS files -->
<property name="plugin-css-folder" value="resources/css"/>
<property name="plugin-css-file" value="${plugin}-min.css"/>
<property name="plugin-css-debug-file" value="${plugin}.css"/>
<property name="plugin-css-file" value="${plugin}.css"/>

<!-- Meta target -->
<target name="all" depends="concat, compress"/>
@@ -68,16 +42,6 @@
<include name="${plugin-file}"/>
<include name="${plugin-debugfile}"/>
</fileset>
<fileset dir="${target-folder}/${plugin-folder}/php">
<include name="**/*.php"/>
</fileset>
<fileset dir="${target-folder}/${plugin-folder}/resources">
<include name="**/*"/>
</fileset>
<fileset dir="${target-folder}/${plugin-folder}/${plugin-css-folder}">
<include name="${plugin-css-debug-file}"/>
<include name="${plugin-css-file}"/>
</fileset>
</delete>
</target>

@@ -89,19 +53,11 @@
<then>
<mkdir dir="${target-folder}/${plugin-folder}/js"/>
<echo message="Concatenating: ${plugin-debugfile}"/>
<!-- TODO: fix JS files for zConcat -->
<!--zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
<zConcat outputFolder="${target-folder}/${plugin-folder}/js" outputFile="${plugin-debugfile}" prioritize="\w+">
<concatfiles>
<fileset dir="js" includes="**/*.js" />
</concatfiles>
</zConcat-->
<concat destfile="${target-folder}/${plugin-folder}/js/${plugin-debugfile}">
<fileset file="js/ABOUT.js" />
<fileset file="js/plugin.contactimporter.js" />
<fileset file="js/data/ResponseHandler.js" />
<fileset file="js/dialogs/ImportContentPanel.js" />
<fileset file="js/dialogs/ImportPanel.js" />
</concat>
</zConcat>
</then>
</if>

@@ -110,8 +66,8 @@
<available file="${plugin-css-folder}" type="dir" />
<then>
<mkdir dir="${target-folder}/${plugin-folder}/${plugin-css-folder}"/>
<echo message="Concatenating: ${plugin-css-debug-file}"/>
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-debug-file}">
<echo message="Concatenating: ${plugin-css-file}"/>
<zConcat outputFolder="${target-folder}/${plugin-folder}/${plugin-css-folder}" outputFile="${plugin-css-file}">
<concatfiles>
<fileset dir="${plugin-css-folder}" includes="**/*.css" />
</concatfiles>
@@ -155,16 +111,7 @@
var npgettext = function(msgctxt, msgid, msgid_plural, count) {};
var pgettext = function(msgctxt, msgid) {};
</externs>
</zCompile>
<!--yui-compressor
warn="false"
munge="true"
preserveallsemicolons="false"
fromdir="${target-folder}/${plugin-folder}/js"
todir="${target-folder}/${plugin-folder}/js">

<include name="${plugin-debugfile}" />
</yui-compressor-->
</zCompile>
</then>
</if>
</target>
@@ -172,105 +119,82 @@
<!-- syntax check all PHP files -->
<target name="validate">
<if>
<available file="config.php" type="file" />
<available file="php" filepath="${env.PATH}" />
<then>
<antcall target="syntax-check">
<param name="file" value="config.php"/>
</antcall>
</then>
</if>
<if>
<available file="php" type="dir" />
<then>
<foreach target="syntax-check" param="file">
<path>
<fileset dir=".">
<include name="**/*.php"/>
</fileset>
</path>
</foreach>
<if>
<available file="config.php" type="file" />
<then>
<antcall target="syntax-check">
<param name="file" value="config.php"/>
</antcall>
</then>
</if>
<if>
<available file="php" type="dir" />
<then>
<foreach target="syntax-check" param="file">
<path>
<fileset dir=".">
<exclude name="php/vendor/**" />
<include name="**/*.php"/>
</fileset>
</path>
</foreach>
</then>
</if>
</then>
<else>
<echo message="WARNING: PHP not available, not performing syntax-check on php files"/>
</else>
</if>
</target>

<target name="syntax-check">
<echo message="validating ${file}"/>
<exec executable="php" failonerror="true" failifexecutionfails="false">
<exec executable="php" failonerror="true">
<arg value="-l"/>
<arg value="${file}"/>
</exec>
</target>
<!-- on windows we do not check the xml file -->
<target name="xml-os-sel" depends="xml-check,xml-copy">
<echo>Processing manifest.xml</echo>
</target>
<!-- check manifest.xml if we are on windows... -->
<target name="xml-check" unless="isWindows">
<echo message="Checking xml: manifest.xml" />
<!-- Copy (and validate) manifest.xml -->
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true" error="/dev/stdout" failifexecutionfails="false">
<arg value="--valid"/>
<arg value="--path"/>
<arg value="${root-folder}/server"/>
<arg value="manifest.xml"/>
</exec>
</target>
<!-- check manifest.xml if we are on windows... -->
<target name="xml-copy" if="isWindows">
<echo message="Copying xml: manifest.xml" />
<!-- Copy manifest.xml -->
<copy todir="${target-folder}/${plugin-folder}">
<fileset dir=".">
<include name="manifest.xml"/>
</fileset>
</copy>
</target>

<!-- Install all files into the target folder -->
<target name="deploy" depends="clean, compress, compresscss, validate, xml-os-sel">
<target name="deploy" depends="compress, validate">
<mkdir dir="${target-folder}/${plugin-folder}"/>

<!-- Copy (and validate) manifest.xml -->
<if>
<available file="xmllint" filepath="${env.PATH}" />
<then>
<exec executable="xmllint" output="${target-folder}/${plugin-folder}/manifest.xml" failonerror="true">
<arg value="--valid"/>
<arg value="--path"/>
<arg value="${server-folder}"/>
<arg value="manifest.xml"/>
</exec>
</then>
<else>
<echo message="WARNING: xmllint not available, not performing syntax-check on manifest.xml"/>
<!-- xmllint is not available, so we must copy the file manually -->
<copy todir="${target-folder}/${plugin-folder}">
<fileset dir=".">
<include name="manifest.xml"/>
</fileset>
</copy>
</else>
</if>

<!-- copy files -->
<copy todir="${target-folder}/${plugin-folder}">
<fileset dir=".">
<include name="resources/**/*"/>
<include name="resources/**/*.*"/>
<include name="external/**/*.*"/>
<include name="php/**/*.php"/>
<include name="config.php"/>
<include name="changelog.txt"/>
<!-- exclude the ant script -->
<exclude name="build.xml"/>
<!-- CSS is generated during build -->
<exclude name="resources/css/*.*"/>
</fileset>
</copy>
<!-- replace all variables... -->
<replace file="${target-folder}/${plugin-folder}/manifest.xml" token="@_@PLUGIN_VERSION@_@" value="${plugin_version}" />
</target>
<!-- compresses each CSS file -->
<target name="compresscss" depends="concat">
<available file="${tools-folder}/lib/yui-compressor-ant-task-0.5.jar" property="YUIANT_AVAILABLE" />
<fail unless="YUIANT_AVAILABLE" message="yui-compressor-ant-task-0.5.jar not found" />
<if>
<available file="${target-folder}/${plugin-folder}/${plugin-css-folder}/${plugin-css-debug-file}" type="file" />
<then>
<yui-compressor
warn="false"
munge="true"
preserveallsemicolons="false"
fromdir="${target-folder}/${plugin-folder}/${plugin-css-folder}"
todir="${target-folder}/${plugin-folder}/${plugin-css-folder}">

<include name="${plugin-css-debug-file}" />
</yui-compressor>
</then>
</if>
</target>

</project>
</project>

+ 8
- 10
config.php View File

@@ -1,12 +1,10 @@
<?php
/** Disable the import plugin for all clients */
define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE', false);
/** Disable the export feature for all clients */
define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false); // currently not available
/** The default addressbook to import to (default: contact)*/
define('PLUGIN_CONTACTIMPORTER_DEFAULT', "contact");
/** Tempory path for uploaded files... */
define('PLUGIN_CONTACTIMPORTER_TMP_UPLOAD', "/var/lib/zarafa-webapp/tmp/");
/** Disable the import plugin for all clients */
define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE', false);

/** The default addressbook to import to (default: Kontakte or Contacts - depending on your language)*/
define('PLUGIN_CONTACTIMPORTER_DEFAULT', "Kontakte");

/** Tempory path for uploaded files... */
define('PLUGIN_CONTACTIMPORTER_TMP_UPLOAD', "/var/lib/zarafa-webapp/tmp/");
?>

+ 22
- 22
js/ABOUT.js View File

@@ -2,7 +2,7 @@
* ABOUT.js zarafa contact to vcf im/exporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2013 Christoph Haas
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
Ext.namespace('Zarafa.plugins.contactimporter');
/**
@@ -29,30 +29,30 @@ Ext.namespace('Zarafa.plugins.contactimporter');
* The copyright string holding the copyright notice for the Zarafa contactimporter Plugin.
*/
Zarafa.plugins.contactimporter.ABOUT = ""
+ "<p>Copyright (C) 2012-2013 Christoph Haas &lt;christoph.h@sprinternet.at&gt;</p>"
+ "<p>Copyright (C) 2012-2016 Christoph Haas &lt;christoph.h@sprinternet.at&gt;</p>"
+ "<p>This program is free software; you can redistribute it and/or "
+ "modify it under the terms of the GNU Lesser General Public "
+ "License as published by the Free Software Foundation; either "
+ "version 2.1 of the License, or (at your option) any later version.</p>"
+ "<p>This program 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 "
+ "Lesser General Public License for more details.</p>"
+ "<p>This program is free software; you can redistribute it and/or "
+ "modify it under the terms of the GNU Lesser General Public "
+ "License as published by the Free Software Foundation; either "
+ "version 2.1 of the License, or (at your option) any later version.</p>"
+ "<p>You should have received a copy of the GNU Lesser General Public "
+ "License along with this program; if not, write to the Free Software "
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>"
+ "<p>This program 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 "
+ "Lesser General Public License for more details.</p>"
+ "<hr />"
+ "<p>You should have received a copy of the GNU Lesser General Public "
+ "License along with this program; if not, write to the Free Software "
+ "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>"
+ "<p>The contactimporter plugin contains the following third-party components:</p>"
+ "<hr />"
+ "<h1>vCard-parser</h1>"
+ "<p>The contactimporter plugin contains the following third-party components:</p>"
+ "<h1>vCard-parser</h1>"
+ "<p>Copyright (C) 2016 Jeroen Desloovere</p>"
+ "<p>Copyright (C) 2012 Nuovo</p>"
+ "<p>Licensed under the MIT License.</p>"
+ "<p>Licensed under the MIT License.</p>"
+ "<p>Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.</p>"
+ "<p>Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.</p>"

+ 19
- 11
js/data/ResponseHandler.js View File

@@ -2,7 +2,7 @@
* ResponseHandler.js zarafa contact im/exporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2013 Christoph Haas
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/**
* ResponseHandler
*
@@ -38,38 +38,46 @@ Zarafa.plugins.contactimporter.data.ResponseHandler = Ext.extend(Zarafa.core.dat
* @cfg {Function} successCallback The function which
* will be called after success request.
*/
successCallback : null,
successCallback: null,
/**
* Call the successCallback callback function.
* @param {Object} response Object contained the response data.
*/
doLoad: function (response) {
this.successCallback(response);
},
/**
* Call the successCallback callback function.
* @param {Object} response Object contained the response data.
*/
doLoad : function(response) {
doImport: function (response) {
this.successCallback(response);
},
/**
* Call the successCallback callback function.
* @param {Object} response Object contained the response data.
*/
doImport : function(response) {
doExport: function (response) {
this.successCallback(response);
},
/**
* Call the successCallback callback function.
* @param {Object} response Object contained the response data.
*/
doImportattachment : function(response) {
doImportattachment: function (response) {
this.successCallback(response);
},
/**
* In case exception happened on server, server will return
* exception response with the code of exception.
* @param {Object} response Object contained the response data.
*/
doError: function(response) {
doError: function (response) {
alert("error response code: " + response.error.info.code);
}
});


+ 14
- 16
js/dialogs/ImportContentPanel.js View File

@@ -2,7 +2,7 @@
* ImportContentPanel.js zarafa contact to vcf im/exporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2013 Christoph Haas
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,13 +19,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/**
* ImportContentPanel
*
* Container for the importpanel.
*/
Ext.namespace("Zarafa.plugins.contactimporter.dialogs");
Ext.namespace("Zarafa.plugins.contactimporter.dialogs");
/**
* @class Zarafa.plugins.contactimporter.dialogs.ImportContentPanel
@@ -40,23 +40,21 @@ Zarafa.plugins.contactimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.co
* @constructor
* @param config Configuration structure
*/
constructor : function(config) {
constructor: function (config) {
config = config || {};
var title = _('Import Contacts');
if(container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/enable_export")){
title = _('Import/Export Contacts');
}
Ext.applyIf(config, {
layout : 'fit',
title : title,
closeOnSave : true,
width : 620,
height : 465,
layout : 'fit',
title : title,
closeOnSave: true,
width : 620,
height : 465,
//Add panel
items : [
items : [
{
xtype : 'contactimporter.importcontactpanel',
filename : config.filename
xtype : 'contactimporter.importcontactpanel',
filename: config.filename,
folder : config.folder
}
]
});
@@ -66,4 +64,4 @@ Zarafa.plugins.contactimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.co
});
Ext.reg('contactimporter.contentpanel' ,Zarafa.plugins.contactimporter.dialogs.ImportContentPanel);
Ext.reg('contactimporter.contentpanel', Zarafa.plugins.contactimporter.dialogs.ImportContentPanel);

+ 358
- 269
js/dialogs/ImportPanel.js View File

@@ -2,7 +2,7 @@
* ImportPanel.js zarafa contact to vcf im/exporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2013 Christoph Haas
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -13,7 +13,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -25,32 +25,39 @@
*
* The main Panel of the contactimporter plugin.
*/
Ext.namespace("Zarafa.plugins.contactimporter.dialogs");
Ext.namespace("Zarafa.plugins.contactimporter.dialogs");

/**
* @class Zarafa.plugins.contactimporter.dialogs.ImportPanel
* @extends Ext.form.FormPanel
* @extends Ext.Panel
*/
Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {

/* path to vcf file on server... */
vcffile: null,
/* The store for the selection grid */
store: null,
store : null,

/* selected folder */
folder : null,

/**
* @constructor
* @param {object} config
*/
constructor : function (config) {
constructor: function (config) {
config = config || {};
var self = this;
if(typeof config.filename !== "undefined") {
if (!Ext.isEmpty(config.filename)) {
this.vcffile = config.filename;
}

if (!Ext.isEmpty(config.folder)) {
this.folder = config.folder;
}

// create the data store
// we only display the firstname, lastname, homephone and primary email address in our grid
this.store = new Ext.data.ArrayStore({
@@ -62,51 +69,42 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
{name: 'record'}
]
});
Ext.apply(config, {
xtype : 'contactimporter.importpanel',
ref : "importcontactpanel",
layout : {
type : 'form',
align : 'stretch'
xtype : 'contactimporter.importpanel',
ref : "importcontactpanel",
layout : {
type : 'form',
align: 'stretch'
},
anchor : '100%',
bodyStyle : 'background-color: inherit;',
defaults : {
border : true,
bodyStyle : 'background-color: inherit; padding: 3px 0px 3px 0px; border-style: none none solid none;'
anchor : '100%',
bodyStyle: 'background-color: inherit;',
defaults : {
border : true,
bodyStyle: 'background-color: inherit; padding: 3px 0px 3px 0px; border-style: none none solid none;'
},
items : [
items : [
this.createSelectBox(),
this.initForm(),
this.createGrid()
],
buttons: [
buttons : [
this.createSubmitAllButton(),
this.createSubmitButton(),
this.createCancelButton()
],
],
listeners: {
afterrender: function (cmp) {
this.loadMask = new Ext.LoadMask(this.getEl(), {msg:'Loading...'});
if(this.vcffile != null) { // if we have got the filename from an attachment
this.loadMask = new Ext.LoadMask(this.getEl(), {msg: 'Loading...'});
if (this.vcffile != null) { // if we have got the filename from an attachment
this.parseContacts(this.vcffile);
}
},
close: function (cmp) {
Ext.getCmp("importcontactsbutton").enable();
},
hide: function (cmp) {
Ext.getCmp("importcontactsbutton").enable();
},
destroy: function (cmp) {
Ext.getCmp("importcontactsbutton").enable();
},
scope: this
scope : this
}
});

Zarafa.plugins.contactimporter.dialogs.ImportPanel.superclass.constructor.call(this, config);
},

@@ -115,44 +113,159 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
* posted and contains the attachments
* @private
*/
initForm : function () {
initForm: function () {
return {
xtype: 'form',
ref: 'addContactFormPanel',
layout : 'column',
xtype : 'form',
ref : 'addContactFormPanel',
layout : 'column',
fileUpload: true,
autoWidth: true,
autoWidth : true,
autoHeight: true,
border: false,
bodyStyle: 'padding: 5px;',
defaults: {
anchor: '95%',
border: false,
border : false,
bodyStyle : 'padding: 5px;',
defaults : {
anchor : '95%',
border : false,
bodyStyle: 'padding: 5px;'
},
items: [this.createUploadField()]
items : [this.createUploadField()]
};
},

/**
* Get all contact folders.
* @param {boolean} asDropdownStore If true, a simple array store will be returned.
* @returns {*}
*/
getAllContactFolders: function (asDropdownStore) {
asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore;

var allFolders = [];

var defaultContactFolder = container.getHierarchyStore().getDefaultFolder('contact');

var inbox = container.getHierarchyStore().getDefaultStore();
var pub = container.getHierarchyStore().getPublicStore();

if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) {
for (var i = 0; i < inbox.subStores.folders.totalLength; i++) {
var folder = inbox.subStores.folders.getAt(i);
if (folder.get("container_class") == "IPF.Contact") {
if (asDropdownStore) {
allFolders.push([
folder.get("entryid"),
folder.get("display_name")
]);
} else {
allFolders.push({
display_name : folder.get("display_name"),
entryid : folder.get("entryid"),
store_entryid: folder.get("store_entryid"),
is_public : false
});
}
}
}
}

if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) {
for (var j = 0; j < pub.subStores.folders.totalLength; j++) {
var folder = pub.subStores.folders.getAt(j);
if (folder.get("container_class") == "IPF.Contact") {
if (asDropdownStore) {
allFolders.push([
folder.get("entryid"),
folder.get("display_name") + " (Public)"
]);
} else {
allFolders.push({
display_name : folder.get("display_name"),
entryid : folder.get("entryid"),
store_entryid: folder.get("store_entryid"),
is_public : true
});
}
}
}
}

if (asDropdownStore) {
return allFolders.sort(this.dynamicSort(1));
} else {
return allFolders;
}
},

/**
* Dynamic sort function, sorts by property name.
* @param {string|int} property
* @returns {Function}
*/
dynamicSort: function (property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0;
return result * sortOrder;
}
},

/**
* Return a contact folder element by name.
* @param {string} name
* @returns {*}
*/
getContactFolderByName: function (name) {
var folders = this.getAllContactFolders(false);

for (var i = 0; i < folders.length; i++) {
if (folders[i].display_name == name) {
return folders[i];
}
}

return container.getHierarchyStore().getDefaultFolder('contact');
},

/**
* Return a contact folder element by entryid.
* @param {string} entryid
* @returns {*}
*/
getContactFolderByEntryid: function (entryid) {
var folders = this.getAllContactFolders(false);

for (var i = 0; i < folders.length; i++) {
if (folders[i].entryid == entryid) {
return folders[i];
}
}

return container.getHierarchyStore().getDefaultFolder('contact');
},

/**
* Reloads the data of the grid
* @private
*/
reloadGridStore: function(contactdata) {
reloadGridStore: function (contactdata) {
var parsedData = [];
if(contactdata) {
if (contactdata) {
parsedData = new Array(contactdata.contacts.length);
var i = 0;
for(i = 0; i < contactdata.contacts.length; i++) {
parsedData[i] = new Array(
for (i = 0; i < contactdata.contacts.length; i++) {
parsedData[i] = [
contactdata.contacts[i]["display_name"],
contactdata.contacts[i]["given_name"],
contactdata.contacts[i]["surname"],
contactdata.contacts[i]["company_name"],
contactdata.contacts[i]
);
];
}
} else {
return null;
@@ -160,193 +273,191 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {

this.store.loadData(parsedData, false);
},
/**
* Init embedded form, this is the form that is
* posted and contains the attachments
* @private
*/
createGrid : function() {
createGrid: function () {
return {
xtype: 'grid',
ref: 'contactGrid',
xtype : 'grid',
ref : 'contactGrid',
columnWidth: 1.0,
store: this.store,
width: '100%',
height: 300,
title: 'Select contacts to import',
frame: false,
viewConfig:{
forceFit:true
store : this.store,
width : '100%',
height : 300,
title : 'Select contacts to import',
frame : false,
viewConfig : {
forceFit: true
},
colModel: new Ext.grid.ColumnModel({
colModel : new Ext.grid.ColumnModel({
defaults: {
width: 300,
width : 300,
sortable: true
},
columns: [
columns : [
{id: 'Displayname', header: 'Displayname', width: 350, sortable: true, dataIndex: 'display_name'},
{header: 'Firstname', width: 200, sortable: true, dataIndex: 'given_name'},
{header: 'Lastname', width: 200, sortable: true, dataIndex: 'surname'},
{header: 'Company', sortable: true, dataIndex: 'company_name'}
]
}),
sm: new Ext.grid.RowSelectionModel({multiSelect:true})
sm : new Ext.grid.RowSelectionModel({multiSelect: true})
}
},
createSelectBox: function() {
var defaultFolder = container.getHierarchyStore().getDefaultFolder('contact'); // @type: Zarafa.hierarchy.data.MAPIFolderRecord
var subFolders = defaultFolder.getChildren();
var myStore = [];
/* add all local contact folders */
var i = 0;
myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()));
for(i = 0; i < subFolders.length; i++) {
/* Store all subfolders */
myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder
}
/* add all shared contact folders */
var pubStore = container.getHierarchyStore().getPublicStore();
if(typeof pubStore !== "undefined") {
try {
var pubFolder = pubStore.getDefaultFolder("publicfolders");
var pubSubFolders = pubFolder.getChildren();
for(i = 0; i < pubSubFolders.length; i++) {
if(pubSubFolders[i].isContainerClass("IPF.Contact")){
myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder
}
}
} catch (e) {
console.log("Error opening the shared folder...");
console.log(e);
}
}

/**
* Generate the UI calendar select box.
* @returns {*}
*/
createSelectBox: function () {
var myStore = this.getAllContactFolders(true);

return {
xtype: "selectbox",
ref: 'addressbookSelector',
editable: false,
name: "choosen_addressbook",
value: container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/default_addressbook"),
width: 100,
fieldLabel: "Select an addressbook",
store: myStore,
mode: 'local',
xtype : "selectbox",
ref : 'addressbookSelector',
editable : false,
name : "choosen_addressbook",
value : Ext.isEmpty(this.folder) ? this.getContactFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/default_addressbook")).entryid : this.folder,
width : 100,
fieldLabel : "Select folder",
store : myStore,
mode : 'local',
labelSeperator: ":",
border: false,
anchor: "100%",
scope: this,
allowBlank: false
border : false,
anchor : "100%",
scope : this,
hidden : Ext.isEmpty(this.folder) ? false : true,
allowBlank : false
}
},
createUploadField: function() {

/**
* Generate the UI upload field.
* @returns {*}
*/
createUploadField: function () {
return {
xtype: "fileuploadfield",
ref: 'contactfileuploadfield',
xtype : "fileuploadfield",
ref : 'contactfileuploadfield',
columnWidth: 1.0,
id: 'form-file',
name: 'vcfdata',
emptyText: 'Select an .vcf addressbook',
border: false,
anchor: "100%",
scope: this,
allowBlank: false,
listeners: {
id : 'form-file',
name : 'vcfdata',
emptyText : 'Select an .vcf addressbook',
border : false,
anchor : "100%",
height : "30",
scope : this,
allowBlank : false,
listeners : {
'fileselected': this.onFileSelected,
scope: this
scope : this
}
}
},
createSubmitButton: function() {

/**
* Generate the UI submit button.
* @returns {*}
*/
createSubmitButton: function () {
return {
xtype: "button",
ref: "../submitButton",
disabled: true,
width: 100,
border: false,
text: _("Import"),
anchor: "100%",
handler: this.importCheckedContacts,
scope: this,
xtype : "button",
ref : "../submitButton",
disabled : true,
width : 100,
border : false,
text : _("Import"),
anchor : "100%",
handler : this.importCheckedContacts,
scope : this,
allowBlank: false
}
},
createSubmitAllButton: function() {

/**
* Generate the UI submit all button.
* @returns {*}
*/
createSubmitAllButton: function () {
return {
xtype: "button",
ref: "../submitAllButton",
disabled: true,
width: 100,
border: false,
text: _("Import All"),
anchor: "100%",
handler: this.importAllContacts,
scope: this,
xtype : "button",
ref : "../submitAllButton",
disabled : true,
width : 100,
border : false,
text : _("Import All"),
anchor : "100%",
handler : this.importAllContacts,
scope : this,
allowBlank: false
}
},
createCancelButton: function() {

/**
* Generate the UI cancel button.
* @returns {*}
*/
createCancelButton: function () {
return {
xtype: "button",
width: 100,
border: false,
text: _("Cancel"),
anchor: "100%",
handler: this.close,
scope: this,
xtype : "button",
width : 100,
border : false,
text : _("Cancel"),
anchor : "100%",
handler : this.close,
scope : this,
allowBlank: false
}
},
/**
* This is called when a file has been seleceted in the file dialog
* in the {@link Ext.ux.form.FileUploadField} and the dialog is closed
* @param {Ext.ux.form.FileUploadField} uploadField being added a file to
*/
onFileSelected : function(uploadField) {
onFileSelected: function (uploadField) {
var form = this.addContactFormPanel.getForm();

if (form.isValid()) {
form.submit({
waitMsg: 'Uploading and parsing contacts...',
url: 'plugins/contactimporter/php/upload.php',
failure: function(file, action) {
url : 'plugins/contactimporter/php/upload.php',
failure: function (file, action) {
this.submitButton.disable();
this.submitAllButton.disable();
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _(action.result.error),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Error'),
msg : _(action.result.error),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
},
success: function(file, action){
success: function (file, action) {
uploadField.reset();
this.vcffile = action.result.vcf_file;
this.parseContacts(this.vcffile);
},
scope : this
scope : this
});
}
},

/**
* Start request to server to parse the given vCard file.
* @param {string} vcfPath
*/
parseContacts: function (vcfPath) {
this.loadMask.show();
// call export function here!
var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: this.handleParsingResult.createDelegate(this)
});
container.getRequest().singleRequest(
'contactmodule',
'load',
@@ -356,147 +467,125 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, {
responseHandler
);
},
handleParsingResult: function(response) {

/**
* Callback for the parsing request.
* @param {Object} response
*/
handleParsingResult: function (response) {
this.loadMask.hide();
if(response["status"] == true) {
if (response["status"] == true) {
this.submitButton.enable();
this.submitAllButton.enable();
this.reloadGridStore(response.parsed);
} else {
this.submitButton.disable();
this.submitAllButton.disable();
Zarafa.common.dialogs.MessageBox.show({
title : _('Parser Error'),
msg : _(response["message"]),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Parser Error'),
msg : _(response["message"]),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
}
},

/**
* Close the UI dialog.
*/
close: function () {
this.addContactFormPanel.getForm().reset();
this.dialog.close()
},

/**
* Create a request to import all selected contacts.
*/
importCheckedContacts: function () {
var newRecords = this.contactGrid.selModel.getSelections();
this.importContacts(newRecords);
},
},

/**
* Check all contacts and import them.
*/
importAllContacts: function () {
//receive Records from grid rows
this.contactGrid.selModel.selectAll(); // select all entries
var newRecords = this.contactGrid.selModel.getSelections();
this.importContacts(newRecords);
},
/**
* This function stores all given events to the appointmentstore
* @param events
},
/**
* This function stores all given events to the contact store
* @param {array} contacts
*/
importContacts: function (contacts) {
//receive existing contact store
var folderValue = this.addressbookSelector.getValue();

if(folderValue == undefined) { // no addressbook choosen
if (folderValue == undefined) { // no addressbook choosen
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _('You have to choose an addressbook!'),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Error'),
msg : _('You have to choose an addressbook!'),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
} else {
var addressbookexist = true;
if(this.contactGrid.selModel.getCount() < 1) {
if (this.contactGrid.selModel.getCount() < 1) {
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _('You have to choose at least one contact to import!'),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Error'),
msg : _('You have to choose at least one contact to import!'),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
} else {
var contactStore = new Zarafa.contact.ContactStore();
var contactFolder = container.getHierarchyStore().getDefaultFolder('contact');
var pubStore = container.getHierarchyStore().getPublicStore();
var pubFolder = pubStore.getDefaultFolder("publicfolders");
var pubSubFolders = pubFolder.getChildren();
if(folderValue != "contact") {
var subFolders = contactFolder.getChildren();
var i = 0;
for(i = 0; i < pubSubFolders.length; i++) {
if(pubSubFolders[i].isContainerClass("IPF.Contact")){
subFolders.push(pubSubFolders[i]);
}
}
for(i=0;i<subFolders.length;i++) {
// look up right folder
// TODO: improve!!
if(subFolders[i].getDisplayName() == folderValue) {
contactFolder = subFolders[i];
break;
}
}
if(contactFolder.isDefaultFolder()) {
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _('Selected addressbook does not exist!'),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
});
addressbookexist = false;
}
}
var contactFolder = this.getContactFolderByEntryid(folderValue);

if(addressbookexist) {
this.loadMask.show();
var uids = new Array();
var store_entryid = "";
//receive Records from grid rows
Ext.each(contacts, function(newRecord) {
uids.push(newRecord.data.record.internal_fields.contact_uid);
}, this);
store_entryid = contactFolder.get('store_entryid');
var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: this.importContactsDone.createDelegate(this)
});
container.getRequest().singleRequest(
'contactmodule',
'import',
{
storeid: contactFolder.get("store_entryid"),
folderid: contactFolder.get("entryid"),
uids: uids,
vcf_filepath: this.vcffile
},
responseHandler
);
}
this.loadMask.show();
var uids = [];

//receive Records from grid rows
Ext.each(contacts, function (newRecord) {
uids.push(newRecord.data.record.internal_fields.contact_uid);
}, this);

var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: this.importContactsDone.createDelegate(this)
});

container.getRequest().singleRequest(
'contactmodule',
'import',
{
storeid : contactFolder.store_entryid,
folderid : contactFolder.entryid,
uids : uids,
vcf_filepath: this.vcffile
},
responseHandler
);
}
}
},
importContactsDone : function (response) {
console.log(response);

/**
* Callback for the import request.
* @param {Object} response
*/
importContactsDone: function (response) {
this.loadMask.hide();
this.dialog.close();
if(response.status == true) {
if (response.status == true) {
container.getNotifier().notify('info', 'Imported', 'Imported ' + response.count + ' contacts. Please reload your addressbook!');
} else {
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _('Import failed: ') + response.message,
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Error'),
msg : _('Import failed: ') + response.message,
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
}
}


+ 172
- 103
js/plugin.contactimporter.js View File

@@ -2,7 +2,7 @@
* plugin.contactimporter.js zarafa contactimporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2013 Christoph Haas
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,175 +19,234 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
Ext.namespace("Zarafa.plugins.contactimporter"); // Assign the right namespace
Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { // create new import plugin
/**
* @constructor
* @param {Object} config Configuration object
*
*/
/**
* @constructor
* @param {Object} config Configuration object
*
*/
constructor: function (config) {
config = config || {};
Zarafa.plugins.contactimporter.ImportPlugin.superclass.constructor.call(this, config);
},
/**
* initialises insertion point for plugin
* @protected
*/
initPlugin : function() {
initPlugin: function () {
Zarafa.plugins.contactimporter.ImportPlugin.superclass.initPlugin.apply(this, arguments);
/* our panel */
Zarafa.core.data.SharedComponentType.addProperty('plugins.contactimporter.dialogs.importcontacts');
/* directly import received vcfs */
this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton);
/* add import button to south navigation */
this.registerInsertionPoint("navigation.south", this.createImportButton, this);
this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton, this);
/* export a contact via rightclick */
this.registerInsertionPoint('context.contact.contextmenu.actions', this.createItemExportInsertionPoint, this);
},
/**
* Creates the button
*
* @return {Object} Configuration object for a {@link Ext.Button button}
*
*/
createImportButton: function () {
var button = {
xtype : 'button',
id : "importcontactsbutton",
text : _('Import Contacts'),
iconCls : 'icon_contactimporter_button',
navigationContext : container.getContextByName('contact'),
handler : this.onImportButtonClick,
scope : this
/**
* This method hooks to the contact context menu and allows users to export users to vcf.
*
* @param include
* @param btn
* @returns {Object}
*/
createItemExportInsertionPoint: function (include, btn) {
return {
text : dgettext('plugin_files', 'Export vCard'),
handler: this.exportToVCF.createDelegate(this, [btn]),
scope : this,
iconCls: 'icon_contactimporter_export'
};
if(container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/enable_export")) {
button.text = _('Import/Export Contacts');
},
/**
* Generates a request to download the selected records as vCard.
* @param {Ext.Button} btn
*/
exportToVCF: function (btn) {
if (btn.records.length == 0) {
return; // skip if no records where given!
}
var recordIds = [];
for (var i = 0; i < btn.records.length; i++) {
recordIds.push(btn.records[i].get("entryid"));
}
var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: this.downloadVCF,
scope : this
});
// request attachment preperation
container.getRequest().singleRequest(
'contactmodule',
'export',
{
storeid: btn.records[0].get("store_entryid"),
records: recordIds
},
responseHandler
);
},
/**
* Callback for the export request.
* @param {Object} response
*/
downloadVCF: function (response) {
if (response.status == false) {
Zarafa.common.dialogs.MessageBox.show({
title : dgettext('plugin_files', 'Warning'),
msg : dgettext('plugin_files', response.message),
icon : Zarafa.common.dialogs.MessageBox.WARNING,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
} else {
var downloadFrame = Ext.getBody().createChild({
tag: 'iframe',
cls: 'x-hidden'
});
var url = document.URL;
var link = url.substring(0, url.lastIndexOf('/') + 1);
link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_vcf";
link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token));
link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename));
downloadFrame.dom.contentWindow.location = link;
}
return button;
},
/**
* Insert import button in all attachment suggestions
* @return {Object} Configuration object for a {@link Ext.Button button}
*/
createAttachmentImportButton : function(include, btn) {
createAttachmentImportButton: function (include, btn) {
return {
text : _('Import Contacts'),
handler : this.getAttachmentFileName.createDelegate(this, [btn, this.gotAttachmentFileName]),
scope : this,
iconCls : 'icon_contactimporter_button',
beforeShow : function(item, record) {
text : _('Import to Contacts'),
handler : this.getAttachmentFileName.createDelegate(this, [btn]),
scope : this,
iconCls : 'icon_contactimporter_button',
beforeShow: function (item, record) {
var extension = record.data.name.split('.').pop().toLowerCase();
if(record.data.filetype == "text/vcard" || extension == "vcf" || extension == "vcard") {
item.setDisabled(false);
if (record.data.filetype == "text/vcard" || record.data.filetype == "text/x-vcard" || extension == "vcf" || extension == "vcard") {
item.setVisible(true);
} else {
item.setDisabled(true);
item.setVisible(false);
}
}
};
},
/**
* Callback for getAttachmentFileName
* @param {Object} response
*/
gotAttachmentFileName: function(response) {
if(response.status == true) {
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'], undefined, {
manager : Ext.WindowMgr,
filename : response.tmpname
});
gotAttachmentFileName: function (response) {
if (response.status == true) {
this.openImportDialog(response.tmpname);
} else {
Zarafa.common.dialogs.MessageBox.show({
title : _('Error'),
msg : _(response["message"]),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons : Zarafa.common.dialogs.MessageBox.OK
title : _('Error'),
msg : _(response["message"]),
icon : Zarafa.common.dialogs.MessageBox.ERROR,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
}
},
/**
* Clickhandler for the button
* @param {Ext.Button} btn
*/
getAttachmentFileName: function (btn, callback) {
getAttachmentFileName: function (btn) {
Zarafa.common.dialogs.MessageBox.show({
title: 'Please wait',
msg: 'Loading attachment...',
title : 'Please wait',
msg : 'Loading attachment...',
progressText: 'Initializing...',
width:300,
progress:true,
closable:false
width : 300,
progress : true,
closable : false
});
// progress bar... ;)
var f = function(v){
return function(){
if(v == 100){
var f = function (v) {
return function () {
if (v == 100) {
Zarafa.common.dialogs.MessageBox.hide();
}else{
Zarafa.common.dialogs.MessageBox.updateProgress(v/100, Math.round(v)+'% loaded');
} else {
Zarafa.common.dialogs.MessageBox.updateProgress(v / 100, Math.round(v) + '% loaded');
}
};
};
};
for(var i = 1; i < 101; i++){
setTimeout(f(i), 20*i);
for (var i = 1; i < 101; i++) {
setTimeout(f(i), 20 * i);
}
/* store the attachment to a temporary folder and prepare it for uploading */
var attachmentRecord = btn.records;
var attachmentStore = attachmentRecord.store;
var store = attachmentStore.getParentRecord().get('store_entryid');
var entryid = attachmentStore.getAttachmentParentRecordEntryId();
var attachNum = new Array(1);
if (attachmentRecord.get('attach_num') != -1)
if (attachmentRecord.get('attach_num') != -1) {
attachNum[0] = attachmentRecord.get('attach_num');
else
} else {
attachNum[0] = attachmentRecord.get('tmpname');
}
var dialog_attachments = attachmentStore.getId();
var filename = attachmentRecord.data.name;
var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: callback
successCallback: this.gotAttachmentFileName.createDelegate(this),
scope : this
});
// request attachment preperation
container.getRequest().singleRequest(
'contactmodule',
'importattachment',
{
entryid : entryid,
store: store,
attachNum: attachNum,
entryid : entryid,
store : store,
attachNum : attachNum,
dialog_attachments: dialog_attachments,
filename: filename
filename : filename
},
responseHandler
);
},
/**
* Clickhandler for the button
* Open the import dialog.
* @param {String} filename
*/
onImportButtonClick: function () {
Ext.getCmp("importcontactsbutton").disable();
Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'], undefined, {
manager : Ext.WindowMgr
});
openImportDialog: function (filename) {
var componentType = Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'];
var config = {
filename: filename,
modal : true
};
Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
},
/**
* Bid for the type of shared component
* and the given record.
@@ -196,11 +255,18 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
* @param {Ext.data.Record} record Optionally passed record.
* @return {Number} The bid for the shared component
*/
bidSharedComponent : function(type, record) {
bidSharedComponent: function (type, record) {
var bid = -1;
switch(type) {
switch (type) {
case Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts']:
bid = 2;
bid = 1;
break;
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
if (record instanceof Zarafa.core.data.MAPIRecord) {
if (record.get('object_type') == Zarafa.core.mapi.ObjectType.MAPI_FOLDER && record.get('container_class') == "IPF.Contact") {
bid = 2;
}
}
break;
}
return bid;
@@ -213,12 +279,15 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
* @param {Ext.data.Record} record Optionally passed record.
* @return {Ext.Component} Component
*/
getSharedComponent : function(type, record) {
getSharedComponent: function (type, record) {
var component;
switch(type) {
switch (type) {
case Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts']:
component = Zarafa.plugins.contactimporter.dialogs.ImportContentPanel;
break;
case Zarafa.core.data.SharedComponentType['common.contextmenu']:
component = Zarafa.plugins.contactimporter.ui.ContextMenu;
break;
}
return component;
@@ -229,11 +298,11 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, {
/*############################################################################################################################
* STARTUP
*############################################################################################################################*/
Zarafa.onReady(function() {
Zarafa.onReady(function () {
container.registerPlugin(new Zarafa.core.PluginMetaData({
name : 'contactimporter',
displayName : _('Contactimporter Plugin'),
about : Zarafa.plugins.contactimporter.ABOUT,
pluginConstructor : Zarafa.plugins.contactimporter.ImportPlugin
name : 'contactimporter',
displayName : _('Contactimporter Plugin'),
about : Zarafa.plugins.contactimporter.ABOUT,
pluginConstructor: Zarafa.plugins.contactimporter.ImportPlugin
}));
});

+ 136
- 0
js/ui/ContextMenu.js View File

@@ -0,0 +1,136 @@
Ext.namespace('Zarafa.plugins.contactimporter.ui');

/**
* @class Zarafa.plugins.contactimporter.ui.ContextMenu
* @extends Zarafa.hierarchy.ui.ContextMenu
* @xtype contactimporter.hierarchycontextmenu
*/
Zarafa.plugins.contactimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.ContextMenu, {

/**
* @constructor
* @param {Object} config Configuration object
*/
constructor: function (config) {
config = config || {};

if (config.contextNode) {
config.contextTree = config.contextNode.getOwnerTree();
}

Zarafa.plugins.contactimporter.ui.ContextMenu.superclass.constructor.call(this, config);

// add item to menu
var additionalItems = this.createAdditionalContextMenuItems(config);
for (var i = 0; i < additionalItems.length; i++) {
config.items[0].push(additionalItems[i]);
}

Zarafa.plugins.contactimporter.ui.ContextMenu.superclass.constructor.call(this, config); // redo ... otherwise menu does not get published
},

/**
* Create the Action context menu items.
* @param {Object} config Configuration object for the {@link Zarafa.plugins.contactimporter.ui.ContextMenu ContextMenu}
* @return {Zarafa.core.ui.menu.ConditionalItem[]} The list of Action context menu items
* @private
*
* Note: All handlers are called within the scope of {@link Zarafa.plugins.contactimporter.ui.ContextMenu HierarchyContextMenu}
*/
createAdditionalContextMenuItems: function (config) {
return [{
xtype: 'menuseparator'
}, {
text : _('Import vCard'),
iconCls : 'icon_contactimporter_import',
handler : this.onContextItemImport,
beforeShow: function (item, record) {
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_MODIFY;
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
item.setDisabled(true);
} else {
item.setDisabled(false);
}
}
}, {
text : _('Export vCard'),
iconCls : 'icon_contactimporter_export',
handler : this.onContextItemExport,
beforeShow: function (item, record) {
var access = record.get('access') & Zarafa.core.mapi.Access.ACCESS_READ;
if (!access || (record.isIPMSubTree() && !record.getMAPIStore().isDefaultStore())) {
item.setDisabled(true);
} else {
item.setDisabled(false);
}
}
}];
},

/**
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.contactimporter.ui.ContextMenu ContextMenu}
* @private
*/
onContextItemExport: function () {
var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({
successCallback: this.downloadVCF,
scope : this
});

// request attachment preperation
container.getRequest().singleRequest(
'contactmodule',
'export',
{
storeid: this.records.get("store_entryid"),
folder : this.records.get("entryid")
},
responseHandler
);
},

/**
* Fires on selecting 'Open' menu option from {@link Zarafa.plugins.contactimporter.ui.ContextMenu ContextMenu}
* @private
*/
onContextItemImport: function () {
var componentType = Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'];
var config = {
modal : true,
folder: this.records.get("entryid")
};

Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config);
},

/**
* Callback for the export request.
* @param {Object} response
*/
downloadVCF: function (response) {
if (response.status == false) {
Zarafa.common.dialogs.MessageBox.show({
title : dgettext('plugin_files', 'Warning'),
msg : dgettext('plugin_files', response.message),
icon : Zarafa.common.dialogs.MessageBox.WARNING,
buttons: Zarafa.common.dialogs.MessageBox.OK
});
} else {
var downloadFrame = Ext.getBody().createChild({
tag: 'iframe',
cls: 'x-hidden'
});

var url = document.URL;
var link = url.substring(0, url.lastIndexOf('/') + 1);

link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_vcf";
link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token));
link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename));

downloadFrame.dom.contentWindow.location = link;
}
}
});

Ext.reg('contactimporter.hierarchycontextmenu', Zarafa.plugins.contactimporter.ui.ContextMenu);

+ 6
- 4
manifest.xml View File

@@ -2,7 +2,7 @@
<!DOCTYPE plugin SYSTEM "manifest.dtd">
<plugin version="2">
<info>
<version>@_@PLUGIN_VERSION@_@</version>
<version>2.0.0</version>
<name>contactimporter</name>
<title>VCF Contact Importer/Exporter</title>
<author>Christoph Haas</author>
@@ -20,16 +20,18 @@
<serverfile type="module" module="contactmodule">php/module.contact.php</serverfile>
</server>
<client>
<clientfile load="release">js/contactimporter.js</clientfile>
<clientfile load="release">js/contactimporter-debug.js</clientfile>
<clientfile load="debug">js/contactimporter-debug.js</clientfile>
<clientfile load="source">js/plugin.contactimporter.js</clientfile>
<clientfile load="source">js/ABOUT.js</clientfile>
<clientfile load="source">js/data/ResponseHandler.js</clientfile>
<clientfile load="source">js/dialogs/ImportContentPanel.js</clientfile>
<clientfile load="source">js/dialogs/ImportPanel.js</clientfile>
<clientfile load="source">js/ui/ContextMenu.js</clientfile>
</client>
<resources>
<resourcefile load="release">resources/css/contactimporter-min.css</resourcefile>
<resourcefile load="release">resources/css/contactimporter.css</resourcefile>
<resourcefile load="debug">resources/css/contactimporter.css</resourcefile>
<resourcefile load="source">resources/css/contactimporter-main.css</resourcefile>
</resources>


+ 5
- 0
php/.gitignore View File

@@ -0,0 +1,5 @@
composer.phar
.composer.lock
composer.lock
vendor
vendor/*

+ 5
- 0
php/composer.json View File

@@ -0,0 +1,5 @@
{
"require": {
"jeroendesloovere/vcard": "1.2.*"
}
}

+ 72
- 0
php/download.php View File

@@ -0,0 +1,72 @@
<?php

/**
* download.php, zarafa contact to vcf im/exporter
*
* Author: Christoph Haas <christoph.h@sprinternet.at>
* Copyright (C) 2012-2016 Christoph Haas
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
class DownloadHandler
{
/**
* Download the given vcf file.
* @return bool
*/
public static function doDownload()
{
if (isset($_GET["token"])) {
$token = $_GET["token"];
} else {
return false;
}

if (isset($_GET["filename"])) {
$filename = $_GET["filename"];
} else {
return false;
}

// validate token
if (!ctype_alnum($t