diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php new file mode 100644 index 0000000000..4bd3df54e3 --- /dev/null +++ b/apps/contacts/ajax/addcontact.php @@ -0,0 +1,60 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); +} +foreach ($_POST as $key=>$element) { + debug('_POST: '.$key.'=>'.$element); +} + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +$l=new OC_L10N('contacts'); + +$aid = $_POST['aid']; +$addressbook = OC_Contacts_App::getAddressbook( $aid ); + +$fn = trim($_POST['fn']); +$n = trim($_POST['n']); + +$vcard = new OC_VObject('VCARD'); +$vcard->setUID(); +$vcard->setString('N',$n); +$vcard->setString('FN',$fn); + +$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); +if(!$id) { + OC_JSON::error(array('data' => array('message' => $l->t('There was an error adding the contact.')))); + OC_Log::write('contacts','ajax/addcontact.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR); + exit(); +} + +OC_JSON::success(array('data' => array( 'id' => $id ))); diff --git a/apps/contacts/ajax/contactdetails.php b/apps/contacts/ajax/contactdetails.php new file mode 100644 index 0000000000..f8f78ad3e8 --- /dev/null +++ b/apps/contacts/ajax/contactdetails.php @@ -0,0 +1,53 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/contactdetails.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/contactdetails.php: '.$msg, OC_Log::DEBUG); +} + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +$l=new OC_L10N('contacts'); + +$id = $_GET['id']; +$vcard = OC_Contacts_App::getContactVCard( $id ); +if(is_null($vcard)) { + bailOut($l->t('Error parsing VCard for ID: "'.$id.'"')); +} +$details = OC_Contacts_VCard::structureContact($vcard); +if(isset($details['PHOTO'])) { + $details['PHOTO'] = true; + //unset($details['PHOTO']); +} else { + $details['PHOTO'] = false; +} +$details['id'] = $id; + +OC_JSON::success(array('data' => $details)); \ No newline at end of file diff --git a/apps/contacts/ajax/cropphoto.php b/apps/contacts/ajax/cropphoto.php new file mode 100644 index 0000000000..878fb5610c --- /dev/null +++ b/apps/contacts/ajax/cropphoto.php @@ -0,0 +1,38 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$tmp_path = $_GET['tmp_path']; +$id = $_GET['id']; +OC_Log::write('contacts','ajax/cropphoto.php: tmp_path: '.$tmp_path.', exists: '.file_exists($tmp_path), OC_Log::DEBUG); +$tmpl = new OC_TEMPLATE("contacts", "part.cropphoto"); +$tmpl->assign('tmp_path', $tmp_path); +$tmpl->assign('id', $id); +$page = $tmpl->fetchPage(); + +OC_JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/ajax/editaddress.php b/apps/contacts/ajax/editaddress.php new file mode 100644 index 0000000000..4e6456f604 --- /dev/null +++ b/apps/contacts/ajax/editaddress.php @@ -0,0 +1,31 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$id = $_GET['id']; +$checksum = isset($_GET['checksum'])?$_GET['checksum']:''; +$vcard = OC_Contacts_App::getContactVCard($id); +$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); + +$tmpl = new OC_TEMPLATE("contacts", "part.edit_address_dialog"); +if($checksum) { + $line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); + $element = $vcard->children[$line]; + $adr = OC_Contacts_VCard::structureProperty($element); + $tmpl->assign('adr',$adr); +} + +$tmpl->assign('id',$id); +$tmpl->assign('adr_types',$adr_types); + +$tmpl->printpage(); + +?> diff --git a/apps/contacts/ajax/editname.php b/apps/contacts/ajax/editname.php new file mode 100644 index 0000000000..6205cc74b0 --- /dev/null +++ b/apps/contacts/ajax/editname.php @@ -0,0 +1,35 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('../../../lib/base.php'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$tmpl = new OC_TEMPLATE("contacts", "part.edit_name_dialog"); + +$id = $_GET['id']; +if($id) { + $vcard = OC_Contacts_App::getContactVCard($id); + + + $name = array('', '', '', '', ''); + if($vcard->__isset('N')) { + $property = $vcard->__get('N'); + if($property) { + $name = OC_Contacts_VCard::structureProperty($property); + } + } + $tmpl->assign('name',$name); + $tmpl->assign('id',$id); +} else { + $addressbooks = OC_Contacts_Addressbook::active(OC_User::getUser()); + $tmpl->assign('addressbooks', $addressbooks); +} +$tmpl->printpage(); + +?> diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php new file mode 100644 index 0000000000..d9f7e737b5 --- /dev/null +++ b/apps/contacts/ajax/loadphoto.php @@ -0,0 +1,53 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + * TODO: Translatable strings. + * Remember to delete tmp file at some point. + */ +// Init owncloud +require_once('../../../lib/base.php'); +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +$l=new OC_L10N('contacts'); + +// foreach ($_POST as $key=>$element) { +// OC_Log::write('contacts','ajax/savecrop.php: '.$key.'=>'.$element, OC_Log::DEBUG); +// } + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + exit(); +} + +$image = null; + +$id = isset($_GET['id']) ? $_GET['id'] : ''; + +if($id == '') { + bailOut('Missing contact id.'); +} + +$tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); +$tmpl->assign('id', $id); +$page = $tmpl->fetchPage(); +OC_JSON::success(array('data' => array('page'=>$page))); +?> diff --git a/apps/contacts/ajax/newcontact.php b/apps/contacts/ajax/newcontact.php new file mode 100644 index 0000000000..3d1a8e7453 --- /dev/null +++ b/apps/contacts/ajax/newcontact.php @@ -0,0 +1,58 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); +} +foreach ($_POST as $key=>$element) { + debug('_POST: '.$key.'=>'.$element); +} + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); + +$addressbooks = OC_Contacts_Addressbook::all(OC_USER::getUser()); + +$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); +$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); +$maxUploadFilesize = min($upload_max_filesize, $post_max_size); + +$freeSpace=OC_Filesystem::free_space('/'); +$freeSpace=max($freeSpace,0); +$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); + +$tmpl = new OC_Template('contacts','part.contact'); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +$tmpl->assign('addressbooks',$addressbooks); +$tmpl->assign('id',''); +$page = $tmpl->fetchPage(); + +OC_JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php new file mode 100644 index 0000000000..7b7384723c --- /dev/null +++ b/apps/contacts/ajax/savecrop.php @@ -0,0 +1,136 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + * TODO: Translatable strings. + * Remember to delete tmp file at some point. + */ +// Init owncloud +require_once('../../../lib/base.php'); +OC_Log::write('contacts','ajax/savecrop.php: Huzzah!!!', OC_Log::DEBUG); + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +$l=new OC_L10N('contacts'); + +// foreach ($_POST as $key=>$element) { +// OC_Log::write('contacts','ajax/savecrop.php: '.$key.'=>'.$element, OC_Log::DEBUG); +// } + +// Firefox and Konqueror tries to download application/json for me. --Arthur +OC_JSON::setContentTypeHeader('text/plain'); + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + exit(); +} + +$image = null; + +$x1 = (isset($_POST['x1']) && $_POST['x1']) ? $_POST['x1'] : -1; +//$x2 = isset($_POST['x2']) ? $_POST['x2'] : -1; +$y1 = (isset($_POST['y1']) && $_POST['y1']) ? $_POST['y1'] : -1; +//$y2 = isset($_POST['y2']) ? $_POST['y2'] : -1; +$w = (isset($_POST['w']) && $_POST['w']) ? $_POST['w'] : -1; +$h = (isset($_POST['h']) && $_POST['h']) ? $_POST['h'] : -1; +$tmp_path = isset($_POST['tmp_path']) ? $_POST['tmp_path'] : ''; +$id = isset($_POST['id']) ? $_POST['id'] : ''; + +if(in_array(-1, array($x1, $y1, $w, $h))) { + bailOut('Wrong crop dimensions: '.implode(', ', array($x1, $y1, $w, $h))); +} + +if($tmp_path == '') { + bailOut('Missing path to temporary file.'); +} + +if($id == '') { + bailOut('Missing contact id.'); +} + +OC_Log::write('contacts','savecrop.php: files: '.$tmp_path.' exists: '.file_exists($tmp_path), OC_Log::DEBUG); + +if(file_exists($tmp_path)) { + $image = new OC_Image(); + if($image->loadFromFile($tmp_path)) { + if($image->crop($x1, $y1, $w, $h)) { + if($image->resize(200)) { + $tmpfname = tempnam("/tmp", "occCropped"); // create a new file because of caching issues. + if($image->save($tmpfname)) { + unlink($tmp_path); + $card = OC_Contacts_App::getContactVCard($id); + if(!$card) { + unlink($tmpfname); + bailOut('Error getting contact object.'); + } + if($card->__isset('PHOTO')) { + OC_Log::write('contacts','savecrop.php: files: PHOTO property exists.', OC_Log::DEBUG); + $property = $card->__get('PHOTO'); + if(!$property) { + unlink($tmpfname); + bailOut('Error getting PHOTO property.'); + } + $property->setValue($image->__toString()); + $property->parameters[] = new Sabre_VObject_Parameter('ENCODING', 'b'); + $property->parameters[] = new Sabre_VObject_Parameter('TYPE', $image->mimeType()); + $card->__set('PHOTO', $property); + } else { + OC_Log::write('contacts','savecrop.php: files: Adding PHOTO property.', OC_Log::DEBUG); + $card->addProperty('PHOTO', $image->__toString(), array('ENCODING' => 'b', 'TYPE' => $image->mimeType())); + } + if(!OC_Contacts_VCard::edit($id,$card->serialize())) { + bailOut('Error saving contact.'); + } + unlink($tmpfname); + //$result=array( "status" => "success", 'mime'=>$image->mimeType(), 'tmp'=>$tmp_path); + $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); + $tmpl->assign('tmp_path', $tmpfname); + $tmpl->assign('mime', $image->mimeType()); + $tmpl->assign('id', $id); + $tmpl->assign('width', $image->width()); + $tmpl->assign('height', $image->height()); + $page = $tmpl->fetchPage(); + OC_JSON::success(array('data' => array('page'=>$page, 'tmp'=>$tmpfname))); + exit(); + } else { + if(file_exists($tmpfname)) { + unlink($tmpfname); + } + bailOut('Error saving temporary image'); + } + } else { + bailOut('Error resizing image'); + } + } else { + bailOut('Error cropping image'); + } + } else { + bailOut('Error creating temporary image'); + } +} else { + bailOut('Error finding image: '.$tmp_path); +} + +if($tmp_path != '' && file_exists($tmp_path)) { + unlink($tmp_path); +} + +?> diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php new file mode 100644 index 0000000000..fd1aa9e35f --- /dev/null +++ b/apps/contacts/ajax/saveproperty.php @@ -0,0 +1,134 @@ +. + * + */ + +// Init owncloud +require_once('../../../lib/base.php'); + +// Check if we are a user +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +$l=new OC_L10N('contacts'); + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); +} +foreach ($_POST as $key=>$element) { + debug('_POST: '.$key.'=>'.$element); +} + +$id = isset($_POST['id'])?$_POST['id']:null; +$name = isset($_POST['name'])?$_POST['name']:null; +$value = isset($_POST['value'])?$_POST['value']:null; +$parameters = isset($_POST['parameters'])?$_POST['parameters']:null; +$checksum = isset($_POST['checksum'])?$_POST['checksum']:null; +// if(!is_null($parameters)) { +// debug('parameters: '.count($parameters)); +// foreach($parameters as $key=>$val ) { +// debug('parameter: '.$key.'=>'.implode('/',$val)); +// } +// } + +if(is_array($value)){ // FIXME: How to strip_tags for compound values? + ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form! + $value = OC_VObject::escapeSemicolons($value); +} else { + $value = trim(strip_tags($value)); +} +if(!$id) { + bailOut($l->t('id is not set.')); +} +if(!$checksum) { + bailOut($l->t('checksum is not set.')); +} +if(!$name) { + bailOut($l->t('element name is not set.')); +} + +$vcard = OC_Contacts_App::getContactVCard( $id ); +$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); +if(is_null($line)) { + bailOut($l->t('Information about vCard is incorrect. Please reload the page.'.$checksum.' "'.$line.'"')); +} +$element = $vcard->children[$line]->name; + +if($element != $name) { + bailOut($l->t('Something went FUBAR. ').$name.' != '.$element); +} + +switch($element) { + case 'BDAY': + $date = New DateTime($value); + //$vcard->setDateTime('BDAY', $date, Sabre_VObject_Element_DateTime::DATE); + $value = $date->format(DateTime::ATOM); + case 'FN': + if(!$value) { + // create a method thats returns an alternative for FN. + //$value = getOtherValue(); + } + case 'N': + case 'ORG': + case 'NICKNAME': + debug('Setting string:'.$name.' '.$value); + $vcard->setString($name, $value); + break; + case 'EMAIL': + $value = strtolower($value); + case 'TEL': + case 'ADR': // should I delete the property if empty or throw an error? + debug('Setting element: (EMAIL/TEL/ADR)'.$element); + if(!$value) { + unset($vcard->children[$line]); // Should never happen... + } else { + $vcard->children[$line]->setValue($value); + $vcard->children[$line]->parameters = array(); + if(!is_null($parameters)) { + debug('Setting parameters: '.$parameters); + foreach($parameters as $key => $parameter) { + debug('Adding parameter: '.$key); + foreach($parameter as $val) { + debug('Adding parameter: '.$key.'=>'.$val); + $vcard->children[$line]->add(new Sabre_VObject_Parameter($key, strtoupper($val))); + } + } + } + } + break; +} +// Do checksum and be happy +$checksum = md5($vcard->children[$line]->serialize()); +debug('New checksum: '.$checksum); + +if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { + OC_JSON::error(array('data' => array('message' => $l->t('Error updating contact property.')))); + OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); + exit(); +} + +//$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); +//$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); + +OC_JSON::success(array('data' => array( 'line' => $line, 'checksum' => $checksum, 'oldchecksum' => $_POST['checksum'] ))); diff --git a/apps/contacts/ajax/uploadphoto.php b/apps/contacts/ajax/uploadphoto.php new file mode 100644 index 0000000000..62cd32f5db --- /dev/null +++ b/apps/contacts/ajax/uploadphoto.php @@ -0,0 +1,133 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ +// Init owncloud +require_once('../../../lib/base.php'); + +// Check if we are a user +// Firefox and Konqueror tries to download application/json for me. --Arthur +OC_JSON::setContentTypeHeader('text/plain'); +OC_JSON::checkLoggedIn(); +OC_JSON::checkAppEnabled('contacts'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/uploadphoto.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/uploadphoto.php: '.$msg, OC_Log::DEBUG); +} + +// foreach ($_SERVER as $key=>$element) { +// debug('$_SERVER: '.$key.'=>'.$element); +// } +// foreach ($_GET as $key=>$element) { +// debug('_GET: '.$key.'=>'.$element); +// } +// foreach ($_POST as $key=>$element) { +// debug('_POST: '.$key.'=>'.$element); +// } +// foreach ($_FILES as $key=>$element) { +// debug('_FILES: '.$key.'=>'.$element); +// } + +// If it is a Drag'n'Drop transfer it's handled here. +$fn = (isset($_SERVER['HTTP_X_FILE_NAME']) ? $_SERVER['HTTP_X_FILE_NAME'] : false); +if ($fn) { + // AJAX call + if (!isset($_GET['id'])) { + OC_Log::write('contacts','ajax/uploadphoto.php: No contact ID was submitted.', OC_Log::DEBUG); + OC_JSON::error(array('data' => array( 'message' => 'No contact ID was submitted.' ))); + exit(); + } + $id = $_GET['id']; + $tmpfname = tempnam('/tmp', 'occOrig'); + file_put_contents($tmpfname, file_get_contents('php://input')); + debug($tmpfname.' uploaded'); + $image = new OC_Image(); + if($image->loadFromFile($tmpfname)) { + if($image->width() > 400 || $image->height() > 400) { + $image->resize(400); // Prettier resizing than with browser and saves bandwidth. + } + if(!$image->fixOrientation()) { // No fatal error so we don't bail out. + debug('Couldn\'t save correct image orientation: '.$tmpfname); + } + if($image->save($tmpfname)) { + OC_JSON::success(array('data' => array('mime'=>$_SERVER['CONTENT_TYPE'], 'name'=>$fn, 'id'=>$id, 'tmp'=>$tmpfname))); + exit(); + } else { + bailOut('Couldn\'t save temporary image: '.$tmpfname); + } + } else { + bailOut('Couldn\'t load temporary image: '.$file['tmp_name']); + } +} + + +if (!isset($_POST['id'])) { + OC_Log::write('contacts','ajax/uploadphoto.php: No contact ID was submitted.', OC_Log::DEBUG); + OC_JSON::error(array('data' => array( 'message' => 'No contact ID was submitted.' ))); + exit(); +} +if (!isset($_FILES['imagefile'])) { + OC_Log::write('contacts','ajax/uploadphoto.php: No file was uploaded. Unknown error.', OC_Log::DEBUG); + OC_JSON::error(array('data' => array( 'message' => 'No file was uploaded. Unknown error' ))); + exit(); +} +$error = $_FILES['imagefile']['error']; +if($error !== UPLOAD_ERR_OK) { + $l=new OC_L10N('contacts'); + $errors = array( + 0=>$l->t("There is no error, the file uploaded with success"), + 1=>$l->t("The uploaded file exceeds the upload_max_filesize directive in php.ini").ini_get('upload_max_filesize'), + 2=>$l->t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form"), + 3=>$l->t("The uploaded file was only partially uploaded"), + 4=>$l->t("No file was uploaded"), + 6=>$l->t("Missing a temporary folder") + ); + bailOut($errors[$error]); +} +$file=$_FILES['imagefile']; + +$tmpfname = tempnam("/tmp", "occOrig"); +if(file_exists($file['tmp_name'])) { + $image = new OC_Image(); + if($image->loadFromFile($file['tmp_name'])) { + if($image->width() > 400 || $image->height() > 400) { + $image->resize(400); // Prettier resizing than with browser and saves bandwidth. + } + if(!$image->fixOrientation()) { // No fatal error so we don't bail out. + debug('Couldn\'t save correct image orientation: '.$tmpfname); + } + if($image->save($tmpfname)) { + OC_JSON::success(array('data' => array('mime'=>$file['type'],'size'=>$file['size'],'name'=>$file['name'], 'id'=>$_POST['id'], 'tmp'=>$tmpfname))); + exit(); + } else { + bailOut('Couldn\'t save temporary image: '.$tmpfname); + } + } else { + bailOut('Couldn\'t load temporary image: '.$file['tmp_name']); + } +} else { + bailOut('Temporary file: \''.$file['tmp_name'].'\' has gone AWOL?'); +} + +?> diff --git a/apps/contacts/contacts.php b/apps/contacts/contacts.php new file mode 100644 index 0000000000..fded839fed --- /dev/null +++ b/apps/contacts/contacts.php @@ -0,0 +1,60 @@ + 0) { + $id = $contacts[0]['id']; +} +if(!is_null($id)) { + $vcard = OC_Contacts_App::getContactVCard($id); + $details = OC_Contacts_VCard::structureContact($vcard); +} +$property_types = OC_Contacts_App::getAddPropertyOptions(); +$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); + +$upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); +$post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); +$maxUploadFilesize = min($upload_max_filesize, $post_max_size); + +$freeSpace=OC_Filesystem::free_space('/'); +$freeSpace=max($freeSpace,0); +$maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); + +OC_Util::addScript('','jquery.multiselect'); +//OC_Util::addScript('contacts','interface'); +OC_Util::addScript('contacts','contacts'); +OC_Util::addScript('contacts','jquery.inview'); +OC_Util::addScript('contacts','jquery.Jcrop'); +OC_Util::addScript('contacts','jquery.jec-1.3.3'); +OC_Util::addStyle('','jquery.multiselect'); +//OC_Util::addStyle('contacts','styles'); +OC_Util::addStyle('contacts','jquery.Jcrop'); +OC_Util::addStyle('contacts','contacts'); + +$tmpl = new OC_Template( "contacts", "index2", "user" ); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +$tmpl->assign('property_types',$property_types); +$tmpl->assign('phone_types',$phone_types); +$tmpl->assign('addressbooks', $addressbooks); +$tmpl->assign('contacts', $contacts); +$tmpl->assign('details', $details ); +$tmpl->assign('id',$id); +$tmpl->printPage(); + +?> diff --git a/apps/contacts/css/Jcrop.gif b/apps/contacts/css/Jcrop.gif new file mode 100644 index 0000000000..72ea7ccb53 Binary files /dev/null and b/apps/contacts/css/Jcrop.gif differ diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css new file mode 100644 index 0000000000..a48533f85a --- /dev/null +++ b/apps/contacts/css/contacts.css @@ -0,0 +1,213 @@ +/*dl > dt { + font-weight: bold; +}*/ + +#contacts { padding-left:2px; padding-top: 5px; background: #fff; } +#leftcontent a { height: 23px; display: block; margin: 0 0 0 0; padding: 0 0 0 25px; } +#chooseaddressbook {margin-right: 170px; float: right;} +#contacts_deletecard {position:absolute;top:15px;right:25px;} +#contacts_downloadcard {position:absolute;top:15px;right:50px;} +#contacts_propertymenu_button { position:absolute;top:15px;right:150px; height: 20px; width: 150px; background:url('../../../core/img/actions/add.svg') no-repeat center; } +#contacts_propertymenu { position:absolute;top:35px;right:150px; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; -moz-border-radius:0.5em; -webkit-border-radius:0.5em; border-radius:0.5em; } +#contacts_propertymenu li { display: block; font-weight: bold; border-left: thin solid #1d2d44; border-right: thin solid #1d2d44; height: 20px; width: 100px; } +#contacts_propertymenu li:first-child { border-top: thin solid #1d2d44; -moz-border-radius-topleft:0.5em; -webkit-border-top-left-radius:0.5em; border-top-left-radius:0.5em; -moz-border-radius-topright:0.5em; -webkit-border-top-right-radius:0.5em; border-top-right-radius:0.5em; } +#contacts_propertymenu li:last-child { border-bottom: thin solid #1d2d44; -moz-border-radius-bottomleft:0.5em; -webkit-border-bottom-left-radius:0.5em; border-bottom-left-radius:0.5em; -moz-border-radius-bottomright:0.5em; -webkit-border-bottom-right-radius:0.5em; border-bottom-right-radius:0.5em; } +#contacts_propertymenu li a { padding: 3px; display: block } +#contacts_propertymenu li:hover { background-color: #1d2d44; } +#contacts_propertymenu li a:hover { color: #fff } +#actionbar { height: 30px; width: 200px; position: fixed; right: 0px; top: 75px; margin: 0 0 0 0; padding: 0 0 0 0;} +#card { /*max-width: 70em;*/ border: thin solid lightgray; display: block; } +#firstrun { /*border: thin solid lightgray;*/ width: 80%; margin: 5em auto auto auto; text-align: center; font-weight:bold; font-size:1.5em; color:#777;} +#firstrun #selections { /*border: thin solid lightgray;*/ font-size:0.8em; width: 100%; margin: 2em auto auto auto; clear: both; } + +#card input[type="text"],input[type="email"],input[type="tel"],input[type="date"], select { background-color: #f8f8f8; border: 0 !important; -webkit-appearance:none !important; -moz-appearance:none !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; } +#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="tel"]:active, select:hover, select:focus, select:active { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; } +input[type="text"]:invalid,input[type="email"]:invalid,input[type="tel"]:invalid,input[type="date"]:invalid { background-color: #ffc0c0 !important; } +/*input[type="text"]:valid,input[type="email"]:valid,input[type="tel"]:valid,input[type="date"]:valid { background-color: #b1d28f !important; }*/ +dl.form +{ + width: 100%; + float: left; + clear: right; + margin: 0; + padding: 0; +} + +.form dt +{ + display: table-cell; + clear: left; + float: left; + width: 7em; + /*overflow: hidden;*/ + margin: 0; + padding: 0.8em 0.5em 0 0; + font-weight: bold; + text-align:right; + text-overflow:ellipsis; + o-text-overflow: ellipsis; + vertical-align: text-bottom; + /* + white-space: pre-wrap; + white-space: -moz-pre-wrap !important; + white-space: -pre-wrap; + white-space: -o-pre-wrap;*/ +} + +.form dd +{ + display: table-cell; + clear: right; + float: left; + margin: 0; + padding: 0px; + white-space: nowrap; + vertical-align: text-bottom; + /*min-width: 20em;*/ + /*background-color: yellow;*/ +} + +.loading { background: url('../../../core/img/loading.gif') no-repeat center !important;} + +/*.add { cursor: pointer; width: 25px; height: 25px; margin: 0px; float: right; position:relative; content: "\+"; font-weight: bold; color: #666; font-size: large; bottom: 0px; right: 0px; clear: both; text-align: center; vertical-align: bottom; display: none; }*/ + +.listactions { height: 1em; width:60px; float: left; clear: right; } +.add,.edit,.delete,.mail, .globe { cursor: pointer; width: 20px; height: 20px; margin: 0; float: left; position:relative; display: none; } +.add { background:url('../../../core/img/actions/add.svg') no-repeat center; clear: both; } +.delete { background:url('../../../core/img/actions/delete.svg') no-repeat center; } +.edit { background:url('../../../core/img/actions/rename.svg') no-repeat center; } +.mail { background:url('../../../core/img/actions/mail.svg') no-repeat center; } +.globe { background:url('../img/globe.svg') no-repeat center; } + +#messagebox_msg { font-weight: bold; font-size: 1.2em; } + +/* Name editor */ +#edit_name_dialog { + /*width: 25em;*/ + padding:0; +} +#edit_name_dialog > input { + width: 15em; +} +/* Address editor */ +#edit_address_dialog { + /*width: 30em;*/ +} +#edit_address_dialog > input { + width: 15em; +} +#edit_photo_dialog_img { + display: block; + width: 150; + height: 200; + border: thin solid black; +} +#fn { + float: left; +} +.jecEditableOption { + margin: 2px; + border-radius: 0.5em; + border: thin solid #bbb; + content: 'Custom'; +} +/** + * Create classes form, floateven and floatodd which flows left and right respectively. + */ +.contactsection { + float: left; + min-width: 30em; + max-width: 40em; + margin: 0.5em; + border: thin solid lightgray; + -webkit-border-radius: 0.5em; + -moz-border-radius: 0.5em; + border-radius: 0.5em; + background-color: #f8f8f8; +} + +.contactpart legend { + /*background: #fff; + font-weight: bold; + left: 1em; + border: thin solid gray; + -webkit-border-radius: 0.5em; + -moz-border-radius: 0.5em; + border-radius: 0.5em; + padding: 3px;*/ +width:auto; padding:.3em; border:1px solid #ddd; font-weight:bold; cursor:pointer; background:#f8f8f8; color:#555; text-shadow:#fff 0 1px 0; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; +} +/*#contacts_details_photo { + cursor: pointer; + z-index:1; + margin: auto; +} +*/ +#cropbox { + margin: auto; +} + +/* Photo editor */ +/*#contacts_details_photo_wrapper { + z-index: 1000; +}*/ +#contacts_details_photo { + border-radius: 0.5em; + border: thin solid #bbb; + padding: 0.5em; + margin: 1em 1em 1em 7em; + cursor: pointer; + /*background: #f8f8f8;*/ + background: url(../../../core/img/loading.gif) no-repeat center center; + clear: right; +} +#contacts_details_photo:hover { + background: #fff; +} +#contacts_details_photo_progress { + margin: 0.3em 0.3em 0.3em 7em; + clear: left; +} +/* Address editor */ +#addressdisplay { padding: 0.5em; } +dl.addresscard { background-color: #fff; float: left; width: 45%; margin: 0 0.3em 0.3em 0.3em; padding: 0; border: thin solid lightgray; } +dl.addresscard dd {} +dl.addresscard dt { padding: 0.3em; border-bottom: thin solid lightgray; font-weight: bold; clear: both;} +dl.addresscard dd > ul { margin: 0.3em; padding: 0.3em; } +#adr_type {} /* Select */ +#adr_pobox {} +#adr_extended {} +#adr_street {} +#adr_city {} +#adr_region {} +#adr_zipcode {} +#adr_country {} + +.delimiter { + height: 10px; + clear: both; +} +.updatebar { + height: 30px; + clear: both; + padding-right: 170px; + border: thin solid lightgray; +} +.updatebar button { + float: left; margin: 1em; +} + +/*input[type="text"] { float: left; max-width: 15em; } +input[type="radio"] { float: left; -khtml-appearance: none; width: 20px; height: 20px; vertical-align: middle; }*/ +#file_upload_target, #crop_target { display:none; } + +#file_upload_start { opacity:0; filter:alpha(opacity=0); z-index:1; position:absolute; left:0; top:0; cursor:pointer; width:0; height:0;} +input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; } +.propertycontainer dd { float: left; width: 25em; } +.propertylist { clear: none; max-width: 28em; } +.propertylist li { /*background-color: cyan; */ min-width: 25em; /*max-width: 30em;*/ display: block; clear: right; } +.propertylist li > input[type="text"],input[type="email"],input[type="tel"] { float: left; max-width: 15em; } +.propertylist li > input[type="checkbox"],input[type="radio"] { float: left; clear: left; width: 20px; height: 20px; vertical-align: middle; } +.propertylist li > select { float: left; max-width: 8em; } +.typelist { float: left; max-width: 10em; } /* for multiselect */ +.addresslist { clear: both; } \ No newline at end of file diff --git a/apps/contacts/css/jquery.Jcrop.css b/apps/contacts/css/jquery.Jcrop.css new file mode 100644 index 0000000000..554f013fd7 --- /dev/null +++ b/apps/contacts/css/jquery.Jcrop.css @@ -0,0 +1,84 @@ +/* jquery.Jcrop.css + The code contained in this file is free software under MIT License + Copyright (c)2008-2011 Tapmodo Interactive LLC +*/ + +/* + The outer-most container in a typical Jcrop instance + If you are having difficulty with formatting related to styles + on a parent element, place any fixes here or in a like selector +*/ +.jcrop-holder { + direction: ltr; + text-align: left; +} + +.jcrop-vline, .jcrop-hline { + background: white url('Jcrop.gif') top left repeat; + font-size: 0px; + position: absolute; +} + +.jcrop-vline { + height: 100%; + width: 1px !important; +} + +.jcrop-hline { + width: 100%; + height: 1px !important; +} + +.jcrop-vline.right { + right: 0px; +} + +.jcrop-hline.bottom { + bottom: 0px; +} + +.jcrop-handle { + background-color: #333; + border: 1px #eee solid; + font-size: 1px; +} + +.jcrop-tracker { + height: 100%; + -webkit-tap-highlight-color: transparent; /* "turn off" link highlight */ + -webkit-touch-callout: none; /* disable callout, image save panel */ + -webkit-user-select: none; /* disable cut copy paste */ + width: 100%; +} + +/* +*/ + +.jcrop-light .jcrop-vline, .jcrop-light .jcrop-hline { + background: white; + filter: Alpha(opacity=70) !important; + opacity: .70 !important; +} + +.jcrop-light .jcrop-handle { + background-color: black; + border-color: white; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +.jcrop-dark .jcrop-vline, .jcrop-dark .jcrop-hline { + background: black; + filter: Alpha(opacity=70) !important; + opacity: 0.70 !important; +} + +.jcrop-dark .jcrop-handle { + background-color: white; + border-color: black; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + diff --git a/apps/contacts/dynphoto.php b/apps/contacts/dynphoto.php new file mode 100644 index 0000000000..8025f559c3 --- /dev/null +++ b/apps/contacts/dynphoto.php @@ -0,0 +1,35 @@ + + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +// Init owncloud +require_once('../../lib/base.php'); +$tmp_path = $_GET['tmp_path']; +$maxsize = isset($_GET['maxsize']) ? $_GET['maxsize'] : -1; +header("Cache-Control: no-cache, no-store, must-revalidate"); + +OC_Log::write('contacts','dynphoto.php: tmp_path: '.$tmp_path.', exists: '.file_exists($tmp_path), OC_Log::DEBUG); + +$image = new OC_Image($tmp_path); +if($maxsize != -1) { + $image->resize($maxsize); +} +$image(); diff --git a/apps/contacts/img/globe.svg b/apps/contacts/img/globe.svg new file mode 100644 index 0000000000..4e43cfba10 --- /dev/null +++ b/apps/contacts/img/globe.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/contacts/img/person_large.png b/apps/contacts/img/person_large.png new file mode 100644 index 0000000000..f57511e100 Binary files /dev/null and b/apps/contacts/img/person_large.png differ diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js new file mode 100644 index 0000000000..c2130e08b5 --- /dev/null +++ b/apps/contacts/js/contacts.js @@ -0,0 +1,1289 @@ +function ucwords (str) { + return (str + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) { + return $1.toUpperCase(); + }); +} + +String.prototype.strip_tags = function(){ + tags = this; + stripped = tags.replace(/[\<\>]/gi, ""); + return stripped; +} + + +Contacts={ + UI:{ + notImplemented:function() { + Contacts.UI.messageBox(t('contacts', 'Not implemented'), t('contacts', 'Sorry, this functionality has not been implemented yet')); + }, + searchOSM:function(obj) { + var adr = Contacts.UI.propertyContainerFor(obj).find('.adr').val(); + console.log('adr 1: ' + adr); + if(adr == undefined) { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Couldn\'t get a valid address.')); + return; + } + // FIXME: I suck at regexp. /Tanghus + var adrarr = adr.split(';'); + var adrstr = ''; + if(adrarr[2].trim() != '') { + adrstr = adrstr + adrarr[2].trim() + ','; + } + if(adrarr[3].trim() != '') { + adrstr = adrstr + adrarr[3].trim() + ','; + } + if(adrarr[4].trim() != '') { + adrstr = adrstr + adrarr[4].trim() + ','; + } + if(adrarr[5].trim() != '') { + adrstr = adrstr + adrarr[5].trim() + ','; + } + if(adrarr[6].trim() != '') { + adrstr = adrstr + adrarr[6].trim(); + } + console.log('adrstr: "' + adrstr + '"'); + adrstr = encodeURIComponent(adrstr); + console.log('adrstr 2: ' + adrstr); + var uri = 'http://open.mapquestapi.com/nominatim/v1/search.php?q=' + adrstr + '&limit=10&addressdetails=1&zoom='; + console.log('uri: ' + uri); + var newWindow = window.open(uri,'_blank'); + newWindow.focus(); + //Contacts.UI.notImplemented(); + }, + mailTo:function(obj) { + var adr = Contacts.UI.propertyContainerFor($(obj)).find('input[type="email"]').val().trim(); + if(adr == '') { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Please enter an email address.')); + return; + } + window.location.href='mailto:' + adr; + }, + propertyContainerFor:function(obj) { + return $(obj).parents('.propertycontainer').first(); + }, + checksumFor:function(obj) { + return $(obj).parents('.propertycontainer').first().data('checksum'); + }, + propertyTypeFor:function(obj) { + return $(obj).parents('.propertycontainer').first().data('element'); + }, + checkListFor:function(obj) { + var type = $(obj).parents('.propertycontainer').first().data('element'); + console.log('checkListFor: ' + type); + switch (type) { + case 'EMAIL': + console.log('emails: '+$('#emaillist>li').length); + if($('#emaillist>li').length == 1) { + $('#emails').hide(); + } + break; + case 'TEL': + console.log('phones: '+$('#phonelist>li').length); + if($('#phonelist>li').length == 1) { + $('#phones').hide(); + } + break; + case 'ADR': + console.log('addresses: '+$('#addressdisplay>dl').length); + if($('#addressdisplay>dl').length == 1) { + $('#addresses').hide(); + } + break; + case 'NICKNAME': + case 'ORG': + case 'BDAY': + break; + } + }, + loading:function(obj, state) { + if(state) { + $(obj).addClass('loading'); + } else { + $(obj).removeClass('loading'); + } + }, + showCardDAVUrl:function(username, bookname){ + $('#carddav_url').val(totalurl + '/' + username + '/' + bookname); + $('#carddav_url').show(); + $('#carddav_url_close').show(); + }, + messageBox:function(title, msg) { + //alert(msg); + if($('#messagebox').dialog('isOpen') == true){ + // NOTE: Do we ever get here? + $('#messagebox').dialog('moveToTop'); + }else{ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(){ + $('#messagebox').dialog( + { + autoOpen: true, + title: title, + buttons: [{ + text: "Ok", + click: function() { $(this).dialog("close"); } + }], + close: function(event, ui) { + $(this).dialog('destroy').remove(); + }, + open: function(event, ui) { + $('#messagebox_msg').html(msg); + } + }); + }); + } + }, + loadListHandlers:function() { + //$('.add,.delete').hide(); + $('.globe,.mail,.delete,.edit').tipsy(); + $('.addresscard,.propertylist li,.propertycontainer').hover( + function () { + $(this).find('.globe,.mail,.delete,.edit').fadeIn(100); + }, + function () { + $(this).find('.globe,.mail,.delete,.edit').fadeOut(100); + } + ); + }, + loadHandlers:function() { + console.log('loadHandlers'); + /* + $('.formfloat').hover( + function () { + $(this).find('.add').fadeIn(500); + }, + function () { + $(this).find('.add').fadeOut(500); + } + );*/ + $('#contacts_deletecard').tipsy({gravity: 'ne'}); + $('#contacts_downloadcard').tipsy({gravity: 'ne'}); + $('.button').tipsy(); + $('#fn').jec(); + $('.jecEditableOption').attr('title', t('contacts','Custom')); + $('#fn').tipsy(); + $('#contacts_details_photo_wrapper').tipsy(); + $('#bday').datepicker({ + dateFormat : 'dd-mm-yy' + }); + // Style phone types + $('#phonelist').find('select[class*="contacts_property"]').multiselect({ + noneSelectedText: t('contacts', 'Select type'), + header: false, + selectedList: 4, + classes: 'typelist' + }); + $('#add_email').click(function(){ + Contacts.UI.Card.addMail(); + }); + $('#add_phone').click(function(){ + Contacts.UI.Card.addPhone(); + }); +// $('#add_address').click(function(){ +// Contacts.UI.Card.editAddress(); +// return false; +// }); + $('#n').click(function(){ + Contacts.UI.Card.editName(); + //return false; + }); + $('#edit_name').click(function(){ + Contacts.UI.Card.editName(); + return false; + }); + + /* Initialize the photo edit dialog */ + $('#edit_photo_dialog').dialog({ autoOpen: false, modal: true, height: 'auto', width: 'auto' }); + $('#edit_photo_dialog' ).dialog( 'option', 'buttons', [ + { + text: "Ok", + click: function() { + Contacts.UI.Card.savePhoto(this); + $(this).dialog('close'); + } + }, + { + text: "Cancel", + click: function() { $(this).dialog('close'); } + } + ] ); + Contacts.UI.loadListHandlers(); + }, + Card:{ + id:'', + fn:'', + fullname:'', + shortname:'', + famname:'', + givname:'', + addname:'', + honpre:'', + honsuf:'', + data:undefined, + export:function() { + document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + this.id; + //$.get(OC.linkTo('contacts', 'export.php'),{'contactid':this.id},function(jsondata){ + //}); + }, + delete:function() { + $('#contacts_deletecard').tipsy('hide'); + $.getJSON('ajax/deletecard.php',{'id':this.id},function(jsondata){ + if(jsondata.status == 'success'){ + $('#leftcontent [data-id="'+jsondata.data.id+'"]').remove(); + $('#rightcontent').data('id',''); + //$('#rightcontent').empty(); + this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = ''; + this.data = undefined; + // Load empty page. + var firstid = $('#contacts li:first-child').data('id'); + console.log('trying to load: ' + firstid); + $.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':firstid},function(jsondata){ + if(jsondata.status == 'success'){ + Contacts.UI.Card.loadContact(jsondata.data); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }); + return false; + }, + loadContact:function(jsondata){ + this.data = jsondata; + this.id = this.data.id; + console.log('loaded: ' + this.data.FN[0]['value']); + this.populateNameFields(); + this.loadPhoto(); + this.loadMails(); + this.loadPhones(); + this.loadAddresses(); + this.loadSingleProperties(); + }, + loadSingleProperties:function() { + var props = ['BDAY', 'NICKNAME', 'ORG']; + // Clear all elements + $('#ident .propertycontainer[class*="propertycontainer"]').each(function(){ + if(props.indexOf($(this).data('element')) > -1) { +// $('#contacts_propertymenu a[data-type="'+$(this).data('element')+'"]').parent().show(); + //console.log($(this).html()); + $(this).data('checksum', ''); + $(this).find('input').val(''); + $(this).hide(); + $(this).prev().hide(); + } + }); + for(var prop in props) { + //console.log('loadSingleProperties: ' + props[prop] + ': ' + this.data[props[prop]]); + if(this.data[props[prop]] != undefined) { + $('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().hide(); + var property = this.data[props[prop]][0]; + var value = property['value'], checksum = property['checksum']; + //console.log('value: ' + property['value']); + //console.log('checksum: ' + property['checksum']); + switch(props[prop]) { + case 'BDAY': + var val = $.datepicker.parseDate('yy-mm-dd', value.substring(0, 10)); + //console.log('Date: ' + val); + value = $.datepicker.formatDate('dd-mm-yy', val); + //console.log('Date: ' + value); + $('#contact_identity').find('#bday').val(value); + $('#contact_identity').find('#bday_value').data('checksum', checksum); + $('#contact_identity').find('#bday_label').show(); + $('#contact_identity').find('#bday_value').show(); + break; + case 'NICKNAME': + //console.log('NICKNAME: ' + value); + $('#contact_identity').find('#nickname').val(value); + $('#contact_identity').find('#nickname_value').data('checksum', checksum); + $('#contact_identity').find('#nickname_label').show(); + $('#contact_identity').find('#nickname_value').show(); + break; + case 'ORG': + //console.log('ORG: ' + value); + $('#contact_identity').find('#org').val(value); + $('#contact_identity').find('#org_value').data('checksum', checksum); + $('#contact_identity').find('#org_label').show(); + $('#contact_identity').find('#org_value').show(); + break; + } + } + } + }, + populateNameFields:function() { + this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = '' + var full = ''; + var narray = undefined; + //console.log('splitting: ' + this.data.N[0]['value']); + this.fn = this.data.FN[0]['value']; + //console.log('FN: ' + this.fn) + if(this.data.N == undefined) { + narray = [this.fn,'','','','']; // Checking for non-existing 'N' property :-P + full = this.fn; + } else { + narray = this.data.N[0]['value']; + } + this.famname = narray[0]; + //console.log('famname: ' + this.famname) + this.givname = narray[1]; + this.addname = narray[2]; + this.honpre = narray[3]; + this.honsuf = narray[4]; + if(this.honpre.length > 0) { + this.fullname += this.honpre + ' '; + } + if(this.givname.length > 0) { + this.fullname += ' ' + this.givname; + } + if(this.addname.length > 0) { + this.fullname += ' ' + this.addname; + } + if(this.famname.length > 0) { + this.fullname += ' ' + this.famname; + } + if(this.honsuf.length > 0) { + this.fullname += ', ' + this.honsuf; + } + //console.log('fullname: ' + this.fullname) + $('#n').html(this.fullname); + $('.jecEditableOption').attr('title', 'Custom'); + $('.jecEditableOption').text(this.fn); + //$('.jecEditableOption').attr('value', 0); + $('#fn').val(0); + $('#full').text(this.fullname); + $('#short').text(this.givname + ' ' + this.famname); + $('#reverse').text(this.famname + ' ' + this.givname); + $('#reverse_comma').text(this.famname + ', ' + this.givname); + $('#contact_identity').find('*[data-element="N"]').data('checksum', this.data.N[0]['checksum']); + $('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']); + }, + editNew:function(){ // add a new contact + //Contacts.UI.notImplemented(); + //return false; + + $.getJSON('ajax/newcontact.php',{},function(jsondata){ + if(jsondata.status == 'success'){ + id = ''; + $('#rightcontent').data('id',''); + $('#rightcontent').html(jsondata.data.page); + console.log('Trying to open name edit dialog'); + Contacts.UI.Card.editName(); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + alert(jsondata.data.message); + } + }); + }, + add:function(n, fn, aid){ // add a new contact + //Contacts.UI.notImplemented(); + //return false; + console.log('Add contact: ' + n + ', ' + fn + ' ' + aid); + $.post(OC.filePath('contacts', 'ajax', 'addcontact.php'), { n: n, fn: fn, aid: aid }, + function(jsondata) { + /* + * Arguments: + * jsondata.status + * jsondata.data.id + */ + if (jsondata.status == 'success'){ + $('#rightcontent').data('id',jsondata.data.id); + id = jsondata.data.id; + $('#contact_identity').show(); + $('#actionbar').show(); + // TODO: Add to contacts list. + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }); + }, + saveProperty:function(obj){ + // I couldn't get the selector to filter on 'contacts_property' so I filter by hand here :-/ + if(!$(obj).hasClass('contacts_property')) { + //console.log('Filtering out object.' + obj); + return false; + } + console.log('saveProperty. ' + $(obj).val()); + if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'This property has to be non-empty.')); + return false; + } + //Contacts.UI.loading(obj, false); + //return false; + container = $(obj).parents('.propertycontainer').first(); // get the parent holding the metadata. + Contacts.UI.loading(container, true); + //console.log('saveProperty. Container: ' + container.data('checksum')); + var checksum = container.data('checksum'); + var name = container.data('element'); + var q = container.find('input,select').serialize(); + if(q == '' || q == undefined) { + console.log('Couldn\'t serialize elements.'); + Contacts.UI.loading(container, false); + return false; + } + q = q + '&id=' + this.id + '&name=' + name; + if(checksum != undefined && checksum != '') { // save + q = q + '&checksum=' + checksum; + console.log('Saving: ' + q); + $.post('ajax/saveproperty.php',q,function(jsondata){ + if(jsondata.status == 'success'){ + container.data('checksum', jsondata.data.checksum); + Contacts.UI.loading(container, false); + return true; + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + Contacts.UI.loading(container, false); + return false; + } + },'json'); + } else { // add + console.log('Adding: ' + q); + $.post('ajax/addproperty.php',q,function(jsondata){ + if(jsondata.status == 'success'){ + container.data('checksum', jsondata.data.checksum); + Contacts.UI.loading(container, false); + return true; + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + Contacts.UI.loading(container, false); + return false; + } + },'json'); + } + }, + addProperty:function(obj){ + var type = $(obj).data('type'); + console.log('addProperty:' + type); + switch (type) { + case 'PHOTO': + $('#contacts_propertymenu a[data-type="PHOTO"]').parent().hide(); + $('#file_upload_form').show(); + break; + case 'EMAIL': + //console.log('emails: '+$('#emaillist>li').length); + if($('#emaillist>li').length == 1) { + $('#emails').show(); + } + Contacts.UI.Card.addMail(); + break; + case 'TEL': + //console.log('phones: '+$('#phonelist>li').length); + if($('#phonelist>li').length == 1) { + $('#phones').show(); + } + Contacts.UI.Card.addPhone(); + break; + case 'ADR': + //console.log('addresses: '+$('#addressdisplay>dl').length); + if($('#addressdisplay>dl').length == 1) { + $('#addresses').show(); + } + Contacts.UI.Card.editAddress('new', true); + break; + case 'NICKNAME': + case 'ORG': + case 'BDAY': + $('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show(); + $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + break; + } + }, + deleteProperty:function(obj, type){ + //console.log('deleteProperty, id: ' + this.id); + Contacts.UI.loading(obj, true); + var checksum = Contacts.UI.checksumFor(obj); + //var checksum = $(obj).parent().data('checksum'); + if(checksum != undefined) { + //alert('deleteProperty: ' + $(obj).val() + ' ' + checksum); + $.getJSON('ajax/deleteproperty.php',{'id': this.id, 'checksum': checksum },function(jsondata){ + if(jsondata.status == 'success'){ + if(type == 'list') { + Contacts.UI.propertyContainerFor(obj).remove(); + Contacts.UI.checkListFor(obj); + } else if(type == 'single') { + var proptype = Contacts.UI.propertyTypeFor(obj); + console.log('deleteProperty, hiding: ' + proptype); + $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); + $('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show(); + Contacts.UI.loading(obj, false); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org')); + Contacts.UI.loading(obj, false); + } + } + else{ + Contacts.UI.loading(obj, false); + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + } else { // Property hasn't been saved so there's nothing to delete. + if(type == 'list') { + Contacts.UI.propertyContainerFor(obj).remove(); + Contacts.UI.checkListFor(obj); + } else if(type == 'single') { + var proptype = Contacts.UI.propertyTypeFor(obj); + console.log('deleteProperty, hiding: ' + proptype); + $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); + $('#contacts_propertymenu a[data-type="'+proptype+'"]').parent().show(); + Contacts.UI.loading(obj, false); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org')); + } + } + }, + editName:function(){ + console.log('editName, id: ' + this.id); + //console.log('editName'); + /* Initialize the name edit dialog */ + if($('#edit_name_dialog').dialog('isOpen') == true){ + $('#edit_name_dialog').dialog('moveToTop'); + }else{ // TODO: If id=='' call addcontact.php (or whatever name) instead and reload view with id. + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(){ + $('#edit_name_dialog' ).dialog({ + modal: (this.id == '' && true || false), + closeOnEscape: (this.id == '' && false || true), + title: (this.id == '' && t('contacts', 'Add contact') || t('contacts', 'Edit name')), + height: 'auto', width: 'auto', + buttons: { + 'Ok':function() { + Contacts.UI.Card.saveName(this); + $(this).dialog('destroy').remove(); + }, + 'Cancel':function() { $(this).dialog('destroy').remove(); } + }, + close : function(event, ui) { + //alert('close'); + $(this).dialog('destroy').remove(); + //return event; + }/*, + open : function(event, ui) { + // load 'N' property - maybe :-P + }*/ + }); + }); + } + }, + saveName:function(dlg){ + console.log('saveName, id: ' + this.id); + // TODO: Check if new, get address book id and call Contacts.UI.Card.add() + var n = new Array($(dlg).find('#fam').val(),$(dlg).find('#giv').val(),$(dlg).find('#add').val(),$(dlg).find('#pre').val(),$(dlg).find('#suf').val()); + this.famname = n[0]; + this.givname = n[1]; + this.addname = n[2]; + this.honpre = n[3]; + this.honsuf = n[4]; + //alert('saveName: ' + n); + $('#n').val(n.join(';')); + /*$('#card > input').each(function(){ + alert($(this).attr('id') + ' ' + $(this).val()); + });*/ + if(n[3].length > 0) { + this.fullname = n[3] + ' '; + } + this.fullname += n[1] + ' ' + n[2] + ' ' + n[0]; + if(n[4].length > 0) { + this.fullname += ', ' + n[4]; + } + $('#short').text(n[1] + ' ' + n[0]); + $('#full').text(this.fullname); + $('#reverse').text(n[0] + ' ' + n[1]); + $('#reverse_comma').text(n[0] + ', ' + n[1]); + //$('#n').html(full); + $('#fn').val(0); + if(this.id == '') { + var aid = $(dlg).find('#aid').val(); + Contacts.UI.Card.add(n, $('#short').text(), aid); + } else { + Contacts.UI.Card.saveProperty($('#n')); + } + }, + loadAddresses:function(){ + $('#addresses').hide(); + $('#addressdisplay dl[class*="propertycontainer"]').remove(); + for(var adr in this.data.ADR) { + $('#addressdisplay dl').first().clone().insertAfter($('#addressdisplay dl').last()).show(); + $('#addressdisplay dl').last().removeClass('template').addClass('propertycontainer'); + $('#addressdisplay dl').last().data('checksum', this.data.ADR[adr]['checksum']); + var adrarray = this.data.ADR[adr]['value']; + var adrtxt = ''; + if(adrarray[0].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[0].strip_tags() + '
  • '; + } + if(adrarray[1].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[1].strip_tags() + '
  • '; + } + if(adrarray[2].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[2].strip_tags() + '
  • '; + } + if(adrarray[3].length > 0 || adrarray[5].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[5].strip_tags() + ' ' + adrarray[3].strip_tags() + '
  • '; + } + if(adrarray[4].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[4].strip_tags() + '
  • '; + } + if(adrarray[6].length > 0) { + adrtxt = adrtxt + '
  • ' + adrarray[6].strip_tags() + '
  • '; + } + $('#addressdisplay dl').last().find('.addresslist').html(adrtxt); + //console.log('ADR: ' + adr); + console.log('checksum: ' + this.data.ADR[adr]['checksum']); + //console.log('type: ' + jQuery.type(this.data.ADR[adr]['value'])); + var types = new Array(); + var ttypes = new Array(); + for(var param in this.data.ADR[adr]['parameters']) { + //console.log('param: ' + param + ': ' + this.data.ADR[adr]['parameters'][param]); + if(param.toUpperCase() == 'TYPE') { + //console.log('param type: ' + jQuery.type(this.data.ADR[adr]['parameters'][param])); + types.push(t('contacts', ucwords(this.data.ADR[adr]['parameters'][param].toLowerCase()))); + ttypes.push(this.data.ADR[adr]['parameters'][param]); + //for(ptype in this.data.ADR[adr]['parameters'][param]) { + // var pt = this.data.ADR[adr]['parameters'][param][ptype]; + // // TODO: Create an array with types, translate, ucwords and join. + //} + } + } + //console.log('# types: ' + types.length); + //console.log('Types:' + types.join('/')); + $('#addressdisplay dl').last().find('.adr_type_label').text(types.join('/')); + $('#addressdisplay dl').last().find('.adr_type').val(ttypes.join(',')); + $('#addressdisplay dl').last().find('.adr').val(adrarray.join(';')); + $('#addressdisplay dl').last().data('checksum', this.data.ADR[adr]['checksum']); + } + if($('#addressdisplay dl').length > 1) { + $('#addresses').show(); + } + Contacts.UI.loadListHandlers(); + return false; + }, + editAddress:function(obj, isnew){ + console.log('editAddress'); + var container = undefined; + var q = q = '?id=' + this.id; + if(obj === 'new') { + isnew = true; + $('#addressdisplay dl').first().clone().insertAfter($('#addressdisplay dl').last()).show(); + container = $('#addressdisplay dl').last(); + container.removeClass('template').addClass('propertycontainer'); + Contacts.UI.loadListHandlers(); + } else { + q = q + '&checksum='+Contacts.UI.checksumFor(obj); + } + //console.log('editAddress: checksum ' + checksum); + /* Initialize the address edit dialog */ + if($('#edit_address_dialog').dialog('isOpen') == true){ + $('#edit_address_dialog').dialog('moveToTop'); + }else{ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(){ + $('#edit_address_dialog' ).dialog({ + /*modal: true,*/ + height: 'auto', width: 'auto', + buttons: { + 'Ok':function() { + console.log('OK:isnew ' + isnew); + console.log('OK:obj ' + obj); + if(isnew) { + Contacts.UI.Card.saveAddress(this, $('#addressdisplay dl:last-child').find('input').first(), isnew); + } else { + Contacts.UI.Card.saveAddress(this, obj, isnew); + } + $(this).dialog('destroy').remove(); + }, + 'Cancel':function() { + $(this).dialog('destroy').remove(); + if(isnew) { + container.remove(); + } + } + }, + close : function(event, ui) { + //alert('close'); + $(this).dialog('destroy').remove(); + if(isnew) { + container.remove(); + } + }/*, + open : function(event, ui) { + // load 'ADR' property - maybe :-P + }*/ + }); + }); + } + }, + saveAddress:function(dlg, obj, isnew){ + if(isnew) { + container = $('#addressdisplay dl').last(); + obj = $('#addressdisplay dl:last-child').find('input').first(); + } else { + checksum = Contacts.UI.checksumFor(obj); + container = Contacts.UI.propertyContainerFor(obj); + } + var adr = new Array($(dlg).find('#adr_pobox').val(),$(dlg).find('#adr_extended').val(),$(dlg).find('#adr_street').val(),$(dlg).find('#adr_city').val(),$(dlg).find('#adr_region').val(),$(dlg).find('#adr_zipcode').val(),$(dlg).find('#adr_country').val()); + $(container).find('.adr').val(adr.join(';')); + $(container).find('.adr_type').val($(dlg).find('#adr_type').val()); + $(container).find('.adr_type_label').html(t('contacts',ucwords($(dlg).find('#adr_type').val().toLowerCase()))); + Contacts.UI.Card.saveProperty($(container).find('input').first()); + var adrtxt = ''; + if(adr[0].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[0] + '
  • '; + } + if(adr[1].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[1] + '
  • '; + } + if(adr[2].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[2] + '
  • '; + } + if(adr[3].length > 0 || adr[5].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[5] + ' ' + adr[3] + '
  • '; + } + if(adr[4].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[4] + '
  • '; + } + if(adr[6].length > 0) { + adrtxt = adrtxt + '
  • ' + adr[6] + '
  • '; + } + $(container).find('.addresslist').html(adrtxt); + }, + uploadPhoto:function(filelist) { + if(!filelist) { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts','No files selected for upload.')); + return; + } + //var file = filelist.item(0); + var file = filelist[0]; + var target = $('#file_upload_target'); + var form = $('#file_upload_form'); + var totalSize=0; + if(file.size > $('#max_upload').val()){ + Contacts.UI.messageBox(t('Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.')); + return; + } else { + target.load(function(){ + var response=jQuery.parseJSON(target.contents().text()); + if(response != undefined && response.status == 'success'){ + Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp); + //alert('File: ' + file.tmp + ' ' + file.name + ' ' + file.mime); + }else{ + Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message); + } + }); + form.submit(); + } + }, + loadPhoto:function(){ + console.log('loadPhoto: ' + this.data.PHOTO); + if(this.data.PHOTO) { + $('#file_upload_form').show(); + $('#contacts_propertymenu a[data-type="PHOTO"]').parent().hide(); + } else { + $('#file_upload_form').hide(); + $('#contacts_propertymenu a[data-type="PHOTO"]').parent().show(); + } + $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ + if(jsondata.status == 'success'){ + //alert(jsondata.data.page); + $('#contacts_details_photo_wrapper').html(jsondata.data.page); + } + else{ + Contacts.UI.messageBox(jsondata.data.message); + } + }); + }, + editPhoto:function(id, tmp_path){ + //alert('editPhoto: ' + tmp_path); + $.getJSON('ajax/cropphoto.php',{'tmp_path':tmp_path,'id':this.id},function(jsondata){ + if(jsondata.status == 'success'){ + //alert(jsondata.data.page); + $('#edit_photo_dialog_img').html(jsondata.data.page); + } + else{ + Contacts.UI.messageBox(jsondata.data.message); + } + }); + if($('#edit_photo_dialog').dialog('isOpen') == true){ + $('#edit_photo_dialog').dialog('moveToTop'); + } else { + $('#edit_photo_dialog').dialog('open'); + } + }, + savePhoto:function(){ + var target = $('#crop_target'); + var form = $('#cropform'); + form.submit(); + target.load(function(){ + var response=jQuery.parseJSON(target.contents().text()); + if(response != undefined && response.status == 'success'){ + // load cropped photo. + $('#contacts_details_photo_wrapper').html(response.data.page); + }else{ + Contacts.UI.messageBox(t('contacts','Error'), response.data.message); + } + }); + $('#contacts [data-id="'+this.id+'"]').find('a').css('background','url(thumbnail.php?id='+this.id+'&refresh=1'+Math.random()+') no-repeat'); + }, + addMail:function() { + //alert('addMail'); + $('#emaillist li[class*="template"]:first-child').clone().appendTo($('#emaillist')).show(); + $('#emaillist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer'); + $('#emaillist li:last-child').find('input[type="email"]').focus(); + Contacts.UI.loadListHandlers(); + return false; + }, + loadMails:function() { + $('#emails').hide(); + $('#emaillist li[class*="propertycontainer"]').remove(); + for(var mail in this.data.EMAIL) { + this.addMail(); + //$('#emaillist li:first-child').clone().appendTo($('#emaillist')).show(); + $('#emaillist li:last-child').data('checksum', this.data.EMAIL[mail]['checksum']) + $('#emaillist li:last-child').find('input[type="email"]').val(this.data.EMAIL[mail]['value']); + //console.log('EMAIL: ' + mail); + //console.log('value: ' + this.data.EMAIL[mail]['value']); + //console.log('checksum: ' + this.data.EMAIL[mail]['checksum']); + for(var param in this.data.EMAIL[mail]['parameters']) { + //console.log('param: ' + param + ': ' + this.data.EMAIL[mail]['parameters'][param]); + if(param.toUpperCase() == 'PREF') { + $('#emaillist li:last-child').find('input[type="checkbox"]').attr('checked', 'checked') + } + } + //console.log('parameters: ' + jQuery.type(this.data.EMAIL[mail]['parameters'])); + } + if($('#emaillist li').length > 1) { + $('#emails').show(); + } + + $('#emaillist li:last-child').find('input[type="text"]').focus(); + Contacts.UI.loadListHandlers(); + return false; + }, + addPhone:function() { + $('#phonelist li[class*="template"]:first-child').clone().appendTo($('#phonelist')); //.show(); + $('#phonelist li[class*="template"]:last-child').find('select').addClass('contacts_property'); + $('#phonelist li[class*="template"]:last-child').removeClass('template').addClass('propertycontainer'); + $('#phonelist li:last-child').find('input[type="text"]').focus(); + Contacts.UI.loadListHandlers(); + $('#phonelist li:last-child').find('select').multiselect({ + noneSelectedText: t('contacts', 'Select type'), + header: false, + selectedList: 4, + classes: 'typelist' + }); + $('#phonelist li:last-child').show(); + return false; + }, + loadPhones:function() { + $('#phones').hide(); + $('#phonelist li[class*="propertycontainer"]').remove(); + for(var phone in this.data.TEL) { + this.addPhone(); + $('#phonelist li:last-child').find('select').multiselect('destroy'); + $('#phonelist li:last-child').data('checksum', this.data.TEL[phone]['checksum']) + $('#phonelist li:last-child').find('input[type="text"]').val(this.data.TEL[phone]['value']); + //console.log('TEL: ' + phone); + //console.log('value: ' + this.data.TEL[phone]['value']); + //console.log('checksum: ' + this.data.TEL[phone]['checksum']); + for(var param in this.data.TEL[phone]['parameters']) { + //console.log('param: ' + param + ': ' + this.data.TEL[phone]['parameters'][param]); + if(param.toUpperCase() == 'PREF') { + $('#phonelist li:last-child').find('input[type="checkbox"]').attr('checked', 'checked'); + } + else if(param.toUpperCase() == 'TYPE') { + //console.log('param type: ' + jQuery.type(this.data.TEL[phone]['parameters'][param])); + for(ptype in this.data.TEL[phone]['parameters'][param]) { + var pt = this.data.TEL[phone]['parameters'][param][ptype]; + $('#phonelist li:last-child').find('select option').each(function(){ + //console.log('Test: ' + $(this).val().toUpperCase() + '==' + pt); + if ($(this).val().toUpperCase() == pt) { + //console.log('Selected: ' + pt); + $(this).attr('selected', 'selected'); + } + }); + } + } + } + $('#phonelist li:last-child').find('select').multiselect({ + noneSelectedText: t('contacts', 'Select type'), + header: false, + selectedList: 4, + classes: 'typelist' + }); + //console.log('parameters: ' + jQuery.type(this.data.EMAIL[mail]['parameters'])); + } + if($('#phonelist li').length > 1) { + $('#phones').show(); + } + return false; + }, + }, + Addressbooks:{ + overview:function(){ + if($('#chooseaddressbook_dialog').dialog('isOpen') == true){ + $('#chooseaddressbook_dialog').dialog('moveToTop'); + }else{ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(){ + $('#chooseaddressbook_dialog').dialog({ + width : 600, + close : function(event, ui) { + $(this).dialog('destroy').remove(); + } + }); + }); + } + }, + activation:function(checkbox, bookid) + { + $.post(OC.filePath('contacts', 'ajax', 'activation.php'), { bookid: bookid, active: checkbox.checked?1:0 }, + function(data) { + /* + * Arguments: + * data.status + * data.bookid + * data.active + */ + if (data.status == 'success'){ + checkbox.checked = data.active == 1; + Contacts.UI.Contacts.update(); + } + }); + }, + newAddressbook:function(object){ + var tr = $(document.createElement('tr')) + .load(OC.filePath('contacts', 'ajax', 'addbook.php')); + $(object).closest('tr').after(tr).hide(); + /* TODO: Shouldn't there be some kinda error checking here? */ + }, + editAddressbook:function(object, bookid){ + var tr = $(document.createElement('tr')) + .load(OC.filePath('contacts', 'ajax', 'editaddressbook.php') + "?bookid="+bookid); + $(object).closest('tr').after(tr).hide(); + }, + deleteAddressbook:function(bookid){ + var check = confirm("Do you really want to delete this address book?"); + if(check == false){ + return false; + }else{ + $.post(OC.filePath('contacts', 'ajax', 'deletebook.php'), { id: bookid}, + function(data) { + if (data.status == 'success'){ + $('#chooseaddressbook_dialog').dialog('destroy').remove(); + Contacts.UI.Contacts.update(); + Contacts.UI.Addressbooks.overview(); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), data.message); + //alert('Error: ' + data.message); + } + }); + } + }, + import:function(){ + Contacts.UI.notImplemented(); + }, + submit:function(button, bookid){ + var displayname = $("#displayname_"+bookid).val(); + var active = $("#edit_active_"+bookid+":checked").length; + var description = $("#description_"+bookid).val(); + + var url; + if (bookid == 'new'){ + url = OC.filePath('contacts', 'ajax', 'createaddressbook.php'); + }else{ + url = OC.filePath('contacts', 'ajax', 'updateaddressbook.php'); + } + $.post(url, { id: bookid, name: displayname, active: active, description: description }, + function(data){ + if(data.status == 'success'){ + $(button).closest('tr').prev().html(data.page).show().next().remove(); + } + }); + Contacts.UI.Contacts.update(); + }, + cancel:function(button, bookid){ + $(button).closest('tr').prev().show().next().remove(); + } + }, + Contacts:{ + /** + * Reload the contacts list. + */ + update:function(){ + $.getJSON('ajax/contacts.php',{},function(jsondata){ + if(jsondata.status == 'success'){ + $('#contacts').html(jsondata.data.page); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message); + //alert(jsondata.data.message); + } + }); + setTimeout(Contacts.UI.Contacts.lazyupdate, 500); + }, + /** + * Add thumbnails to the contact list as they become visible in the viewport. + */ + lazyupdate:function(){ + $('#contacts li').live('inview', function(){ + if (!$(this).find('a').attr('style')) { + $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); + } + }); + } + } + } +} +$(document).ready(function(){ + + Contacts.UI.loadHandlers(); + + /** + * Show the Addressbook chooser + */ + $('#chooseaddressbook').click(function(){ + Contacts.UI.Addressbooks.overview(); + return false; + }); + + /** + * Open blank form to add new contact. + * FIXME: Load the same page but only show name data and popup the name edit dialog. + * On save load the page again with an id and show all fields. + * NOTE: Or: Load the full page and popup name dialog modal. On success set the newly aquired ID, on + * Cancel or failure give appropriate message and show ... something else :-P + */ + $('#contacts_newcontact').click(function(){ + Contacts.UI.Card.editNew(); +// $.getJSON('ajax/addcontact.php',{},function(jsondata){ +// if(jsondata.status == 'success'){ +// $('#rightcontent').data('id',''); +// $('#rightcontent').html(jsondata.data.page) +// .find('select').chosen(); +// } +// else{ +// Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); +// //alert(jsondata.data.message); +// } +// }); +// return false; + }); + + /** + * Load the details view for a contact. + */ + $('#leftcontent li').live('click',function(){ + var id = $(this).data('id'); + var oldid = $('#rightcontent').data('id'); + if(oldid != 0){ + $('#leftcontent li[data-id="'+oldid+'"]').removeClass('active'); + } + $.getJSON('ajax/contactdetails.php',{'id':id},function(jsondata){ + if(jsondata.status == 'success'){ + Contacts.UI.Card.loadContact(jsondata.data); + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }); + // NOTE: Deprecated. +// $.getJSON('ajax/getdetails.php',{'id':id, 'new':1},function(jsondata){ +// if(jsondata.status == 'success'){ +// $('#rightcontent').data('id',jsondata.data.id); +// $('#rightcontent').html(jsondata.data.page); +// $('#leftcontent li[data-id="'+jsondata.data.id+'"]').addClass('active'); +// //Contacts.UI.loadHandlers(); +// } +// else{ +// Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); +// //alert(jsondata.data.message); +// } +// }); + return false; + }); + + /** + * Delete currently selected contact TODO: and clear page + */ + $('#contacts_deletecard').live('click',function(){ + Contacts.UI.Card.delete(); + }); + + /** + * Add and insert a new contact into the list. + */ + $('#contacts_addcardform input[type="submit"]').live('click',function(){ + $.post('ajax/addcontact.php',$('#contact_identity').serialize(),function(jsondata){ + if(jsondata.status == 'success'){ + $('#rightcontent').data('id',jsondata.data.id); + $('#rightcontent').html(jsondata.data.page); + $('#leftcontent .active').removeClass('active'); + var item = '
  • '+jsondata.data.name+'
  • '; + var added = false; + $('#leftcontent ul li').each(function(){ + if ($(this).text().toLowerCase() > jsondata.data.name.toLowerCase()) { + $(this).before(item).fadeIn('fast'); + added = true; + return false; + } + }); + if(!added) { + $('#leftcontent ul').append(item); + } + } + else{ + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + //alert(jsondata.data.message); + } + }, 'json'); + return false; + }); + + $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { + if (isInView) { //NOTE: I've kept all conditions for future reference ;-) + // element is now visible in the viewport + if (visiblePartY == 'top') { + // top part of element is visible + } else if (visiblePartY == 'bottom') { + // bottom part of element is visible + } else { + // whole part of element is visible + if (!$(this).find('a').attr('style')) { + //alert($(this).data('id') + ' has background: ' + $(this).attr('style')); + $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); + }/* else { + alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url')); + }*/ + } + } else { + // element has gone out of viewport + } + }); + + $('.button').tipsy(); + // Triggers invisible file input + $('#contacts_details_photo').live('click', function() { + $('#file_upload_start').trigger('click'); + return false; + }); + + // NOTE: For some reason the selector doesn't work when I select by '.contacts_property' too... + // I do the filtering in the event handler instead. + $('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){ + Contacts.UI.Card.saveProperty(this); + }); + + // Name has changed. Update it and reorder. + $('#fn').live('change',function(){ + var name = $('#fn').val(); + var item = $('#contacts [data-id="'+Contacts.UI.Card.id+'"]').clone(); + $('#contacts [data-id="'+Contacts.UI.Card.id+'"]').remove(); + $(item).find('a').html(name); + var added = false; + $('#contacts li').each(function(){ + if ($(this).text().toLowerCase() > name.toLowerCase()) { + $(this).before(item).fadeIn('fast'); + added = true; + return false; + } + }); + if(!added) { + $('#leftcontent ul').append(item); + } + }); + + /** + * Profile picture upload handling + */ + // New profile picture selected + $('#file_upload_start').live('change',function(){ + Contacts.UI.Card.uploadPhoto(this.files); + }); + $('#contacts_details_photo').bind('dragover',function(event){ + console.log('dragover'); + $(event.target).css('background-color','red'); + event.stopPropagation(); + event.preventDefault(); + }); + $('#contacts_details_photo').bind('dragleave',function(event){ + console.log('dragleave'); + $(event.target).css('background-color','white'); + //event.stopPropagation(); + //event.preventDefault(); + }); + $('#contacts_details_photo').bind('drop',function(event){ + event.stopPropagation(); + event.preventDefault(); + console.log('drop'); + $(event.target).css('background-color','white') + $.fileUpload(event.originalEvent.dataTransfer.files); + }); + + /** + * Upload function for dropped files. Should go in the Contacts class/object. + */ + $.fileUpload = function(files){ + var file = files[0]; + console.log('size: '+file.size); + if(file.size > $('#max_upload').val()){ + Contacts.UI.messageBox(t('contacts','Upload too large'), t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.')); + return; + } + if (file.type.indexOf("image") != 0) { + Contacts.UI.messageBox(t('contacts','Wrong file type'), t('contacts','Only image files can be used as profile picture.')); + return; + } + var xhr = new XMLHttpRequest(); + + if (!xhr.upload) { + Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.')) + } + fileUpload = xhr.upload, + xhr.onreadystatechange = function() { + if (xhr.readyState == 4){ + response = $.parseJSON(xhr.responseText); + if(response.status == 'success') { + if(xhr.status == 200) { + Contacts.UI.Card.editPhoto(response.data.id, response.data.tmp); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), xhr.status + ': ' + xhr.responseText); + } + } else { + //alert(xhr.responseText); + Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message); + } + // stop loading indicator + //$('#contacts_details_photo_progress').hide(); + } + }; + + fileUpload.onprogress = function(e){ + if (e.lengthComputable){ + var _progress = Math.round((e.loaded * 100) / e.total); + if (_progress != 100){ + $('#contacts_details_photo_progress').text(_progress + '%'); + $('#contacts_details_photo_progress').val(_progress); + } + } + }; + // Start loading indicator. + //$('#contacts_details_photo_progress').show()(); + xhr.open("POST", 'ajax/uploadphoto.php?id='+Contacts.UI.Card.id+'&imagefile='+encodeURIComponent(file.name), true); + xhr.setRequestHeader('Cache-Control', 'no-cache'); + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name)); + //xhr.setRequestHeader("X_FILENAME", file.name); + xhr.setRequestHeader('X-File-Size', file.size); + xhr.setRequestHeader('Content-Type', file.type); + xhr.send(file); + } + + $('#contacts_propertymenu a').live('click',function(){ + Contacts.UI.Card.addProperty(this); + }); + + +}); diff --git a/apps/contacts/js/jquery.Jcrop.js b/apps/contacts/js/jquery.Jcrop.js new file mode 100644 index 0000000000..36f9a0f08f --- /dev/null +++ b/apps/contacts/js/jquery.Jcrop.js @@ -0,0 +1,1765 @@ +/** + * jquery.Jcrop.js v0.9.9 {{{ + * + * jQuery Image Cropping Plugin - released under MIT License + * Author: Kelly Hallman + * http://github.com/tapmodo/Jcrop + * + * }}} + * Copyright (c) 2008-2012 Tapmodo Interactive LLC {{{ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * }}} + */ + +(function ($) { + + $.Jcrop = function (obj, opt) { + var options = $.extend({}, $.Jcrop.defaults), + docOffset, lastcurs, ie6mode = false; + + // Internal Methods {{{ + function px(n) { + return parseInt(n, 10) + 'px'; + } + function cssClass(cl) { + return options.baseClass + '-' + cl; + } + function supportsColorFade() { + return $.fx.step.hasOwnProperty('backgroundColor'); + } + function getPos(obj) //{{{ + { + var pos = $(obj).offset(); + return [pos.left, pos.top]; + } + //}}} + function mouseAbs(e) //{{{ + { + return [(e.pageX - docOffset[0]), (e.pageY - docOffset[1])]; + } + //}}} + function setOptions(opt) //{{{ + { + if (typeof(opt) !== 'object') opt = {}; + options = $.extend(options, opt); + + $.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e) { + if (typeof(options[e]) !== 'function') options[e] = function () {}; + }); + } + //}}} + function startDragMode(mode, pos) //{{{ + { + docOffset = getPos($img); + Tracker.setCursor(mode === 'move' ? mode : mode + '-resize'); + + if (mode === 'move') { + return Tracker.activateHandlers(createMover(pos), doneSelect); + } + + var fc = Coords.getFixed(); + var opp = oppLockCorner(mode); + var opc = Coords.getCorner(oppLockCorner(opp)); + + Coords.setPressed(Coords.getCorner(opp)); + Coords.setCurrent(opc); + + Tracker.activateHandlers(dragmodeHandler(mode, fc), doneSelect); + } + //}}} + function dragmodeHandler(mode, f) //{{{ + { + return function (pos) { + if (!options.aspectRatio) { + switch (mode) { + case 'e': + pos[1] = f.y2; + break; + case 'w': + pos[1] = f.y2; + break; + case 'n': + pos[0] = f.x2; + break; + case 's': + pos[0] = f.x2; + break; + } + } else { + switch (mode) { + case 'e': + pos[1] = f.y + 1; + break; + case 'w': + pos[1] = f.y + 1; + break; + case 'n': + pos[0] = f.x + 1; + break; + case 's': + pos[0] = f.x + 1; + break; + } + } + Coords.setCurrent(pos); + Selection.update(); + }; + } + //}}} + function createMover(pos) //{{{ + { + var lloc = pos; + KeyManager.watchKeys(); + + return function (pos) { + Coords.moveOffset([pos[0] - lloc[0], pos[1] - lloc[1]]); + lloc = pos; + + Selection.update(); + }; + } + //}}} + function oppLockCorner(ord) //{{{ + { + switch (ord) { + case 'n': + return 'sw'; + case 's': + return 'nw'; + case 'e': + return 'nw'; + case 'w': + return 'ne'; + case 'ne': + return 'sw'; + case 'nw': + return 'se'; + case 'se': + return 'nw'; + case 'sw': + return 'ne'; + } + } + //}}} + function createDragger(ord) //{{{ + { + return function (e) { + if (options.disabled) { + return false; + } + if ((ord === 'move') && !options.allowMove) { + return false; + } + + // Fix position of crop area when dragged the very first time. + // Necessary when crop image is in a hidden element when page is loaded. + docOffset = getPos($img); + + btndown = true; + startDragMode(ord, mouseAbs(e)); + e.stopPropagation(); + e.preventDefault(); + return false; + }; + } + //}}} + function presize($obj, w, h) //{{{ + { + var nw = $obj.width(), + nh = $obj.height(); + if ((nw > w) && w > 0) { + nw = w; + nh = (w / $obj.width()) * $obj.height(); + } + if ((nh > h) && h > 0) { + nh = h; + nw = (h / $obj.height()) * $obj.width(); + } + xscale = $obj.width() / nw; + yscale = $obj.height() / nh; + $obj.width(nw).height(nh); + } + //}}} + function unscale(c) //{{{ + { + return { + x: parseInt(c.x * xscale, 10), + y: parseInt(c.y * yscale, 10), + x2: parseInt(c.x2 * xscale, 10), + y2: parseInt(c.y2 * yscale, 10), + w: parseInt(c.w * xscale, 10), + h: parseInt(c.h * yscale, 10) + }; + } + //}}} + function doneSelect(pos) //{{{ + { + var c = Coords.getFixed(); + if ((c.w > options.minSelect[0]) && (c.h > options.minSelect[1])) { + Selection.enableHandles(); + Selection.done(); + } else { + Selection.release(); + } + Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); + } + //}}} + function newSelection(e) //{{{ + { + if (options.disabled) { + return false; + } + if (!options.allowSelect) { + return false; + } + btndown = true; + docOffset = getPos($img); + Selection.disableHandles(); + Tracker.setCursor('crosshair'); + var pos = mouseAbs(e); + Coords.setPressed(pos); + Selection.update(); + Tracker.activateHandlers(selectDrag, doneSelect); + KeyManager.watchKeys(); + + e.stopPropagation(); + e.preventDefault(); + return false; + } + //}}} + function selectDrag(pos) //{{{ + { + Coords.setCurrent(pos); + Selection.update(); + } + //}}} + function newTracker() //{{{ + { + var trk = $('
    ').addClass(cssClass('tracker')); + if ($.browser.msie) { + trk.css({ + opacity: 0, + backgroundColor: 'white' + }); + } + return trk; + } + //}}} + + // }}} + // Initialization {{{ + // Sanitize some options {{{ + if ($.browser.msie && ($.browser.version.split('.')[0] === '6')) { + ie6mode = true; + } + if (typeof(obj) !== 'object') { + obj = $(obj)[0]; + } + if (typeof(opt) !== 'object') { + opt = {}; + } + // }}} + setOptions(opt); + // Initialize some jQuery objects {{{ + // The values are SET on the image(s) for the interface + // If the original image has any of these set, they will be reset + // However, if you destroy() the Jcrop instance the original image's + // character in the DOM will be as you left it. + var img_css = { + border: 'none', + visibility: 'visible', + margin: 0, + padding: 0, + position: 'absolute', + top: 0, + left: 0 + }; + + var $origimg = $(obj), + img_mode = true; + + if (obj.tagName == 'IMG') { + // Fix size of crop image. + // Necessary when crop image is within a hidden element when page is loaded. + if ($origimg[0].width != 0 && $origimg[0].height != 0) { + // Obtain dimensions from contained img element. + $origimg.width($origimg[0].width); + $origimg.height($origimg[0].height); + } else { + // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0). + var tempImage = new Image(); + tempImage.src = $origimg[0].src; + $origimg.width(tempImage.width); + $origimg.height(tempImage.height); + } + + var $img = $origimg.clone().removeAttr('id').css(img_css).show(); + + $img.width($origimg.width()); + $img.height($origimg.height()); + $origimg.after($img).hide(); + + } else { + $img = $origimg.css(img_css).show(); + img_mode = false; + if (options.shade === null) { options.shade = true; } + } + + presize($img, options.boxWidth, options.boxHeight); + + var boundx = $img.width(), + boundy = $img.height(), + + + $div = $('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({ + position: 'relative', + backgroundColor: options.bgColor + }).insertAfter($origimg).append($img); + + if (options.addClass) { + $div.addClass(options.addClass); + } + + var $img2 = $('
    '), + + $img_holder = $('
    ') + .width('100%').height('100%').css({ + zIndex: 310, + position: 'absolute', + overflow: 'hidden' + }), + + $hdl_holder = $('
    ') + .width('100%').height('100%').css('zIndex', 320), + + $sel = $('
    ') + .css({ + position: 'absolute', + zIndex: 600 + }).dblclick(function(){ + var c = Coords.getFixed(); + options.onDblClick.call(api,c); + }).insertBefore($img).append($img_holder, $hdl_holder); + + if (img_mode) { + + $img2 = $('') + .attr('src', $img.attr('src')).css(img_css).width(boundx).height(boundy), + + $img_holder.append($img2); + + } + + if (ie6mode) { + $sel.css({ + overflowY: 'hidden' + }); + } + + var bound = options.boundary; + var $trk = newTracker().width(boundx + (bound * 2)).height(boundy + (bound * 2)).css({ + position: 'absolute', + top: px(-bound), + left: px(-bound), + zIndex: 290 + }).mousedown(newSelection); + + /* }}} */ + // Set more variables {{{ + var bgcolor = options.bgColor, + bgopacity = options.bgOpacity, + xlimit, ylimit, xmin, ymin, xscale, yscale, enabled = true, + btndown, animating, shift_down; + + docOffset = getPos($img); + // }}} + // }}} + // Internal Modules {{{ + // Touch Module {{{ + var Touch = (function () { + // Touch support detection function adapted (under MIT License) + // from code by Jeffrey Sambells - http://github.com/iamamused/ + function hasTouchSupport() { + var support = {}, + events = ['touchstart', 'touchmove', 'touchend'], + el = document.createElement('div'), i; + + try { + for(i=0; i x1 + ox) { + ox -= ox + x1; + } + if (0 > y1 + oy) { + oy -= oy + y1; + } + + if (boundy < y2 + oy) { + oy += boundy - (y2 + oy); + } + if (boundx < x2 + ox) { + ox += boundx - (x2 + ox); + } + + x1 += ox; + x2 += ox; + y1 += oy; + y2 += oy; + } + //}}} + function getCorner(ord) //{{{ + { + var c = getFixed(); + switch (ord) { + case 'ne': + return [c.x2, c.y]; + case 'nw': + return [c.x, c.y]; + case 'se': + return [c.x2, c.y2]; + case 'sw': + return [c.x, c.y2]; + } + } + //}}} + function getFixed() //{{{ + { + if (!options.aspectRatio) { + return getRect(); + } + // This function could use some optimization I think... + var aspect = options.aspectRatio, + min_x = options.minSize[0] / xscale, + + + //min_y = options.minSize[1]/yscale, + max_x = options.maxSize[0] / xscale, + max_y = options.maxSize[1] / yscale, + rw = x2 - x1, + rh = y2 - y1, + rwa = Math.abs(rw), + rha = Math.abs(rh), + real_ratio = rwa / rha, + xx, yy, w, h; + + if (max_x === 0) { + max_x = boundx * 10; + } + if (max_y === 0) { + max_y = boundy * 10; + } + if (real_ratio < aspect) { + yy = y2; + w = rha * aspect; + xx = rw < 0 ? x1 - w : w + x1; + + if (xx < 0) { + xx = 0; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h : h + y1; + } else if (xx > boundx) { + xx = boundx; + h = Math.abs((xx - x1) / aspect); + yy = rh < 0 ? y1 - h : h + y1; + } + } else { + xx = x2; + h = rwa / aspect; + yy = rh < 0 ? y1 - h : y1 + h; + if (yy < 0) { + yy = 0; + w = Math.abs((yy - y1) * aspect); + xx = rw < 0 ? x1 - w : w + x1; + } else if (yy > boundy) { + yy = boundy; + w = Math.abs(yy - y1) * aspect; + xx = rw < 0 ? x1 - w : w + x1; + } + } + + // Magic %-) + if (xx > x1) { // right side + if (xx - x1 < min_x) { + xx = x1 + min_x; + } else if (xx - x1 > max_x) { + xx = x1 + max_x; + } + if (yy > y1) { + yy = y1 + (xx - x1) / aspect; + } else { + yy = y1 - (xx - x1) / aspect; + } + } else if (xx < x1) { // left side + if (x1 - xx < min_x) { + xx = x1 - min_x; + } else if (x1 - xx > max_x) { + xx = x1 - max_x; + } + if (yy > y1) { + yy = y1 + (x1 - xx) / aspect; + } else { + yy = y1 - (x1 - xx) / aspect; + } + } + + if (xx < 0) { + x1 -= xx; + xx = 0; + } else if (xx > boundx) { + x1 -= xx - boundx; + xx = boundx; + } + + if (yy < 0) { + y1 -= yy; + yy = 0; + } else if (yy > boundy) { + y1 -= yy - boundy; + yy = boundy; + } + + return makeObj(flipCoords(x1, y1, xx, yy)); + } + //}}} + function rebound(p) //{{{ + { + if (p[0] < 0) { + p[0] = 0; + } + if (p[1] < 0) { + p[1] = 0; + } + + if (p[0] > boundx) { + p[0] = boundx; + } + if (p[1] > boundy) { + p[1] = boundy; + } + + return [p[0], p[1]]; + } + //}}} + function flipCoords(x1, y1, x2, y2) //{{{ + { + var xa = x1, + xb = x2, + ya = y1, + yb = y2; + if (x2 < x1) { + xa = x2; + xb = x1; + } + if (y2 < y1) { + ya = y2; + yb = y1; + } + return [Math.round(xa), Math.round(ya), Math.round(xb), Math.round(yb)]; + } + //}}} + function getRect() //{{{ + { + var xsize = x2 - x1, + ysize = y2 - y1, + delta; + + if (xlimit && (Math.abs(xsize) > xlimit)) { + x2 = (xsize > 0) ? (x1 + xlimit) : (x1 - xlimit); + } + if (ylimit && (Math.abs(ysize) > ylimit)) { + y2 = (ysize > 0) ? (y1 + ylimit) : (y1 - ylimit); + } + + if (ymin / yscale && (Math.abs(ysize) < ymin / yscale)) { + y2 = (ysize > 0) ? (y1 + ymin / yscale) : (y1 - ymin / yscale); + } + if (xmin / xscale && (Math.abs(xsize) < xmin / xscale)) { + x2 = (xsize > 0) ? (x1 + xmin / xscale) : (x1 - xmin / xscale); + } + + if (x1 < 0) { + x2 -= x1; + x1 -= x1; + } + if (y1 < 0) { + y2 -= y1; + y1 -= y1; + } + if (x2 < 0) { + x1 -= x2; + x2 -= x2; + } + if (y2 < 0) { + y1 -= y2; + y2 -= y2; + } + if (x2 > boundx) { + delta = x2 - boundx; + x1 -= delta; + x2 -= delta; + } + if (y2 > boundy) { + delta = y2 - boundy; + y1 -= delta; + y2 -= delta; + } + if (x1 > boundx) { + delta = x1 - boundy; + y2 -= delta; + y1 -= delta; + } + if (y1 > boundy) { + delta = y1 - boundy; + y2 -= delta; + y1 -= delta; + } + + return makeObj(flipCoords(x1, y1, x2, y2)); + } + //}}} + function makeObj(a) //{{{ + { + return { + x: a[0], + y: a[1], + x2: a[2], + y2: a[3], + w: a[2] - a[0], + h: a[3] - a[1] + }; + } + //}}} + + return { + flipCoords: flipCoords, + setPressed: setPressed, + setCurrent: setCurrent, + getOffset: getOffset, + moveOffset: moveOffset, + getCorner: getCorner, + getFixed: getFixed + }; + }()); + + //}}} + // Shade Module {{{ + var Shade = (function() { + var enabled = false, + holder = $('
    ').css({ + position: 'absolute', + zIndex: 240, + opacity: 0 + }), + shades = { + top: createShade(), + left: createShade().height(boundy), + right: createShade().height(boundy), + bottom: createShade() + }; + + function resizeShades(w,h) { + shades.left.css({ height: px(h) }); + shades.right.css({ height: px(h) }); + } + function updateAuto() + { + return updateShade(Coords.getFixed()); + } + function updateShade(c) + { + shades.top.css({ + left: px(c.x), + width: px(c.w), + height: px(c.y) + }); + shades.bottom.css({ + top: px(c.y2), + left: px(c.x), + width: px(c.w), + height: px(boundy-c.y2) + }); + shades.right.css({ + left: px(c.x2), + width: px(boundx-c.x2) + }); + shades.left.css({ + width: px(c.x) + }); + } + function createShade() { + return $('
    ').css({ + position: 'absolute', + backgroundColor: options.shadeColor||options.bgColor + }).appendTo(holder); + } + function enableShade() { + if (!enabled) { + enabled = true; + holder.insertBefore($img); + updateAuto(); + Selection.setBgOpacity(1,0,1); + $img2.hide(); + + setBgColor(options.shadeColor||options.bgColor,1); + if (Selection.isAwake()) + { + setOpacity(options.bgOpacity,1); + } + else setOpacity(1,1); + } + } + function setBgColor(color,now) { + colorChangeMacro(getShades(),color,now); + } + function disableShade() { + if (enabled) { + holder.remove(); + $img2.show(); + enabled = false; + if (Selection.isAwake()) { + Selection.setBgOpacity(options.bgOpacity,1,1); + } else { + Selection.setBgOpacity(1,1,1); + Selection.disableHandles(); + } + colorChangeMacro($div,0,1); + } + } + function setOpacity(opacity,now) { + if (enabled) { + if (options.bgFade && !now) { + holder.animate({ + opacity: 1-opacity + },{ + queue: false, + duration: options.fadeTime + }); + } + else holder.css({opacity:1-opacity}); + } + } + function refreshAll() { + options.shade ? enableShade() : disableShade(); + if (Selection.isAwake()) setOpacity(options.bgOpacity); + } + function getShades() { + return holder.children(); + } + + return { + update: updateAuto, + updateRaw: updateShade, + getShades: getShades, + setBgColor: setBgColor, + enable: enableShade, + disable: disableShade, + resize: resizeShades, + refresh: refreshAll, + opacity: setOpacity + }; + }()); + // }}} + // Selection Module {{{ + var Selection = (function () { + var awake, hdep = 370; + var borders = {}; + var handle = {}; + var seehandles = false; + var hhs = options.handleOffset; + + // Private Methods + function insertBorder(type) //{{{ + { + var jq = $('
    ').css({ + position: 'absolute', + opacity: options.borderOpacity + }).addClass(cssClass(type)); + $img_holder.append(jq); + return jq; + } + //}}} + function dragDiv(ord, zi) //{{{ + { + var jq = $('
    ').mousedown(createDragger(ord)).css({ + cursor: ord + '-resize', + position: 'absolute', + zIndex: zi + }).addClass('ord-'+ord); + + if (Touch.support) { + jq.bind('touchstart.jcrop', Touch.createDragger(ord)); + } + + $hdl_holder.append(jq); + return jq; + } + //}}} + function insertHandle(ord) //{{{ + { + var hs = options.handleSize; + return dragDiv(ord, hdep++).css({ + top: px(-hhs + 1), + left: px(-hhs + 1), + opacity: options.handleOpacity + }).width(hs).height(hs).addClass(cssClass('handle')); + } + //}}} + function insertDragbar(ord) //{{{ + { + var s = options.handleSize, + h = s, + w = s, + t = hhs, + l = hhs; + + switch (ord) { + case 'n': + case 's': + w = '100%'; + break; + case 'e': + case 'w': + h = '100%'; + break; + } + + return dragDiv(ord, hdep++).width(w).height(h).css({ + top: px(-t + 1), + left: px(-l + 1) + }); + } + //}}} + function createHandles(li) //{{{ + { + var i; + for (i = 0; i < li.length; i++) { + handle[li[i]] = insertHandle(li[i]); + } + } + //}}} + function moveHandles(c) //{{{ + { + var midvert = Math.round((c.h / 2) - hhs), + midhoriz = Math.round((c.w / 2) - hhs), + north = -hhs + 1, + west = -hhs + 1, + east = c.w - hhs, + south = c.h - hhs, + x, y; + + if (handle.e) { + handle.e.css({ + top: px(midvert), + left: px(east) + }); + handle.w.css({ + top: px(midvert) + }); + handle.s.css({ + top: px(south), + left: px(midhoriz) + }); + handle.n.css({ + left: px(midhoriz) + }); + } + if (handle.ne) { + handle.ne.css({ + left: px(east) + }); + handle.se.css({ + top: px(south), + left: px(east) + }); + handle.sw.css({ + top: px(south) + }); + } + if (handle.b) { + handle.b.css({ + top: px(south) + }); + handle.r.css({ + left: px(east) + }); + } + } + //}}} + function moveto(x, y) //{{{ + { + if (!options.shade) { + $img2.css({ + top: px(-y), + left: px(-x) + }); + } + $sel.css({ + top: px(y), + left: px(x) + }); + } + //}}} + function resize(w, h) //{{{ + { + $sel.width(w).height(h); + } + //}}} + function refresh() //{{{ + { + var c = Coords.getFixed(); + + Coords.setPressed([c.x, c.y]); + Coords.setCurrent([c.x2, c.y2]); + + updateVisible(); + } + //}}} + + // Internal Methods + function updateVisible(select) //{{{ + { + if (awake) { + return update(select); + } + } + //}}} + function update(select) //{{{ + { + var c = Coords.getFixed(); + + resize(c.w, c.h); + moveto(c.x, c.y); + if (options.shade) Shade.updateRaw(c); + + if (seehandles) { + moveHandles(c); + } + if (!awake) { + show(); + } + + if (select) { + options.onSelect.call(api, unscale(c)); + } else { + options.onChange.call(api, unscale(c)); + } + } + //}}} + function setBgOpacity(opacity,force,now) + { + if (!awake && !force) return; + if (options.bgFade && !now) { + $img.animate({ + opacity: opacity + },{ + queue: false, + duration: options.fadeTime + }); + } else { + $img.css('opacity', opacity); + } + } + function show() //{{{ + { + $sel.show(); + + if (options.shade) Shade.opacity(bgopacity); + else setBgOpacity(bgopacity,true); + + awake = true; + } + //}}} + function release() //{{{ + { + disableHandles(); + $sel.hide(); + + if (options.shade) Shade.opacity(1); + else setBgOpacity(1); + + awake = false; + options.onRelease.call(api); + } + //}}} + function showHandles() //{{{ + { + if (seehandles) { + moveHandles(Coords.getFixed()); + $hdl_holder.show(); + } + } + //}}} + function enableHandles() //{{{ + { + seehandles = true; + if (options.allowResize) { + moveHandles(Coords.getFixed()); + $hdl_holder.show(); + return true; + } + } + //}}} + function disableHandles() //{{{ + { + seehandles = false; + $hdl_holder.hide(); + } + //}}} + function animMode(v) //{{{ + { + if (animating === v) { + disableHandles(); + } else { + enableHandles(); + } + } + //}}} + function done() //{{{ + { + animMode(false); + refresh(); + } + //}}} + /* Insert draggable elements {{{*/ + + // Insert border divs for outline + if (options.drawBorders) { + borders = { + top: insertBorder('hline'), + bottom: insertBorder('hline bottom'), + left: insertBorder('vline'), + right: insertBorder('vline right') + }; + } + + // Insert handles on edges + if (options.dragEdges) { + handle.t = insertDragbar('n'); + handle.b = insertDragbar('s'); + handle.r = insertDragbar('e'); + handle.l = insertDragbar('w'); + } + + // Insert side and corner handles + if (options.sideHandles) { + createHandles(['n', 's', 'e', 'w']); + } + if (options.cornerHandles) { + createHandles(['sw', 'nw', 'ne', 'se']); + } + //}}} + + // This is a hack for iOS5 to support drag/move touch functionality + $(document).bind('touchstart.jcrop-ios',function(e) { + if ($(e.currentTarget).hasClass('jcrop-tracker')) e.stopPropagation(); + }); + + var $track = newTracker().mousedown(createDragger('move')).css({ + cursor: 'move', + position: 'absolute', + zIndex: 360 + }); + + if (Touch.support) { + $track.bind('touchstart.jcrop', Touch.createDragger('move')); + } + + $img_holder.append($track); + disableHandles(); + + return { + updateVisible: updateVisible, + update: update, + release: release, + refresh: refresh, + isAwake: function () { + return awake; + }, + setCursor: function (cursor) { + $track.css('cursor', cursor); + }, + enableHandles: enableHandles, + enableOnly: function () { + seehandles = true; + }, + showHandles: showHandles, + disableHandles: disableHandles, + animMode: animMode, + setBgOpacity: setBgOpacity, + done: done + }; + }()); + + //}}} + // Tracker Module {{{ + var Tracker = (function () { + var onMove = function () {}, + onDone = function () {}, + trackDoc = options.trackDocument; + + function toFront() //{{{ + { + $trk.css({ + zIndex: 450 + }); + if (Touch.support) { + $(document) + .bind('touchmove.jcrop', trackTouchMove) + .bind('touchend.jcrop', trackTouchEnd); + } + if (trackDoc) { + $(document) + .bind('mousemove.jcrop',trackMove) + .bind('mouseup.jcrop',trackUp); + } + } + //}}} + function toBack() //{{{ + { + $trk.css({ + zIndex: 290 + }); + $(document).unbind('.jcrop'); + } + //}}} + function trackMove(e) //{{{ + { + onMove(mouseAbs(e)); + return false; + } + //}}} + function trackUp(e) //{{{ + { + e.preventDefault(); + e.stopPropagation(); + + if (btndown) { + btndown = false; + + onDone(mouseAbs(e)); + + if (Selection.isAwake()) { + options.onSelect.call(api, unscale(Coords.getFixed())); + } + + toBack(); + onMove = function () {}; + onDone = function () {}; + } + + return false; + } + //}}} + function activateHandlers(move, done) //{{{ + { + btndown = true; + onMove = move; + onDone = done; + toFront(); + return false; + } + //}}} + function trackTouchMove(e) //{{{ + { + e.pageX = e.originalEvent.changedTouches[0].pageX; + e.pageY = e.originalEvent.changedTouches[0].pageY; + return trackMove(e); + } + //}}} + function trackTouchEnd(e) //{{{ + { + e.pageX = e.originalEvent.changedTouches[0].pageX; + e.pageY = e.originalEvent.changedTouches[0].pageY; + return trackUp(e); + } + //}}} + function setCursor(t) //{{{ + { + $trk.css('cursor', t); + } + //}}} + + if (!trackDoc) { + $trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp); + } + + $img.before($trk); + return { + activateHandlers: activateHandlers, + setCursor: setCursor + }; + }()); + //}}} + // KeyManager Module {{{ + var KeyManager = (function () { + var $keymgr = $('').css({ + position: 'fixed', + left: '-120px', + width: '12px' + }), + $keywrap = $('
    ').css({ + position: 'absolute', + overflow: 'hidden' + }).append($keymgr); + + function watchKeys() //{{{ + { + if (options.keySupport) { + $keymgr.show(); + $keymgr.focus(); + } + } + //}}} + function onBlur(e) //{{{ + { + $keymgr.hide(); + } + //}}} + function doNudge(e, x, y) //{{{ + { + if (options.allowMove) { + Coords.moveOffset([x, y]); + Selection.updateVisible(true); + } + e.preventDefault(); + e.stopPropagation(); + } + //}}} + function parseKey(e) //{{{ + { + if (e.ctrlKey || e.metaKey) { + return true; + } + shift_down = e.shiftKey ? true : false; + var nudge = shift_down ? 10 : 1; + + switch (e.keyCode) { + case 37: + doNudge(e, -nudge, 0); + break; + case 39: + doNudge(e, nudge, 0); + break; + case 38: + doNudge(e, 0, -nudge); + break; + case 40: + doNudge(e, 0, nudge); + break; + case 27: + if (options.allowSelect) Selection.release(); + break; + case 9: + return true; + } + + return false; + } + //}}} + + if (options.keySupport) { + $keymgr.keydown(parseKey).blur(onBlur); + if (ie6mode || !options.fixedSupport) { + $keymgr.css({ + position: 'absolute', + left: '-20px' + }); + $keywrap.append($keymgr).insertBefore($img); + } else { + $keymgr.insertBefore($img); + } + } + + + return { + watchKeys: watchKeys + }; + }()); + //}}} + // }}} + // API methods {{{ + function setClass(cname) //{{{ + { + $div.removeClass().addClass(cssClass('holder')).addClass(cname); + } + //}}} + function animateTo(a, callback) //{{{ + { + var x1 = parseInt(a[0], 10) / xscale, + y1 = parseInt(a[1], 10) / yscale, + x2 = parseInt(a[2], 10) / xscale, + y2 = parseInt(a[3], 10) / yscale; + + if (animating) { + return; + } + + var animto = Coords.flipCoords(x1, y1, x2, y2), + c = Coords.getFixed(), + initcr = [c.x, c.y, c.x2, c.y2], + animat = initcr, + interv = options.animationDelay, + ix1 = animto[0] - initcr[0], + iy1 = animto[1] - initcr[1], + ix2 = animto[2] - initcr[2], + iy2 = animto[3] - initcr[3], + pcent = 0, + velocity = options.swingSpeed; + + x = animat[0]; + y = animat[1]; + x2 = animat[2]; + y2 = animat[3]; + + Selection.animMode(true); + var anim_timer; + + function queueAnimator() { + window.setTimeout(animator, interv); + } + var animator = (function () { + return function () { + pcent += (100 - pcent) / velocity; + + animat[0] = x + ((pcent / 100) * ix1); + animat[1] = y + ((pcent / 100) * iy1); + animat[2] = x2 + ((pcent / 100) * ix2); + animat[3] = y2 + ((pcent / 100) * iy2); + + if (pcent >= 99.8) { + pcent = 100; + } + if (pcent < 100) { + setSelectRaw(animat); + queueAnimator(); + } else { + Selection.done(); + if (typeof(callback) === 'function') { + callback.call(api); + } + } + }; + }()); + queueAnimator(); + } + //}}} + function setSelect(rect) //{{{ + { + setSelectRaw([parseInt(rect[0], 10) / xscale, parseInt(rect[1], 10) / yscale, parseInt(rect[2], 10) / xscale, parseInt(rect[3], 10) / yscale]); + options.onSelect.call(api, unscale(Coords.getFixed())); + Selection.enableHandles(); + } + //}}} + function setSelectRaw(l) //{{{ + { + Coords.setPressed([l[0], l[1]]); + Coords.setCurrent([l[2], l[3]]); + Selection.update(); + } + //}}} + function tellSelect() //{{{ + { + return unscale(Coords.getFixed()); + } + //}}} + function tellScaled() //{{{ + { + return Coords.getFixed(); + } + //}}} + function setOptionsNew(opt) //{{{ + { + setOptions(opt); + interfaceUpdate(); + } + //}}} + function disableCrop() //{{{ + { + options.disabled = true; + Selection.disableHandles(); + Selection.setCursor('default'); + Tracker.setCursor('default'); + } + //}}} + function enableCrop() //{{{ + { + options.disabled = false; + interfaceUpdate(); + } + //}}} + function cancelCrop() //{{{ + { + Selection.done(); + Tracker.activateHandlers(null, null); + } + //}}} + function destroy() //{{{ + { + $div.remove(); + $origimg.show(); + $(obj).removeData('Jcrop'); + } + //}}} + function setImage(src, callback) //{{{ + { + Selection.release(); + disableCrop(); + var img = new Image(); + img.onload = function () { + var iw = img.width; + var ih = img.height; + var bw = options.boxWidth; + var bh = options.boxHeight; + $img.width(iw).height(ih); + $img.attr('src', src); + $img2.attr('src', src); + presize($img, bw, bh); + boundx = $img.width(); + boundy = $img.height(); + $img2.width(boundx).height(boundy); + $trk.width(boundx + (bound * 2)).height(boundy + (bound * 2)); + $div.width(boundx).height(boundy); + Shade.resize(boundx,boundy); + enableCrop(); + + if (typeof(callback) === 'function') { + callback.call(api); + } + }; + img.src = src; + } + //}}} + function colorChangeMacro($obj,color,now) { + var mycolor = color || options.bgColor; + if (options.bgFade && supportsColorFade() && options.fadeTime && !now) { + $obj.animate({ + backgroundColor: mycolor + }, { + queue: false, + duration: options.fadeTime + }); + } else { + $obj.css('backgroundColor', mycolor); + } + } + function interfaceUpdate(alt) //{{{ + // This method tweaks the interface based on options object. + // Called when options are changed and at end of initialization. + { + if (options.allowResize) { + if (alt) { + Selection.enableOnly(); + } else { + Selection.enableHandles(); + } + } else { + Selection.disableHandles(); + } + + Tracker.setCursor(options.allowSelect ? 'crosshair' : 'default'); + Selection.setCursor(options.allowMove ? 'move' : 'default'); + + if (options.hasOwnProperty('trueSize')) { + xscale = options.trueSize[0] / boundx; + yscale = options.trueSize[1] / boundy; + } + + if (options.hasOwnProperty('setSelect')) { + setSelect(options.setSelect); + Selection.done(); + delete(options.setSelect); + } + + Shade.refresh(); + + if (options.bgColor != bgcolor) { + colorChangeMacro( + options.shade? Shade.getShades(): $div, + options.shade? + (options.shadeColor || options.bgColor): + options.bgColor + ); + bgcolor = options.bgColor; + } + + if (bgopacity != options.bgOpacity) { + bgopacity = options.bgOpacity; + if (options.shade) Shade.refresh(); + else Selection.setBgOpacity(bgopacity); + } + + xlimit = options.maxSize[0] || 0; + ylimit = options.maxSize[1] || 0; + xmin = options.minSize[0] || 0; + ymin = options.minSize[1] || 0; + + if (options.hasOwnProperty('outerImage')) { + $img.attr('src', options.outerImage); + delete(options.outerImage); + } + + Selection.refresh(); + } + //}}} + //}}} + + if (Touch.support) $trk.bind('touchstart.jcrop', Touch.newSelection); + + $hdl_holder.hide(); + interfaceUpdate(true); + + var api = { + setImage: setImage, + animateTo: animateTo, + setSelect: setSelect, + setOptions: setOptionsNew, + tellSelect: tellSelect, + tellScaled: tellScaled, + setClass: setClass, + + disable: disableCrop, + enable: enableCrop, + cancel: cancelCrop, + release: Selection.release, + destroy: destroy, + + focus: KeyManager.watchKeys, + + getBounds: function () { + return [boundx * xscale, boundy * yscale]; + }, + getWidgetSize: function () { + return [boundx, boundy]; + }, + getScaleFactor: function () { + return [xscale, yscale]; + }, + + ui: { + holder: $div, + selection: $sel + } + }; + + if ($.browser.msie) { + $div.bind('selectstart', function () { + return false; + }); + } + + $origimg.data('Jcrop', api); + return api; + }; + $.fn.Jcrop = function (options, callback) //{{{ + { + var api; + // Iterate over each object, attach Jcrop + this.each(function () { + // If we've already attached to this object + if ($(this).data('Jcrop')) { + // The API can be requested this way (undocumented) + if (options === 'api') return $(this).data('Jcrop'); + // Otherwise, we just reset the options... + else $(this).data('Jcrop').setOptions(options); + } + // If we haven't been attached, preload and attach + else { + if (this.tagName == 'IMG') + $.Jcrop.Loader(this,function(){ + $(this).css({display:'block',visibility:'hidden'}); + api = $.Jcrop(this, options); + if ($.isFunction(callback)) callback.call(api); + }); + else { + $(this).css({display:'block',visibility:'hidden'}); + api = $.Jcrop(this, options); + if ($.isFunction(callback)) callback.call(api); + } + } + }); + + // Return "this" so the object is chainable (jQuery-style) + return this; + }; + //}}} + // $.Jcrop.Loader - basic image loader {{{ + + $.Jcrop.Loader = function(imgobj,success,error){ + var $img = $(imgobj), img = $img[0]; + + function completeCheck(){ + if (img.complete) { + $img.unbind('.jcloader'); + if ($.isFunction(success)) success.call(img); + } + else window.setTimeout(completeCheck,50); + } + + $img + .bind('load.jcloader',completeCheck) + .bind('error.jcloader',function(e){ + $img.unbind('.jcloader'); + if ($.isFunction(error)) error.call(img); + }); + + if (img.complete && $.isFunction(success)){ + $img.unbind('.jcloader'); + success.call(img); + } + }; + + //}}} + // Global Defaults {{{ + $.Jcrop.defaults = { + + // Basic Settings + allowSelect: true, + allowMove: true, + allowResize: true, + + trackDocument: true, + + // Styling Options + baseClass: 'jcrop', + addClass: null, + bgColor: 'black', + bgOpacity: 0.6, + bgFade: false, + borderOpacity: 0.4, + handleOpacity: 0.5, + handleSize: 7, + handleOffset: 5, + + aspectRatio: 0, + keySupport: true, + cornerHandles: true, + sideHandles: true, + drawBorders: true, + dragEdges: true, + fixedSupport: true, + touchSupport: null, + + shade: null, + + boxWidth: 0, + boxHeight: 0, + boundary: 2, + fadeTime: 400, + animationDelay: 20, + swingSpeed: 3, + + minSelect: [0, 0], + maxSize: [0, 0], + minSize: [0, 0], + + // Callbacks / Event Handlers + onChange: function () {}, + onSelect: function () {}, + onDblClick: function () {}, + onRelease: function () {} + }; + + // }}} +}(jQuery)); diff --git a/apps/contacts/js/jquery.Jcrop.min.js b/apps/contacts/js/jquery.Jcrop.min.js new file mode 100644 index 0000000000..0c05d67c22 --- /dev/null +++ b/apps/contacts/js/jquery.Jcrop.min.js @@ -0,0 +1,255 @@ +/** + * jquery.Jcrop.min.js v0.9.9 {{{ (build:20120102) + * jQuery Image Cropping Plugin - released under MIT License + * Copyright (c) 2008-2012 Tapmodo Interactive LLC + * https://github.com/tapmodo/Jcrop + */ + +(function($){$.Jcrop=function(obj,opt){var options=$.extend({},$.Jcrop.defaults),docOffset,lastcurs,ie6mode=false;function px(n){return parseInt(n,10)+'px';} +function cssClass(cl){return options.baseClass+'-'+cl;} +function supportsColorFade(){return $.fx.step.hasOwnProperty('backgroundColor');} +function getPos(obj) +{var pos=$(obj).offset();return[pos.left,pos.top];} +function mouseAbs(e) +{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];} +function setOptions(opt) +{if(typeof(opt)!=='object')opt={};options=$.extend(options,opt);$.each(['onChange','onSelect','onRelease','onDblClick'],function(i,e){if(typeof(options[e])!=='function')options[e]=function(){};});} +function startDragMode(mode,pos) +{docOffset=getPos($img);Tracker.setCursor(mode==='move'?mode:mode+'-resize');if(mode==='move'){return Tracker.activateHandlers(createMover(pos),doneSelect);} +var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);} +function dragmodeHandler(mode,f) +{return function(pos){if(!options.aspectRatio){switch(mode){case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}}else{switch(mode){case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}} +Coords.setCurrent(pos);Selection.update();};} +function createMover(pos) +{var lloc=pos;KeyManager.watchKeys();return function(pos){Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};} +function oppLockCorner(ord) +{switch(ord){case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';}} +function createDragger(ord) +{return function(e){if(options.disabled){return false;} +if((ord==='move')&&!options.allowMove){return false;} +docOffset=getPos($img);btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};} +function presize($obj,w,h) +{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0){nw=w;nh=(w/$obj.width())*$obj.height();} +if((nh>h)&&h>0){nh=h;nw=(h/$obj.height())*$obj.width();} +xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);} +function unscale(c) +{return{x:parseInt(c.x*xscale,10),y:parseInt(c.y*yscale,10),x2:parseInt(c.x2*xscale,10),y2:parseInt(c.y2*yscale,10),w:parseInt(c.w*xscale,10),h:parseInt(c.h*yscale,10)};} +function doneSelect(pos) +{var c=Coords.getFixed();if((c.w>options.minSelect[0])&&(c.h>options.minSelect[1])){Selection.enableHandles();Selection.done();}else{Selection.release();} +Tracker.setCursor(options.allowSelect?'crosshair':'default');} +function newSelection(e) +{if(options.disabled){return false;} +if(!options.allowSelect){return false;} +btndown=true;docOffset=getPos($img);Selection.disableHandles();Tracker.setCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Selection.update();Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();e.stopPropagation();e.preventDefault();return false;} +function selectDrag(pos) +{Coords.setCurrent(pos);Selection.update();} +function newTracker() +{var trk=$('
    ').addClass(cssClass('tracker'));if($.browser.msie){trk.css({opacity:0,backgroundColor:'white'});} +return trk;} +if($.browser.msie&&($.browser.version.split('.')[0]==='6')){ie6mode=true;} +if(typeof(obj)!=='object'){obj=$(obj)[0];} +if(typeof(opt)!=='object'){opt={};} +setOptions(opt);var img_css={border:'none',visibility:'visible',margin:0,padding:0,position:'absolute',top:0,left:0};var $origimg=$(obj),img_mode=true;if(obj.tagName=='IMG'){if($origimg[0].width!=0&&$origimg[0].height!=0){$origimg.width($origimg[0].width);$origimg.height($origimg[0].height);}else{var tempImage=new Image();tempImage.src=$origimg[0].src;$origimg.width(tempImage.width);$origimg.height(tempImage.height);} +var $img=$origimg.clone().removeAttr('id').css(img_css).show();$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();}else{$img=$origimg.css(img_css).show();img_mode=false;if(options.shade===null){options.shade=true;}} +presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('
    ').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);if(options.addClass){$div.addClass(options.addClass);} +var $img2=$('
    '),$img_holder=$('
    ').width('100%').height('100%').css({zIndex:310,position:'absolute',overflow:'hidden'}),$hdl_holder=$('
    ').width('100%').height('100%').css('zIndex',320),$sel=$('
    ').css({position:'absolute',zIndex:600}).dblclick(function(){var c=Coords.getFixed();options.onDblClick.call(api,c);}).insertBefore($img).append($img_holder,$hdl_holder);if(img_mode){$img2=$('').attr('src',$img.attr('src')).css(img_css).width(boundx).height(boundy),$img_holder.append($img2);} +if(ie6mode){$sel.css({overflowY:'hidden'});} +var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var bgcolor=options.bgColor,bgopacity=options.bgOpacity,xlimit,ylimit,xmin,ymin,xscale,yscale,enabled=true,btndown,animating,shift_down;docOffset=getPos($img);var Touch=(function(){function hasTouchSupport(){var support={},events=['touchstart','touchmove','touchend'],el=document.createElement('div'),i;try{for(i=0;ix1+ox){ox-=ox+x1;} +if(0>y1+oy){oy-=oy+y1;} +if(boundyboundx){xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}else{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0){yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}else if(yy>boundy){yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}} +if(xx>x1){if(xx-x1max_x){xx=x1+max_x;} +if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xxmax_x){xx=x1-max_x;} +if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}} +if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;} +if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;} +return makeObj(flipCoords(x1,y1,xx,yy));} +function rebound(p) +{if(p[0]<0){p[0]=0;} +if(p[1]<0){p[1]=0;} +if(p[0]>boundx){p[0]=boundx;} +if(p[1]>boundy){p[1]=boundy;} +return[p[0],p[1]];} +function flipCoords(x1,y1,x2,y2) +{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2xlimit)){x2=(xsize>0)?(x1+xlimit):(x1-xlimit);} +if(ylimit&&(Math.abs(ysize)>ylimit)){y2=(ysize>0)?(y1+ylimit):(y1-ylimit);} +if(ymin/yscale&&(Math.abs(ysize)0)?(y1+ymin/yscale):(y1-ymin/yscale);} +if(xmin/xscale&&(Math.abs(xsize)0)?(x1+xmin/xscale):(x1-xmin/xscale);} +if(x1<0){x2-=x1;x1-=x1;} +if(y1<0){y2-=y1;y1-=y1;} +if(x2<0){x1-=x2;x2-=x2;} +if(y2<0){y1-=y2;y2-=y2;} +if(x2>boundx){delta=x2-boundx;x1-=delta;x2-=delta;} +if(y2>boundy){delta=y2-boundy;y1-=delta;y2-=delta;} +if(x1>boundx){delta=x1-boundy;y2-=delta;y1-=delta;} +if(y1>boundy){delta=y1-boundy;y2-=delta;y1-=delta;} +return makeObj(flipCoords(x1,y1,x2,y2));} +function makeObj(a) +{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};} +return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}());var Shade=(function(){var enabled=false,holder=$('
    ').css({position:'absolute',zIndex:240,opacity:0}),shades={top:createShade(),left:createShade().height(boundy),right:createShade().height(boundy),bottom:createShade()};function resizeShades(w,h){shades.left.css({height:px(h)});shades.right.css({height:px(h)});} +function updateAuto() +{return updateShade(Coords.getFixed());} +function updateShade(c) +{shades.top.css({left:px(c.x),width:px(c.w),height:px(c.y)});shades.bottom.css({top:px(c.y2),left:px(c.x),width:px(c.w),height:px(boundy-c.y2)});shades.right.css({left:px(c.x2),width:px(boundx-c.x2)});shades.left.css({width:px(c.x)});} +function createShade(){return $('
    ').css({position:'absolute',backgroundColor:options.shadeColor||options.bgColor}).appendTo(holder);} +function enableShade(){if(!enabled){enabled=true;holder.insertBefore($img);updateAuto();Selection.setBgOpacity(1,0,1);$img2.hide();setBgColor(options.shadeColor||options.bgColor,1);if(Selection.isAwake()) +{setOpacity(options.bgOpacity,1);} +else setOpacity(1,1);}} +function setBgColor(color,now){colorChangeMacro(getShades(),color,now);} +function disableShade(){if(enabled){holder.remove();$img2.show();enabled=false;if(Selection.isAwake()){Selection.setBgOpacity(options.bgOpacity,1,1);}else{Selection.setBgOpacity(1,1,1);Selection.disableHandles();} +colorChangeMacro($div,0,1);}} +function setOpacity(opacity,now){if(enabled){if(options.bgFade&&!now){holder.animate({opacity:1-opacity},{queue:false,duration:options.fadeTime});} +else holder.css({opacity:1-opacity});}} +function refreshAll(){options.shade?enableShade():disableShade();if(Selection.isAwake())setOpacity(options.bgOpacity);} +function getShades(){return holder.children();} +return{update:updateAuto,updateRaw:updateShade,getShades:getShades,setBgColor:setBgColor,enable:enableShade,disable:disableShade,resize:resizeShades,refresh:refreshAll,opacity:setOpacity};}());var Selection=(function(){var awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;function insertBorder(type) +{var jq=$('
    ').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;} +function dragDiv(ord,zi) +{var jq=$('
    ').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi}).addClass('ord-'+ord);if(Touch.support){jq.bind('touchstart.jcrop',Touch.createDragger(ord));} +$hdl_holder.append(jq);return jq;} +function insertHandle(ord) +{var hs=options.handleSize;return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).width(hs).height(hs).addClass(cssClass('handle'));} +function insertDragbar(ord) +{var s=options.handleSize,h=s,w=s,t=hhs,l=hhs;switch(ord){case'n':case's':w='100%';break;case'e':case'w':h='100%';break;} +return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});} +function createHandles(li) +{var i;for(i=0;i').css({position:'fixed',left:'-120px',width:'12px'}),$keywrap=$('
    ').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys() +{if(options.keySupport){$keymgr.show();$keymgr.focus();}} +function onBlur(e) +{$keymgr.hide();} +function doNudge(e,x,y) +{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible(true);} +e.preventDefault();e.stopPropagation();} +function parseKey(e) +{if(e.ctrlKey||e.metaKey){return true;} +shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode){case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:if(options.allowSelect)Selection.release();break;case 9:return true;} +return false;} +if(options.keySupport){$keymgr.keydown(parseKey).blur(onBlur);if(ie6mode||!options.fixedSupport){$keymgr.css({position:'absolute',left:'-20px'});$keywrap.append($keymgr).insertBefore($img);}else{$keymgr.insertBefore($img);}} +return{watchKeys:watchKeys};}());function setClass(cname) +{$div.removeClass().addClass(cssClass('holder')).addClass(cname);} +function animateTo(a,callback) +{var x1=parseInt(a[0],10)/xscale,y1=parseInt(a[1],10)/yscale,x2=parseInt(a[2],10)/xscale,y2=parseInt(a[3],10)/yscale;if(animating){return;} +var animto=Coords.flipCoords(x1,y1,x2,y2),c=Coords.getFixed(),initcr=[c.x,c.y,c.x2,c.y2],animat=initcr,interv=options.animationDelay,ix1=animto[0]-initcr[0],iy1=animto[1]-initcr[1],ix2=animto[2]-initcr[2],iy2=animto[3]-initcr[3],pcent=0,velocity=options.swingSpeed;x=animat[0];y=animat[1];x2=animat[2];y2=animat[3];Selection.animMode(true);var anim_timer;function queueAnimator(){window.setTimeout(animator,interv);} +var animator=(function(){return function(){pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent>=99.8){pcent=100;} +if(pcent<100){setSelectRaw(animat);queueAnimator();}else{Selection.done();if(typeof(callback)==='function'){callback.call(api);}}};}());queueAnimator();} +function setSelect(rect) +{setSelectRaw([parseInt(rect[0],10)/xscale,parseInt(rect[1],10)/yscale,parseInt(rect[2],10)/xscale,parseInt(rect[3],10)/yscale]);options.onSelect.call(api,unscale(Coords.getFixed()));Selection.enableHandles();} +function setSelectRaw(l) +{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();} +function tellSelect() +{return unscale(Coords.getFixed());} +function tellScaled() +{return Coords.getFixed();} +function setOptionsNew(opt) +{setOptions(opt);interfaceUpdate();} +function disableCrop() +{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');} +function enableCrop() +{options.disabled=false;interfaceUpdate();} +function cancelCrop() +{Selection.done();Tracker.activateHandlers(null,null);} +function destroy() +{$div.remove();$origimg.show();$(obj).removeData('Jcrop');} +function setImage(src,callback) +{Selection.release();disableCrop();var img=new Image();img.onload=function(){var iw=img.width;var ih=img.height;var bw=options.boxWidth;var bh=options.boxHeight;$img.width(iw).height(ih);$img.attr('src',src);$img2.attr('src',src);presize($img,bw,bh);boundx=$img.width();boundy=$img.height();$img2.width(boundx).height(boundy);$trk.width(boundx+(bound*2)).height(boundy+(bound*2));$div.width(boundx).height(boundy);Shade.resize(boundx,boundy);enableCrop();if(typeof(callback)==='function'){callback.call(api);}};img.src=src;} +function colorChangeMacro($obj,color,now){var mycolor=color||options.bgColor;if(options.bgFade&&supportsColorFade()&&options.fadeTime&&!now){$obj.animate({backgroundColor:mycolor},{queue:false,duration:options.fadeTime});}else{$obj.css('backgroundColor',mycolor);}} +function interfaceUpdate(alt) +{if(options.allowResize){if(alt){Selection.enableOnly();}else{Selection.enableHandles();}}else{Selection.disableHandles();} +Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');if(options.hasOwnProperty('trueSize')){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;} +if(options.hasOwnProperty('setSelect')){setSelect(options.setSelect);Selection.done();delete(options.setSelect);} +Shade.refresh();if(options.bgColor!=bgcolor){colorChangeMacro(options.shade?Shade.getShades():$div,options.shade?(options.shadeColor||options.bgColor):options.bgColor);bgcolor=options.bgColor;} +if(bgopacity!=options.bgOpacity){bgopacity=options.bgOpacity;if(options.shade)Shade.refresh();else Selection.setBgOpacity(bgopacity);} +xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if(options.hasOwnProperty('outerImage')){$img.attr('src',options.outerImage);delete(options.outerImage);} +Selection.refresh();} +if(Touch.support)$trk.bind('touchstart.jcrop',Touch.newSelection);$hdl_holder.hide();interfaceUpdate(true);var api={setImage:setImage,animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,setClass:setClass,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,release:Selection.release,destroy:destroy,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},getScaleFactor:function(){return[xscale,yscale];},ui:{holder:$div,selection:$sel}};if($.browser.msie){$div.bind('selectstart',function(){return false;});} +$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options,callback) +{var api;this.each(function(){if($(this).data('Jcrop')){if(options==='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);} +else{if(this.tagName=='IMG') +$.Jcrop.Loader(this,function(){$(this).css({display:'block',visibility:'hidden'});api=$.Jcrop(this,options);if($.isFunction(callback))callback.call(api);});else{$(this).css({display:'block',visibility:'hidden'});api=$.Jcrop(this,options);if($.isFunction(callback))callback.call(api);}}});return this;};$.Jcrop.Loader=function(imgobj,success,error){var $img=$(imgobj),img=$img[0];function completeCheck(){if(img.complete){$img.unbind('.jcloader');if($.isFunction(success))success.call(img);} +else window.setTimeout(completeCheck,50);} +$img.bind('load.jcloader',completeCheck).bind('error.jcloader',function(e){$img.unbind('.jcloader');if($.isFunction(error))error.call(img);});if(img.complete&&$.isFunction(success)){$img.unbind('.jcloader');success.call(img);}};$.Jcrop.defaults={allowSelect:true,allowMove:true,allowResize:true,trackDocument:true,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:0.6,bgFade:false,borderOpacity:0.4,handleOpacity:0.5,handleSize:7,handleOffset:5,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,fixedSupport:true,touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}};}(jQuery)); \ No newline at end of file diff --git a/apps/contacts/js/jquery.jec-1.3.3.js b/apps/contacts/js/jquery.jec-1.3.3.js new file mode 100644 index 0000000000..a0367dac2a --- /dev/null +++ b/apps/contacts/js/jquery.jec-1.3.3.js @@ -0,0 +1,863 @@ +/** + * jQuery jEC (jQuery Editable Combobox) 1.3.3 + * http://code.google.com/p/jquery-jec + * + * Copyright (c) 2008-2009 Lukasz Rajchel (lukasz@rajchel.pl | http://rajchel.pl) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Documentation : http://code.google.com/p/jquery-jec/wiki/Documentation + * Changelog : http://code.google.com/p/jquery-jec/wiki/Changelog + * + * Contributors : Lukasz Rajchel, Artem Orlov + */ + +/*jslint maxerr: 50, indent: 4, maxlen: 120*/ +/*global Array, Math, String, clearInterval, document, jQuery, setInterval*/ +/*members ':', Handle, Remove, Set, acceptedKeys, addClass, all, append, appendTo, array, attr, before, bind, +blinkingCursor, blinkingCursorInterval, blur, bool, browser, ceil, change, charCode, classes, clearCursor, click, css, +cursorState, data, destroy, disable, each, editable, enable, eq, expr, extend, filter, find, floor, fn, focus, +focusOnNewOption, fromCharCode, get, getId, handleCursor, ignoredKeys, ignoreOptGroups, inArray, init, initJS, integer, +isArray, isPlainObject, jEC, jECTimer, jec, jecKill, jecOff, jecOn, jecPref, jecValue, keyCode, keyDown, keyPress, +keyRange, keyUp, keys, length, max, maxLength, min, msie, object, openedState, optionClasses, optionStyles, parent, +position, pref, prop, push, random, remove, removeAttr, removeClass, removeData, removeProp, safari, setEditableOption, +styles, substring, text, trigger, triggerChangeEvent, unbind, uneditable, useExistingOptions, val, value, +valueIsEditable, which*/ +(function ($) { + 'use strict'; + + $.jEC = (function () { + var pluginClass = 'jecEditableOption', cursorClass = 'hasCursor', options = {}, values = {}, lastKeyCode, + defaults, Validators, EventHandlers, Combobox, activeCombobox; + + if ($.fn.prop === undefined) { + $.fn.extend({ + 'prop': function (key, valueSet) { + if (valueSet) { + $(this).attr(key, key); + } else { + $(this).removeAttr(key); + } + }, + 'removeProp': function (key) { + $(this).removeAttr(key); + } + }); + } + + defaults = { + position: 0, + ignoreOptGroups: false, + maxLength: 255, + classes: [], + styles: {}, + optionClasses: [], + optionStyles: {}, + triggerChangeEvent: false, + focusOnNewOption: false, + useExistingOptions: false, + blinkingCursor: false, + blinkingCursorInterval: 1000, + ignoredKeys: [], + acceptedKeys: [[32, 126], [191, 382]] + }; + + Validators = (function () { + return { + integer: function (value) { + return typeof value === 'number' && Math.ceil(value) === Math.floor(value); + }, + + keyRange: function (value) { + var min, max; + if ($.isPlainObject(value)) { + min = value.min; + max = value.max; + } else if ($.isArray(value) && value.length === 2) { + min = value[0]; + max = value[1]; + } + return Validators.integer(min) && Validators.integer(max) && min <= max; + } + }; + }()); + + EventHandlers = (function () { + var getKeyCode; + + getKeyCode = function (event) { + var charCode = event.charCode; + if (charCode !== undefined && charCode !== 0) { + return charCode; + } else { + return event.keyCode; + } + }; + + return { + // focus event handler + // enables blinking cursor + focus: function () { + var opt = options[Combobox.getId($(this))]; + if (opt.blinkingCursor && $.jECTimer === undefined) { + activeCombobox = $(this); + $.jECTimer = setInterval($.jEC.handleCursor, opt.blinkingCursorInterval); + } + }, + + // blur event handler + // disables blinking cursor + blur: function () { + if ($.jECTimer !== undefined) { + clearInterval($.jECTimer); + $.jECTimer = undefined; + activeCombobox = undefined; + Combobox.clearCursor($(this)); + } + Combobox.openedState($(this), false); + }, + + // keydown event handler + // handles keys pressed on select (backspace and delete must be handled + // in keydown event in order to work in IE) + keyDown: function (event) { + var keyCode = getKeyCode(event), option, value; + + lastKeyCode = keyCode; + + switch (keyCode) { + case 8: // backspace + case 46: // delete + option = $(this).find('option.' + pluginClass); + if (option.val().length >= 1) { + value = option.text().substring(0, option.text().length - 1); + option.val(value).text(value).prop('selected', true); + } + return (keyCode !== 8); + default: + break; + } + }, + + // keypress event handler + // handles the rest of the keys (keypress event gives more informations + // about pressed keys) + keyPress: function (event) { + var keyCode = getKeyCode(event), opt = options[Combobox.getId($(this))], + option, value, specialKeys, exit = false, text; + + Combobox.clearCursor($(this)); + if (keyCode !== 9 && keyCode !== 13 && keyCode !== 27) { + // special keys codes + specialKeys = [37, 38, 39, 40, 46]; + // handle special keys + $.each(specialKeys, function (i, val) { + if (keyCode === val && keyCode === lastKeyCode) { + exit = true; + } + }); + + // don't handle ignored keys + if (!exit && $.inArray(keyCode, opt.ignoredKeys) === -1) { + // remove selection from all options + $(this).find('option:selected').removeProp('selected'); + + if ($.inArray(keyCode, opt.acceptedKeys) !== -1) { + option = $(this).find('option.' + pluginClass); + text = option.text(); + + if (text.length < opt.maxLength) { + value = text + String.fromCharCode(getKeyCode(event)); + option.val(value).text(value); + } + + option.prop('selected', true); + } + } + + return false; + } + }, + + keyUp: function () { + var opt = options[Combobox.getId($(this))]; + if (opt.triggerChangeEvent) { + $(this).trigger('change'); + } + }, + + // change event handler + // handles editable option changing based on a pre-existing values + change: function () { + var opt = options[Combobox.getId($(this))]; + if (opt.useExistingOptions) { + Combobox.setEditableOption($(this)); + } + }, + + click: function () { + if (!$.browser.safari) { + Combobox.openedState($(this), !Combobox.openedState($(this))); + } + } + }; + }()); + + // Combobox + Combobox = (function () { + var Parameters, EditableOption, generateId, setup; + + // validates and set combobox parameters + Parameters = (function () { + var Set, Remove, Handle; + + Set = (function () { + var parseKeys, Handles; + + parseKeys = function (value) { + var keys = []; + if ($.isArray(value)) { + $.each(value, function (i, val) { + var j, min, max; + if (Validators.keyRange(val)) { + if ($.isArray(val)) { + min = val[0]; + max = val[1]; + } else { + min = val.min; + max = val.max; + } + for (j = min; j <= max; j += 1) { + keys.push(j); + } + } else if (typeof val === 'number' && Validators.integer(val)) { + keys.push(val); + } + }); + } + return keys; + }; + + Handles = (function () { + return { + integer: function (elem, name, value) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && Validators.integer(value)) { + opt[name] = value; + return true; + } + return false; + }, + bool: function (elem, name, value) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && typeof value === 'boolean') { + opt[name] = value; + return true; + } + return false; + }, + array: function (elem, name, value) { + if (typeof value === 'string') { + value = [value]; + } + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && $.isArray(value)) { + opt[name] = value; + return true; + } + return false; + }, + object: function (elem, name, value) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && value !== null && $.isPlainObject(value)) { + opt[name] = value; + } + }, + keys: function (elem, name, value) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && $.isArray(value)) { + opt[name] = parseKeys(value); + } + } + }; + }()); + + return { + position: function (elem, value) { + if (Handles.integer(elem, 'position', value)) { + var id = Combobox.getId(elem), opt = options[id], optionsCount; + optionsCount = + elem.find('option:not(.' + pluginClass + ')').length; + if (value > optionsCount) { + opt.position = optionsCount; + } + } + }, + + ignoreOptGroups: function (elem, value) { + Handles.bool(elem, 'ignoreOptGroups', value); + }, + + maxLength: function (elem, value) { + if (Handles.integer(elem, 'maxLength', value)) { + var id = Combobox.getId(elem), opt = options[id]; + if (value < 0 || value > 255) { + opt.maxLength = 255; + } + } + }, + + classes: function (elem, value) { + Handles.array(elem, 'classes', value); + }, + + optionClasses: function (elem, value) { + Handles.array(elem, 'optionClasses', value); + }, + + styles: function (elem, value) { + Handles.object(elem, 'styles', value); + }, + + optionStyles: function (elem, value) { + Handles.object(elem, 'optionStyles', value); + }, + + triggerChangeEvent: function (elem, value) { + Handles.bool(elem, 'triggerChangeEvent', value); + }, + + focusOnNewOption: function (elem, value) { + Handles.bool(elem, 'focusOnNewOption', value); + }, + + useExistingOptions: function (elem, value) { + Handles.bool(elem, 'useExistingOptions', value); + }, + + blinkingCursor: function (elem, value) { + Handles.bool(elem, 'blinkingCursor', value); + }, + + blinkingCursorInterval: function (elem, value) { + Handles.integer(elem, 'blinkingCursorInterval', value); + }, + + ignoredKeys: function (elem, value) { + Handles.keys(elem, 'ignoredKeys', value); + }, + + acceptedKeys: function (elem, value) { + Handles.keys(elem, 'acceptedKeys', value); + } + }; + }()); + + Remove = (function () { + var removeClasses, removeStyles; + + removeClasses = function (elem, classes) { + $.each(classes, function (i, val) { + elem.removeClass(val); + }); + }; + + removeStyles = function (elem, styles) { + $.each(styles, function (key) { + elem.css(key, ''); + }); + }; + + return { + classes: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + removeClasses(elem, opt.classes); + } + }, + + optionClasses: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + removeClasses(elem.find('option.' + pluginClass), + opt.optionClasses); + } + }, + + styles: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + removeStyles(elem, opt.styles); + } + }, + + optionStyles: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + removeStyles(elem.find('option.' + pluginClass), + opt.optionStyles); + } + }, + + all: function (elem) { + Remove.classes(elem); + Remove.optionClasses(elem); + Remove.styles(elem); + Remove.optionStyles(elem); + } + }; + }()); + + Handle = (function () { + var setClasses, setStyles; + + setClasses = function (elem, classes) { + $.each(classes, function (i, val) { + elem.addClass(String(val)); + }); + }; + + setStyles = function (elem, styles) { + $.each(styles, function (key, val) { + elem.css(key, val); + }); + }; + + return { + position: function (elem) { + var opt = options[Combobox.getId(elem)], option, uneditableOptions, container; + option = elem.find('option.' + pluginClass); + + uneditableOptions = elem.find('option:not(.' + pluginClass + ')'); + if (opt.position < uneditableOptions.length) { + container = uneditableOptions.eq(opt.position); + + if (!opt.ignoreOptGroups && container.parent('optgroup').length > 0) { + uneditableOptions.eq(opt.position).parent().before(option); + } else { + uneditableOptions.eq(opt.position).before(option); + } + } else { + elem.append(option); + } + }, + + classes: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + setClasses(elem, opt.classes); + } + }, + + optionClasses: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + setClasses(elem.find('option.' + pluginClass), opt.optionClasses); + } + }, + + styles: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + setStyles(elem, opt.styles); + } + }, + + optionStyles: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined) { + setStyles(elem.find('option.' + pluginClass), opt.optionStyles); + } + }, + + focusOnNewOption: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && opt.focusOnNewOption) { + elem.find(':not(option.' + pluginClass + ')').removeProp('selected'); + elem.find('option.' + pluginClass).prop('selected', true); + } + }, + + useExistingOptions: function (elem) { + var id = Combobox.getId(elem), opt = options[id]; + if (opt !== undefined && opt.useExistingOptions) { + Combobox.setEditableOption(elem); + } + }, + + all: function (elem) { + Handle.position(elem); + Handle.classes(elem); + Handle.optionClasses(elem); + Handle.styles(elem); + Handle.optionStyles(elem); + Handle.focusOnNewOption(elem); + Handle.useExistingOptions(elem); + } + }; + }()); + + return { + Set: Set, + Remove: Remove, + Handle: Handle + }; + }()); + + EditableOption = (function () { + return { + init: function (elem) { + if (!elem.find('option.' + pluginClass).length) { + var editableOption = $('
    +
    +
      + inc("part.contacts"); ?> +
    +
    +
    + inc('part.contact'); + } + else{ + echo $this->inc('part.no_contacts'); + } + ?> +
    + +
    + diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php new file mode 100644 index 0000000000..0e3611b2e4 --- /dev/null +++ b/apps/contacts/templates/part.contact.php @@ -0,0 +1,210 @@ +format('d-m-Y'); +} +$card['NICKNAME'] = (array_key_exists('NICKNAME',$_['details'])) ? $_['details']['NICKNAME'][0] : null; +$card['EMAIL'] = (array_key_exists('EMAIL',$_['details'])) ? $_['details']['EMAIL'] : array(); +$card['TEL'] = (array_key_exists('TEL',$_['details'])) ? $_['details']['TEL'] : array(); +$card['ADR'] = (array_key_exists('ADR',$_['details'])) ? $_['details']['ADR'] : array(); +?> +
    + + +
    + +
    id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target"> +
    +
    + + +
    + + + + + +
    +
    +
    > + +
    +
    + +
    + +
    +
    + +
    + + + + + + +
    +
    +
    +
    + + +
    +
    + +
    0?'':'style="display:none;"'); ?>> +
    + t('Email'); ?> +
      + + +
    • + /> + +
    • + +
    +
    + + +
    0?'':'style="display:none;"'); ?>> +
    + t('Phone'); ?> +
      + + +
    • + /> + + +
    • + +
    +
    + + +
    0?'':'style="display:none;"'); ?>> +
    + t('Address'); ?> +
    + + + +
    +
    + + + + 0) { + //array_walk($address['parameters'], ) Nah, this wont work... + $translated = array(); + foreach($address['parameters'] as $type) { + $translated[] = $l->t(ucwords(strtolower($type))); + } + echo implode('/', $translated); + } + ?> +
    +
    +
      + '.$adr[0].'':''); + $tmp .= ($adr[1]?'
    • '.$adr[1].'
    • ':''); + $tmp .= ($adr[2]?'
    • '.$adr[2].'
    • ':''); + $tmp .= ($adr[3]||$adr[5]?'
    • '.$adr[5].' '.$adr[3].'
    • ':''); + $tmp .= ($adr[4]?'
    • '.$adr[4].'
    • ':''); + $tmp .= ($adr[6]?'
    • '.$adr[6].'
    • ':''); + echo $tmp; + + ?> +
    +
    +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    +
    + diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php new file mode 100644 index 0000000000..7d7ab23756 --- /dev/null +++ b/apps/contacts/templates/part.contactphoto.php @@ -0,0 +1,9 @@ + + src="?id=&refresh=" /> + + + diff --git a/apps/contacts/templates/part.cropphoto.php b/apps/contacts/templates/part.cropphoto.php new file mode 100644 index 0000000000..cb416f0e41 --- /dev/null +++ b/apps/contacts/templates/part.cropphoto.php @@ -0,0 +1,62 @@ + + + +
    + + + +
    + + + + + + +
    + +
    + + diff --git a/apps/contacts/templates/part.edit_address_dialog.php b/apps/contacts/templates/part.edit_address_dialog.php new file mode 100644 index 0000000000..0ecdc4e191 --- /dev/null +++ b/apps/contacts/templates/part.edit_address_dialog.php @@ -0,0 +1,67 @@ + +
    + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    diff --git a/apps/contacts/templates/part.edit_name_dialog.php b/apps/contacts/templates/part.edit_name_dialog.php new file mode 100644 index 0000000000..d525fd1f99 --- /dev/null +++ b/apps/contacts/templates/part.edit_name_dialog.php @@ -0,0 +1,59 @@ + +
    +
    +
    +
    + + + +
    +
    + +
    + +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php new file mode 100644 index 0000000000..ab6129cdde --- /dev/null +++ b/apps/contacts/templates/part.no_contacts.php @@ -0,0 +1,8 @@ +
    +You have no contacts in your list. +
    + + + +
    +
    \ No newline at end of file diff --git a/core/img/actions/add.png b/core/img/actions/add.png new file mode 100644 index 0000000000..db1b1970f1 Binary files /dev/null and b/core/img/actions/add.png differ diff --git a/core/img/actions/add.svg b/core/img/actions/add.svg new file mode 100644 index 0000000000..29994747c3 --- /dev/null +++ b/core/img/actions/add.svg @@ -0,0 +1,109 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/core/img/actions/mail.png b/core/img/actions/mail.png new file mode 100644 index 0000000000..ea811ac545 Binary files /dev/null and b/core/img/actions/mail.png differ diff --git a/core/img/actions/mail.svg b/core/img/actions/mail.svg new file mode 100644 index 0000000000..54a24faf85 --- /dev/null +++ b/core/img/actions/mail.svg @@ -0,0 +1,345 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +