From 496c1581d76a920fb6c6a50bc080c936d6ffbd31 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 16 Feb 2012 23:24:23 +0100 Subject: [PATCH 01/61] ETags must be quoted. --- lib/response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/response.php b/lib/response.php index 2fa0a5adcd3..9431d7af1ce 100644 --- a/lib/response.php +++ b/lib/response.php @@ -85,7 +85,7 @@ class OC_Response { self::setStatus(self::STATUS_NOT_MODIFIED); exit; } - header('ETag: '.$etag); + header('ETag: "'.$etag.'"'); } static public function setLastModifiedHeader($lastModified) { From 98b2d2db3dfb4a4ae286b0773b2297296c2cb70f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 17 Feb 2012 09:35:18 +0100 Subject: [PATCH 02/61] Removed obsolete commented code and made minor speed improvements. Added stub function for loading categories. --- apps/contacts/js/contacts.js | 63 +++++++----------------- apps/contacts/templates/part.contact.php | 53 -------------------- 2 files changed, 17 insertions(+), 99 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 30793625746..c9d1dc30f03 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -117,7 +117,7 @@ Contacts={ $('#carddav_url_close').show(); }, messageBox:function(title, msg) { - if(msg.toLowerCase().indexOf('auth') > 0) { + if(msg.toLowerCase().indexOf('auth') != -1) { // fugly hack, I know alert(msg); } @@ -335,17 +335,6 @@ Contacts={ // Load first in list. if($('#contacts li').length > 0) { Contacts.UI.Card.update(); - /* - 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 { // load intro page $.getJSON('ajax/loadintro.php',{},function(jsondata){ @@ -374,6 +363,7 @@ Contacts={ $('#rightcontent').data('id',this.id); //console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); + this.loadCategories(); this.loadPhoto(); this.loadMails(); this.loadPhones(); @@ -455,9 +445,6 @@ Contacts={ this.fullname += ', ' + this.honsuf; } $('#n').html(this.fullname); - //$('.jecEditableOption').attr('title', 'Custom'); - //$('.jecEditableOption').text(this.fn); - //$('.jecEditableOption').attr('value', 0); $('#fn_select option').remove(); $('#fn_select').combobox('value', this.fn); var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; @@ -466,17 +453,16 @@ Contacts={ .append($('') .text(value)); }); - /*$('#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']); $('#contact_identity').show(); }, + loadCategories:function(){ + if(this.data.CATEGORIES) { + // + } + }, editNew:function(){ // add a new contact - //Contacts.UI.notImplemented(); - //return false; this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = ''; $.getJSON('ajax/newcontact.php',{},function(jsondata){ if(jsondata.status == 'success'){ @@ -713,12 +699,6 @@ Contacts={ .text(value)); }); - /*$('#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.join(';'), $('#short').text(), aid); @@ -889,21 +869,22 @@ Contacts={ }, loadPhoto:function(){ if(this.data.PHOTO) { + $.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); + } + }); $('#file_upload_form').show(); $('#contacts_propertymenu a[data-type="PHOTO"]').parent().hide(); } else { + $('#contacts_details_photo_wrapper').empty(); $('#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); @@ -1143,13 +1124,6 @@ $(document).ready(function(){ 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(); }); @@ -1175,9 +1149,6 @@ $(document).ready(function(){ return false; }); - /** - * Delete currently selected contact TODO: and clear page - */ $('#contacts_deletecard').live('click',function(){ Contacts.UI.Card.delete(); }); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 408b595dc95..5be20964f4b 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -70,14 +70,6 @@ $id = isset($_['id']) ? $_['id'] : ''; - -
  • - /> - -
  • - @@ -93,17 +85,6 @@ $id = isset($_['id']) ? $_['id'] : ''; - -
  • - /> - - -
  • - @@ -118,40 +99,6 @@ $id = isset($_['id']) ? $_['id'] : '';
      - -
      -
      - - - - 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; - - ?> -
      -
      -
      - From 6e35d50cbb7b131bdc4bb245e3dc80042d4d8f99 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 17 Feb 2012 19:04:12 +0100 Subject: [PATCH 03/61] Avoid errors from missing GD library. --- apps/contacts/photo.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/contacts/photo.php b/apps/contacts/photo.php index 8dfbcb6fb10..298f1215e3c 100644 --- a/apps/contacts/photo.php +++ b/apps/contacts/photo.php @@ -13,10 +13,19 @@ require_once('../../lib/base.php'); OC_Util::checkLoggedIn(); OC_Util::checkAppEnabled('contacts'); +function getStandardImage(){ + OC_Response::setExpiresHeader('P10D'); + OC_Response::enableCaching(); + OC_Response::redirect(OC_Helper::imagePath('contacts', 'person_large.png')); +} + $id = $_GET['id']; $contact = OC_Contacts_App::getContactVCard($id); $image = new OC_Image(); +if(!$image) { + getStandardImage(); +} // invalid vcard if( is_null($contact)) { OC_Log::write('contacts','photo.php. The VCard for ID '.$id.' is not RFC compatible',OC_Log::ERROR); @@ -45,7 +54,8 @@ if( is_null($contact)) { } if (!$image->valid()) { // Not found :-( - $image->loadFromFile('img/person_large.png'); + getStandardImage(); + //$image->loadFromFile('img/person_large.png'); } header('Content-Type: '.$image->mimeType()); $image->show(); From a3e58157eeb51eea414d6320cccc7188cb5995d4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 18 Feb 2012 11:42:58 +0100 Subject: [PATCH 04/61] Strip tags on address on client side. --- apps/contacts/js/contacts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index c9d1dc30f03..d33f983a429 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -815,7 +815,7 @@ Contacts={ 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()); + var adr = new Array($(dlg).find('#adr_pobox').val().strip_tags(),$(dlg).find('#adr_extended').val().strip_tags(),$(dlg).find('#adr_street').val().strip_tags(),$(dlg).find('#adr_city').val().strip_tags(),$(dlg).find('#adr_region').val().strip_tags(),$(dlg).find('#adr_zipcode').val().strip_tags(),$(dlg).find('#adr_country').val().strip_tags()); $(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()))); From 0203f55fbfc985ea45ffff375b356d6ab0795336 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 18 Feb 2012 11:45:36 +0100 Subject: [PATCH 05/61] Added first draft of OC_VCategories. --- lib/vcategories.php | 198 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 lib/vcategories.php diff --git a/lib/vcategories.php b/lib/vcategories.php new file mode 100644 index 00000000000..69955d109ad --- /dev/null +++ b/lib/vcategories.php @@ -0,0 +1,198 @@ + +* +* 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 . +* +*/ + + +/** + * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. + * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or anything else + * that is either parsed from a vobject or that the user chooses to add. + * Category names are not case-sensitive, but will be saved with the case they are + * entered in. If a user already has a category 'family' for an app, and tries to add + * a category named 'Family' it will be silently ignored. + */ +OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'deleteUser'); +class OC_VCategories { + /** + * cache + */ + protected static $cache = array(); + + /** + * Categories + */ + private $categories = array(); + + /** + * @brief Constructor. + * @param $app The application identifier e.g. 'contacts' or 'calendar'. + */ + public function __construct($app, $user=null) { + if(is_null($user)) { + $user = OC_User::getUser(); + } + // Use cache if possible - I doubt this is ever the case. Copy/paste from OC_L10N. + if(array_key_exists($app.'::'.$user, self::$cache)){ + OC_Log::write('core','OC_Categories::ctor, using cache', OC_Log::DEBUG); + $this->categories = self::$cache[$app.'::'.$user]; + } else { + $result = null; + try { + $stmt = OC_DB::prepare('SELECT DISTINCT name FROM *PREFIX*categories WHERE userid = ? AND appid = ? ORDER BY name'); + $result = $stmt->execute(array($user, $app)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::ctor, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::ctor, app: '.$app.', user: '.$user, OC_Log::ERROR); + } + if(!is_null($result)) { + while( $row = $result->fetchRow()){ + $this->categories[] = $row['name']; + } + self::$cache[$app.'::'.$user] = $this->categories; + } + } + } + + /** + * @brief Get the categories for a specific. + * @returns array containing the categories as strings. + */ + public function categories() { + return $this->categories; + } + + /** + * @brief Checks whether a category is already saved. + * @param $name The name to check for. + * @returns bool + */ + public function hasCategory($name) { + return ($this->in_arrayi($name, $this->categories) == false ? false : true); + } + + /** + * @brief Add a new category name. + * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. + * @returns bool Returns false on error. + */ + public function add($app, $names) { + $user = OC_User::getUser(); + $newones = array(); + if(!is_array($names)) { + $names = array($names); + } + $names = array_map('trim', $names); + foreach($names as $name) { + if(($this->in_arrayi($name, $this->categories) == false) && $name != '') { + $newones[] = $name; + } + } + if(count($newones) > 0) { + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*categories (userid,appid,name) VALUES(?,?,?)' ); + foreach($newones as $name) { + $this->categories[] = $name; + try { + $result = $stmt->execute(array($user, $app, $name)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::add, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::add, app: '.$app.', user: '.$user.', name: '.$name, OC_Log::ERROR); + return false; + } + } + natcasesort($this->categories); // Dunno if this is necessary + } + return true; + } + + /** + * @brief Extracts categories from a vobject and add the ones not already present. + * @param $vobject The instance of OC_VObject to load the categories from. + * @returns bool Returns false if the name already exist (case insensitive) or on error. + */ + public function loadFromVObject($app, $vobject) { + $this->add($vobject->getAsArray('CATEGORIES')); + } + + /** + * @brief Delete a category from the db and from all the vobject supplied + * @param $app + * @param $name + * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. + */ + public function delete($app, $name, array &$objects) { + if(!$this->hasCategory($name)) { + return; + } + try { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE UPPER(name) = ?'); + $result = $stmt->execute(array(strtoupper($name),)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::delete, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::delete, name: '.$name, OC_Log::ERROR); + return false; + } + unset($this->categories[$this->array_searchi($name, $this->categories)]); + foreach($objects as $key=>&$value) { + $vobject = OC_VObject::parse($value[1]); + if(!is_null($vobject)){ + $categories = $vobject->getAsArray('CATEGORIES'); + $idx = $this->array_searchi($name, $categories); + if($idx) { + unset($categories[$this->array_searchi($name, $categories)]); + $vobject->setString('CATEGORIES', implode(',', $categories)); + $value[1] = $vobject->serialize(); + $objects[$key] = $value; + } + } else { + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 10).'(...)', OC_Log::DEBUG); + } + } + } + + /** + * @brief Delete all categories for a specific user. Connected to OC_User::post_deleteUser + * @param $parameters The id of the user. + * @returns bool Returns false on error. + */ + public function deleteUser($parameters) { + $user = $parameters['uid']; + try { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE user = ?'); + $result = $stmt->execute(array($user,)); + } catch(Exception $e) { + OC_Log::write('core','OC_VCategories::deleteFromUser, exception: '.$e->getMessage(), OC_Log::ERROR); + OC_Log::write('core','OC_VCategories::deleteFromUser, user: '.$user, OC_Log::ERROR); + return false; + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + return array_search(strtolower($needle),array_map('strtolower',$haystack)); + } +} +?> \ No newline at end of file From 8a1b671fdd902b1ec1b6b6e7f23ef8fe732905ce Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 19 Feb 2012 17:00:07 +0100 Subject: [PATCH 06/61] Switch from using separate db table to use OC_Preferences. There is a limitation in that the the configvalue field in the preferences table is a varchar(255). --- lib/vcategories.php | 96 ++++++++++++++------------------------------- 1 file changed, 29 insertions(+), 67 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 69955d109ad..6cc7511e656 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -28,47 +28,26 @@ * Category names are not case-sensitive, but will be saved with the case they are * entered in. If a user already has a category 'family' for an app, and tries to add * a category named 'Family' it will be silently ignored. + * NOTE: There is a limitation in that the the configvalue field in the preferences table is a varchar(255). */ -OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'deleteUser'); class OC_VCategories { - /** - * cache - */ - protected static $cache = array(); - /** * Categories */ private $categories = array(); + + private $app = ''; /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. */ public function __construct($app, $user=null) { + $this->app = $app; if(is_null($user)) { $user = OC_User::getUser(); } - // Use cache if possible - I doubt this is ever the case. Copy/paste from OC_L10N. - if(array_key_exists($app.'::'.$user, self::$cache)){ - OC_Log::write('core','OC_Categories::ctor, using cache', OC_Log::DEBUG); - $this->categories = self::$cache[$app.'::'.$user]; - } else { - $result = null; - try { - $stmt = OC_DB::prepare('SELECT DISTINCT name FROM *PREFIX*categories WHERE userid = ? AND appid = ? ORDER BY name'); - $result = $stmt->execute(array($user, $app)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::ctor, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::ctor, app: '.$app.', user: '.$user, OC_Log::ERROR); - } - if(!is_null($result)) { - while( $row = $result->fetchRow()){ - $this->categories[] = $row['name']; - } - self::$cache[$app.'::'.$user] = $this->categories; - } - } + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($user, $app, 'extra categories', '')); } /** @@ -93,7 +72,7 @@ class OC_VCategories { * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. * @returns bool Returns false on error. */ - public function add($app, $names) { + public function add($names) { $user = OC_User::getUser(); $newones = array(); if(!is_array($names)) { @@ -106,17 +85,8 @@ class OC_VCategories { } } if(count($newones) > 0) { - $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*categories (userid,appid,name) VALUES(?,?,?)' ); - foreach($newones as $name) { - $this->categories[] = $name; - try { - $result = $stmt->execute(array($user, $app, $name)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::add, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::add, app: '.$app.', user: '.$user.', name: '.$name, OC_Log::ERROR); - return false; - } - } + $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); + OC_Preferences::setValue(OC_User::getUser(), $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); natcasesort($this->categories); // Dunno if this is necessary } return true; @@ -127,29 +97,23 @@ class OC_VCategories { * @param $vobject The instance of OC_VObject to load the categories from. * @returns bool Returns false if the name already exist (case insensitive) or on error. */ - public function loadFromVObject($app, $vobject) { + public function loadFromVObject($vobject) { $this->add($vobject->getAsArray('CATEGORIES')); } /** * @brief Delete a category from the db and from all the vobject supplied - * @param $app * @param $name * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ - public function delete($app, $name, array &$objects) { + public function delete($name, array &$objects) { + $user = OC_User::getUser(); if(!$this->hasCategory($name)) { return; } - try { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE UPPER(name) = ?'); - $result = $stmt->execute(array(strtoupper($name),)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::delete, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::delete, name: '.$name, OC_Log::ERROR); - return false; - } unset($this->categories[$this->array_searchi($name, $this->categories)]); + $this->categories = $this->cleanArray($this->categories); + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ @@ -167,24 +131,6 @@ class OC_VCategories { } } - /** - * @brief Delete all categories for a specific user. Connected to OC_User::post_deleteUser - * @param $parameters The id of the user. - * @returns bool Returns false on error. - */ - public function deleteUser($parameters) { - $user = $parameters['uid']; - try { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*categories WHERE user = ?'); - $result = $stmt->execute(array($user,)); - } catch(Exception $e) { - OC_Log::write('core','OC_VCategories::deleteFromUser, exception: '.$e->getMessage(), OC_Log::ERROR); - OC_Log::write('core','OC_VCategories::deleteFromUser, user: '.$user, OC_Log::ERROR); - return false; - } - return true; - } - // case-insensitive in_array private function in_arrayi($needle, $haystack) { return in_array(strtolower($needle), array_map('strtolower', $haystack)); @@ -194,5 +140,21 @@ class OC_VCategories { private function array_searchi($needle, $haystack) { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } + + private function cleanArray($array, $remove_null_number = true){ + $new_array = array(); + $null_exceptions = array(); + + foreach ($array as $key => $value){ + $value = trim($value); + if($remove_null_number){ + $null_exceptions[] = '0'; + } + if(!in_array($value, $null_exceptions) && $value != "") { + $new_array[] = $value; + } + } + return $new_array; + } } ?> \ No newline at end of file From c62673d3601abdefba2ca81ac7d8f8d42fd7f6a5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 19 Feb 2012 23:32:09 +0100 Subject: [PATCH 07/61] Added public static OC_VCategories object to OC_Contacts_App. Parse cards for new categories in add and edit methods. --- apps/contacts/lib/app.php | 2 ++ apps/contacts/lib/vcard.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index ff348403a9b..48298952c12 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -10,8 +10,10 @@ * This class manages our app actions */ OC_Contacts_App::$l10n = new OC_L10N('contacts'); +OC_Contacts_App::$categories = new OC_VCategories('contacts'); class OC_Contacts_App { public static $l10n; + public static $categories; /** * Render templates/part.details to json output diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index ece203bd458..de95e732559 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -114,6 +114,8 @@ class OC_Contacts_VCard{ $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); + $fn = $card->getAsString('FN'); if(!$fn){ // Fix missing 'FN' field. $n = $card->getAsString('N'); @@ -187,6 +189,7 @@ class OC_Contacts_VCard{ $email = null; $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; @@ -245,6 +248,7 @@ class OC_Contacts_VCard{ $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; @@ -279,6 +283,7 @@ class OC_Contacts_VCard{ $fn = null; $card = OC_VObject::parse($data); if(!is_null($card)){ + OC_Contacts_App::$categories->loadFromVObject($card); foreach($card->children as $property){ if($property->name == 'FN'){ $fn = $property->value; From 430ccef09cb303e1b2136cd0599f3baddf4acbcd Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 20 Feb 2012 13:16:51 +0100 Subject: [PATCH 08/61] Added OC_VCategories::rescan() --- lib/vcategories.php | 55 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 6cc7511e656..63ed367230b 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -36,18 +36,21 @@ class OC_VCategories { */ private $categories = array(); - private $app = ''; + private $app = null; + private $user = null; /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. + * @param $user The user whos data the object will operate on. This parameter should normally be omitted + * but to make an app able to update categories for all users it is made possible to provide it. */ public function __construct($app, $user=null) { $this->app = $app; if(is_null($user)) { - $user = OC_User::getUser(); + $this->user = OC_User::getUser(); } - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($user, $app, 'extra categories', '')); + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, 'extra categories', '')); } /** @@ -72,8 +75,8 @@ class OC_VCategories { * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. * @returns bool Returns false on error. */ - public function add($names) { - $user = OC_User::getUser(); + public function add($names, $sync=true) { + $user = is_null($this->user) ? OC_User::getUser() : $this->user; $newones = array(); if(!is_array($names)) { $names = array($names); @@ -86,7 +89,9 @@ class OC_VCategories { } if(count($newones) > 0) { $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); - OC_Preferences::setValue(OC_User::getUser(), $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + if($sync) { + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + } natcasesort($this->categories); // Dunno if this is necessary } return true; @@ -97,8 +102,38 @@ class OC_VCategories { * @param $vobject The instance of OC_VObject to load the categories from. * @returns bool Returns false if the name already exist (case insensitive) or on error. */ - public function loadFromVObject($vobject) { - $this->add($vobject->getAsArray('CATEGORIES')); + public function loadFromVObject($vobject, $sync=true) { + $this->add($vobject->getAsArray('CATEGORIES'), $sync); + } + + /** + * @brief Reset saved categories and rescan supplied vobjects for categories. + * @param $objects An array of vobjects (as text). + * To get the object array, do something like: + * // For Addressbook: + * $categories = new OC_VCategories('contacts'); + * $stmt = OC_DB::prepare( 'SELECT carddata FROM *PREFIX*contacts_cards' ); + * $result = $stmt->execute(); + * $objects = array(); + * if(!is_null($result)) { + * while( $row = $result->fetchRow()){ + * $objects[] = $row['carddata']; + * } + * } + * $categories->rescan($objects); + */ + public function rescan($objects) { + $user = is_null($this->user) ? OC_User::getUser() : $this->user; + $this->categories = array(); + foreach($objects as $object) { + $vobject = OC_VObject::parse($object); + if(!is_null($vobject)){ + $this->loadFromVObject($vobject, false); + } else { + OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + } + } + OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); } /** @@ -107,7 +142,7 @@ class OC_VCategories { * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ public function delete($name, array &$objects) { - $user = OC_User::getUser(); + $user = is_null($this->user) ? OC_User::getUser() : $this->user; if(!$this->hasCategory($name)) { return; } @@ -126,7 +161,7 @@ class OC_VCategories { $objects[$key] = $value; } } else { - OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 10).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); } } } From 77ab89a7cb1003c88a3035a225ae78e1c5037b5b Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 20 Feb 2012 22:32:57 +0100 Subject: [PATCH 09/61] Review changes of OC_VCategory --- lib/vcategories.php | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 63ed367230b..8bd03d44239 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -4,6 +4,7 @@ * * @author Thomas Tanghus * @copyright 2012 Thomas Tanghus +* @copyright 2012 Bart Visscher bartv@thisnet.nl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -23,14 +24,17 @@ /** * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. - * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or anything else - * that is either parsed from a vobject or that the user chooses to add. - * Category names are not case-sensitive, but will be saved with the case they are - * entered in. If a user already has a category 'family' for an app, and tries to add - * a category named 'Family' it will be silently ignored. - * NOTE: There is a limitation in that the the configvalue field in the preferences table is a varchar(255). + * A Category can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Category names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a category 'family' for an app, and + * tries to add a category named 'Family' it will be silently ignored. + * NOTE: There is a limitation in that the the configvalue field in the + * preferences table is a varchar(255). */ class OC_VCategories { + const PREF_CATEGORIES_LABEL = 'extra categories'; /** * Categories */ @@ -38,23 +42,24 @@ class OC_VCategories { private $app = null; private $user = null; - + /** * @brief Constructor. * @param $app The application identifier e.g. 'contacts' or 'calendar'. - * @param $user The user whos data the object will operate on. This parameter should normally be omitted - * but to make an app able to update categories for all users it is made possible to provide it. + * @param $user The user whos data the object will operate on. This + * parameter should normally be omitted but to make an app able to + * update categories for all users it is made possible to provide it. */ public function __construct($app, $user=null) { $this->app = $app; if(is_null($user)) { $this->user = OC_User::getUser(); } - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, 'extra categories', '')); + $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); } /** - * @brief Get the categories for a specific. + * @brief Get the categories for a specific user. * @returns array containing the categories as strings. */ public function categories() { @@ -67,21 +72,22 @@ class OC_VCategories { * @returns bool */ public function hasCategory($name) { - return ($this->in_arrayi($name, $this->categories) == false ? false : true); + return $this->in_arrayi($name, $this->categories); } /** * @brief Add a new category name. - * @param $names A string with a name or an array of strings containing the name(s) of the categor(y|ies) to add. + * @param $names A string with a name or an array of strings containing + * the name(s) of the categor(y|ies) to add. + * @param $sync bool When true, save the categories * @returns bool Returns false on error. */ public function add($names, $sync=true) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; - $newones = array(); if(!is_array($names)) { $names = array($names); } $names = array_map('trim', $names); + $newones = array(); foreach($names as $name) { if(($this->in_arrayi($name, $this->categories) == false) && $name != '') { $newones[] = $name; @@ -89,10 +95,10 @@ class OC_VCategories { } if(count($newones) > 0) { $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); - if($sync) { - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); - } natcasesort($this->categories); // Dunno if this is necessary + if($sync) { + $this->save(); + } } return true; } @@ -100,7 +106,6 @@ class OC_VCategories { /** * @brief Extracts categories from a vobject and add the ones not already present. * @param $vobject The instance of OC_VObject to load the categories from. - * @returns bool Returns false if the name already exist (case insensitive) or on error. */ public function loadFromVObject($vobject, $sync=true) { $this->add($vobject->getAsArray('CATEGORIES'), $sync); @@ -123,17 +128,24 @@ class OC_VCategories { * $categories->rescan($objects); */ public function rescan($objects) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; $this->categories = array(); foreach($objects as $object) { $vobject = OC_VObject::parse($object); - if(!is_null($vobject)){ + if(!is_null($vobject)) { $this->loadFromVObject($vobject, false); } else { OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); } } - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + $this->save(); + } + + /** + * @brief Save the list with categories + */ + public function save() { + $escaped_categories = OC_VObject::escapeSemicolons($this->categories); + OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); } /** @@ -142,13 +154,12 @@ class OC_VCategories { * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ public function delete($name, array &$objects) { - $user = is_null($this->user) ? OC_User::getUser() : $this->user; if(!$this->hasCategory($name)) { return; } unset($this->categories[$this->array_searchi($name, $this->categories)]); $this->categories = $this->cleanArray($this->categories); - OC_Preferences::setValue($user, $this->app, 'extra categories', OC_VObject::escapeSemicolons($this->categories)); + $this->save(); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ @@ -172,10 +183,13 @@ class OC_VCategories { } // case-insensitive array_search - private function array_searchi($needle, $haystack) { + private function array_searchi($needle, $haystack) { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } + /* + * this is for a bug in the code, need to check if it is still needed + */ private function cleanArray($array, $remove_null_number = true){ $new_array = array(); $null_exceptions = array(); @@ -192,4 +206,4 @@ class OC_VCategories { return $new_array; } } -?> \ No newline at end of file +?> From 7c7031df44bd78bf8253d44a801b8bf25490f4bb Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 21 Feb 2012 00:02:27 +0100 Subject: [PATCH 10/61] Forgot to assign param. --- lib/vcategories.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 8bd03d44239..f9e4d1b3489 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -52,9 +52,7 @@ class OC_VCategories { */ public function __construct($app, $user=null) { $this->app = $app; - if(is_null($user)) { - $this->user = OC_User::getUser(); - } + $this->user = is_null($user) ? OC_User::getUser() : $user; $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); } From be948a9baad3eda5821f1dfaebefc8271454872b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 21 Feb 2012 09:53:03 +0100 Subject: [PATCH 11/61] Check for empty value in ctor and being conservative about configvalue name ;-) --- lib/vcategories.php | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index f9e4d1b3489..250aa608c1d 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -34,7 +34,7 @@ * preferences table is a varchar(255). */ class OC_VCategories { - const PREF_CATEGORIES_LABEL = 'extra categories'; + const PREF_CATEGORIES_LABEL = 'extra_categories'; /** * Categories */ @@ -53,7 +53,8 @@ class OC_VCategories { public function __construct($app, $user=null) { $this->app = $app; $this->user = is_null($user) ? OC_User::getUser() : $user; - $this->categories = OC_VObject::unescapeSemicolons(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); + $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); + $this->categories = $categories != '' ? OC_VObject::unescapeSemicolons($categories) : array(); } /** @@ -92,7 +93,7 @@ class OC_VCategories { } } if(count($newones) > 0) { - $this->categories = $this->cleanArray(array_merge($this->categories, $newones)); + $this->categories = array_merge($this->categories, $newones); natcasesort($this->categories); // Dunno if this is necessary if($sync) { $this->save(); @@ -156,7 +157,6 @@ class OC_VCategories { return; } unset($this->categories[$this->array_searchi($name, $this->categories)]); - $this->categories = $this->cleanArray($this->categories); $this->save(); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); @@ -185,23 +185,5 @@ class OC_VCategories { return array_search(strtolower($needle),array_map('strtolower',$haystack)); } - /* - * this is for a bug in the code, need to check if it is still needed - */ - private function cleanArray($array, $remove_null_number = true){ - $new_array = array(); - $null_exceptions = array(); - - foreach ($array as $key => $value){ - $value = trim($value); - if($remove_null_number){ - $null_exceptions[] = '0'; - } - if(!in_array($value, $null_exceptions) && $value != "") { - $new_array[] = $value; - } - } - return $new_array; - } } ?> From faf6055baa224fbf4248a70d28ae4416c9c7eb1c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 22 Feb 2012 14:19:23 +0100 Subject: [PATCH 12/61] Translate and fix copy/paste error. --- apps/contacts/ajax/loadphoto.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 358e046942b..1f4cde0b535 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -18,8 +18,6 @@ * 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'); @@ -33,7 +31,7 @@ OC_JSON::checkAppEnabled('contacts'); function bailOut($msg) { OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('contacts','ajax/loadphoto.php: '.$msg, OC_Log::DEBUG); exit(); } @@ -42,7 +40,7 @@ $image = null; $id = isset($_GET['id']) ? $_GET['id'] : ''; if($id == '') { - bailOut('Missing contact id.'); + bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); From 0a78849391761a616f392b8ad5468318dd84b4ff Mon Sep 17 00:00:00 2001 From: Bartek Przybylski Date: Sun, 4 Mar 2012 18:28:41 +0100 Subject: [PATCH 13/61] multilevel gallery --- apps/gallery/ajax/galleryOp.php | 32 ++++++++++++---- apps/gallery/appinfo/database.xml | 34 ++++++++++------- apps/gallery/appinfo/info.xml | 2 +- apps/gallery/css/styles.css | 11 +++--- apps/gallery/js/album_cover.js | 62 ++++++++++++++++++++++--------- apps/gallery/js/albums.js | 13 ++++++- apps/gallery/lib/album.php | 22 ++++++++--- apps/gallery/lib/scanner.php | 13 ++----- apps/gallery/templates/index.php | 11 +++++- 9 files changed, 136 insertions(+), 64 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index e768ce00c17..ee919daeacb 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -41,7 +41,6 @@ function handleRemove($name) { function handleGetThumbnails($albumname) { OC_Response::enableCaching(3600 * 24); // 24 hour - error_log(htmlentities($albumname)); $thumbnail = OC::$CONFIG_DATADIRECTORY.'/../gallery/'.urldecode($albumname).'.png'; header('Content-Type: '.OC_Image::getMimeTypeForFile($thumbnail)); OC_Response::sendFile($thumbnail); @@ -88,20 +87,36 @@ function handleStoreSettings($root, $order) { OC_JSON::success(array('rescan' => $rescan)); } - -function handleGetGalleries() { +function handleGetGallery($path) { $a = array(); + $root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/'); + if (strlen($root) > 1) + $path = $root.'/'.trim($path, '/'); + else + $path = '/'.ltrim($path, '/'); + if (strlen($path) > 1) $path = rtrim($path, '/'); + error_log($path); + $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path); + $album_details = $result->fetchRow(); - $result = OC_Gallery_Album::find(OC_User::getUser()); + $result = OC_Gallery_Album::find(OC_User::getUser(), null, null, $path); while ($r = $result->fetchRow()) { $album_name = $r['album_name']; $tmp_res = OC_Gallery_Photo::find($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10), 'bgPath' => OC::$WEBROOT.'/data/'.OC_User::getUser().'/gallery/'.$album_name.'.png'); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10)); + } + + $result = OC_Gallery_Photo::find($album_details['album_id']); + + $p = array(); + + while ($r = $result->fetchRow()) { + $p[] = utf8_encode($r['file_path']); } - OC_JSON::success(array('albums'=>$a)); + OC_JSON::success(array('albums'=>$a, 'photos'=>$p)); } if ($_GET['operation']) { @@ -130,7 +145,10 @@ if ($_GET['operation']) { handleStoreSettings($_GET['root'], $_GET['order']); break; case 'get_galleries': - handleGetGalleries(); + handleGetGalleries($_GET['path']); + break; + case 'get_gallery': + handleGetGallery($_GET['path']); break; default: OC_JSON::error(array('cause' => 'Unknown operation')); diff --git a/apps/gallery/appinfo/database.xml b/apps/gallery/appinfo/database.xml index db88e4c1b5a..62fdbee9cd8 100644 --- a/apps/gallery/appinfo/database.xml +++ b/apps/gallery/appinfo/database.xml @@ -11,9 +11,9 @@ album_id integer 0 - true - 1 - 4 + true + 1 + 4 uid_owner @@ -27,12 +27,18 @@ true 100 - - album_path - text - true - 100 - + + album_path + text + true + 100 + + + parent_path + text + true + 100 + @@ -42,16 +48,16 @@ photo_idinteger0 - true - 1 - 4 + true + 1 + 4 album_id integer 0 - true - 4 + true + 4 file_path diff --git a/apps/gallery/appinfo/info.xml b/apps/gallery/appinfo/info.xml index 9aecb0c781d..19c5dc8b25e 100644 --- a/apps/gallery/appinfo/info.xml +++ b/apps/gallery/appinfo/info.xml @@ -2,7 +2,7 @@ gallery Gallery - 0.3 + 0.4 AGPL Bartek Przybylski 2 diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index da94f9ac9e5..1bff610c78c 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -1,13 +1,14 @@ div#gallery_list { margin: 4.5em 2em 0 2em; } div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; bottom:0px; text-align: center; overflow: auto; } -div.gallery_album_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} -div.gallery_album_box h1 { font-size: 9pt; font-family: Verdana; } +div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} +div.album {border: 1px solid #e0e0e0; border-radius: 7px;} +div.gallery_box h1 { font-size: 9pt; font-family: Verdana; } div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} -div.gallery_album_box:hover { color: black; } -div.gallery_album_box:hover div.gallery_album_decoration { opacity: 0.7;} +div.gallery_box:hover { color: black; } +div.gallery_box:hover div.gallery_album_decoration { opacity: 0.7;} div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;} div.gallery_album_cover { width: 200px; height: 200px; border: 0; padding: 0; position:relative;} -div.gallery_album_box:hover div.gallery_control_overlay { opacity:0.5 } +div.gallery_box:hover div.gallery_control_overlay { opacity:0.5 } div.gallery_control_overlay a { color:white; } #gallery_images.rightcontent { padding:10px 5px; bottom: 0px; overflow: auto; right:0px} #scan { position:absolute; right:13.5em; top:0em; } diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index e63bed05fe4..98f29072816 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,34 +1,62 @@ var actual_cover; -$(document).ready(function() { - $.getJSON('ajax/galleryOp.php', {operation: 'get_galleries'}, function(r) { +var paths = ''; +var crumbCount = 0; +$(document).ready(returnToElement(0)); + +function returnToElement(num) { + while (crumbCount != num) { + $('#g-album-navigation .last').remove(); + $('#g-album-navigation .crumb :last').parent().addClass('last'); + crumbCount--; + paths = paths.substring(0, paths.lastIndexOf('\/')); + } + $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); +} + +function albumClick(e) { + var title = decodeURIComponent(escape(e.data.title)); + paths += '/' + title; + crumbCount++; + $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); + if ($('#g-album-navigation :last-child')) + $('#g-album-navigation :last-child').removeClass('last'); + $('#g-album-navigation').append(''); +} + +function albumClickHandler(r) { + Albums.photos = []; + Albums.albums = []; if (r.status == 'success') { for (var i in r.albums) { var a = r.albums[i]; Albums.add(a.name, a.numOfItems); } + for (var i in r.photos) { + Albums.photos.push(r.photos[i]); + } var targetDiv = document.getElementById('gallery_list'); if (targetDiv) { $(targetDiv).html(''); Albums.display(targetDiv); - $('#gallery_list').sortable({revert:true}); - $('.gallery_album_box').each(function(i, e) { - $(e).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}) + //$('#gallery_list').sortable({revert:true}); + $('.album').each(function(i, el) { + $(el).click({title:$(el).attr('title')}, albumClick); + //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); }); } else { - alert('Error occured: no such layer `gallery_list`'); + OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); } } else { - alert('Error occured: ' + r.message); + OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); } - }); -}); +} function createNewAlbum() { var name = prompt("album name", ""); if (name != null && name != "") { $.getJSON("ajax/createAlbum.php", {album_name: name}, function(r) { if (r.status == "success") { - var v = ''; + var v = ''; $('div#gallery_list').append(v); } }); @@ -53,11 +81,7 @@ function scanForAlbums(cleanup) { } $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); for(var a in r.paths) { - $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { - - if (r.status == 'success') { - Albums.add(r.album_details.albumName, r.album_details.imagesCount); - } + $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { albumCounter++; $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); @@ -66,7 +90,9 @@ function scanForAlbums(cleanup) { var targetDiv = document.getElementById('gallery_list'); if (targetDiv) { targetDiv.innerHTML = ''; - Albums.display(targetDiv); + Albums.photos = []; + Albums.albums = []; + returnToElement(0); } else { alert('Error occured: no such layer `gallery_list`'); } @@ -87,7 +113,7 @@ function galleryRemove(albumName) { if (decision) { $.getJSON("ajax/galleryOp.php", {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { if (r.status == "success") { - $(".gallery_album_box").filterAttr('data-album',albumName).remove(); + $(".gallery_box").filterAttr('data-album',albumName).remove(); Albums.remove(albumName); } else { OC.dialogs.alert(r.cause, "Error"); @@ -109,7 +135,7 @@ function galleryRename(name) { } $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { if (r.status == 'success') { - Albums.rename($(".gallery_album_box").filterAttr('data-album',name), newname); + Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); } else { OC.dialogs.alert('Error: ' + r.cause, 'Error'); } diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index adecd24cc75..c12cbacf5bc 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -7,6 +7,7 @@ Albums={ // to display to user as preview picture when scrolling throught // the album cover albums:new Array(), + photos:new Array(), // add simply adds new album to internal structure // however albums names must be unique so other // album with the same name wont be insered, @@ -41,10 +42,11 @@ Albums={ // displays gallery in linear representation // on given element, and apply default styles for gallery display: function(element) { - var displayTemplate = ''; + var displayTemplate = ''; for (var i in Albums.albums) { var a = Albums.albums[i]; var local=$(displayTemplate); + local.attr('title', a.name); local.attr('data-album',a.name); $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ event.preventDefault(); @@ -54,7 +56,7 @@ Albums={ event.preventDefault(); galleryRemove(event.data.name); }); - $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); + // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); $('h1',local).text(decodeURIComponent(escape(a.name))); $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); @@ -73,6 +75,13 @@ Albums={ }); $(element).append(local); } + var photoDisplayTemplate = ''; + for (var i in Albums.photos) { + $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); + } + $("a[rel=images]").fancybox({ + 'titlePosition': 'inside' + }); }, rename: function(element, new_name) { if (new_name) { diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index d1405333ac7..317e8209de4 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -23,10 +23,11 @@ class OC_Gallery_Album { public static function create($owner, $name, $path){ - $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path) VALUES (?, ?, ?)'); - $stmt->execute(array($owner, $name, $path)); + $id = self::getParentPath($path); + $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path, parent_path) VALUES (?, ?, ?, ?)'); + $stmt->execute(array($owner, $name, $path, $id)); } - + public static function rename($oldname, $newname, $owner) { $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_name=? WHERE uid_owner=? AND album_name=?'); $stmt->execute(array($newname, $owner, $oldname)); @@ -39,7 +40,14 @@ class OC_Gallery_Album { self::remove(OC_User::getUser(), $r['album_name']); } } - + + public static function getParentPath($path) { + if (strlen($path)==1) return ''; + $path = substr($path, 0, strrpos($path, '/')); + if ($path == '') $path = '/'; + return $path; + } + public static function remove($owner, $name=null) { $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner = ?'; $args = array($owner); @@ -66,7 +74,7 @@ class OC_Gallery_Album { } } - public static function find($owner, $name=null, $path=null){ + public static function find($owner, $name=null, $path=null, $parent=null){ $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE uid_owner = ?'; $args = array($owner); if (!is_null($name)){ @@ -77,6 +85,10 @@ class OC_Gallery_Album { $sql .= ' AND album_path = ?'; $args[] = $path; } + if (!is_null($parent)){ + $sql .= ' AND parent_path = ?'; + $args[] = $parent; + } $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC'); $sql .= ' ORDER BY album_name ' . $order; diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 19906c07152..8dcd77821cb 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -21,7 +21,7 @@ * */ -require_once('base.php'); // base lib +require_once('base.php'); require_once('images_utils.php'); class OC_Gallery_Scanner { @@ -40,20 +40,14 @@ class OC_Gallery_Scanner { } public static function createName($name) { - $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); - $name = str_replace('/', '.', str_replace(OC::$CONFIG_DATADIRECTORY, '', $name)); - if (substr($name, 0, strlen($root)) == str_replace('/','.',$root)) { - $name = substr($name, strlen($root)); - } - $name = ($name==='.') ? 'main' : trim($name,'.'); - return $name; + return basename($name); } public static function scanDir($path, &$albums) { $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); $current_album['name'] = self::createName($current_album['name']); - if ($dh = OC_Filesystem::opendir($path.'/')) { + if ($dh = OC_Filesystem::opendir($path)) { while (($filename = readdir($dh)) !== false) { $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename; if (substr($filename, 0, 1) == '.') continue; @@ -108,7 +102,6 @@ class OC_Gallery_Scanner { foreach($images as $image){ $path=dirname($image); if(array_search($path,$paths)===false){ - error_log($path); $paths[]=$path; } } diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php index 1b8d53e82d4..7f0281e6a39 100644 --- a/apps/gallery/templates/index.php +++ b/apps/gallery/templates/index.php @@ -2,6 +2,10 @@ OC_Util::addStyle('gallery', 'styles'); OC_Util::addScript('gallery', 'albums'); OC_Util::addScript('gallery', 'album_cover'); +OC_Util::addStyle('files', 'files'); +OC_Util::addScript('files_imageviewer', 'jquery.mousewheel-3.0.4.pack'); +OC_Util::addScript('files_imageviewer', 'jquery.fancybox-1.3.4.pack'); +OC_Util::addStyle( 'files_imageviewer', 'jquery.fancybox-1.3.4' ); $l = new OC_L10N('gallery'); ?> @@ -9,10 +13,13 @@ $l = new OC_L10N('gallery');
      -
      -
      +
      +
      + main +
      +
      From fb88bdba69443e81f8bed5172510b4308897ae47 Mon Sep 17 00:00:00 2001 From: rok Date: Fri, 2 Mar 2012 21:32:17 +0100 Subject: [PATCH 14/61] Ability to save an arbitrary number of external sites --- apps/external/ajax/setsites.php | 25 +++++++ apps/external/ajax/seturls.php | 24 ------- apps/external/appinfo/app.php | 58 ++++++++-------- apps/external/css/style.css | 14 ++++ apps/external/index.php | 59 +++++++++-------- apps/external/js/admin.js | 99 +++++++++++++--------------- apps/external/lib/external.php | 36 ++++++++++ apps/external/settings.php | 12 ---- apps/external/templates/settings.php | 30 ++++----- 9 files changed, 191 insertions(+), 166 deletions(-) create mode 100644 apps/external/ajax/setsites.php delete mode 100644 apps/external/ajax/seturls.php create mode 100644 apps/external/css/style.css create mode 100644 apps/external/lib/external.php diff --git a/apps/external/ajax/setsites.php b/apps/external/ajax/setsites.php new file mode 100644 index 00000000000..0537b7ea581 --- /dev/null +++ b/apps/external/ajax/setsites.php @@ -0,0 +1,25 @@ + + * 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_Util::checkAdminUser(); + +$sites = array(); +for ($i = 0; $i < sizeof($_POST['site_name']); $i++) { + if (!empty($_POST['site_name'][$i]) && !empty($_POST['site_url'][$i])) { + array_push($sites, array($_POST['site_name'][$i], $_POST['site_url'][$i])); + } +} + +if (sizeof($sites) == 0) + OC_Appconfig::deleteKey('external', 'sites'); +else + OC_Appconfig::setValue('external', 'sites', json_encode($sites)); + +echo 'true'; +?> diff --git a/apps/external/ajax/seturls.php b/apps/external/ajax/seturls.php deleted file mode 100644 index e994385a199..00000000000 --- a/apps/external/ajax/seturls.php +++ /dev/null @@ -1,24 +0,0 @@ - - * 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_Util::checkAdminUser(); - -if(isset($_POST['s1name'])) OC_Appconfig::setValue( 'external','site1name', $_POST['s1name'] ); -if(isset($_POST['s1url'])) OC_Appconfig::setValue( 'external','site1url', $_POST['s1url'] ); -if(isset($_POST['s2name'])) OC_Appconfig::setValue( 'external','site2name', $_POST['s2name'] ); -if(isset($_POST['s2url'])) OC_Appconfig::setValue( 'external','site2url', $_POST['s2url'] ); -if(isset($_POST['s3name'])) OC_Appconfig::setValue( 'external','site3name', $_POST['s3name'] ); -if(isset($_POST['s3url'])) OC_Appconfig::setValue( 'external','site3url', $_POST['s3url'] ); -if(isset($_POST['s4name'])) OC_Appconfig::setValue( 'external','site4name', $_POST['s4name'] ); -if(isset($_POST['s4url'])) OC_Appconfig::setValue( 'external','site4url', $_POST['s4url'] ); -if(isset($_POST['s5name'])) OC_Appconfig::setValue( 'external','site5name', $_POST['s5name'] ); -if(isset($_POST['s5url'])) OC_Appconfig::setValue( 'external','site5url', $_POST['s5url'] ); - -echo 'true'; - -?> diff --git a/apps/external/appinfo/app.php b/apps/external/appinfo/app.php index 0f536cbf418..74e6d5c94c6 100644 --- a/apps/external/appinfo/app.php +++ b/apps/external/appinfo/app.php @@ -1,37 +1,35 @@ . -* -*/ + * ownCloud - External plugin + * + * @author Frank Karlitschek + * @copyright 2011 Frank Karlitschek karlitschek@kde.org + * + * 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 Lesser General Public + * License along with this library. If not, see . + * + */ -OC_APP::registerAdmin('external','settings'); +OC::$CLASSPATH['OC_External'] = 'apps/external/lib/external.php'; +OC_Util::addStyle( 'external', 'style'); -OC_App::register( array( 'order' => 70, 'id' => 'external', 'name' => 'External' )); +OC_APP::registerAdmin('external', 'settings'); -if(OC_Appconfig::getValue( "external","site1name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index1', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=1', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site1name", '' ))); - -if(OC_Appconfig::getValue( "external","site2name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index2', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=2', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site2name", '' ))); - -if(OC_Appconfig::getValue( "external","site3name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index3', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=3', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site3name", '' ))); - -if(OC_Appconfig::getValue( "external","site4name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index4', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=4', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site4name", '' ))); - -if(OC_Appconfig::getValue( "external","site5name", '' )<>'') OC_App::addNavigationEntry( array( 'id' => 'external_index5', 'order' => 80, 'href' => OC_Helper::linkTo( 'external', 'index.php' ).'?id=5', 'icon' => OC_Helper::imagePath( 'external', 'external.png' ), 'name' => OC_Appconfig::getValue( "external","site5name", '' ))); +OC_App::register(array('order' => 70, 'id' => 'external', 'name' => 'External')); +$sites = OC_External::getSites(); +for ($i = 0; $i < sizeof($sites); $i++) { + OC_App::addNavigationEntry( + array('id' => 'external_index' . ($i + 1), 'order' => 80 + $i, 'href' => OC_Helper::linkTo('external', 'index.php') . '?id=' . ($i + 1), 'icon' => OC_Helper::imagePath('external', 'external.png'), 'name' => $sites[$i][0])); +} \ No newline at end of file diff --git a/apps/external/css/style.css b/apps/external/css/style.css new file mode 100644 index 00000000000..f891cb4bc55 --- /dev/null +++ b/apps/external/css/style.css @@ -0,0 +1,14 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +.site_url { + width: 250px; +} + +.delete_button { + display: none; +} + +.external_sites { + width: 450px; +} diff --git a/apps/external/index.php b/apps/external/index.php index 51cdc344bbf..1c20f59eaff 100644 --- a/apps/external/index.php +++ b/apps/external/index.php @@ -1,42 +1,43 @@ . -* -*/ - + * ownCloud - External plugin + * + * @author Frank Karlitschek + * @copyright 2011 Frank Karlitschek karlitschek@kde.org + * + * 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 Lesser General Public + * License along with this library. If not, see . + * + */ require_once('../../lib/base.php'); +require_once('lib/external.php'); OC_Util::checkLoggedIn(); -if(isset($_GET['id'])){ +if (isset($_GET['id'])) { - $id=$_GET['id']; + $id = $_GET['id']; $id = (int) $id; - $url=OC_Appconfig::getValue( "external","site".$id."url", '' ); - OC_App::setActiveNavigationEntry( 'external_index'.$id ); - - $tmpl = new OC_Template( 'external', 'frame', 'user' ); - $tmpl->assign('url',$url); - $tmpl->printPage(); + $sites = OC_External::getSites(); + if (sizeof($sites) >= $id) { + $url = $sites[$id - 1][1]; + OC_App::setActiveNavigationEntry('external_index' . $id); + $tmpl = new OC_Template('external', 'frame', 'user'); + $tmpl->assign('url', $url); + $tmpl->printPage(); + } } - ?> diff --git a/apps/external/js/admin.js b/apps/external/js/admin.js index 6b9b6c67737..0caaabd0b96 100644 --- a/apps/external/js/admin.js +++ b/apps/external/js/admin.js @@ -1,68 +1,57 @@ $(document).ready(function(){ + newSiteHtml = '
    • \n\ + \n\ +
    • '; - - - $('#s1name').blur(function(event){ + // Handler functions + function addSiteEventHandler(event) { event.preventDefault(); - var post = $( "#s1name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1name .msg', data); }); - }); + + saveSites(); + } - $('#s2name').blur(function(event){ + function deleteButtonEventHandler(event) { event.preventDefault(); - var post = $( "#s2name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2name .msg', data); }); - }); - $('#s3name').blur(function(event){ + $(this).tipsy('hide'); + $(this).parent().remove(); + + saveSites(); + } + + function saveSites() { + var post = $('#external').serialize(); + $.post( OC.filePath('external','ajax','setsites.php') , post, function(data) { + // OC.msg.finishedSaving('#site_name .msg', data); + }); + } + + function showDeleteButton(event) { + $(this).find('img.delete_button').fadeIn(100); + } + + function hideDeleteButton(event) { + $(this).find('img.delete_button').fadeOut(100); + } + + // Initialize events + $('input[name^=site_]').change(addSiteEventHandler); + $('img.delete_button').click(deleteButtonEventHandler); + $('img.delete_button').tipsy(); + + $('#external li').hover(showDeleteButton, hideDeleteButton); + + $('#add_external_site').click(function(event) { event.preventDefault(); - var post = $( "#s3name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3name .msg', data); }); - }); + $('#external ul').append(newSiteHtml); - $('#s4name').blur(function(event){ - event.preventDefault(); - var post = $( "#s4name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4name .msg', data); }); + $('input.site_url:last').prev('input.site_name').andSelf().change(addSiteEventHandler); + $('img.delete_button').click(deleteButtonEventHandler); + $('img.delete_button:last').tipsy(); + $('#external li:last').hover(showDeleteButton, hideDeleteButton); + }); - $('#s5name').blur(function(event){ - event.preventDefault(); - var post = $( "#s5name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5name .msg', data); }); - }); - - $('#s1url').blur(function(event){ - event.preventDefault(); - var post = $( "#s1url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s1url .msg', data); }); - }); - - $('#s2url').blur(function(event){ - event.preventDefault(); - var post = $( "#s2url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s2url .msg', data); }); - }); - - $('#s3url').blur(function(event){ - event.preventDefault(); - var post = $( "#s3url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3url .msg', data); }); - }); - - $('#s4url').blur(function(event){ - event.preventDefault(); - var post = $( "#s4url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s4url .msg', data); }); - }); - - $('#s5url').blur(function(event){ - event.preventDefault(); - var post = $( "#s5url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5url .msg', data); }); - }); - - }); diff --git a/apps/external/lib/external.php b/apps/external/lib/external.php new file mode 100644 index 00000000000..9dd32321135 --- /dev/null +++ b/apps/external/lib/external.php @@ -0,0 +1,36 @@ +. + * + */ + +class OC_External { + + public static function getSites() { + if (($sites = json_decode(OC_Appconfig::getValue("external", "sites", ''))) != NULL) { + return $sites; + } + + return array(); + } + +} + +?> diff --git a/apps/external/settings.php b/apps/external/settings.php index 3e0c3425128..416c9a5c11f 100644 --- a/apps/external/settings.php +++ b/apps/external/settings.php @@ -6,17 +6,5 @@ OC_Util::addScript( "external", "admin" ); $tmpl = new OC_Template( 'external', 'settings'); - $tmpl->assign('s1name',OC_Appconfig::getValue( "external","site1name", '' )); - $tmpl->assign('s2name',OC_Appconfig::getValue( "external","site2name", '' )); - $tmpl->assign('s3name',OC_Appconfig::getValue( "external","site3name", '' )); - $tmpl->assign('s4name',OC_Appconfig::getValue( "external","site4name", '' )); - $tmpl->assign('s5name',OC_Appconfig::getValue( "external","site5name", '' )); - - $tmpl->assign('s1url',OC_Appconfig::getValue( "external","site1url", '' )); - $tmpl->assign('s2url',OC_Appconfig::getValue( "external","site2url", '' )); - $tmpl->assign('s3url',OC_Appconfig::getValue( "external","site3url", '' )); - $tmpl->assign('s4url',OC_Appconfig::getValue( "external","site4url", '' )); - $tmpl->assign('s5url',OC_Appconfig::getValue( "external","site5url", '' )); - return $tmpl->fetchPage(); ?> diff --git a/apps/external/templates/settings.php b/apps/external/templates/settings.php index a72327d35c8..a130477d465 100644 --- a/apps/external/templates/settings.php +++ b/apps/external/templates/settings.php @@ -1,23 +1,21 @@
      External Sites
      - - -
      - - -
      - - -
      - - -
      - - -
      +
        + + + + '; + } + ?> - +
      + + +
      From 9f015337102193ae7cff59b47c577f15c05259c4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 15:44:46 +0100 Subject: [PATCH 15/61] fix for webdav when having additional storage backends mounted --- lib/connector/sabre/directory.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php index bb03851e39d..cc37bf22d5d 100644 --- a/lib/connector/sabre/directory.php +++ b/lib/connector/sabre/directory.php @@ -73,8 +73,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa $nodes = array(); // foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); - if( OC_Filesystem::is_dir($this->path)){ - $dh = OC_Filesystem::opendir($this->path); + if( OC_Filesystem::is_dir($this->path . '/')){ + $dh = OC_Filesystem::opendir($this->path . '/'); while(( $node = readdir($dh)) !== false ){ if($node!='.' && $node!='..'){ $nodes[] = $this->getChild($node); From a4543175cea05373906ce7f9507af597a78c5dc4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:24:49 +0100 Subject: [PATCH 16/61] make gallary work with archives --- apps/gallery/ajax/galleryOp.php | 1 - apps/gallery/lib/scanner.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index ee919daeacb..74ac905d072 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -95,7 +95,6 @@ function handleGetGallery($path) { else $path = '/'.ltrim($path, '/'); if (strlen($path) > 1) $path = rtrim($path, '/'); - error_log($path); $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path); $album_details = $result->fetchRow(); diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 8dcd77821cb..1e8fdb63fb3 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -47,7 +47,7 @@ class OC_Gallery_Scanner { $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); $current_album['name'] = self::createName($current_album['name']); - if ($dh = OC_Filesystem::opendir($path)) { + if ($dh = OC_Filesystem::opendir($path.'/')) { while (($filename = readdir($dh)) !== false) { $filepath = ($path[strlen($path)-1]=='/'?$path:$path.'/').$filename; if (substr($filename, 0, 1) == '.') continue; From 41817db2e2fb657a9efad5b8924fd059e98524e5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:27:51 +0100 Subject: [PATCH 17/61] no rounded borders for album decoration --- apps/gallery/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index 1bff610c78c..013cd1b262d 100644 --- a/apps/gallery/css/styles.css +++ b/apps/gallery/css/styles.css @@ -3,7 +3,7 @@ div#gallery_list.leftcontent { padding-top: 15pt; margin: 0; position: absolute; div.gallery_box { width: 200px; position:relative; text-align: center; border: 0; display: inline-block; margin: 5pt; vertical-align: top; padding: 5px 5px 5px 5px; position: relative; -webkit-transition: color 0.5s ease-in-out; -o-transition: color 0.5s ease-in-out; -moz-transition: color 0.5s ease-in-out;color: #BBB;} div.album {border: 1px solid #e0e0e0; border-radius: 7px;} div.gallery_box h1 { font-size: 9pt; font-family: Verdana; } -div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; border-bottom-right-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -moz-border-radius-bottomleft:7px;} +div.gallery_album_decoration { width: 200px; position: absolute; border: 0; height: 20px; top: 5px; text-align:right; vertical-align:middle; background-color: #eee; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; } div.gallery_box:hover { color: black; } div.gallery_box:hover div.gallery_album_decoration { opacity: 0.7;} div.gallery_album_decoration a {padding: 0 4pt; cursor: pointer;} From 1d88ab57ec31c33e2edcd2bd7e54868927e999e0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 16:28:57 +0100 Subject: [PATCH 18/61] dont open the album when clicking the remove/rename button --- apps/gallery/js/albums.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index c12cbacf5bc..3882deb5146 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -50,10 +50,12 @@ Albums={ local.attr('data-album',a.name); $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ event.preventDefault(); + event.stopPropagation(); galleryRename(event.data.name); }); $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){ event.preventDefault(); + event.stopPropagation(); galleryRemove(event.data.name); }); // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); From 75323b86d157c48031b9ac8c151e4a41577a1481 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 7 Mar 2012 16:39:56 +0100 Subject: [PATCH 19/61] Contacts: UI updates and ajax methods for categories. --- apps/contacts/ajax/addproperty.php | 15 +- apps/contacts/ajax/categories/add.php | 39 +++ apps/contacts/ajax/categories/checksumfor.php | 28 ++ apps/contacts/ajax/categories/delete.php | 60 ++++ apps/contacts/ajax/categories/edit.php | 28 ++ apps/contacts/ajax/categories/list.php | 17 + apps/contacts/ajax/contactdetails.php | 2 +- apps/contacts/ajax/saveproperty.php | 32 +- apps/contacts/css/contacts.css | 15 +- apps/contacts/index.php | 2 + apps/contacts/js/contacts.js | 311 +++++++++++++++--- apps/contacts/lib/vcard.php | 65 +++- apps/contacts/templates/part.contact.php | 14 +- lib/vcategories.php | 66 ++-- 14 files changed, 593 insertions(+), 101 deletions(-) create mode 100644 apps/contacts/ajax/categories/add.php create mode 100644 apps/contacts/ajax/categories/checksumfor.php create mode 100644 apps/contacts/ajax/categories/delete.php create mode 100644 apps/contacts/ajax/categories/edit.php create mode 100644 apps/contacts/ajax/categories/list.php diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index 028974e1c66..a28aed34d2c 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -27,14 +27,16 @@ require_once('../../../lib/base.php'); OC_JSON::checkLoggedIn(); OC_JSON::checkAppEnabled('contacts'); -$id = $_POST['id']; -$vcard = OC_Contacts_App::getContactVCard( $id ); +$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']:array(); + +$vcard = OC_Contacts_App::getContactVCard($id); -$name = $_POST['name']; -$value = $_POST['value']; if(!is_array($value)){ $value = trim($value); - if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME'))) { + if(!$value && in_array($name, array('TEL', 'EMAIL', 'ORG', 'BDAY', 'NICKNAME', 'NOTE'))) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Cannot add empty property.')))); exit(); } @@ -51,7 +53,6 @@ if(!is_array($value)){ exit(); } } -$parameters = isset($_POST['parameters']) ? $_POST['parameters'] : array(); // Prevent setting a duplicate entry $current = $vcard->select($name); @@ -82,7 +83,9 @@ switch($name) { } case 'N': case 'ORG': + case 'NOTE': case 'NICKNAME': + // TODO: Escape commas and semicolons. break; case 'EMAIL': $value = strtolower($value); diff --git a/apps/contacts/ajax/categories/add.php b/apps/contacts/ajax/categories/add.php new file mode 100644 index 00000000000..9b6c262978b --- /dev/null +++ b/apps/contacts/ajax/categories/add.php @@ -0,0 +1,39 @@ + + * 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'); + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/add.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/add.php: '.$msg, OC_Log::DEBUG); +} + +$category = isset($_GET['category'])?strip_tags($_GET['category']):null; + +if(is_null($category)) { + bailOut(OC_Contacts_App::$l10n->t('No category to add?')); +} + +debug(print_r($category, true)); + +$categories = new OC_VCategories('contacts'); +if($categories->hasCategory($category)) { + bailOut(OC_Contacts_App::$l10n->t('This category already exists: '.$category)); +} else { + $categories->add($category, true); +} + +OC_JSON::success(array('data' => array('categories'=>$categories->categories()))); + +?> diff --git a/apps/contacts/ajax/categories/checksumfor.php b/apps/contacts/ajax/categories/checksumfor.php new file mode 100644 index 00000000000..ff535866bf0 --- /dev/null +++ b/apps/contacts/ajax/categories/checksumfor.php @@ -0,0 +1,28 @@ + + * 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 = isset($_GET['id'])?$_GET['id']:null; +if(is_null($id)) { + OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('No ID provided')))); + exit(); +} +$vcard = OC_Contacts_App::getContactVCard( $id ); +foreach($vcard->children as $property){ + //OC_Log::write('contacts','ajax/categories/checksumfor.php: '.$property->name, OC_Log::DEBUG); + if($property->name == 'CATEGORIES') { + $checksum = md5($property->serialize()); + OC_JSON::success(array('data' => array('checksum'=>$checksum))); + exit(); + } +} +OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error setting checksum.')))); +?> diff --git a/apps/contacts/ajax/categories/delete.php b/apps/contacts/ajax/categories/delete.php new file mode 100644 index 00000000000..3ba5aa16068 --- /dev/null +++ b/apps/contacts/ajax/categories/delete.php @@ -0,0 +1,60 @@ + + * 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'); + +foreach ($_POST as $key=>$element) { + debug('_POST: '.$key.'=>'.print_r($element, true)); +} + +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/delete.php: '.$msg, OC_Log::DEBUG); +} + +$categories = isset($_POST['categories'])?$_POST['categories']:null; + +if(is_null($categories)) { + bailOut(OC_Contacts_App::$l10n->t('No categories selected for deletion.')); +} + +debug(print_r($categories, true)); + +$addressbooks = OC_Contacts_Addressbook::all(OC_User::getUser()); +if(count($addressbooks) == 0) { + bailOut(OC_Contacts_App::$l10n->t('No address books found.')); +} +$addressbookids = array(); +foreach($addressbooks as $addressbook) { + $addressbookids[] = $addressbook['id']; +} +$contacts = OC_Contacts_VCard::all($addressbookids); +if(count($contacts) == 0) { + bailOut(OC_Contacts_App::$l10n->t('No contacts found.')); +} + +$cards = array(); +foreach($contacts as $contact) { + $cards[] = array($contact['id'], $contact['carddata']); +} + +debug('Before delete: '.print_r($categories, true)); + +$catman = new OC_VCategories('contacts'); +$catman->delete($categories, $cards); +debug('After delete: '.print_r($catman->categories(), true)); +OC_Contacts_VCard::updateDataByID($cards); +OC_JSON::success(array('data' => array('categories'=>$catman->categories()))); + +?> diff --git a/apps/contacts/ajax/categories/edit.php b/apps/contacts/ajax/categories/edit.php new file mode 100644 index 00000000000..8ecc3540b11 --- /dev/null +++ b/apps/contacts/ajax/categories/edit.php @@ -0,0 +1,28 @@ + + * 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'); +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('contacts','ajax/categories/edit.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/edit.php: '.$msg, OC_Log::DEBUG); +} + +$tmpl = new OC_TEMPLATE("contacts", "part.edit_categories_dialog"); + +$categories = OC_Contacts_App::$categories->categories(); +debug(print_r($categories, true)); +$tmpl->assign('categories',$categories); +$tmpl->printpage(); + +?> diff --git a/apps/contacts/ajax/categories/list.php b/apps/contacts/ajax/categories/list.php new file mode 100644 index 00000000000..3b41b7bfa95 --- /dev/null +++ b/apps/contacts/ajax/categories/list.php @@ -0,0 +1,17 @@ + + * 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'); + +$categories = OC_Contacts_App::$categories->categories(); + +OC_JSON::success(array('data' => array('categories'=>$categories))); + +?> diff --git a/apps/contacts/ajax/contactdetails.php b/apps/contacts/ajax/contactdetails.php index f35fd595c56..03895c862aa 100644 --- a/apps/contacts/ajax/contactdetails.php +++ b/apps/contacts/ajax/contactdetails.php @@ -71,5 +71,5 @@ if(isset($details['PHOTO'])) { $details['PHOTO'] = false; } $details['id'] = $id; - +OC_Contacts_App::setLastModifiedHeader($vcard); OC_JSON::success(array('data' => $details)); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 6f8366243fe..e31c4b7c238 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -36,7 +36,7 @@ function debug($msg) { OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); } foreach ($_POST as $key=>$element) { - debug('_POST: '.$key.'=>'.$element); + debug('_POST: '.$key.'=>'.print_r($element, true)); } $id = isset($_POST['id'])?$_POST['id']:null; @@ -51,12 +51,8 @@ $checksum = isset($_POST['checksum'])?$_POST['checksum']:null; // } // } -if(is_array($value)){ - $value = array_map('strip_tags', $value); - 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(!$name) { + bailOut(OC_Contacts_App::$l10n->t('element name is not set.')); } if(!$id) { bailOut(OC_Contacts_App::$l10n->t('id is not set.')); @@ -64,14 +60,22 @@ if(!$id) { if(!$checksum) { bailOut(OC_Contacts_App::$l10n->t('checksum is not set.')); } -if(!$name) { - bailOut(OC_Contacts_App::$l10n->t('element name is not set.')); +if(is_array($value)){ + $value = array_map('strip_tags', $value); + ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form! + if($name == 'CATEGORIES') { + $value = OC_Contacts_VCard::escapeDelimiters($value, ','); + } else { + $value = OC_Contacts_VCard::escapeDelimiters($value, ';'); + } +} else { + $value = trim(strip_tags($value)); } $vcard = OC_Contacts_App::getContactVCard( $id ); $line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); if(is_null($line)) { - bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page.'.$checksum.' "'.$line.'"')); + bailOut(OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page: ').$checksum); } $element = $vcard->children[$line]->name; @@ -91,7 +95,9 @@ switch($element) { } case 'N': case 'ORG': + case 'NOTE': case 'NICKNAME': + case 'CATEGORIES': debug('Setting string:'.$name.' '.$value); $vcard->setString($name, $value); break; @@ -123,12 +129,8 @@ $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' => OC_Contacts_App::$l10n->t('Error updating contact property.')))); - OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); + bailOut(OC_Contacts_App::$l10n->t('Error updating contact property.')); 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/css/contacts.css b/apps/contacts/css/contacts.css index 384541f3751..65a6eb24809 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -20,7 +20,8 @@ #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"].contacts_property,input[type="email"].contacts_property { width: 16em; } +#card input[type="text"].contacts_property,input[type="email"].contacts_property { width: 14em; } +.categories { float: left; width: 16em; } #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; } @@ -68,7 +69,7 @@ dl.form /*background-color: yellow;*/ } -.loading { background: url('../../../core/img/loading.gif') no-repeat center !important;} +.loading { background: url('../../../core/img/loading.gif') no-repeat center !important; /*cursor: progress; */ cursor: wait; } /*.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; }*/ @@ -185,4 +186,12 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; } .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 +.addresslist { clear: both; } + +#categoryform .scrollarea { position: absolute; left: 10px; top: 10px; right: 10px; bottom: 50px; overflow: auto; border:1px solid #ddd; background: #f8f8f8; } +#categoryform .bottombuttons { position: absolute; bottom: 10px;} +#categoryform .bottombuttons * { float: left;} +/*#categorylist { border:1px solid #ddd;}*/ +#categorylist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } +#categorylist li:hover, li:active { background:#eee; } +#category_addinput { width: 10em; } \ No newline at end of file diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 0a21ddd04b6..a7817d35e58 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -34,6 +34,7 @@ if(!is_null($id)) { } $property_types = OC_Contacts_App::getAddPropertyOptions(); $phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); +$categories = OC_Contacts_App::$categories->categories(); $upload_max_filesize = OC_Helper::computerFileSize(ini_get('upload_max_filesize')); $post_max_size = OC_Helper::computerFileSize(ini_get('post_max_size')); @@ -59,6 +60,7 @@ $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('categories',$categories); $tmpl->assign('addressbooks', $addressbooks); $tmpl->assign('contacts', $contacts); $tmpl->assign('details', $details ); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 11661320c59..7306e5714c9 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -4,13 +4,105 @@ function ucwords (str) { }); } -String.prototype.strip_tags = function(){ - tags = this; - stripped = tags.replace(/[\<\>]/gi, ""); - return stripped; +Categories={ + edit:function(){ + console.log('Categories.edit'); + $('body').append('
      '); + $('#category_dialog').load(OC.filePath('contacts', 'ajax', 'categories/edit.php'), function(response, status, xhr){ + try { + var response = jQuery.parseJSON(response); + console.log('status: ' + status + ', response: ' + response + ', response.status:' + response.status); + if(response.status == 'error'){ + alert(response.data.message); + } else { + alert(response); + } + } catch(e) { + $('#edit_categories_dialog').dialog({ + modal: true, + height: 350, minHeight:200, width: 250, minWidth: 200, + buttons: { + 'Delete':function() { + Categories.delete(); + }, + 'Rescan':function() { + Categories.rescan(); + } + }, + close : function(event, ui) { + //alert('close'); + $(this).dialog('destroy').remove(); + $('#category_dialog').remove(); + }, + open : function(event, ui) { + $('#category_addinput').live('input',function(){ + if($(this).val().length > 0) { + $('#category_addbutton').removeAttr('disabled'); + } + }); + $('#categoryform').submit(function() { + Categories.add($('#category_addinput').val()); + $('#category_addinput').val(''); + $('#category_addbutton').attr('disabled', 'disabled'); + return false; + }); + $('#category_addbutton').live('click',function(e){ + e.preventDefault(); + if($('#category_addinput').val().length > 0) { + Categories.add($('#category_addinput').val()); + $('#category_addinput').val(''); + } + }); + } + }); + } + }); + }, + delete:function(){ + var categories = $('#categorylist').find('input[type="checkbox"]').serialize(); + console.log('Categories.delete: ' + categories); + $.post(OC.filePath('contacts', 'ajax', 'categories/delete.php'),categories,function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + }, + add:function(category){ + console.log('Categories.add ' + category); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/add.php'),{'category':category},function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + return false; + }, + rescan:function(){ + console.log('Categories.rescan'); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/rescan.php'),{},function(jsondata){ + if(jsondata.status == 'success'){ + Categories._update(jsondata.data.categories); + } else { + alert(jsondata.data.message); + } + }); + }, + _update:function(categories){ + var categorylist = $('#categorylist'); + categorylist.find('li').remove(); + for(var category in categories) { + var item = '
    • ' + categories[category] + '
    • '; + $(item).appendTo(categorylist); + } + if(Categories.changed != undefined) { + Categories.changed(categories); + } + } } - Contacts={ UI:{ notImplemented:function() { @@ -125,22 +217,26 @@ Contacts={ // 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); - } - }); + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(jsondata){ + if(jsondata.status != 'error'){ + $('#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); + } + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -182,6 +278,12 @@ Contacts={ $('#bday').datepicker({ dateFormat : 'dd-mm-yy' }); + $('#categories_value').find('select').multiselect({ + noneSelectedText: t('contacts', 'Select categories'), + header: false, + selectedList: 6, + classes: 'categories' + }); // Style phone types $('#phonelist').find('select[class*="contacts_property"]').multiselect({ noneSelectedText: t('contacts', 'Select type'), @@ -361,7 +463,7 @@ Contacts={ this.data = jsondata; this.id = this.data.id; $('#rightcontent').data('id',this.id); - //console.log('loaded: ' + this.data.FN[0]['value']); + console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); this.loadCategories(); this.loadPhoto(); @@ -369,6 +471,16 @@ Contacts={ this.loadPhones(); this.loadAddresses(); this.loadSingleProperties(); + // TODO: load NOTE ;-) + if(this.data.NOTE) { + $('#note').data('checksum', this.data.NOTE[0]['checksum']); + $('#note').find('textarea').val(this.data.NOTE[0]['value']); + $('#note').show(); + } else { + $('#note').data('checksum', ''); + $('#note').find('textarea').val(''); + $('#note').hide(); + } }, loadSingleProperties:function() { var props = ['BDAY', 'NICKNAME', 'ORG']; @@ -457,21 +569,64 @@ Contacts={ $('#contact_identity').find('*[data-element="FN"]').data('checksum', this.data.FN[0]['checksum']); $('#contact_identity').show(); }, - loadCategories:function(){ + hasCategory:function(category) { if(this.data.CATEGORIES) { - // + for(var c in this.data.CATEGORIES[0]['value']) { + var cat = this.data.CATEGORIES[0]['value'][c]; + //console.log('hasCategory: ' + cat + ' === ' + category + '?'); + if(typeof cat === 'string' && (cat.toUpperCase() === category.toUpperCase())) { + //console.log('Yes'); + return true; + } + } } + return false; + }, + categoriesChanged:function(categories) { // Categories added/deleted. + console.log('categoriesChanged for ' + Contacts.UI.Card.id + ' : ' + categories); + var categorylist = $('#categories_value').find('select'); + categorylist.find('option').remove(); + for(var category in categories) { + console.log('categoriesChanged: ' + categories[category]); + var selected = Contacts.UI.Card.hasCategory(categories[category]) ? ' selected="selected"' : ''; + var item = ''; + $(item).appendTo(categorylist); + } + $('#categories_value').find('select').multiselect('refresh'); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/checksumfor.php'),{'id':Contacts.UI.Card.id},function(jsondata){ + if(jsondata.status == 'success'){ + console.log('Setting checksum: ' + jsondata.data.checksum); + $('#categories_value').data('checksum', jsondata.data.checksum); + } else { + Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } + }); + }, + loadCategories:function(){ // On loading contact. + var categories = $('#categories_value').find('select'); + if(this.data.CATEGORIES) { + $('#categories_value').data('checksum', this.data.CATEGORIES[0]['checksum']); + } else { + $('#categories_value').data('checksum', ''); + } + categories.find('option').each(function(){ + if(Contacts.UI.Card.hasCategory($(this).val())) { + $(this).attr('selected', 'selected'); + } else { + $(this).removeAttr('selected'); + } + }); + categories.multiselect('refresh'); }, editNew:function(){ // add a new contact this.id = ''; this.fn = ''; this.fullname = ''; this.givname = ''; this.famname = ''; this.addname = ''; this.honpre = ''; this.honsuf = ''; - $.getJSON('ajax/newcontact.php',{},function(jsondata){ + $.getJSON(OC.filePath('contacts', 'ajax', 'newcontact.php'),{},function(jsondata){ if(jsondata.status == 'success'){ id = ''; $('#rightcontent').data('id',''); $('#rightcontent').html(jsondata.data.page); Contacts.UI.Card.editName(); - } - else{ + } else { Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); //alert(jsondata.data.message); } @@ -479,14 +634,19 @@ Contacts={ }, savePropertyInternal:function(name, fields, oldchecksum, checksum){ // TODO: Add functionality for new fields. - //console.log('savePropertyInternal: ' + name + ', checksum: ' + checksum); - //console.log('savePropertyInternal: ' + this.data[name]); + console.log('savePropertyInternal: ' + name + ', fields: ' + fields + 'checksum: ' + checksum); + console.log('savePropertyInternal: ' + this.data[name]); + var multivalue = ['CATEGORIES']; var params = {}; - var value = undefined; + var value = multivalue.indexOf(name) != -1 ? new Array() : undefined; jQuery.each(fields, function(i, field){ //.substring(11,'parameters[TYPE][]'.indexOf(']')) if(field.name.substring(0, 5) === 'value') { - value = field.value; + if(multivalue.indexOf(name) != -1) { + value.push(field.value); + } else { + value = field.value; + } } else if(field.name.substring(0, 10) === 'parameters') { var p = field.name.substring(11,'parameters[TYPE][]'.indexOf(']')); if(!(p in params)) { @@ -506,7 +666,7 @@ Contacts={ 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); + console.log('Filtering out object.' + obj); return false; } if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') { @@ -529,32 +689,38 @@ Contacts={ if(checksum != undefined && checksum != '') { // save q = q + '&checksum=' + checksum; console.log('Saving: ' + q); + $(obj).attr('disabled', 'disabled'); $.post('ajax/saveproperty.php',q,function(jsondata){ if(jsondata.status == 'success'){ container.data('checksum', jsondata.data.checksum); Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return true; } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return false; } },'json'); } else { // add console.log('Adding: ' + q); + $(obj).attr('disabled', 'disabled'); $.post('ajax/addproperty.php',q,function(jsondata){ if(jsondata.status == 'success'){ container.data('checksum', jsondata.data.checksum); // TODO: savePropertyInternal doesn't know about new fields //Contacts.UI.Card.savePropertyInternal(name, fields, checksum, jsondata.data.checksum); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return true; } else{ Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return false; } },'json'); @@ -565,10 +731,14 @@ Contacts={ console.log('addProperty:' + type); switch (type) { case 'PHOTO': - this.loadPhoto(); + this.loadPhoto(true); $('#file_upload_form').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; + case 'NOTE': + $('#note').show(); + $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + break; case 'EMAIL': if($('#emaillist>li').length == 1) { $('#emails').show(); @@ -647,8 +817,9 @@ Contacts={ 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({ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editname.php')+'?id='+this.id, function(jsondata){ + if(jsondata.status != 'error'){ + $('#edit_name_dialog' ).dialog({ modal: (isnew && true || false), closeOnEscape: (isnew == '' && false || true), title: (isnew && t('contacts', 'Add contact') || t('contacts', 'Edit name')), @@ -667,7 +838,10 @@ Contacts={ open : function(event, ui) { // load 'N' property - maybe :-P }*/ - }); + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -692,7 +866,14 @@ Contacts={ $('#fn_select option').remove(); //$('#fn_select').combobox('value', this.fn); - var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + var tmp = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + var names = new Array(); + for(var name in tmp) { + console.log('idx: ' + names.indexOf(tmp[name])); + if(names.indexOf(tmp[name]) == -1) { + names.push(tmp[name]); + } + } $.each(names, function(key, value) { $('#fn_select') .append($('') @@ -771,8 +952,9 @@ Contacts={ 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({ + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'editaddress.php')+q, function(jsondata){ + if(jsondata.status != 'error'){ + $('#edit_address_dialog' ).dialog({ /*modal: true,*/ height: 'auto', width: 'auto', buttons: { @@ -803,7 +985,10 @@ Contacts={ open : function(event, ui) { // load 'ADR' property - maybe :-P }*/ - }); + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -867,8 +1052,8 @@ Contacts={ form.submit(); } }, - loadPhoto:function(){ - if(this.data.PHOTO) { + loadPhoto:function(force){ + if(this.data.PHOTO||force==true) { $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); @@ -1006,13 +1191,17 @@ Contacts={ 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(); - } - }); + $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(jsondata){ + if(jsondata.status != 'error'){ + $('#chooseaddressbook_dialog').dialog({ + width : 600, + close : function(event, ui) { + $(this).dialog('destroy').remove(); + } + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -1121,6 +1310,7 @@ Contacts={ $(document).ready(function(){ Contacts.UI.loadHandlers(); + Categories.changed = Contacts.UI.Card.categoriesChanged; /** * Show the Addressbook chooser @@ -1189,7 +1379,8 @@ $(document).ready(function(){ // 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(){ + //$('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){ + $('.contacts_property').live('change', function(){ Contacts.UI.Card.saveProperty(this); }); @@ -1298,11 +1489,29 @@ $(document).ready(function(){ xhr.send(file); } + $('body').live('click',function(e){ + if(!$(e.target).is('#contacts_propertymenu_button')) { + $('#contacts_propertymenu').hide(); + } + }); $('#contacts_propertymenu_button').live('click',function(){ - $('#contacts_propertymenu').is(':hidden') && $('#contacts_propertymenu').slideDown() || $('#contacts_propertymenu').slideUp(); + var menu = $('#contacts_propertymenu'); + if(menu.is(':hidden')) { + menu.show(); + menu.find('ul').focus(); + } else { + menu.hide(); + } }); $('#contacts_propertymenu a').live('click',function(){ Contacts.UI.Card.addProperty(this); $('#contacts_propertymenu').hide(); }); }); + +String.prototype.strip_tags = function(){ + tags = this; + stripped = tags.replace(/[\<\>]/gi, ""); + return stripped; +} + diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 99b1edd656f..3c95dd19abf 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -4,6 +4,7 @@ * * @author Jakob Sack * @copyright 2011 Jakob Sack mail@jakobsack.de + * @copyright 2012 Thomas Tanghus * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -275,6 +276,29 @@ class OC_Contacts_VCard{ return $newid; } + /** + * @brief Mass updates an array of cards + * @param array $objects An array of [id, carddata]. + */ + public static function updateDataByID($objects){ + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET carddata = ?, lastmodified = ? WHERE id = ?' ); + $now = new DateTime; + foreach($objects as $object) { + $vcard = OC_VObject::parse($object[1]); + if(!is_null($vcard)){ + $vcard->setString('REV', $now->format(DateTime::W3C)); + $data = $vcard->serialize(); + try { + $result = $stmt->execute(array($data,time(),$object[0])); + //OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0].': '.$object[1],OC_Log::DEBUG); + } catch(Exception $e) { + OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID:, exception: '.$e->getMessage(),OC_Log::DEBUG); + OC_Log::write('contacts','OC_Contacts_VCard::updateDataByID, id: '.$object[0],OC_Log::DEBUG); + } + } + } + } + /** * @brief edits a card * @param integer $id id of card @@ -378,6 +402,43 @@ class OC_Contacts_VCard{ return true; } + /** + * @brief Escapes delimiters from an array and returns a string. + * @param array $value + * @param char $delimiter + * @return string + */ + public static function escapeDelimiters($value, $delimiter=';') { + foreach($value as &$i ) { + $i = implode("\\$delimiter", explode($delimiter, $i)); + } + return implode($delimiter, $value); + } + + + /** + * @brief Creates an array out of a multivalue property + * @param string $value + * @param char $delimiter + * @return array + */ + public static function unescapeDelimiters($value, $delimiter=';') { + $array = explode($delimiter,$value); + for($i=0;$ivalue; //$value = htmlspecialchars($value); if($property->name == 'ADR' || $property->name == 'N'){ - $value = OC_VObject::unescapeSemicolons($value); + $value = self::unescapeDelimiters($value); + } elseif($property->name == 'CATEGORIES') { + $value = self::unescapeDelimiters($value, ','); } $temp = array( 'name' => $property->name, diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5be20964f4b..59bb6c2cc29 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -13,6 +13,7 @@ $id = isset($_['id']) ? $_['id'] : '';
    • t('Phone'); ?>
    • t('Email'); ?>
    • t('Address'); ?>
    • +
    • t('Note'); ?>
    • @@ -45,7 +46,7 @@ $id = isset($_['id']) ? $_['id'] : '';
      +
      @@ -53,8 +54,19 @@ $id = isset($_['id']) ? $_['id'] : ''; +
      +
      + + +
      + diff --git a/lib/vcategories.php b/lib/vcategories.php index 250aa608c1d..7a31a5268d1 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -49,12 +49,14 @@ class OC_VCategories { * @param $user The user whos data the object will operate on. This * parameter should normally be omitted but to make an app able to * update categories for all users it is made possible to provide it. + * @param $defcategories An array of default categories to be used if none is stored. + * NOTE: Not implemented. */ - public function __construct($app, $user=null) { + public function __construct($app, $user=null, $defcategories=null) { $this->app = $app; $this->user = is_null($user) ? OC_User::getUser() : $user; $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); - $this->categories = $categories != '' ? OC_VObject::unescapeSemicolons($categories) : array(); + $this->categories = $categories != '' ? unserialize($categories) : array(); } /** @@ -62,6 +64,7 @@ class OC_VCategories { * @returns array containing the categories as strings. */ public function categories() { + OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG); return $this->categories; } @@ -81,7 +84,7 @@ class OC_VCategories { * @param $sync bool When true, save the categories * @returns bool Returns false on error. */ - public function add($names, $sync=true) { + public function add($names, $sync=false) { if(!is_array($names)) { $names = array($names); } @@ -95,7 +98,7 @@ class OC_VCategories { if(count($newones) > 0) { $this->categories = array_merge($this->categories, $newones); natcasesort($this->categories); // Dunno if this is necessary - if($sync) { + if($sync === true) { $this->save(); } } @@ -106,7 +109,7 @@ class OC_VCategories { * @brief Extracts categories from a vobject and add the ones not already present. * @param $vobject The instance of OC_VObject to load the categories from. */ - public function loadFromVObject($vobject, $sync=true) { + public function loadFromVObject($vobject, $sync=false) { $this->add($vobject->getAsArray('CATEGORIES'), $sync); } @@ -126,14 +129,15 @@ class OC_VCategories { * } * $categories->rescan($objects); */ - public function rescan($objects) { + public function rescan($objects, $sync=true) { $this->categories = array(); foreach($objects as $object) { + //OC_Log::write('core','OC_VCategories::rescan: '.substr($object, 0, 100).'(...)', OC_Log::DEBUG); $vobject = OC_VObject::parse($object); if(!is_null($vobject)) { - $this->loadFromVObject($vobject, false); + $this->loadFromVObject($vobject, $sync); } else { - OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG); } } $this->save(); @@ -142,35 +146,51 @@ class OC_VCategories { /** * @brief Save the list with categories */ - public function save() { - $escaped_categories = OC_VObject::escapeSemicolons($this->categories); + private function save() { + $escaped_categories = serialize($this->categories); + OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG); OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); } /** - * @brief Delete a category from the db and from all the vobject supplied - * @param $name + * @brief Delete categories from the db and from all the vobject supplied + * @param $names An array of categories to delete * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. */ - public function delete($name, array &$objects) { - if(!$this->hasCategory($name)) { - return; + public function delete($names, array &$objects) { + if(!is_array($names)) { + $names = array($names); + } + OC_Log::write('core','OC_VCategories::delete, before: '.print_r($this->categories, true), OC_Log::DEBUG); + foreach($names as $name) { + OC_Log::write('core','OC_VCategories::delete: '.$name, OC_Log::DEBUG); + if($this->hasCategory($name)) { + OC_Log::write('core','OC_VCategories::delete: '.$name.' got it', OC_Log::DEBUG); + unset($this->categories[$this->array_searchi($name, $this->categories)]); + } } - unset($this->categories[$this->array_searchi($name, $this->categories)]); $this->save(); + OC_Log::write('core','OC_VCategories::delete, after: '.print_r($this->categories, true), OC_Log::DEBUG); foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)){ $categories = $vobject->getAsArray('CATEGORIES'); - $idx = $this->array_searchi($name, $categories); - if($idx) { - unset($categories[$this->array_searchi($name, $categories)]); - $vobject->setString('CATEGORIES', implode(',', $categories)); - $value[1] = $vobject->serialize(); - $objects[$key] = $value; + //OC_Log::write('core','OC_VCategories::delete, before: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); + foreach($names as $name) { + $idx = $this->array_searchi($name, $categories); + OC_Log::write('core','OC_VCategories::delete, loop: '.$name.', '.print_r($idx, true), OC_Log::DEBUG); + if($idx !== false) { + OC_Log::write('core','OC_VCategories::delete, unsetting: '.$categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG); + unset($categories[$this->array_searchi($name, $categories)]); + //unset($categories[$idx]); + } } + OC_Log::write('core','OC_VCategories::delete, after: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); + $vobject->setString('CATEGORIES', implode(',', $categories)); + $value[1] = $vobject->serialize(); + $objects[$key] = $value; } else { - OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 20).'(...)', OC_Log::DEBUG); + OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG); } } } From d8d293966852e28168c3ec42c79c2a271a8c8ade Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 17:31:01 +0100 Subject: [PATCH 20/61] dont use numRows and fix some of the gallary hooks --- apps/gallery/ajax/galleryOp.php | 4 ++-- apps/gallery/lib/album.php | 7 +++++++ apps/gallery/lib/hooks_handlers.php | 31 +++++++++++++++-------------- apps/gallery/lib/scanner.php | 8 ++++---- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index 74ac905d072..f33eb46041b 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -102,9 +102,9 @@ function handleGetGallery($path) { while ($r = $result->fetchRow()) { $album_name = $r['album_name']; - $tmp_res = OC_Gallery_Photo::find($r['album_id']); + $size=OC_Gallery_Album::getAlbumSize($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($tmp_res->numRows(), 10)); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10)); } $result = OC_Gallery_Photo::find($album_details['album_id']); diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index 317e8209de4..5adb57b554d 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -107,6 +107,13 @@ class OC_Gallery_Album { rename($thumbpath.$oldname.'.png', $thumbpath.$newname.'.png'); } + public static function getAlbumSize($id){ + $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $result=$stmt->execute(array($id))->fetchRow(); + return $result['size']; + } + } ?> diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index 046866e5c5d..3c101b1f8a1 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -37,7 +37,7 @@ class OC_Gallery_Hooks_Handlers { } private static function directoryContainsPhotos($dirpath) { - $dirhandle = opendir(OC::$CONFIG_DATADIRECTORY.$dirpath); + $dirhandle = OC_Filesystem::opendir($dirpath.'/'); if ($dirhandle != FALSE) { while (($filename = readdir($dirhandle)) != FALSE) { if ($filename[0] == '.') continue; @@ -76,9 +76,9 @@ class OC_Gallery_Hooks_Handlers { public static function removePhoto($params) { $path = $params[OC_Filesystem::signal_param_path]; - if (OC_Filesystem::is_dir($path) && self::directoryContainsPhotos($path)) { + if (OC_Filesystem::is_dir($path.'/') && self::directoryContainsPhotos($path)) { if(!self::pathInRoot($path)) return; - OC_Gallery_Album::removeByPath($path.'/', OC_User::getUser()); + OC_Gallery_Album::removeByPath($path, OC_User::getUser()); } elseif (self::isPhoto($path)) { OC_Gallery_Photo::removeByPath($path); } @@ -87,11 +87,11 @@ class OC_Gallery_Hooks_Handlers { public static function renamePhoto($params) { $oldpath = $params[OC_Filesystem::signal_param_oldpath]; $newpath = $params[OC_Filesystem::signal_param_newpath]; - if (OC_Filesystem::is_dir($newpath) && self::directoryContainsPhotos($newpath)) { + if (OC_Filesystem::is_dir($newpath.'/') && self::directoryContainsPhotos($newpath)) { OC_Gallery_Album::changePath($oldpath, $newpath, OC_User::getUser()); - } elseif (!self::isPhoto($newpath)) { - $olddir = substr($oldpath, 0, strrpos($oldpath, '/')); - $newdir = substr($newpath, 0, strrpos($newpath, '/')); + } elseif (self::isPhoto($newpath)) { + $olddir = dirname($oldpath); + $newdir = dirname($newpath); if ($olddir == '') $olddir = '/'; if ($newdir == '') $newdir = '/'; if (!self::isPhoto($newpath)) return; @@ -101,25 +101,26 @@ class OC_Gallery_Hooks_Handlers { $oldAlbumId; if ($olddir == $newdir) { // album changing is not needed - $album = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); - if ($album->numRows() == 0) { - $album = self::createAlbum($newdir); + $albums = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); + $album = $albums->fetchRow(); + if (!$album) { + $albums = self::createAlbum($newdir); + $album = $albums->fetchRow(); } - $album = $album->fetchRow(); $newAlbumId = $oldAlbumId = $album['album_id']; } else { $newalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $newdir); $oldalbum = OC_Gallery_Album::find(OC_User::getUser(), null, $olddir); - if ($newalbum->numRows() == 0) { + if (!($newalbum = $newalbum->fetchRow())) { $newalbum = self::createAlbum($newdir); + $newalbum = $newalbum->fetchRow(); } - $newalbum = $newalbum->fetchRow(); - if ($oldalbum->numRows() == 0) { + $oldalbum = $oldalbum->fetchRow(); + if (!$oldalbum) { OC_Gallery_Photo::create($newalbum['album_id'], $newpath); return; } - $oldalbum = $oldalbum->fetchRow(); $newAlbumId = $newalbum['album_id']; $oldAlbumId = $oldalbum['album_id']; diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 1e8fdb63fb3..dbe1abff10e 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -62,15 +62,15 @@ class OC_Gallery_Scanner { $result = OC_Gallery_Album::find(OC_User::getUser(), /*$current_album['name']*/ null, $path); // don't duplicate galleries with same path (bug oc-33) - if ($result->numRows() == 0 && count($current_album['images'])) { - OC_Gallery_Album::create(OC_User::getUser(), $current_album['name'], $path); + if (!($albumId = $result->fetchRow()) && count($current_album['images'])) { + OC_Gallery_Album::create(OC_User::getUser(), $current_album['name'], $path); $result = OC_Gallery_Album::find(OC_User::getUser(), $current_album['name']); + $albumId = $result->fetchRow(); } - $albumId = $result->fetchRow(); $albumId = $albumId['album_id']; foreach ($current_album['images'] as $img) { $result = OC_Gallery_Photo::find($albumId, $img); - if ($result->numRows() == 0) { + if (!$result->fetchRow()) { OC_Gallery_Photo::create($albumId, $img); } } From cf5d63f0abc2b4537098962ad5051180861f965b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 18:58:10 +0100 Subject: [PATCH 21/61] some js cleanup for gallary also tabs no spaces --- apps/gallery/ajax/galleryOp.php | 2 +- apps/gallery/js/album_cover.js | 309 ++++++++++++++++---------------- apps/gallery/js/albums.js | 192 ++++++++++---------- 3 files changed, 252 insertions(+), 251 deletions(-) diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index f33eb46041b..64f1b1697ba 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -104,7 +104,7 @@ function handleGetGallery($path) { $album_name = $r['album_name']; $size=OC_Gallery_Album::getAlbumSize($r['album_id']); - $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10)); + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10),'path'=>$r['album_path']); } $result = OC_Gallery_Photo::find($album_details['album_id']); diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index 98f29072816..71de1adae11 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,184 +1,187 @@ var actual_cover; -var paths = ''; +var paths = []; var crumbCount = 0; $(document).ready(returnToElement(0)); function returnToElement(num) { - while (crumbCount != num) { - $('#g-album-navigation .last').remove(); - $('#g-album-navigation .crumb :last').parent().addClass('last'); - crumbCount--; - paths = paths.substring(0, paths.lastIndexOf('\/')); - } - $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); + while (crumbCount != num) { + $('#g-album-navigation .last').remove(); + $('#g-album-navigation .crumb :last').parent().addClass('last'); + crumbCount--; + paths.pop(); + } + path=paths[paths.length-1]; + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: path }, albumClickHandler); } -function albumClick(e) { - var title = decodeURIComponent(escape(e.data.title)); - paths += '/' + title; - crumbCount++; - $.getJSON('ajax/galleryOp.php', {operation: 'get_gallery', path: paths }, albumClickHandler); - if ($('#g-album-navigation :last-child')) - $('#g-album-navigation :last-child').removeClass('last'); - $('#g-album-navigation').append(''); +function albumClick(title,path) { + paths.push(path); + crumbCount++; + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: path }, albumClickHandler); + if ($('#g-album-navigation :last-child')) + $('#g-album-navigation :last-child').removeClass('last'); + $('#g-album-navigation').append(''); } function albumClickHandler(r) { - Albums.photos = []; - Albums.albums = []; - if (r.status == 'success') { - for (var i in r.albums) { - var a = r.albums[i]; - Albums.add(a.name, a.numOfItems); - } - for (var i in r.photos) { - Albums.photos.push(r.photos[i]); - } - var targetDiv = document.getElementById('gallery_list'); - if (targetDiv) { - $(targetDiv).html(''); - Albums.display(targetDiv); - //$('#gallery_list').sortable({revert:true}); - $('.album').each(function(i, el) { - $(el).click({title:$(el).attr('title')}, albumClick); - //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); - }); - } else { - OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); - } - } else { - OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); - } + Albums.photos = []; + Albums.albums = []; + if (r.status == 'success') { + for (var i in r.albums) { + var a = r.albums[i]; + Albums.add(a.name, a.numOfItems,a.path); + } + for (var i in r.photos) { + Albums.photos.push(r.photos[i]); + } + var targetDiv = document.getElementById('gallery_list'); + if (targetDiv) { + $(targetDiv).html(''); + Albums.display(targetDiv); + //$('#gallery_list').sortable({revert:true}); + $('.album').each(function(i, el) { + $(el).click(albumClick.bind(null,$(el).attr('title'),$(el).data('path'))); + //$(el).draggable({connectToSortable: '#gallery_list', handle: '.dummy'}); + }); + } else { + OC.dialogs.alert(t('gallery', 'Error: no such layer `gallery_list`'), t('gallery', 'Internal error')); + } + } else { + OC.dialogs.alert(t('gallery', 'Error: ') + r.message, t('gallery', 'Internal error')); + } } function createNewAlbum() { - var name = prompt("album name", ""); - if (name != null && name != "") { - $.getJSON("ajax/createAlbum.php", {album_name: name}, function(r) { - if (r.status == "success") { - var v = ''; - $('div#gallery_list').append(v); - } - }); - } + var name = prompt("album name", ""); + if (name != null && name != "") { + $.getJSON(OC.filePath('gallery','ajax','createAlbum.php'), {album_name: name}, function(r) { + if (r.status == "success") { + var v = ''; + $('div#gallery_list').append(v); + } + }); + } } var albumCounter = 0; var totalAlbums = 0; function scanForAlbums(cleanup) { - cleanup = cleanup?true:false; - var albumCounter = 0; - var totalAlbums = 0; - $('#g-scan-button').attr('disabled', 'true'); - $.getJSON('ajax/galleryOp.php?operation=filescan', {cleanup: cleanup}, function(r) { + cleanup = cleanup?true:false; + var albumCounter = 0; + var totalAlbums = 0; + $('#g-scan-button').attr('disabled', 'true'); + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {cleanup: cleanup,operation:'filescan'}, function(r) { - if (r.status == 'success') { - totalAlbums = r.paths.length; - if (totalAlbums == 0) { - $('#notification').text(t('gallery', "No photos found")).fadeIn().slideDown().delay(3000).fadeOut().slideUp(); - return; - } - $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); - for(var a in r.paths) { - $.getJSON('ajax/galleryOp.php',{operation:'partial_create','path':r.paths[a]}, function(r) { + if (r.status == 'success') { + totalAlbums = r.paths.length; + if (totalAlbums == 0) { + $('#notification').text(t('gallery', "No photos found")).fadeIn().slideDown().delay(3000).fadeOut().slideUp(); + return; + } + $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }).fadeIn(); + for(var a in r.paths) { + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'),{operation:'partial_create','path':r.paths[a]}, function(r) { - albumCounter++; - $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); - if (albumCounter == totalAlbums) { - $('#scanprogressbar').fadeOut(); - var targetDiv = document.getElementById('gallery_list'); - if (targetDiv) { - targetDiv.innerHTML = ''; - Albums.photos = []; - Albums.albums = []; - returnToElement(0); - } else { - alert('Error occured: no such layer `gallery_list`'); - } - $('#g-scan-button').attr('disabled', null); - } - }); - } - } else { - alert('Error occured: ' + r.message); - } - }); + albumCounter++; + $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); + if (albumCounter == totalAlbums) { + $('#scanprogressbar').fadeOut(); + var targetDiv = document.getElementById('gallery_list'); + if (targetDiv) { + targetDiv.innerHTML = ''; + Albums.photos = []; + Albums.albums = []; + returnToElement(0); + } else { + alert('Error occured: no such layer `gallery_list`'); + } + $('#g-scan-button').attr('disabled', null); + } + }); + } + } else { + alert('Error occured: ' + r.message); + } + }); } function galleryRemove(albumName) { - OC.dialogs.confirm(t('gallery', 'Do you want to remove album ') + decodeURIComponent(escape(albumName)), - t('gallery', 'Remove confirmation'), - function(decision) { - if (decision) { - $.getJSON("ajax/galleryOp.php", {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { - if (r.status == "success") { - $(".gallery_box").filterAttr('data-album',albumName).remove(); - Albums.remove(albumName); - } else { - OC.dialogs.alert(r.cause, "Error"); - } - }); - } - }); + OC.dialogs.confirm(t('gallery', 'Do you want to remove album ') + decodeURIComponent(escape(albumName)), + t('gallery', 'Remove confirmation'), + function(decision) { + if (decision) { + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: "remove", name: decodeURIComponent(escape(albumName))}, function(r) { + if (r.status == "success") { + $(".gallery_box").filterAttr('data-album',albumName).remove(); + Albums.remove(albumName); + } else { + OC.dialogs.alert(r.cause, "Error"); + } + }); + } + } + ); } function galleryRename(name) { - OC.dialogs.prompt(t('gallery', 'New album name'), - t('gallery', 'Change name'), - name, - function(newname) { - if (newname == name || newname == '') return; - if (Albums.find(newname)) { - OC.dialogs.alert('Album ' + newname + ' exists', 'Alert'); - return; - } - $.getJSON('ajax/galleryOp.php', {operation: 'rename', oldname: name, newname: newname}, function(r) { - if (r.status == 'success') { - Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); - } else { - OC.dialogs.alert('Error: ' + r.cause, 'Error'); - } - }); - }); + OC.dialogs.prompt(t('gallery', 'New album name'), + t('gallery', 'Change name'), + name, + function(newname) { + if (newname == name || newname == '') return; + if (Albums.find(newname)) { + OC.dialogs.alert('Album ' + newname + ' exists', 'Alert'); + return; + } + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'rename', oldname: name, newname: newname}, function(r) { + if (r.status == 'success') { + Albums.rename($(".gallery_box").filterAttr('data-album',name), newname); + } else { + OC.dialogs.alert('Error: ' + r.cause, 'Error'); + } + }); + } + ); } function settings() { - $( '#g-dialog-settings' ).dialog({ - height: 180, - width: 350, - modal: false, - buttons: [{ - text: t('gallery', 'Apply'), - click: function() { - var scanning_root = $('#g-scanning-root').val(); - var disp_order = $('#g-display-order option:selected').val(); - if (scanning_root == '') { - alert('Scanning root cannot be empty'); - return; - } - $.getJSON('ajax/galleryOp.php', {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) { - if (r.status == 'success') { - if (r.rescan == 'yes') { - $('#g-dialog-settings').dialog('close'); - Albums.clear(document.getElementById('gallery_list')); - scanForAlbums(true); - return; - } - } else { - alert('Error: ' + r.cause); - return; - } - $('#g-dialog-settings').dialog('close'); - }); - } - }, - { - text: t('gallery', 'Cancel'), - click: function() { - $(this).dialog('close'); - } - } - ], - }); + $( '#g-dialog-settings' ).dialog({ + height: 180, + width: 350, + modal: false, + buttons: [ + { + text: t('gallery', 'Apply'), + click: function() { + var scanning_root = $('#g-scanning-root').val(); + var disp_order = $('#g-display-order option:selected').val(); + if (scanning_root == '') { + alert('Scanning root cannot be empty'); + return; + } + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'store_settings', root: scanning_root, order: disp_order}, function(r) { + if (r.status == 'success') { + if (r.rescan == 'yes') { + $('#g-dialog-settings').dialog('close'); + Albums.clear(document.getElementById('gallery_list')); + scanForAlbums(true); + return; + } + } else { + alert('Error: ' + r.cause); + return; + } + $('#g-dialog-settings').dialog('close'); + }); + } + }, + { + text: t('gallery', 'Cancel'), + click: function() { + $(this).dialog('close'); + } + } + ], + }); } diff --git a/apps/gallery/js/albums.js b/apps/gallery/js/albums.js index 3882deb5146..afdfbd3cc83 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -1,100 +1,98 @@ Albums={ - // album item in this array should look as follow - // {name: string, - // numOfCovers: int} - // - // previews array should be an array of base64 decoded images - // to display to user as preview picture when scrolling throught - // the album cover - albums:new Array(), - photos:new Array(), - // add simply adds new album to internal structure - // however albums names must be unique so other - // album with the same name wont be insered, - // and false will be returned - // true on success - add: function(album_name, num) { - if (Albums.albums[album_name] != undefined) return false; - Albums.albums[album_name] = {name: album_name, numOfCovers: num}; - return true; - }, - // remove element with given name - // returns remove element or undefined if no such element was present - remove: function(name) { - var i = -1, tmp = 0; - for (var a in Albums.albums) { - if (a.name == name) { - i = tmp; - break; - } - tmp++; - } - if (i != -1) { - return Albums.albums.splice(i,1); - } - return undefined; - }, - // return element which match given name - // of undefined if such element do not exist - find: function(name) { - return Albums.albums[name]; - }, - // displays gallery in linear representation - // on given element, and apply default styles for gallery - display: function(element) { - var displayTemplate = ''; - for (var i in Albums.albums) { - var a = Albums.albums[i]; - var local=$(displayTemplate); - local.attr('title', a.name); - local.attr('data-album',a.name); - $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - event.stopPropagation(); - galleryRename(event.data.name); - }); - $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - event.stopPropagation(); - galleryRemove(event.data.name); - }); - // $("a.view", local).attr('href','?view='+decodeURIComponent(escape(a.name))); - $('h1',local).text(decodeURIComponent(escape(a.name))); - $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); - $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); - $(".gallery_album_cover", local).css('background-position', '0'); - $(".gallery_album_cover", local).css('background-image','url("ajax/galleryOp.php?operation=get_covers&albumname='+escape(a.name)+'")'); - $(".gallery_album_cover", local).mousemove(function(e) { - - var albumMetadata = Albums.find(this.title); - if (albumMetadata == undefined) { - return; - } - var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers)); - x *= this.offsetWidth; - if (x < 0) x=0; - $(this).css('background-position', -x+'px 0'); - }); - $(element).append(local); - } - var photoDisplayTemplate = ''; - for (var i in Albums.photos) { - $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); - } - $("a[rel=images]").fancybox({ - 'titlePosition': 'inside' - }); - }, - rename: function(element, new_name) { - if (new_name) { - $(element).attr("data-album", new_name); - $("a.view", element).attr("href", "?view="+new_name); - $("h1", element).text(new_name); + // album item in this array should look as follow + // {name: string, + // numOfCovers: int} + // + // previews array should be an array of base64 decoded images + // to display to user as preview picture when scrolling throught + // the album cover + albums:new Array(), + photos:new Array(), + // add simply adds new album to internal structure + // however albums names must be unique so other + // album with the same name wont be insered, + // and false will be returned + // true on success + add: function(album_name, num,path) { + if (Albums.albums[album_name] != undefined) return false; + Albums.albums[album_name] = {name: album_name, numOfCovers: num, path:path}; + return true; + }, + // remove element with given name + // returns remove element or undefined if no such element was present + remove: function(name) { + var i = -1, tmp = 0; + for (var a in Albums.albums) { + if (a.name == name) { + i = tmp; + break; + } + tmp++; + } + if (i != -1) { + return Albums.albums.splice(i,1); + } + return undefined; + }, + // return element which match given name + // of undefined if such element do not exist + find: function(name) { + return Albums.albums[name]; + }, + // displays gallery in linear representation + // on given element, and apply default styles for gallery + display: function(element) { + var displayTemplate = ''; + for (var i in Albums.albums) { + var a = Albums.albums[i]; + var local=$(displayTemplate); + local.attr('title', a.name); + local.attr('data-path', a.path); + local.attr('data-album',a.name); + $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(name,event){ + event.preventDefault(); + event.stopPropagation(); + galleryRename(name); + }.bind(null,a.name)); + $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(name,event){ + event.preventDefault(); + event.stopPropagation(); + galleryRemove(name); + }.bind(null,a.name)); + $('h1',local).text(decodeURIComponent(escape(a.name))); + $(".gallery_album_cover", local).attr('title',decodeURIComponent(escape(a.name))); + $(".gallery_album_cover", local).css('background-repeat', 'no-repeat'); + $(".gallery_album_cover", local).css('background-position', '0'); + $(".gallery_album_cover", local).css('background-image','url("'+OC.filePath('gallery','ajax','galleryOp.php')+'?operation=get_covers&albumname='+escape(a.name)+'")'); + $(".gallery_album_cover", local).mousemove(function(e) { + var albumMetadata = Albums.find(this.title); + if (albumMetadata == undefined) { + return; + } + var x = Math.floor((e.layerX - this.offsetLeft)/(this.offsetWidth/albumMetadata.numOfCovers)); + x *= this.offsetWidth; + if (x < 0) x=0; + $(this).css('background-position', -x+'px 0'); + }); + $(element).append(local); + } + var photoDisplayTemplate = ''; + for (var i in Albums.photos) { + $(element).append(photoDisplayTemplate.replace("IMGPATH", escape(Albums.photos[i])).replace("URLPATH", escape(Albums.photos[i]))); + } + $("a[rel=images]").fancybox({ + 'titlePosition': 'inside' + }); + }, + rename: function(element, new_name) { + if (new_name) { + $(element).attr("data-album", new_name); + $("a.view", element).attr("href", "?view="+new_name); + $("h1", element).text(new_name); + } + }, + clear: function(element) { + Albums.albums = new Array(); + element.innerHTML = ''; } - }, - clear: function(element) { - Albums.albums = new Array(); - element.innerHTML = ''; - } - } From 018f0c4b72d9d2ca1c27c4c543a805b227745beb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 7 Mar 2012 21:43:44 +0100 Subject: [PATCH 22/61] add option to add file from url --- files/ajax/newfile.php | 26 +++++++++++++-- files/ajax/newfolder.php | 4 +-- files/js/files.js | 69 ++++++++++++++++++++++++--------------- files/templates/index.php | 1 + 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/files/ajax/newfile.php b/files/ajax/newfile.php index afc444bc0ac..2d1372f06ee 100644 --- a/files/ajax/newfile.php +++ b/files/ajax/newfile.php @@ -6,15 +6,35 @@ require_once('../../lib/base.php'); OC_JSON::checkLoggedIn(); // Get the params -$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : ''; -$filename = isset( $_GET['filename'] ) ? stripslashes($_GET['filename']) : ''; -$content = isset( $_GET['content'] ) ? $_GET['content'] : ''; +$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : ''; +$filename = isset( $_POST['filename'] ) ? stripslashes($_POST['filename']) : ''; +$content = isset( $_POST['content'] ) ? $_POST['content'] : ''; +$source = isset( $_POST['source'] ) ? stripslashes($_POST['source']) : ''; if($filename == '') { OC_JSON::error(array("data" => array( "message" => "Empty Filename" ))); exit(); } +if($source){ + if(substr($source,0,8)!='https://' and substr($source,0,7)!='http://'){ + OC_JSON::error(array("data" => array( "message" => "Not a valid source" ))); + exit(); + } + $sourceStream=fopen($source,'rb'); + $target=$dir.'/'.$filename; + $result=OC_Filesystem::file_put_contents($target,$sourceStream); + if($result){ + $mime=OC_Filesystem::getMimetype($target); + OC_JSON::success(array("data" => array('mime'=>$mime))); + exit(); + }else{ + OC_JSON::error(array("data" => array( "message" => "Error while downloading ".$source. ' to '.$target ))); + exit(); + } +} + + if(OC_Files::newFile($dir, $filename, 'file')) { if($content){ OC_Filesystem::file_put_contents($dir.'/'.$filename,$content); diff --git a/files/ajax/newfolder.php b/files/ajax/newfolder.php index 6db045c4e17..228e369fbef 100644 --- a/files/ajax/newfolder.php +++ b/files/ajax/newfolder.php @@ -6,8 +6,8 @@ require_once('../../lib/base.php'); OC_JSON::checkLoggedIn(); // Get the params -$dir = isset( $_GET['dir'] ) ? stripslashes($_GET['dir']) : ''; -$foldername = isset( $_GET['foldername'] ) ? stripslashes($_GET['foldername']) : ''; +$dir = isset( $_POST['dir'] ) ? stripslashes($_POST['dir']) : ''; +$foldername = isset( $_POST['foldername'] ) ? stripslashes($_POST['foldername']) : ''; if(trim($foldername) == '') { OC_JSON::error(array("data" => array( "message" => "Empty Foldername" ))); diff --git a/files/js/files.js b/files/js/files.js index f5dc40ad45d..a678e12cc2d 100644 --- a/files/js/files.js +++ b/files/js/files.js @@ -127,20 +127,6 @@ $(document).ready(function() { procesSelection(); }); - $('#file_newfolder_form').submit(function(event) { - event.preventDefault(); - $.ajax({ - url: 'ajax/newfolder.php', - data: "dir="+$('#dir').val()+"&foldername="+$('#file_newfolder_name').val(), - complete: function(data){boolOperationFinished(data, function(){ - var date=new Date(); - FileList.addDir($('#file_newfolder_name').val(),0,date); - $('#file_newfolder_name').val('New Folder'); - $('#file_newfolder_name').blur(); - });} - }); - }); - $('#file_newfolder_name').click(function(){ if($('#file_newfolder_name').val() == 'New Folder'){ $('#file_newfolder_name').val(''); @@ -312,10 +298,10 @@ $(document).ready(function() { var name=$(this).val(); switch(type){ case 'file': - $.ajax({ - url: OC.filePath('files','ajax','newfile.php'), - data: "dir="+encodeURIComponent($('#dir').val())+"&filename="+encodeURIComponent(name)+'&content=%20%0A', - complete: function(data){boolOperationFinished(data, function(){ + $.post( + OC.filePath('files','ajax','newfile.php'), + {dir:$('#dir').val(),filename:name,content:" \n"}, + function(data){ var date=new Date(); FileList.addFile(name,0,date); var tr=$('tr').filterAttr('data-file',name); @@ -323,18 +309,49 @@ $(document).ready(function() { getMimeIcon('text/plain',function(path){ tr.find('td.filename').attr('style','background-image:url('+path+')'); }); - });} - }); + } + ); break; case 'folder': - $.ajax({ - url: OC.filePath('files','ajax','newfolder.php'), - data: "dir="+encodeURIComponent($('#dir').val())+"&foldername="+encodeURIComponent(name), - complete: function(data){boolOperationFinished(data, function(){ + $.post( + OC.filePath('files','ajax','newfolder.php'), + {dir:$('#dir').val(),foldername:name}, + function(data){ var date=new Date(); FileList.addDir(name,0,date); - });} - }); + } + ); + break; + case 'web': + if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){ + name='http://'.name; + } + var localName=name; + if(localName.substr(localName.length-1,1)=='/'){//strip / + localName=localName.substr(0,localName.length-1) + } + if(localName.indexOf('/')){//use last part of url + localName=localName.split('/').pop(); + }else{//or the domain + localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.',''); + } + $.post( + OC.filePath('files','ajax','newfile.php'), + {dir:$('#dir').val(),source:name,filename:localName}, + function(result){ + if(result.status == 'success'){ + var date=new Date(); + FileList.addFile(localName,0,date); + var tr=$('tr').filterAttr('data-file',localName); + tr.data('mime',result.data.mime); + getMimeIcon(result.data.mime,function(path){ + tr.find('td.filename').attr('style','background-image:url('+path+')'); + }); + }else{ + + } + } + ); break; } var li=$(this).parent(); diff --git a/files/templates/index.php b/files/templates/index.php index 7e9505dec2f..7fc51c288e1 100644 --- a/files/templates/index.php +++ b/files/templates/index.php @@ -7,6 +7,7 @@
      From 9ccf46d350f2a17ae8234a348ec668e1f06fd9ec Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:02:44 +0100 Subject: [PATCH 23/61] Contacts: convert class attribute selectors to class selectors --- apps/contacts/js/contacts.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index d033e3f21cd..60ee8b9e56c 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -68,7 +68,7 @@ Contacts={ return $(obj).parents('.propertycontainer').first().data('element'); }, showHideContactInfo:function() { - var show = ($('#emaillist li[class*="propertycontainer"]').length > 0 || $('#phonelist li[class*="propertycontainer"]').length > 0 || $('#addressdisplay dl[class*="propertycontainer"]').length > 0); + var show = ($('#emaillist li.propertycontainer').length > 0 || $('#phonelist li.propertycontainer').length > 0 || $('#addressdisplay dl.propertycontainer').length > 0); console.log('showHideContactInfo: ' + show); if(show) { $('#contact_communication').show(); @@ -82,19 +82,19 @@ Contacts={ switch (type) { case 'EMAIL': console.log('emails: '+$('#emaillist>li').length); - if($('#emaillist li[class*="propertycontainer"]').length == 0) { + if($('#emaillist li.propertycontainer').length == 0) { $('#emails').hide(); } break; case 'TEL': console.log('phones: '+$('#phonelist>li').length); - if($('#phonelist li[class*="propertycontainer"]').length == 0) { + if($('#phonelist li.propertycontainer').length == 0) { $('#phones').hide(); } break; case 'ADR': console.log('addresses: '+$('#addressdisplay>dl').length); - if($('#addressdisplay dl[class*="propertycontainer"]').length == 0) { + if($('#addressdisplay dl.propertycontainer').length == 0) { $('#addresses').hide(); } break; @@ -183,7 +183,7 @@ Contacts={ dateFormat : 'dd-mm-yy' }); // Style phone types - $('#phonelist').find('select[class*="contacts_property"]').multiselect({ + $('#phonelist').find('select.contacts_property').multiselect({ noneSelectedText: t('contacts', 'Select type'), header: false, selectedList: 4, @@ -373,7 +373,7 @@ Contacts={ loadSingleProperties:function() { var props = ['BDAY', 'NICKNAME', 'ORG']; // Clear all elements - $('#ident .propertycontainer[class*="propertycontainer"]').each(function(){ + $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { $(this).data('checksum', ''); $(this).find('input').val(''); @@ -518,8 +518,8 @@ Contacts={ var checksum = container.data('checksum'); var name = container.data('element'); console.log('saveProperty: ' + name); - var fields = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serializeArray(); - var q = container.find('input[class*="contacts_property"],select[class*="contacts_property"]').serialize(); + var fields = container.find('input.contacts_property,select.contacts_property').serializeArray(); + var q = container.find('input.contacts_property,select.contacts_property').serialize(); if(q == '' || q == undefined) { console.log('Couldn\'t serialize elements.'); Contacts.UI.loading(container, false); @@ -708,7 +708,7 @@ Contacts={ }, loadAddresses:function(){ $('#addresses').hide(); - $('#addressdisplay dl[class*="propertycontainer"]').remove(); + $('#addressdisplay dl.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'); @@ -920,15 +920,15 @@ Contacts={ }, 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.template:first-child').clone().appendTo($('#emaillist')).show(); + $('#emaillist li.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(); + $('#emaillist li.propertycontainer').remove(); for(var mail in this.data.EMAIL) { this.addMail(); //$('#emaillist li:first-child').clone().appendTo($('#emaillist')).show(); @@ -950,9 +950,9 @@ Contacts={ 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.template:first-child').clone().appendTo($('#phonelist')); //.show(); + $('#phonelist li.template:last-child').find('select').addClass('contacts_property'); + $('#phonelist li.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({ @@ -966,7 +966,7 @@ Contacts={ }, loadPhones:function() { $('#phones').hide(); - $('#phonelist li[class*="propertycontainer"]').remove(); + $('#phonelist li.propertycontainer').remove(); for(var phone in this.data.TEL) { this.addPhone(); $('#phonelist li:last-child').find('select').multiselect('destroy'); From 46aa011ef90c02098ddfa75a93fe9bf2759b622a Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:03:33 +0100 Subject: [PATCH 24/61] Contacts: Add Organisation as Name property choice --- apps/contacts/js/contacts.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 60ee8b9e56c..94876f5cd09 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -448,6 +448,9 @@ Contacts={ $('#fn_select option').remove(); $('#fn_select').combobox('value', this.fn); var names = [this.fullname, this.givname + ' ' + this.famname, this.famname + ' ' + this.givname, this.famname + ', ' + this.givname]; + if(this.data.ORG) { + names[names.length]=this.data.ORG[0].value; + } $.each(names, function(key, value) { $('#fn_select') .append($('') From 97ab706a6a1d85f9e37589c9f88cedbdfa817f6e Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:05:30 +0100 Subject: [PATCH 25/61] Contacts: No random token for contactphoto --- apps/contacts/templates/part.contactphoto.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php index 9e3f5876cd1..8107650d161 100644 --- a/apps/contacts/templates/part.contactphoto.php +++ b/apps/contacts/templates/part.contactphoto.php @@ -3,7 +3,7 @@ $id = $_['id']; $wattr = isset($_['width'])?'width="'.$_['width'].'"':''; $hattr = isset($_['height'])?'height="'.$_['height'].'"':''; ?> - src="?id=&refresh=" /> + src="?id=" /> From ab760578f8141e5ab20345c2f84cb7a545c2e076 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Mon, 5 Mar 2012 22:06:01 +0100 Subject: [PATCH 26/61] Allow overflow of rightcontent area --- core/css/styles.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/css/styles.css b/core/css/styles.css index 62f5299ef78..f5a181c4529 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -60,7 +60,7 @@ input[type="submit"].highlight{ background:#ffc100; border:1px solid #db0; text- #leftcontent, .leftcontent { position:fixed; overflow: auto; top:6.4em; width:20em; background:#f8f8f8; border-right:1px solid #ddd; } #leftcontent li, .leftcontent li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; } #leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; } -#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; } +#rightcontent, .rightcontent { position:fixed; top: 6.4em; left: 32.5em; overflow: auto } /* LOG IN & INSTALLATION ------------------------------------------------------------ */ From 95995482034a607085d2cdc8000e5ea437c0cb1f Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:27:03 +0100 Subject: [PATCH 27/61] Contacts: change card parameter type of VCard::edit and VCard::add changed to OC_VObject --- apps/contacts/ajax/addcard.php | 2 +- apps/contacts/ajax/addcontact.php | 2 +- apps/contacts/ajax/addproperty.php | 2 +- apps/contacts/ajax/deleteproperty.php | 2 +- apps/contacts/ajax/savecrop.php | 2 +- apps/contacts/ajax/saveproperty.php | 2 +- apps/contacts/ajax/setproperty.php | 2 +- apps/contacts/import.php | 14 ++-- apps/contacts/lib/app.php | 2 +- apps/contacts/lib/vcard.php | 109 ++++++++------------------ 10 files changed, 51 insertions(+), 88 deletions(-) diff --git a/apps/contacts/ajax/addcard.php b/apps/contacts/ajax/addcard.php index b1dc69a4691..49a4a16170b 100644 --- a/apps/contacts/ajax/addcard.php +++ b/apps/contacts/ajax/addcard.php @@ -92,7 +92,7 @@ foreach( $add as $propname){ } } } -$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); +$id = OC_Contacts_VCard::add($aid,$vcard); if(!$id) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('There was an error adding the contact.')))); OC_Log::write('contacts','ajax/addcard.php: Recieved non-positive ID on adding card: '.$id, OC_Log::ERROR); diff --git a/apps/contacts/ajax/addcontact.php b/apps/contacts/ajax/addcontact.php index 5d17631caa4..839a3919981 100644 --- a/apps/contacts/ajax/addcontact.php +++ b/apps/contacts/ajax/addcontact.php @@ -52,7 +52,7 @@ $vcard->setUID(); $vcard->setString('FN',$fn); $vcard->setString('N',$n); -$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); +$id = OC_Contacts_VCard::add($aid,$vcard); if(!$id) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->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); diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php index 028974e1c66..b6b5dc7c416 100644 --- a/apps/contacts/ajax/addproperty.php +++ b/apps/contacts/ajax/addproperty.php @@ -113,7 +113,7 @@ foreach ($parameters as $key=>$element) { } $checksum = md5($vcard->children[$line]->serialize()); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error adding contact property.')))); OC_Log::write('contacts','ajax/addproperty.php: Error updating contact property: '.$name, OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/deleteproperty.php b/apps/contacts/ajax/deleteproperty.php index a9afffaad4c..ab0958cac58 100644 --- a/apps/contacts/ajax/deleteproperty.php +++ b/apps/contacts/ajax/deleteproperty.php @@ -39,7 +39,7 @@ if(is_null($line)){ unset($vcard->children[$line]); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error deleting contact property.')))); OC_Log::write('contacts','ajax/deleteproperty.php: Error deleting contact property', OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php index 1a84f6fdfae..ffbfaeb6e38 100644 --- a/apps/contacts/ajax/savecrop.php +++ b/apps/contacts/ajax/savecrop.php @@ -95,7 +95,7 @@ if(file_exists($tmp_path)) { 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())) { + if(!OC_Contacts_VCard::edit($id,$card)) { bailOut('Error saving contact.'); } unlink($tmpfname); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 6f8366243fe..db209fedfc7 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -122,7 +122,7 @@ switch($element) { $checksum = md5($vcard->children[$line]->serialize()); debug('New checksum: '.$checksum); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { OC_JSON::error(array('data' => array('message' => OC_Contacts_App::$l10n->t('Error updating contact property.')))); OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); exit(); diff --git a/apps/contacts/ajax/setproperty.php b/apps/contacts/ajax/setproperty.php index f9e2a8e8647..8e07b4a8f1c 100644 --- a/apps/contacts/ajax/setproperty.php +++ b/apps/contacts/ajax/setproperty.php @@ -80,7 +80,7 @@ foreach($missingparameters as $i){ // NOTE: This checksum is not used..? $checksum = md5($vcard->children[$line]->serialize()); -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { +if(!OC_Contacts_VCard::edit($id,$vcard)) { 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(); diff --git a/apps/contacts/import.php b/apps/contacts/import.php index 4638bf0d73c..04cfc397d56 100644 --- a/apps/contacts/import.php +++ b/apps/contacts/import.php @@ -97,11 +97,15 @@ if(is_writable('import_tmp/')){ fclose($progressfopen); } if(count($parts) == 1){ - OC_Contacts_VCard::add($id, $file); -}else{ - foreach($importready as $import){ - OC_Contacts_VCard::add($id, $import); + $importready = array($file); +} +foreach($importready as $import){ + $card = OC_VObject::parse($import); + if (!$card) { + OC_Log::write('contacts','Import: skipping card. Error parsing VCard: '.$import, OC_Log::ERROR); + continue; // Ditch cards that can't be parsed by Sabre. } + OC_Contacts_VCard::add($id, $card); } //done the import if(is_writable('import_tmp/')){ @@ -113,4 +117,4 @@ sleep(3); if(is_writable('import_tmp/')){ unlink($progressfile); } -OC_JSON::success(); \ No newline at end of file +OC_JSON::success(); diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index ce52df4b75e..e8c3087c8a2 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -92,7 +92,7 @@ class OC_Contacts_App { OC_Log::write('contacts','getContactVCard, found FN field: '.$vcard->__get('FN'), OC_Log::DEBUG); $n = implode(';', array_reverse(array_slice(explode(' ', $vcard->__get('FN')), 0, 2))).';;;'; $vcard->setString('N', $n); - OC_Contacts_VCard::edit( $id, $vcard->serialize()); + OC_Contacts_VCard::edit( $id, $vcard); } else { // Else just add an empty 'N' field :-P $vcard->setString('N', 'Unknown;Name;;;'); } diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 0b8d95a2d97..9324f158cc7 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -217,31 +217,35 @@ class OC_Contacts_VCard{ /** * @brief Adds a card - * @param integer $id Addressbook id - * @param string $data vCard file - * @return insertid on success or null if card is not parseable. + * @param integer $aid Addressbook id + * @param OC_VObject $card vCard file + * @param string $uri the uri of the card, default based on the UID + * @return insertid on success or null if no card. */ - public static function add($id,$data){ - $fn = null; - - $card = OC_VObject::parse($data); - if(!is_null($card)){ - self::updateValuesFromAdd($card); - $data = $card->serialize(); - } - else{ - OC_Log::write('contacts','OC_Contacts_VCard::add. Error parsing VCard: '.$data,OC_Log::ERROR); - return null; // Ditch cards that can't be parsed by Sabre. + public static function add($aid, $card, $uri=null){ + if(is_null($card)){ + OC_Log::write('contacts','OC_Contacts_VCard::add. No vCard supplied', OC_Log::ERROR); + return null; }; + self::updateValuesFromAdd($card); + $fn = $card->getAsString('FN'); - $uid = $card->getAsString('UID'); - $uri = $uid.'.vcf'; + if (empty($fn)) { + $fn = null; + } + + if (!$uri) { + $uid = $card->getAsString('UID'); + $uri = $uid.'.vcf'; + } + + $data = $card->serialize(); $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); - $result = $stmt->execute(array($id,$fn,$data,$uri,time())); + $result = $stmt->execute(array($aid,$fn,$data,$uri,time())); $newid = OC_DB::insertid('*PREFIX*contacts_cards'); - OC_Contacts_Addressbook::touch($id); + OC_Contacts_Addressbook::touch($aid); return $newid; } @@ -255,49 +259,31 @@ class OC_Contacts_VCard{ */ public static function addFromDAVData($id,$uri,$data){ $card = OC_VObject::parse($data); - if(!is_null($card)){ - self::updateValuesFromAdd($card); - $data = $card->serialize(); - } else { - OC_Log::write('contacts','OC_Contacts_VCard::addFromDAVData. Error parsing VCard: '.$data, OC_Log::ERROR); - return null; // Ditch cards that can't be parsed by Sabre. - }; - $fn = $card->getAsString('FN'); - - $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); - $result = $stmt->execute(array($id,$fn,$data,$uri,time())); - $newid = OC_DB::insertid('*PREFIX*contacts_cards'); - - OC_Contacts_Addressbook::touch($id); - - return $newid; + return self::add($id, $data, $uri); } /** * @brief edits a card * @param integer $id id of card - * @param string $data vCard file + * @param OC_VObject $card vCard file * @return boolean */ - public static function edit($id, $data){ + public static function edit($id, OC_VObject $card){ $oldcard = self::find($id); - $fn = null; - $card = OC_VObject::parse($data); - if(!is_null($card)){ - foreach($card->children as $property){ - if($property->name == 'FN'){ - $fn = $property->value; - break; - } - } - } else { + if(is_null($card)) { return false; } + + $fn = $card->getAsString('FN'); + if (empty($fn)) { + $fn = null; + } + $now = new DateTime; $card->setString('REV', $now->format(DateTime::W3C)); - $data = $card->serialize(); + $data = $card->serialize(); $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); $result = $stmt->execute(array($fn,$data,time(),$id)); @@ -315,27 +301,8 @@ class OC_Contacts_VCard{ */ public static function editFromDAVData($aid,$uri,$data){ $oldcard = self::findWhereDAVDataIs($aid,$uri); - - $fn = null; $card = OC_VObject::parse($data); - if(!is_null($card)){ - foreach($card->children as $property){ - if($property->name == 'FN'){ - $fn = $property->value; - break; - } - } - } - $now = new DateTime; - $card->setString('REV', $now->format(DateTime::W3C)); - $data = $card->serialize(); - - $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); - $result = $stmt->execute(array($fn,$data,time(),$oldcard['id'])); - - OC_Contacts_Addressbook::touch($oldcard['addressbookid']); - - return true; + return self::edit($oldcard['id'], $card); } /** @@ -351,14 +318,6 @@ class OC_Contacts_VCard{ return true; } - /** - * @brief Creates a UID - * @return string - */ - public static function createUID(){ - return substr(md5(rand().time()),0,10); - } - /** * @brief deletes a card with the data provided by sabredav * @param integer $aid Addressbook id From d8cfe77ba5348d29a9e2b046e2c7efc1dd4758cb Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:29:23 +0100 Subject: [PATCH 28/61] Contacts: small fixes and cleanups --- apps/calendar/lib/object.php | 11 +---------- apps/contacts/ajax/loadphoto.php | 6 ++---- apps/contacts/lib/vcard.php | 5 +++++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/apps/calendar/lib/object.php b/apps/calendar/lib/object.php index b84e575bc83..e0c0e83d5d0 100644 --- a/apps/calendar/lib/object.php +++ b/apps/calendar/lib/object.php @@ -96,8 +96,7 @@ class OC_Calendar_Object{ list($type,$startdate,$enddate,$summary,$repeating,$uid) = self::extractData($object); if(is_null($uid)){ - $uid = self::createUID(); - $object->add('UID',$uid); + $object->setUID(); $data = $object->serialize(); } @@ -208,14 +207,6 @@ class OC_Calendar_Object{ return true; } - /** - * @brief Creates a UID - * @return string - */ - protected static function createUID(){ - return substr(md5(rand().time()),0,10); - } - /** * @brief Extracts data from a vObject-Object * @param Sabre_VObject $object diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 358e046942b..1f4cde0b535 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -18,8 +18,6 @@ * 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'); @@ -33,7 +31,7 @@ OC_JSON::checkAppEnabled('contacts'); function bailOut($msg) { OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('contacts','ajax/savecrop.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('contacts','ajax/loadphoto.php: '.$msg, OC_Log::DEBUG); exit(); } @@ -42,7 +40,7 @@ $image = null; $id = isset($_GET['id']) ? $_GET['id'] : ''; if($id == '') { - bailOut('Missing contact id.'); + bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php index 9324f158cc7..eade8859e76 100644 --- a/apps/contacts/lib/vcard.php +++ b/apps/contacts/lib/vcard.php @@ -174,6 +174,9 @@ class OC_Contacts_VCard{ if($property->name == 'UID'){ $uid = $property->value; } + if($property->name == 'ORG'){ + $org = $property->value; + } if($property->name == 'EMAIL' && is_null($email)){ // only use the first email as substitute for missing N or FN. $email = $property->value; } @@ -184,6 +187,8 @@ class OC_Contacts_VCard{ $fn = join(' ', array_reverse(array_slice(explode(';', $n), 0, 2))); } elseif($email) { $fn = $email; + } elseif($org) { + $fn = $org; } else { $fn = 'Unknown Name'; } From 340320625e8da301e4c03752143db6d4837ca545 Mon Sep 17 00:00:00 2001 From: Bart Visscher Date: Wed, 7 Mar 2012 21:50:55 +0100 Subject: [PATCH 29/61] Contacts: Add UI for categories --- apps/contacts/ajax/saveproperty.php | 1 + apps/contacts/index.php | 2 + apps/contacts/js/contacts.js | 10 +++- apps/contacts/js/jquery.multi-autocomplete.js | 47 +++++++++++++++++++ apps/contacts/lib/app.php | 4 ++ apps/contacts/templates/index.php | 1 + apps/contacts/templates/part.contact.php | 3 ++ 7 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 apps/contacts/js/jquery.multi-autocomplete.js diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index db209fedfc7..c1d5cebfd06 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -92,6 +92,7 @@ switch($element) { case 'N': case 'ORG': case 'NICKNAME': + case 'CATEGORIES': debug('Setting string:'.$name.' '.$value); $vcard->setString($name, $value); break; diff --git a/apps/contacts/index.php b/apps/contacts/index.php index 0a21ddd04b6..b8dfc1b7709 100644 --- a/apps/contacts/index.php +++ b/apps/contacts/index.php @@ -48,6 +48,7 @@ OC_Util::addScript('contacts','contacts'); OC_Util::addScript('contacts','jquery.combobox'); OC_Util::addScript('contacts','jquery.inview'); OC_Util::addScript('contacts','jquery.Jcrop'); +OC_Util::addScript('contacts','jquery.multi-autocomplete'); OC_Util::addStyle('','jquery.multiselect'); //OC_Util::addStyle('contacts','styles'); OC_Util::addStyle('contacts','jquery.combobox'); @@ -58,6 +59,7 @@ $tmpl = new OC_Template( "contacts", "index", "user" ); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); $tmpl->assign('property_types',$property_types); +$tmpl->assign('categories',OC_Contacts_App::getCategories()); $tmpl->assign('phone_types',$phone_types); $tmpl->assign('addressbooks', $addressbooks); $tmpl->assign('contacts', $contacts); diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 94876f5cd09..0c63b5fcb76 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -223,6 +223,7 @@ Contacts={ click: function() { $(this).dialog('close'); } } ] ); + $('#categories').multiple_autocomplete({source: categories}); Contacts.UI.loadListHandlers(); }, Card:{ @@ -371,7 +372,7 @@ Contacts={ this.loadSingleProperties(); }, loadSingleProperties:function() { - var props = ['BDAY', 'NICKNAME', 'ORG']; + var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES']; // Clear all elements $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { @@ -407,6 +408,12 @@ Contacts={ $('#contact_identity').find('#org_label').show(); $('#contact_identity').find('#org_value').show(); break; + case 'CATEGORIES': + $('#contact_identity').find('#categories').val(value); + $('#contact_identity').find('#categories_value').data('checksum', checksum); + $('#contact_identity').find('#categories_label').show(); + $('#contact_identity').find('#categories_value').show(); + break; } } else { $('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().show(); @@ -596,6 +603,7 @@ Contacts={ case 'NICKNAME': case 'ORG': case 'BDAY': + case 'CATEGORIES': $('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js new file mode 100644 index 00000000000..4be8d901c96 --- /dev/null +++ b/apps/contacts/js/jquery.multi-autocomplete.js @@ -0,0 +1,47 @@ +/** + * Inspired by http://jqueryui.com/demos/autocomplete/#multiple + */ + +(function( $ ) { + $.widget('ui.multiple_autocomplete', { + _create: function() { + function split( val ) { + return val.split( /,\s*/ ); + } + function extractLast( term ) { + return split( term ).pop(); + } + //console.log('_create: ' + this.options['id']); + var self = this; + this.element.bind( "keydown", function( event ) { + if ( event.keyCode === $.ui.keyCode.TAB && + $( this ).data( "autocomplete" ).menu.active ) { + event.preventDefault(); + } + }) + .autocomplete({ + minLength: 0, + source: function( request, response ) { + // delegate back to autocomplete, but extract the last term + response( $.ui.autocomplete.filter( + self.options.source, extractLast( request.term ) ) ); + }, + focus: function() { + // prevent value inserted on focus + return false; + }, + select: function( event, ui ) { + var terms = split( this.value ); + // remove the current input + terms.pop(); + // add the selected item + terms.push( ui.item.value ); + // add placeholder to get the comma-and-space at the end + terms.push( "" ); + this.value = terms.join( ", " ); + return false; + } + }); + }, + }); +})( jQuery ); diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index 1fa441475d2..cc33c733007 100644 --- a/apps/contacts/lib/app.php +++ b/apps/contacts/lib/app.php @@ -155,6 +155,10 @@ class OC_Contacts_App { } } + public static function getCategories() { + return self::$categories->categories(); + } + public static function setLastModifiedHeader($contact) { $rev = $contact->getAsString('REV'); if ($rev) { diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php index e81597f23d6..efd797e25cb 100644 --- a/apps/contacts/templates/index.php +++ b/apps/contacts/templates/index.php @@ -1,5 +1,6 @@
      diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5be20964f4b..783dc469075 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -13,6 +13,7 @@ $id = isset($_['id']) ? $_['id'] : '';
    • t('Phone'); ?>
    • t('Email'); ?>
    • t('Address'); ?>
    • +
    • t('Categories'); ?>
    • @@ -53,6 +54,8 @@ $id = isset($_['id']) ? $_['id'] : ''; + + From 91d85e9b1640e9d62707cd1c232c8c7a9fc8b9c3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 7 Mar 2012 22:57:37 +0100 Subject: [PATCH 30/61] Use OC.dialogs. --- apps/contacts/js/contacts.js | 110 +++++++++++++---------------------- 1 file changed, 39 insertions(+), 71 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 626672cf788..d86842a4317 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -19,9 +19,9 @@ Categories={ var response = jQuery.parseJSON(response); console.log('status: ' + status + ', response: ' + response + ', response.status:' + response.status); if(response.status == 'error'){ - alert(response.data.message); + OC.dialogs.alert(response.data.message, 'Error'); } else { - alert(response); + OC.dialogs.alert(response, 'Error'); } } catch(e) { $('#edit_categories_dialog').dialog({ @@ -71,7 +71,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); }, @@ -81,7 +81,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); return false; @@ -92,7 +92,7 @@ Categories={ if(jsondata.status == 'success'){ Categories._update(jsondata.data.categories); } else { - alert(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, 'Error'); } }); }, @@ -112,13 +112,13 @@ Categories={ Contacts={ UI:{ notImplemented:function() { - Contacts.UI.messageBox(t('contacts', 'Not implemented'), t('contacts', 'Sorry, this functionality has not been implemented yet')); + OC.dialogs.alert(t('contacts', 'Sorry, this functionality has not been implemented yet'), t('contacts', 'Not implemented')); }, 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.')); + OC.dialogs.alert(t('contacts', 'Couldn\'t get a valid address.'), t('contacts', 'Error')); return; } // FIXME: I suck at regexp. /Tanghus @@ -151,7 +151,7 @@ Contacts={ 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.')); + OC.dialogs.alert(t('contacts', 'Please enter an email address.'), t('contacts', 'Error')); return; } window.location.href='mailto:' + adr; @@ -214,38 +214,6 @@ Contacts={ $('#carddav_url').show(); $('#carddav_url_close').show(); }, - messageBox:function(title, msg) { - if(msg.toLowerCase().indexOf('auth') != -1) { - // fugly hack, I know - 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(jsondata){ - if(jsondata.status != 'error'){ - $('#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); - } - }); - } else { - alert(jsondata.data.message); - } - }); - }; - }, loadListHandlers:function() { //$('.add,.delete').hide(); $('.globe,.mail,.delete,.edit').tipsy(); @@ -360,12 +328,12 @@ Contacts={ if(jsondata.status == 'success'){ Contacts.UI.Card.loadContact(jsondata.data); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } @@ -377,7 +345,7 @@ Contacts={ $('#rightcontent').data('id',''); $('#rightcontent').html(jsondata.data.page); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } @@ -417,7 +385,7 @@ Contacts={ } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -426,7 +394,7 @@ Contacts={ // TODO: Add to contacts list. } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -452,13 +420,13 @@ Contacts={ $('#rightcontent').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -604,7 +572,7 @@ Contacts={ console.log('Setting checksum: ' + jsondata.data.checksum); $('#categories_value').data('checksum', jsondata.data.checksum); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); }, @@ -633,7 +601,7 @@ Contacts={ $('#rightcontent').html(jsondata.data.page); Contacts.UI.Card.editName(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -676,7 +644,7 @@ Contacts={ return false; } if($(obj).hasClass('nonempty') && $(obj).val().trim() == '') { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'This property has to be non-empty.')); + OC.dialogs.alert(t('contacts', 'This property has to be non-empty.'), t('contacts', 'Error')); return false; } container = $(obj).parents('.propertycontainer').first(); // get the parent holding the metadata. @@ -705,7 +673,7 @@ Contacts={ return true; } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); Contacts.UI.loading(container, false); $(obj).removeAttr('disabled'); return false; @@ -724,7 +692,7 @@ Contacts={ return true; } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); Contacts.UI.loading(container, false); $(obj).removeAttr('disabled'); return false; @@ -792,13 +760,13 @@ Contacts={ $('#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')); + OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error')); Contacts.UI.loading(obj, false); } } else{ Contacts.UI.loading(obj, false); - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); } else { // Property hasn't been saved so there's nothing to delete. @@ -813,7 +781,7 @@ Contacts={ $('#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')); + OC.dialogs.alert(t('contacts', '\'deleteProperty\' called without type argument. Please report at bugs.owncloud.org'), t('contacts', 'Error')); } } }, @@ -1034,7 +1002,7 @@ Contacts={ }, uploadPhoto:function(filelist) { if(!filelist) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts','No files selected for upload.')); + OC.dialogs.alert(t('contacts','No files selected for upload.'), t('contacts', 'Error')); return; } //var file = filelist.item(0); @@ -1043,7 +1011,7 @@ Contacts={ 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.')); + OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts', 'Error')); return; } else { target.load(function(){ @@ -1052,7 +1020,7 @@ Contacts={ 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); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } }); form.submit(); @@ -1066,7 +1034,7 @@ Contacts={ $('#contacts_details_photo_wrapper').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); $('#file_upload_form').show(); @@ -1085,7 +1053,7 @@ Contacts={ $('#edit_photo_dialog_img').html(jsondata.data.page); } else{ - Contacts.UI.messageBox(jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); if($('#edit_photo_dialog').dialog('isOpen') == true){ @@ -1104,7 +1072,7 @@ Contacts={ // load cropped photo. $('#contacts_details_photo_wrapper').html(response.data.page); }else{ - Contacts.UI.messageBox(t('contacts','Error'), response.data.message); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } }); $('#contacts [data-id="'+this.id+'"]').find('a').css('background','url(thumbnail.php?id='+this.id+'&refresh=1'+Math.random()+') no-repeat'); @@ -1244,7 +1212,7 @@ Contacts={ Contacts.UI.Contacts.update(); Contacts.UI.Addressbooks.overview(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert('Error: ' + data.message); } }); @@ -1259,7 +1227,7 @@ Contacts={ var description = $("#description_"+bookid).val(); if(displayname.length == 0) { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Displayname cannot be empty.')); + OC.dialogs.alert(t('contacts', 'Displayname cannot be empty.'), t('contacts', 'Error')); return false; } var url; @@ -1274,7 +1242,7 @@ Contacts={ $(button).closest('tr').prev().html(jsondata.page).show().next().remove(); Contacts.UI.Contacts.update(); } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); } }); }, @@ -1294,7 +1262,7 @@ Contacts={ Contacts.UI.Card.update(); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -1344,7 +1312,7 @@ $(document).ready(function(){ Contacts.UI.Card.loadContact(jsondata.data); } else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); @@ -1443,17 +1411,17 @@ $(document).ready(function(){ 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.')); + OC.dialogs.alert(t('contacts','The file you are trying to upload exceed the maximum size for file uploads on this server.'), t('contacts','Upload too large')); 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.')); + OC.dialogs.alert(t('contacts','Only image files can be used as profile picture.'), t('contacts','Wrong file type')); 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.')) + OC.dialogs.alert(t('contacts', 'Your browser doesn\'t support AJAX upload. Please click on the profile picture to select a photo to upload.'), t('contacts', 'Error')) } fileUpload = xhr.upload, xhr.onreadystatechange = function() { @@ -1463,11 +1431,11 @@ $(document).ready(function(){ 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); + OC.dialogs.alert(xhr.status + ': ' + xhr.responseText, t('contacts', 'Error')); } } else { //alert(xhr.responseText); - Contacts.UI.messageBox(t('contacts', 'Error'), response.data.message); + OC.dialogs.alert(response.data.message, t('contacts', 'Error')); } // stop loading indicator //$('#contacts_details_photo_progress').hide(); From 700a120c225f056070f1c5601ca91f88b3bbe870 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 8 Mar 2012 15:47:49 +0100 Subject: [PATCH 31/61] fix write hook for gallery --- apps/gallery/lib/hooks_handlers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index 3c101b1f8a1..480e41a8bf9 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -68,7 +68,7 @@ class OC_Gallery_Hooks_Handlers { if (!self::isPhoto($fullpath)) return; - $path = substr($fullpath, 0, strrpos($fullpath, '/')); + $path = dirname($fullpath); if (!self::pathInRoot($path)) return; OC_Gallery_Scanner::scanDir($path, $albums); From 8495e1a63e20e9cae0f1c1835de558606d1ecfc4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 22 Feb 2012 11:25:45 +0100 Subject: [PATCH 32/61] Add missing file. --- apps/contacts/ajax/loadcard.php | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 apps/contacts/ajax/loadcard.php diff --git a/apps/contacts/ajax/loadcard.php b/apps/contacts/ajax/loadcard.php new file mode 100644 index 00000000000..037fe2a6df2 --- /dev/null +++ b/apps/contacts/ajax/loadcard.php @@ -0,0 +1,59 @@ + + * + * 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/loadcard.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/loadcard.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'); + +$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); +$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); +$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); + +$tmpl = new OC_Template('contacts','part.contact'); +$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); +$tmpl->assign('uploadMaxHumanFilesize', OC_Helper::humanFileSize($maxUploadFilesize)); +$tmpl->assign('adr_types',$adr_types); +$tmpl->assign('phone_types',$phone_types); +$tmpl->assign('id',''); +$page = $tmpl->fetchPage(); + +OC_JSON::success(array('data' => array( 'page' => $page ))); From bc5d9f58684acad4602bc7d43170b040a15f6dd5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 9 Mar 2012 07:36:05 +0100 Subject: [PATCH 33/61] Parses malformed N fields a bit more tolerantly. Thanks to nibbler for the patch :-) --- apps/contacts/js/contacts.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 94876f5cd09..4ede2ff4336 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -424,11 +424,11 @@ Contacts={ } else { narray = this.data.N[0]['value']; } - this.famname = narray[0]; - this.givname = narray[1]; - this.addname = narray[2]; - this.honpre = narray[3]; - this.honsuf = narray[4]; + this.famname = narray[0] || ''; + 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 + ' '; } From 8228a554a4d2cbdadb7187d026e1b5c25d2b404a Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 9 Mar 2012 10:29:00 +0100 Subject: [PATCH 34/61] Temporarily disabled multi_autoselect. --- apps/contacts/js/contacts.js | 14 +++++++------- apps/contacts/templates/part.contact.php | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 5f6129ca654..3ca6bc1ae9a 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -252,12 +252,12 @@ Contacts={ $('#bday').datepicker({ dateFormat : 'dd-mm-yy' }); - /*$('#categories_value').find('select').multiselect({ + $('#categories_value').find('select').multiselect({ noneSelectedText: t('contacts', 'Select categories'), header: false, selectedList: 6, classes: 'categories' - });*/ + }); // Style phone types $('#phonelist').find('select.contacts_property').multiselect({ noneSelectedText: t('contacts', 'Select type'), @@ -299,7 +299,7 @@ Contacts={ click: function() { $(this).dialog('close'); } } ] ); - $('#categories').multiple_autocomplete({source: categories}); + //$('#categories').multiple_autocomplete({source: categories}); Contacts.UI.loadListHandlers(); }, Card:{ @@ -440,7 +440,7 @@ Contacts={ $('#rightcontent').data('id',this.id); console.log('loaded: ' + this.data.FN[0]['value']); this.populateNameFields(); - //this.loadCategories(); + this.loadCategories(); this.loadPhoto(); this.loadMails(); this.loadPhones(); @@ -458,7 +458,7 @@ Contacts={ } }, loadSingleProperties:function() { - var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES']; + var props = ['BDAY', 'NICKNAME', 'ORG']; //, 'CATEGORIES']; // Clear all elements $('#ident .propertycontainer').each(function(){ if(props.indexOf($(this).data('element')) > -1) { @@ -494,12 +494,12 @@ Contacts={ $('#contact_identity').find('#org_label').show(); $('#contact_identity').find('#org_value').show(); break; - case 'CATEGORIES': + /*case 'CATEGORIES': $('#contact_identity').find('#categories').val(value); $('#contact_identity').find('#categories_value').data('checksum', checksum); $('#contact_identity').find('#categories_label').show(); $('#contact_identity').find('#categories_value').show(); - break; + break;*/ } } else { $('#contacts_propertymenu a[data-type="'+props[prop]+'"]').parent().show(); diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 115458470ba..67838238e2b 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -55,15 +55,15 @@ $id = isset($_['id']) ? $_['id'] : ''; - - - + + -
      From 9e83f0247ff9c259a3dbf86106a6eeb06de42ba4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 13 Mar 2012 14:28:38 +0100 Subject: [PATCH 58/61] Added sync path for iOS/OS X. --- apps/contacts/templates/settings.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/contacts/templates/settings.php b/apps/contacts/templates/settings.php index 8673e4521d9..f56de0ec8b0 100644 --- a/apps/contacts/templates/settings.php +++ b/apps/contacts/templates/settings.php @@ -1,7 +1,12 @@ -
      +
      t('Contacts'); ?>
      - t('CardDAV syncing address:'); ?> -
      + t('CardDAV syncing addresses:'); ?> +
      +
      t('Primary address (Kontact et al)'); ?>
      +
      /
      +
      t('iOS/OS X'); ?>
      +
      /principals//
      +
      From 4a91c6dbed149fd8828b6652c73db8e796c3c055 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 13 Mar 2012 14:56:03 +0100 Subject: [PATCH 59/61] Make PHOTO deletable. --- apps/contacts/ajax/loadphoto.php | 11 ++++++++++- apps/contacts/js/contacts.js | 5 ++++- apps/contacts/templates/part.contact.php | 5 +++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 1f4cde0b535..2c8bb7bf1ed 100644 --- a/apps/contacts/ajax/loadphoto.php +++ b/apps/contacts/ajax/loadphoto.php @@ -43,8 +43,17 @@ if($id == '') { bailOut(OC_Contacts_App::$l10n->t('Missing contact id.')); } +$checksum = ''; +$vcard = OC_Contacts_App::getContactVCard( $id ); +foreach($vcard->children as $property){ + if($property->name == 'PHOTO') { + $checksum = md5($property->serialize()); + break; + } +} + $tmpl = new OC_TEMPLATE("contacts", "part.contactphoto"); $tmpl->assign('id', $id); $page = $tmpl->fetchPage(); -OC_JSON::success(array('data' => array('page'=>$page))); +OC_JSON::success(array('data' => array('page'=>$page, 'checksum'=>$checksum))); ?> diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js index 13d71be384d..18214cb1cc5 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -662,7 +662,9 @@ Contacts={ } else if(type == 'single') { var proptype = Contacts.UI.propertyTypeFor(obj); console.log('deleteProperty, hiding: ' + proptype); - if(proptype == 'NOTE') { + var othertypes = ['NOTE', 'PHOTO']; + if(othertypes.indexOf(proptype) != -1) { + console.log('NOTE or PHOTO'); Contacts.UI.propertyContainerFor(obj).hide(); Contacts.UI.propertyContainerFor(obj).data('checksum', ''); } else { @@ -943,6 +945,7 @@ Contacts={ $.getJSON('ajax/loadphoto.php',{'id':this.id},function(jsondata){ if(jsondata.status == 'success'){ //alert(jsondata.data.page); + $('#file_upload_form').data('checksum', jsondata.data.checksum); $('#contacts_details_photo_wrapper').html(jsondata.data.page); } else{ diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index a3b4917ae98..cb1e080a40a 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -23,8 +23,9 @@ $id = isset($_['id']) ? $_['id'] : '';
      - +
      +
      @@ -63,7 +64,7 @@ $id = isset($_['id']) ? $_['id'] : ''; - +