diff options
author | Tom Needham <needham.thomas@gmail.com> | 2012-03-27 20:19:38 +0000 |
---|---|---|
committer | Tom Needham <needham.thomas@gmail.com> | 2012-03-27 20:19:38 +0000 |
commit | c8acd4a594d4ed21f9becca927762aa83f24c3d3 (patch) | |
tree | 270141aa92ec900831d976029551699770807725 /apps | |
parent | 892343c7c11e7ba967f69174820a501b3954badb (diff) | |
parent | cb2dd97509ffd039fbd321aea4a8d631e3effcc7 (diff) | |
download | nextcloud-server-c8acd4a594d4ed21f9becca927762aa83f24c3d3.tar.gz nextcloud-server-c8acd4a594d4ed21f9becca927762aa83f24c3d3.zip |
Merge branch 'master' into migration
Diffstat (limited to 'apps')
101 files changed, 3617 insertions, 2267 deletions
diff --git a/apps/bookmarks/bookmarksHelper.php b/apps/bookmarks/bookmarksHelper.php index 8def7401e2f..7ada69014fb 100644 --- a/apps/bookmarks/bookmarksHelper.php +++ b/apps/bookmarks/bookmarksHelper.php @@ -71,7 +71,7 @@ function getURLMetadata($url) { return $metadata; } -function addBookmark($url, $title='', $tags='') { +function addBookmark($url, $title, $tags='') { $CONFIG_DBTYPE = OC_Config::getValue( "dbtype", "sqlite" ); if( $CONFIG_DBTYPE == 'sqlite' or $CONFIG_DBTYPE == 'sqlite3' ){ $_ut = "strftime('%s','now')"; @@ -93,6 +93,11 @@ function addBookmark($url, $title='', $tags='') { $title = $metadata['title']; } + if(empty($title)) { + $l = new OC_L10N('bookmarks'); + $title = $l->t('unnamed'); + } + $params=array( htmlspecialchars_decode($url), htmlspecialchars_decode($title), diff --git a/apps/bookmarks/js/bookmarks.js b/apps/bookmarks/js/bookmarks.js index fa5adde2545..9502af0a00d 100644 --- a/apps/bookmarks/js/bookmarks.js +++ b/apps/bookmarks/js/bookmarks.js @@ -9,9 +9,7 @@ $(document).ready(function() { fillWindow($('.bookmarks_list')); }); $(window).resize(); - $($('.bookmarks_list')).scroll(updateOnBottom); - - $('.bookmarks_list').empty(); + $('.bookmarks_list').scroll(updateOnBottom).empty().width($('#content').width()); getBookmarks(); }); @@ -145,7 +143,7 @@ function updateBookmarksList(bookmark) { '<p class="bookmark_title">'+ '<a href="' + encodeEntities(bookmark.url) + '" target="_blank" class="bookmark_link">' + encodeEntities(bookmark.title) + '</a>' + '</p>' + - '<p class="bookmark_url">' + encodeEntities(bookmark.url) + '</p>' + + '<p class="bookmark_url"><a href="' + encodeEntities(bookmark.url) + '" target="_blank" class="bookmark_link">' + encodeEntities(bookmark.url) + '</a></p>' + '</div>' ); if(taglist != '') { diff --git a/apps/calendar/ajax/events.php b/apps/calendar/ajax/events.php index a912889f292..c62f93c540e 100755 --- a/apps/calendar/ajax/events.php +++ b/apps/calendar/ajax/events.php @@ -8,11 +8,13 @@ require_once ('../../../lib/base.php'); require_once('when/When.php'); - +$l = new OC_L10N('calendar'); +$unnamed = $l->t('unnamed'); function create_return_event($event, $vevent){ $return_event = array(); + global $unnamed; $return_event['id'] = (int)$event['id']; - $return_event['title'] = htmlspecialchars($event['summary']); + $return_event['title'] = htmlspecialchars(($event['summary']!=NULL || $event['summary'] != '')?$event['summary']: $unnamed); $return_event['description'] = isset($vevent->DESCRIPTION)?htmlspecialchars($vevent->DESCRIPTION->value):''; $last_modified = $vevent->__get('LAST-MODIFIED'); if ($last_modified){ @@ -27,8 +29,13 @@ function create_return_event($event, $vevent){ OC_JSON::checkLoggedIn(); OC_JSON::checkAppEnabled('calendar'); -$start = DateTime::createFromFormat('U', $_GET['start']); -$end = DateTime::createFromFormat('U', $_GET['end']); +if(version_compare(PHP_VERSION, '5.3.0', '>=')){ + $start = DateTime::createFromFormat('U', $_GET['start']); + $end = DateTime::createFromFormat('U', $_GET['end']); +}else{ + $start = new DateTime('@' . $_GET['start']); + $end = new DateTime('@' . $_GET['end']); +} $calendar_id = $_GET['calendar_id']; if (is_numeric($calendar_id)) { diff --git a/apps/calendar/appinfo/app.php b/apps/calendar/appinfo/app.php index 0968737219a..f297c4d16d4 100644 --- a/apps/calendar/appinfo/app.php +++ b/apps/calendar/appinfo/app.php @@ -1,25 +1,23 @@ <?php -if(version_compare(PHP_VERSION, '5.3.0', '>=')){ - $l=new OC_L10N('calendar'); - OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php'; - OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php'; - OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php'; - OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php'; - OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php'; - OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; - OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); - OC_Hook::connect('OC_DAV', 'initialize', 'OC_Calendar_Hooks', 'initializeCalDAV'); - OC_Util::addScript('calendar','loader'); - OC_App::register( array( - 'order' => 10, - 'id' => 'calendar', - 'name' => 'Calendar' )); - OC_App::addNavigationEntry( array( - 'id' => 'calendar_index', - 'order' => 10, - 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ), - 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ), - 'name' => $l->t('Calendar'))); - OC_App::registerPersonal('calendar', 'settings'); - OC_Search::registerProvider('OC_Search_Provider_Calendar'); -} +$l=new OC_L10N('calendar'); +OC::$CLASSPATH['OC_Calendar_App'] = 'apps/calendar/lib/app.php'; +OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php'; +OC::$CLASSPATH['OC_Calendar_Object'] = 'apps/calendar/lib/object.php'; +OC::$CLASSPATH['OC_Calendar_Hooks'] = 'apps/calendar/lib/hooks.php'; +OC::$CLASSPATH['OC_Connector_Sabre_CalDAV'] = 'apps/calendar/lib/connector_sabre.php'; +OC::$CLASSPATH['OC_Search_Provider_Calendar'] = 'apps/calendar/lib/search.php'; +OC_HOOK::connect('OC_User', 'post_deleteUser', 'OC_Calendar_Hooks', 'deleteUser'); +OC_Hook::connect('OC_DAV', 'initialize', 'OC_Calendar_Hooks', 'initializeCalDAV'); +OC_Util::addScript('calendar','loader'); +OC_App::register( array( + 'order' => 10, + 'id' => 'calendar', + 'name' => 'Calendar' )); +OC_App::addNavigationEntry( array( + 'id' => 'calendar_index', + 'order' => 10, + 'href' => OC_Helper::linkTo( 'calendar', 'index.php' ), + 'icon' => OC_Helper::imagePath( 'calendar', 'icon.svg' ), + 'name' => $l->t('Calendar'))); +OC_App::registerPersonal('calendar', 'settings'); +OC_Search::registerProvider('OC_Search_Provider_Calendar');
\ No newline at end of file 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(); } @@ -209,14 +208,6 @@ class OC_Calendar_Object{ } /** - * @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 * @return array diff --git a/apps/calendar/templates/settings.php b/apps/calendar/templates/settings.php index f74a45203e1..fb2a04a6498 100644 --- a/apps/calendar/templates/settings.php +++ b/apps/calendar/templates/settings.php @@ -31,7 +31,7 @@ </select><input type="checkbox" name="timezonedetection" id="timezonedetection"><label for="timezonedetection"><?php echo $l->t('Check always for changes of the timezone'); ?></label></td></tr> <tr><td><label for="timeformat" class="bold"><?php echo $l->t('Timeformat');?></label></td><td> - <select style="display: none;" id="timeformat" title="<?php echo "timeformat"; ?>" name="timeformat"> + <select style="display: none; width: 60px;" id="timeformat" title="<?php echo "timeformat"; ?>" name="timeformat"> <option value="24" id="24h"><?php echo $l->t("24h"); ?></option> <option value="ampm" id="ampm"><?php echo $l->t("12h"); ?></option> </select> diff --git a/apps/contacts/ajax/addcard.php b/apps/contacts/ajax/addcard.php deleted file mode 100644 index b1dc69a4691..00000000000 --- a/apps/contacts/ajax/addcard.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php -/** - * ownCloud - Addressbook - * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -// Init owncloud -require_once('../../../lib/base.php'); -function bailOut($msg) { - OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('contacts','ajax/addcard.php: '.$msg, OC_Log::DEBUG); - exit(); -} - -// Check if we are a user -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('contacts'); - -$aid = $_POST['id']; -OC_Contacts_App::getAddressbook( $aid ); // is owner access check - -$fn = trim($_POST['fn']); -$values = $_POST['value']; -$parameters = $_POST['parameters']; - -$vcard = new OC_VObject('VCARD'); -$vcard->setUID(); - -$n = isset($values['N'][0])?trim($values['N'][0]).';':';'; -$n .= isset($values['N'][1])?trim($values['N'][1]).';':';'; -$n .= isset($values['N'][2])?trim($values['N'][2]).';;':';;'; - -if(!$fn || ($n == ';;;;')) { - bailOut('You have to enter both the extended name and the display name.'); -} - -$vcard->setString('N',$n); -$vcard->setString('FN',$fn); - -// Data to add ... -$add = array('TEL', 'EMAIL', 'ORG'); -$address = false; -for($i = 0; $i < 7; $i++){ - if( isset($values['ADR'][$i] ) && $values['ADR'][$i]) $address = true; -} -if( $address ) $add[] = 'ADR'; - -// Add data -foreach( $add as $propname){ - if( !( isset( $values[$propname] ) && $values[$propname] )){ - continue; - } - $value = $values[$propname]; - if( isset( $parameters[$propname] ) && count( $parameters[$propname] )){ - $prop_parameters = $parameters[$propname]; - } else { - $prop_parameters = array(); - } - if(is_array($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); - } - $vcard->addProperty($propname, strip_tags($value)); //, $prop_parameters); - $line = count($vcard->children) - 1; - foreach ($prop_parameters as $key=>$element) { - if(is_array($element) && strtoupper($key) == 'TYPE') { - // FIXME: Maybe this doesn't only apply for TYPE? - // And it probably shouldn't be done here anyways :-/ - foreach($element as $e){ - if($e != '' && !is_null($e)){ - $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($key,$e); - } - } - } else { - $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($key,$element); - } - } -} -$id = OC_Contacts_VCard::add($aid,$vcard->serialize()); -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); - exit(); -} - -// NOTE: Why is this in OC_Contacts_App? -OC_Contacts_App::renderDetails($id, $vcard); 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..d2c0291e8c6 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); @@ -113,19 +116,10 @@ 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(); } -$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); -$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - -$tmpl = new OC_Template('contacts','part.property'); -$tmpl->assign('adr_types',$adr_types); -$tmpl->assign('phone_types',$phone_types); -$tmpl->assign('property',OC_Contacts_VCard::structureProperty($property,$line)); -$page = $tmpl->fetchPage(); - -OC_JSON::success(array('data' => array( 'checksum' => $checksum, 'page' => $page ))); +OC_JSON::success(array('data' => array( 'checksum' => $checksum ))); diff --git a/apps/contacts/ajax/categories/categoriesfor.php b/apps/contacts/ajax/categories/categoriesfor.php new file mode 100644 index 00000000000..c02c37914a2 --- /dev/null +++ b/apps/contacts/ajax/categories/categoriesfor.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * 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('value'=>$property->value, '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 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * 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/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 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * 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/categories/rescan.php b/apps/contacts/ajax/categories/rescan.php new file mode 100644 index 00000000000..dd27192baa0 --- /dev/null +++ b/apps/contacts/ajax/categories/rescan.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright (c) 2012 Thomas Tanghus <thomas@tanghus.net> + * 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/rescan.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('contacts','ajax/categories/rescan.php: '.$msg, OC_Log::DEBUG); +} + +$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[] = $contact['carddata']; +} + +OC_Contacts_App::$categories->rescan($cards); +$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/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/showsetproperty.php b/apps/contacts/ajax/loadcard.php index 73bef655351..037fe2a6df2 100644 --- a/apps/contacts/ajax/showsetproperty.php +++ b/apps/contacts/ajax/loadcard.php @@ -2,8 +2,8 @@ /** * ownCloud - Addressbook * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de + * @author Thomas Tanghus + * @copyright 2012 Thomas Tanghus <thomas@tanghus.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -22,31 +22,38 @@ // 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'); -$id = $_GET['id']; -$checksum = $_GET['checksum']; - -$vcard = OC_Contacts_App::getContactVCard( $id ); - -$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); -if(is_null($line)){ - OC_JSON::error(array('data' => array( 'message' => OC_Contacts_App::$l10n->t('Information about vCard is incorrect. Please reload the page.')))); - exit(); -} +$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.setpropertyform'); -$tmpl->assign('id',$id); -$tmpl->assign('checksum',$checksum); -$tmpl->assign('property',OC_Contacts_VCard::structureProperty($vcard->children[$line])); +$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 ))); diff --git a/apps/contacts/ajax/loadphoto.php b/apps/contacts/ajax/loadphoto.php index 358e046942b..2c8bb7bf1ed 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 <http://www.gnu.org/licenses/>. * - * 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,11 +40,20 @@ $image = null; $id = isset($_GET['id']) ? $_GET['id'] : ''; if($id == '') { - bailOut('Missing contact 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/ajax/messagebox.php b/apps/contacts/ajax/messagebox.php deleted file mode 100644 index 408e7a537aa..00000000000 --- a/apps/contacts/ajax/messagebox.php +++ /dev/null @@ -1,15 +0,0 @@ -<?php -/** - * Copyright (c) 2011 Thomas Tanghus <thomas@tanghus.net> - * 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'); - -$output = new OC_TEMPLATE("contacts", "part.messagebox"); -$output -> printpage(); -?> diff --git a/apps/contacts/ajax/savecrop.php b/apps/contacts/ajax/savecrop.php index 1a84f6fdfae..0df4e1998cb 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); @@ -104,6 +104,7 @@ if(file_exists($tmp_path)) { $tmpl->assign('tmp_path', $tmpfname); $tmpl->assign('mime', $image->mimeType()); $tmpl->assign('id', $id); + $tmpl->assign('refresh', true); $tmpl->assign('width', $image->width()); $tmpl->assign('height', $image->height()); $page = $tmpl->fetchPage(); diff --git a/apps/contacts/ajax/saveproperty.php b/apps/contacts/ajax/saveproperty.php index 6f8366243fe..924d873652c 100644 --- a/apps/contacts/ajax/saveproperty.php +++ b/apps/contacts/ajax/saveproperty.php @@ -35,9 +35,9 @@ function bailOut($msg) { function debug($msg) { OC_Log::write('contacts','ajax/saveproperty.php: '.$msg, OC_Log::DEBUG); } -foreach ($_POST as $key=>$element) { - debug('_POST: '.$key.'=>'.$element); -} +// foreach ($_POST as $key=>$element) { +// debug('_POST: '.$key.'=>'.print_r($element, true)); +// } $id = isset($_POST['id'])?$_POST['id']:null; $name = isset($_POST['name'])?$_POST['name']: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; @@ -79,24 +83,47 @@ if($element != $name) { bailOut(OC_Contacts_App::$l10n->t('Something went FUBAR. ').$name.' != '.$element); } +/* preprocessing value */ switch($element) { case 'BDAY': $date = New DateTime($value); //$vcard->setDateTime('BDAY', $date, Sabre_VObject_Element_DateTime::DATE); $value = $date->format(DateTime::ATOM); + break; case 'FN': if(!$value) { // create a method thats returns an alternative for FN. //$value = getOtherValue(); } + break; + case 'CATEGORIES': + /* multi autocomplete triggers an save with empty value */ + if (!$value) { + $value = $vcard->getAsString('CATEGORIES'); + } + break; + case 'EMAIL': + $value = strtolower($value); + break; +} + +if(!$value) { + bailOut(OC_Contacts_App::$l10n->t('Cannot save empty value.')); +} + +/* setting value */ +switch($element) { + case 'BDAY': + case 'FN': case 'N': case 'ORG': + case 'NOTE': case 'NICKNAME': + case 'CATEGORIES': debug('Setting string:'.$name.' '.$value); $vcard->setString($name, $value); break; case 'EMAIL': - $value = strtolower($value); case 'TEL': case 'ADR': // should I delete the property if empty or throw an error? debug('Setting element: (EMAIL/TEL/ADR)'.$element); @@ -122,13 +149,9 @@ switch($element) { $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); +if(!OC_Contacts_VCard::edit($id,$vcard)) { + 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/ajax/setproperty.php b/apps/contacts/ajax/setproperty.php deleted file mode 100644 index f9e2a8e8647..00000000000 --- a/apps/contacts/ajax/setproperty.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php -/** - * ownCloud - Addressbook - * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -// Init owncloud -require_once('../../../lib/base.php'); - -// Check if we are a user -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('contacts'); - -$id = $_POST['id']; -$checksum = $_POST['checksum']; - -$vcard = OC_Contacts_App::getContactVCard( $id ); -$line = OC_Contacts_App::getPropertyLineByChecksum($vcard, $checksum); - -// Set the value -$value = $_POST['value']; -if(is_array($value)){ - ksort($value); // NOTE: Important, otherwise the compound value will be set in the order the fields appear in the form! - foreach(array_keys($value) as $key) { - OC_Log::write('contacts','ajax/setproperty.php: setting: '.$key.': '.$value[$key], OC_Log::DEBUG); - } - $value = OC_VObject::escapeSemicolons($value); -} -OC_Log::write('contacts','ajax/setproperty.php: setting: '.$vcard->children[$line]->name.': '.$value, OC_Log::DEBUG); -$vcard->children[$line]->setValue(strip_tags($value)); - -// Add parameters -$postparameters = isset($_POST['parameters'])?$_POST['parameters']:array(); -if ($vcard->children[$line]->name == 'TEL' && !array_key_exists('TYPE', $postparameters)){ - $postparameters['TYPE']=''; -} -for($i=0;$i<count($vcard->children[$line]->parameters);$i++){ - $name = $vcard->children[$line]->parameters[$i]->name; - if(array_key_exists($name,$postparameters)){ - if($postparameters[$name] == '' || is_null($postparameters[$name])){ - unset($vcard->children[$line]->parameters[$i]); - } - else{ - unset($vcard->children[$line][$name]); - $values = $postparameters[$name]; - if (!is_array($values)){ - $values = array($values); - } - foreach($values as $value){ - $vcard->children[$line]->add($name, $value); - } - } - unset($postparameters[$name]); - } -} -$missingparameters = array_keys($postparameters); -foreach($missingparameters as $i){ - if(!$postparameters[$i] == '' && !is_null($postparameters[$i])){ - $vcard->children[$line]->parameters[] = new Sabre_VObject_Parameter($i,$postparameters[$i]); - } -} - -// Do checksum and be happy -// NOTE: This checksum is not used..? -$checksum = md5($vcard->children[$line]->serialize()); - -if(!OC_Contacts_VCard::edit($id,$vcard->serialize())) { - OC_JSON::error(array('data' => array('message' => $l->t('Error updating contact property.')))); - OC_Log::write('contacts','ajax/setproperty.php: Error updating contact property: '.$value, OC_Log::ERROR); - exit(); -} - -$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); -$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - -if ($vcard->children[$line]->name == 'FN'){ - $tmpl = new OC_Template('contacts','part.property.FN'); -} -elseif ($vcard->children[$line]->name == 'N'){ - $tmpl = new OC_Template('contacts','part.property.N'); -} -else{ - $tmpl = new OC_Template('contacts','part.property'); -} -$tmpl->assign('adr_types',$adr_types); -$tmpl->assign('phone_types',$phone_types); -$tmpl->assign('property',OC_Contacts_VCard::structureProperty($vcard->children[$line],$line)); -$page = $tmpl->fetchPage(); - -OC_JSON::success(array('data' => array( 'page' => $page, 'line' => $line, 'checksum' => $checksum, 'oldchecksum' => $_POST['checksum'] ))); diff --git a/apps/contacts/ajax/showaddcard.php b/apps/contacts/ajax/showaddcard.php deleted file mode 100644 index 54592c89c0d..00000000000 --- a/apps/contacts/ajax/showaddcard.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * ownCloud - Addressbook - * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -// Init owncloud -require_once('../../../lib/base.php'); - -// Check if we are a user -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('contacts'); - -$adr_types = OC_Contacts_App::getTypesOfProperty('ADR'); -$phone_types = OC_Contacts_App::getTypesOfProperty('TEL'); - -$addressbooks = OC_Contacts_Addressbook::all(OC_USER::getUser()); -$tmpl = new OC_Template('contacts','part.addcardform'); -$tmpl->assign('addressbooks',$addressbooks); -$tmpl->assign('adr_types',$adr_types); -$tmpl->assign('phone_types',$phone_types); -$page = $tmpl->fetchPage(); - -OC_JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/ajax/showaddproperty.php b/apps/contacts/ajax/showaddproperty.php deleted file mode 100644 index 30eb7634f80..00000000000 --- a/apps/contacts/ajax/showaddproperty.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * ownCloud - Addressbook - * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - -// Init owncloud -require_once('../../../lib/base.php'); - -// Check if we are a user -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('contacts'); - -$id = $_GET['id']; -$card = OC_Contacts_App::getContactObject( $id ); - -$tmpl = new OC_Template('contacts','part.addpropertyform'); -$tmpl->assign('id',$id); -$page = $tmpl->fetchPage(); - -OC_JSON::success(array('data' => array( 'page' => $page ))); diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css index b24ec438f24..7c36a511d6e 100644 --- a/apps/contacts/css/contacts.css +++ b/apps/contacts/css/contacts.css @@ -20,7 +20,8 @@ #firstrun { width: 100%; position: absolute; top: 5em; left: 0; text-align: center; font-weight:bold; font-size:1.5em; color:#777; } #firstrun #selections { font-size:0.8em; 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,5 @@ 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; } + diff --git a/apps/contacts/css/styles.css b/apps/contacts/css/styles.css deleted file mode 100644 index 58e1bf6c93e..00000000000 --- a/apps/contacts/css/styles.css +++ /dev/null @@ -1,37 +0,0 @@ -#contacts { padding-left:2px; padding-top: 5px; background: #fff; } -#leftcontent a { height: 23px; display: block; margin: 0 0 0 0; padding: 0 0 0 25px; } -#chooseaddressbook {margin-right: 170px; float: right;} -#contacts_details_name { font-weight:bold;font-size:1.1em;margin-left:25%;} -#contacts_details_name_n { font-size:0.8em;margin-left:25%;color:#666;} -#contacts_details_photo { margin:.5em 0em .5em 25%; } - -#contacts_deletecard {position:absolute;top:15px;right:25px;} -#contacts_downloadcard {position:absolute;top:15px;right:50px;} -#contacts_details_list { list-style:none; } -#contacts_details_list li { overflow:visible; } -#contacts_details_list li p.contacts_property_name { width:25%; float:left;text-align:right;padding-right:0.3em;color:#666; } -#contacts_details_list li p.contacts_property_data, #contacts_details_list li ul.contacts_property_data { width:72%;float:left; clear: right; } -#contacts_setproperty_button { margin-left:25%; } - -#contacts_addcardform legend,label { font-weight: bold; width: 10em; overflow: ellipsis; } -#contacts_addcardform legend { padding-left: 3em; font-size:1.1em; } -#contacts_addcardform input[type="text"] { width: 25em; } -#contacts_addcardform input[type="email"] { width: 15em; } -#contacts_addcardform input[type="tel"] { width: 15em; } - -dl.form { width: 100%; float: left; clear: right; margin: 1em; padding: 0; } -.form dt { display: table-cell; clear: left; float: left; min-width: 10em; margin: 0; padding-top: 0.5em; padding-right: 1em;font-weight: bold; text-align:right; vertical-align: text-bottom; bottom: 0px; } -.form dd { display: table-cell; clear: right; float: left; min-width: 20em; margin: 0; padding: 0; white-space: nowrap; top: 0px; } -.form input { position: relative; width: 20em; } - -.contacts_property_data ul, ol.contacts_property_data { list-style:none; } -.contacts_property_data li { overflow: hidden; } -.contacts_property_data li label { width:20%; float:left; text-align:right;padding-right:0.3em; } -.contacts_property_data input { float:left; } -.contacts_property_data li input { width:70%;overflow:hidden; } - -.chzn-container { margin:3px 0 0; } -.chzn-container .chzn-choices { border-radius: 0.5em; } -.chzn-container.chzn-container-active .chzn-choices { border-bottom-left-radius: 0;border-bottom-right-radius: 0; } -.chzn-container .chzn-drop { border-bottom-left-radius: 0.5em;border-bottom-right-radius: 0.5em; } - 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/index.php b/apps/contacts/index.php index 0a21ddd04b6..04f6c65a145 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')); @@ -44,12 +45,14 @@ $freeSpace=max($freeSpace,0); $maxUploadFilesize = min($maxUploadFilesize ,$freeSpace); OC_Util::addScript('','jquery.multiselect'); +OC_Util::addScript('','oc-vcategories'); 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('','oc-vcategories'); OC_Util::addStyle('contacts','jquery.combobox'); OC_Util::addStyle('contacts','jquery.Jcrop'); OC_Util::addStyle('contacts','contacts'); @@ -58,7 +61,9 @@ $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('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 d033e3f21cd..e1827027453 100644 --- a/apps/contacts/js/contacts.js +++ b/apps/contacts/js/contacts.js @@ -10,17 +10,16 @@ String.prototype.strip_tags = function(){ return stripped; }; - 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 @@ -48,12 +47,11 @@ Contacts={ console.log('uri: ' + uri); var newWindow = window.open(uri,'_blank'); newWindow.focus(); - //Contacts.UI.notImplemented(); }, mailTo:function(obj) { var adr = Contacts.UI.propertyContainerFor($(obj)).find('input[type="email"]').val().trim(); if(adr == '') { - Contacts.UI.messageBox(t('contacts', 'Error'), t('contacts', 'Please enter an email address.')); + OC.dialogs.alert(t('contacts', 'Please enter an email address.'), t('contacts', 'Error')); return; } window.location.href='mailto:' + adr; @@ -68,7 +66,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 +80,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; @@ -116,34 +114,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(){ - $('#messagebox').dialog( - { - autoOpen: true, - title: title, - buttons: [{ - text: "Ok", - click: function() { $(this).dialog("close"); } - }], - close: function(event, ui) { - $(this).dialog('destroy').remove(); - }, - open: function(event, ui) { - $('#messagebox_msg').html(msg); - } - }); - }); - }; - }, loadListHandlers:function() { //$('.add,.delete').hide(); $('.globe,.mail,.delete,.edit').tipsy(); @@ -182,8 +152,14 @@ 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({ + $('#phonelist').find('select.contacts_property').multiselect({ noneSelectedText: t('contacts', 'Select type'), header: false, selectedList: 4, @@ -223,6 +199,7 @@ Contacts={ click: function() { $(this).dialog('close'); } } ] ); + $('#categories').multiple_autocomplete({source: categories}); Contacts.UI.loadListHandlers(); }, Card:{ @@ -252,12 +229,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')); } }); } @@ -269,7 +246,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')); } }); } @@ -309,7 +286,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); } }); @@ -318,7 +295,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); } }); @@ -344,13 +321,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); } }); @@ -361,19 +338,29 @@ 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.loadCategories(); this.loadPhoto(); this.loadMails(); 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']; + var props = ['BDAY', 'NICKNAME', 'ORG', 'CATEGORIES']; // 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(''); @@ -407,6 +394,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(); @@ -424,11 +417,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 + ' '; } @@ -448,6 +441,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($('<option></option>') @@ -457,36 +453,79 @@ 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) { - // + var categories = this.data.CATEGORIES[0]['value'].split(/,\s*/); + for(var c in categories) { + 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(newcategories) { // Categories added/deleted. + console.log('categoriesChanged for ' + Contacts.UI.Card.id + ' : ' + newcategories); + categories = newcategories; + var categorylist = $('#categories_value').find('input'); + $.getJSON(OC.filePath('contacts', 'ajax', 'categories/categoriesfor.php'),{'id':Contacts.UI.Card.id},function(jsondata){ + if(jsondata.status == 'success'){ + console.log('Setting checksum: ' + jsondata.data.checksum + ', value: ' + jsondata.data.value); + $('#categories_value').data('checksum', jsondata.data.checksum); + categorylist.val(jsondata.data.value); + } else { + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); + } + }); + }, + /*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{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); + } else { + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); //alert(jsondata.data.message); } }); }, 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,11 +545,11 @@ 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() == '') { - 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. @@ -518,8 +557,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,textarea.contacts_property').serialize(); if(q == '' || q == undefined) { console.log('Couldn\'t serialize elements.'); Contacts.UI.loading(container, false); @@ -529,32 +568,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); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); 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); + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); Contacts.UI.loading(container, false); + $(obj).removeAttr('disabled'); return false; } },'json'); @@ -565,9 +610,15 @@ 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(); + $('#file_upload_start').trigger('click'); + break; + case 'NOTE': + $('#note').show(); + $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); + $('#note').find('textarea').focus(); break; case 'EMAIL': if($('#emaillist>li').length == 1) { @@ -593,7 +644,9 @@ Contacts={ case 'NICKNAME': case 'ORG': case 'BDAY': + case 'CATEGORIES': $('dl dt[data-element="'+type+'"],dd[data-element="'+type+'"]').show(); + $('dd[data-element="'+type+'"]').find('input').focus(); $('#contacts_propertymenu a[data-type="'+type+'"]').parent().hide(); break; } @@ -612,17 +665,32 @@ Contacts={ } else if(type == 'single') { var proptype = Contacts.UI.propertyTypeFor(obj); console.log('deleteProperty, hiding: ' + proptype); - $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); + 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', ''); + if(proptype == 'PHOTO') { + console.log('Delete PHOTO'); + Contacts.UI.Contacts.refreshThumbnail(Contacts.UI.Card.id); + } else if(proptype == 'NOTE') { + $('#note').find('textarea').val(''); + } + } else { + $('dl dt[data-element="'+proptype+'"],dd[data-element="'+proptype+'"]').hide(); + $('dl dd[data-element="'+proptype+'"]').data('checksum', ''); + $('dl dd[data-element="'+proptype+'"]').find('input').val(''); + } $('#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. @@ -637,7 +705,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')); } } }, @@ -647,8 +715,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 +736,10 @@ Contacts={ open : function(event, ui) { // load 'N' property - maybe :-P }*/ - }); + }); + } else { + OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error')); + } }); } }, @@ -692,7 +764,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($('<option></option>') @@ -708,7 +787,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'); @@ -771,8 +850,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 +883,10 @@ Contacts={ open : function(event, ui) { // load 'ADR' property - maybe :-P }*/ - }); + }); + } else { + alert(jsondata.data.message); + } }); } }, @@ -843,7 +926,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); @@ -852,7 +935,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(){ @@ -861,21 +944,22 @@ 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(); } }, - 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); + $('#file_upload_form').data('checksum', jsondata.data.checksum); $('#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(); @@ -894,7 +978,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){ @@ -913,22 +997,22 @@ 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'); + Contacts.UI.Contacts.refreshThumbnail(this.id); }, 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 +1034,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 +1050,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'); @@ -1006,13 +1090,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); + } }); } }, @@ -1049,7 +1137,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); } }); @@ -1064,7 +1152,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; @@ -1079,7 +1167,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')); } }); }, @@ -1099,7 +1187,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); } }); @@ -1114,6 +1202,9 @@ Contacts={ $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); } }); + }, + refreshThumbnail:function(id){ + $('#contacts [data-id="'+id+'"]').find('a').css('background','url(thumbnail.php?id='+id+'&refresh=1'+Math.random()+') no-repeat'); } } } @@ -1121,6 +1212,8 @@ Contacts={ $(document).ready(function(){ Contacts.UI.loadHandlers(); + OCCategories.changed = Contacts.UI.Card.categoriesChanged; + OCCategories.app = 'contacts'; /** * Show the Addressbook chooser @@ -1148,7 +1241,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); } }); @@ -1189,7 +1282,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); }); @@ -1246,17 +1340,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() { @@ -1266,11 +1360,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(); @@ -1298,8 +1392,19 @@ $(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); diff --git a/apps/contacts/js/interface.js b/apps/contacts/js/interface.js deleted file mode 100644 index 5908dd767a2..00000000000 --- a/apps/contacts/js/interface.js +++ /dev/null @@ -1,409 +0,0 @@ -/** - * ownCloud - Addressbook - * - * @author Jakob Sack - * @copyright 2011 Jakob Sack mail@jakobsack.de - * @copyright 2011-2012 Thomas Tanghus <thomas@tanghus.net> - * - * 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 <http://www.gnu.org/licenses/>. - * - */ - - -Contacts={ - UI:{ - showCardDAVUrl:function(username, bookname){ - $('#carddav_url').val(totalurl + '/' + username + '/' + bookname); - $('#carddav_url').show(); - $('#carddav_url_close').show(); - }, - messageBox:function(title, msg) { - if($('#messagebox').dialog('isOpen') == true){ - // NOTE: Do we ever get here? - $('#messagebox').dialog('moveToTop'); - }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'messagebox.php'), function(){ - $('#messagebox').dialog( - { - autoOpen: true, - title: title, - buttons: [{ - text: "Ok", - click: function() { $(this).dialog("close"); } - }], - close: function(event, ui) { - $(this).dialog('destroy').remove(); - }, - open: function(event, ui) { - $('#messagebox_msg').html(msg); - } - }); - }); - } - }, - Addressbooks:{ - overview:function(){ - if($('#chooseaddressbook_dialog').dialog('isOpen') == true){ - $('#chooseaddressbook_dialog').dialog('moveToTop'); - }else{ - $('#dialog_holder').load(OC.filePath('contacts', 'ajax', 'chooseaddressbook.php'), function(){ - $('#chooseaddressbook_dialog').dialog({ - width : 600, - close : function(event, ui) { - $(this).dialog('destroy').remove(); - } - }); - }); - } - }, - activation:function(checkbox, bookid) - { - $.post(OC.filePath('contacts', 'ajax', 'activation.php'), { bookid: bookid, active: checkbox.checked?1:0 }, - function(data) { - /* - * Arguments: - * data.status - * data.bookid - * data.active - */ - if (data.status == 'success'){ - checkbox.checked = data.active == 1; - Contacts.UI.Contacts.update(); - } - }); - }, - newAddressbook:function(object){ - var tr = $(document.createElement('tr')) - .load(OC.filePath('contacts', 'ajax', 'addbook.php')); - $(object).closest('tr').after(tr).hide(); - /* TODO: Shouldn't there be some kinda error checking here? */ - }, - editAddressbook:function(object, bookid){ - var tr = $(document.createElement('tr')) - .load(OC.filePath('contacts', 'ajax', 'editaddressbook.php') + "?bookid="+bookid); - $(object).closest('tr').after(tr).hide(); - }, - deleteAddressbook:function(bookid){ - var check = confirm("Do you really want to delete this address book?"); - if(check == false){ - return false; - }else{ - $.post(OC.filePath('contacts', 'ajax', 'deletebook.php'), { id: bookid}, - function(data) { - if (data.status == 'success'){ - $('#chooseaddressbook_dialog').dialog('destroy').remove(); - Contacts.UI.Contacts.update(); - Contacts.UI.Addressbooks.overview(); - } else { - Contacts.UI.messageBox(t('contacts', 'Error'), data.message); - //alert('Error: ' + data.message); - } - }); - } - }, - submit:function(button, bookid){ - var displayname = $("#displayname_"+bookid).val(); - var active = $("#edit_active_"+bookid+":checked").length; - var description = $("#description_"+bookid).val(); - - var url; - if (bookid == 'new'){ - url = OC.filePath('contacts', 'ajax', 'createaddressbook.php'); - }else{ - url = OC.filePath('contacts', 'ajax', 'updateaddressbook.php'); - } - $.post(url, { id: bookid, name: displayname, active: active, description: description }, - function(jsondata){ - if(jsondata.status == 'success'){ - $(button).closest('tr').prev().html(data.page).show().next().remove(); - Contacts.UI.Contacts.update(); - } else { - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - } - }); - }, - cancel:function(button, bookid){ - $(button).closest('tr').prev().show().next().remove(); - } - }, - Contacts:{ - /** - * Reload the contacts list. - */ - update:function(){ - $.getJSON('ajax/contacts.php',{},function(jsondata){ - if(jsondata.status == 'success'){ - $('#contacts').html(jsondata.data.page); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'),jsondata.data.message); - //alert(jsondata.data.message); - } - }); - setTimeout(Contacts.UI.Contacts.lazyupdate, 500); - }, - /** - * Add thumbnails to the contact list as they become visible in the viewport. - */ - lazyupdate:function(){ - $('#contacts li').live('inview', function(){ - if (!$(this).find('a').attr('style')) { - $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); - } - }); - } - } - } -} - -$(document).ready(function(){ - /*------------------------------------------------------------------------- - * Event handlers - *-----------------------------------------------------------------------*/ - - /** - * Load the details view for a contact. - */ - $('#leftcontent li').live('click',function(){ - var id = $(this).data('id'); - var oldid = $('#rightcontent').data('id'); - if(oldid != 0){ - $('#leftcontent li[data-id="'+oldid+'"]').removeClass('active'); - } - $.getJSON('ajax/getdetails.php',{'id':id},function(jsondata){ - if(jsondata.status == 'success'){ - $('#rightcontent').data('id',jsondata.data.id); - $('#rightcontent').html(jsondata.data.page); - $('#leftcontent li[data-id="'+jsondata.data.id+'"]').addClass('active'); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - return false; - }); - - /** - * Delete currently selected contact (and clear form?) - */ - $('#contacts_deletecard').live('click',function(){ - $('#contacts_deletecard').tipsy('hide'); - var id = $('#rightcontent').data('id'); - $.getJSON('ajax/deletecard.php',{'id':id},function(jsondata){ - if(jsondata.status == 'success'){ - $('#leftcontent [data-id="'+jsondata.data.id+'"]').remove(); - $('#rightcontent').data('id',''); - $('#rightcontent').empty(); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - return false; - }); - - /** - * Add a property to the contact. - * NOTE: Where does 'contacts_addproperty' exist? - */ - $('#contacts_addproperty').live('click',function(){ - var id = $('#rightcontent').data('id'); - $.getJSON('ajax/showaddproperty.php',{'id':id},function(jsondata){ - if(jsondata.status == 'success'){ - $('#contacts_details_list').append(jsondata.data.page); - $('#contacts_addproperty').hide(); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - alert('From handler: '+jsondata.data.message); - } - }); - return false; - }); - - /** - * Change the inputs based on which type of property is selected for addition. - */ - $('#contacts_addpropertyform [name="name"]').live('change',function(){ - $('#contacts_addpropertyform #contacts_addresspart').remove(); - $('#contacts_addpropertyform #contacts_phonepart').remove(); - $('#contacts_addpropertyform #contacts_fieldpart').remove(); - $('#contacts_addpropertyform #contacts_generic').remove(); - if($(this).val() == 'ADR'){ - $('#contacts_addresspart').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name')); - } - else if($(this).val() == 'TEL'){ - $('#contacts_phonepart').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name')); - } - else{ - $('#contacts_generic').clone().insertAfter($('#contacts_addpropertyform .contacts_property_name')); - } - $('#contacts_addpropertyform .contacts_property_data select').chosen(); - }); - - $('#contacts_addpropertyform input[type="submit"]').live('click',function(){ - $.post('ajax/addproperty.php',$('#contacts_addpropertyform').serialize(),function(jsondata){ - if(jsondata.status == 'success'){ - $('#contacts_addpropertyform').before(jsondata.data.page); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - } - }, 'json'); - return false; - }); - - /** - * Show the Addressbook chooser - */ - $('#chooseaddressbook').click(function(){ - Contacts.UI.Addressbooks.overview(); - return false; - }); - - /** - * Open blank form to add new contact. - */ - $('#contacts_newcontact').click(function(){ - $.getJSON('ajax/showaddcard.php',{},function(jsondata){ - if(jsondata.status == 'success'){ - $('#rightcontent').data('id',''); - $('#rightcontent').html(jsondata.data.page) - .find('select').chosen(); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - return false; - }); - - /** - * Add and insert a new contact into the list. - */ - $('#contacts_addcardform input[type="submit"]').live('click',function(){ - $.post('ajax/addcard.php',$('#contacts_addcardform').serialize(),function(jsondata){ - if(jsondata.status == 'success'){ - $('#rightcontent').data('id',jsondata.data.id); - $('#rightcontent').html(jsondata.data.page); - $('#leftcontent .active').removeClass('active'); - var item = '<li data-id="'+jsondata.data.id+'" class="active"><a href="index.php?id='+jsondata.data.id+'" style="background: url(thumbnail.php?id='+jsondata.data.id+') no-repeat scroll 0% 0% transparent;">'+jsondata.data.name+'</a></li>'; - var added = false; - $('#leftcontent ul li').each(function(){ - if ($(this).text().toLowerCase() > jsondata.data.name.toLowerCase()) { - $(this).before(item).fadeIn('fast'); - added = true; - return false; - } - }); - if(!added) { - $('#leftcontent ul').append(item); - } - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }, 'json'); - return false; - }); - - /** - * Show inputs for editing a property. - */ - $('.contacts_property [data-use="edit"]').live('click',function(){ - var id = $('#rightcontent').data('id'); - var checksum = $(this).parents('.contacts_property').first().data('checksum'); - $.getJSON('ajax/showsetproperty.php',{'id': id, 'checksum': checksum },function(jsondata){ - if(jsondata.status == 'success'){ - $('.contacts_property[data-checksum="'+checksum+'"]').html(jsondata.data.page) - .find('select').chosen(); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - return false; - }); - - /** - * Save the edited property - */ - $('#contacts_setpropertyform input[type="submit"]').live('click',function(){ - $.post('ajax/setproperty.php',$(this).parents('form').first().serialize(),function(jsondata){ - if(jsondata.status == 'success'){ - $('.contacts_property[data-checksum="'+jsondata.data.oldchecksum+'"]').replaceWith(jsondata.data.page); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - },'json'); - return false; - }); - - $('.contacts_property [data-use="delete"]').live('click',function(){ - var id = $('#rightcontent').data('id'); - var checksum = $(this).parents('li').first().data('checksum'); - $.getJSON('ajax/deleteproperty.php',{'id': id, 'checksum': checksum },function(jsondata){ - if(jsondata.status == 'success'){ - $('.contacts_property[data-checksum="'+checksum+'"]').remove(); - } - else{ - Contacts.UI.messageBox(t('contacts', 'Error'), jsondata.data.message); - //alert(jsondata.data.message); - } - }); - return false; - }); - - - $('.contacts_property').live('mouseenter',function(){ - $(this).find('span[data-use]').show(); - }); - - $('.contacts_property').live('mouseleave',function(){ - $(this).find('span[data-use]').hide(); - }); - - $('#contacts_addcardform select').chosen(); - - $('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) { - if (isInView) { //NOTE: I've kept all conditions for future reference ;-) - // element is now visible in the viewport - if (visiblePartY == 'top') { - // top part of element is visible - } else if (visiblePartY == 'bottom') { - // bottom part of element is visible - } else { - // whole part of element is visible - if (!$(this).find('a').attr('style')) { - //alert($(this).data('id') + ' has background: ' + $(this).attr('style')); - $(this).find('a').css('background','url(thumbnail.php?id='+$(this).data('id')+') no-repeat'); - }/* else { - alert($(this).data('id') + ' has style ' + $(this).attr('style').match('url')); - }*/ - } - } else { - // element has gone out of viewport - } - }); - - $('.button').tipsy(); - //Contacts.UI.messageBox('Hello','Sailor'); -}); diff --git a/apps/contacts/js/jquery.multi-autocomplete.js b/apps/contacts/js/jquery.multi-autocomplete.js new file mode 100644 index 00000000000..7607de3f918 --- /dev/null +++ b/apps/contacts/js/jquery.multi-autocomplete.js @@ -0,0 +1,92 @@ +/** + * Inspired by http://jqueryui.com/demos/autocomplete/#multiple + */ + +(function( $ ) { + $.widget('ui.multiple_autocomplete', { + _create: function() { + var self = this; + function split( val ) { + return val.split( /,\s*/ ); + } + function extractLast( term ) { + return split( term ).pop(); + } + function showOptions() { + if(!self.element.autocomplete('widget').is(':visible') && self.element.val().trim() == '') { + self.element.autocomplete('search', ''); + } + } + //console.log('_create: ' + this.options['id']); + this.element.bind('click', function( event ) { + showOptions(); + }); + this.element.bind('input', function( event ) { + showOptions(); + }); + this.element.bind('blur', function( event ) { + var tmp = self.element.val().trim(); + if(tmp[tmp.length-1] == ',') { + self.element.val(tmp.substring(0, tmp.length-1)); + } else { + self.element.val(tmp); + } + self.element.trigger('change'); // Changes wasn't saved when only using the dropdown. + }); + 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; + } + }); + this.button = $( "<button type='button'> </button>" ) + .attr( "tabIndex", -1 ) + .attr( "title", "Show All Items" ) + .insertAfter( this.element ) + .addClass('svg') + .addClass('action') + .addClass('combo-button') + .click(function() { + // close if already visible + if ( self.element.autocomplete( "widget" ).is( ":visible" ) ) { + self.element.autocomplete( "close" ); + return; + } + + // work around a bug (likely same cause as #5265) + $( this ).blur(); + + var tmp = self.element.val().trim(); + if(tmp[tmp.length-1] != ',') { + self.element.val(tmp+', '); + } + // pass empty string as value to search for, displaying all results + self.element.autocomplete( "search", "" ); + self.element.focus(); + }); + }, + }); +})( jQuery ); diff --git a/apps/contacts/js/loader.js b/apps/contacts/js/loader.js index eb59185d728..95fd7dc94ea 100644 --- a/apps/contacts/js/loader.js +++ b/apps/contacts/js/loader.js @@ -77,5 +77,7 @@ $(document).ready(function(){ if(typeof FileActions !== 'undefined'){ FileActions.register('text/vcard','importaddressbook', '', Contacts_Import.importdialog); FileActions.setDefault('text/vcard','importaddressbook'); + FileActions.register('text/x-vcard','importaddressbook', '', Contacts_Import.importdialog); + FileActions.setDefault('text/x-vcard','importaddressbook'); }; });
\ No newline at end of file diff --git a/apps/contacts/l10n/xgettextfiles b/apps/contacts/l10n/xgettextfiles index 91d5da46db0..e2492431ff8 100644 --- a/apps/contacts/l10n/xgettextfiles +++ b/apps/contacts/l10n/xgettextfiles @@ -1,20 +1,17 @@ ../appinfo/app.php ../ajax/activation.php ../ajax/addbook.php -../ajax/addcard.php ../ajax/addproperty.php ../ajax/createaddressbook.php ../ajax/deletebook.php ../ajax/deleteproperty.php ../ajax/getdetails.php -../ajax/setproperty.php +../ajax/saveproperty.php ../ajax/updateaddressbook.php ../lib/app.php ../templates/index.php -../templates/part.addcardform.php ../templates/part.chooseaddressbook.php ../templates/part.chooseaddressbook.rowfields.php -../templates/part.details.php ../templates/part.editaddressbook.php ../templates/part.property.php ../templates/part.setpropertyform.php diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php index ce52df4b75e..cc33c733007 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 @@ -92,7 +94,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;;;'); } @@ -153,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/lib/vcard.php b/apps/contacts/lib/vcard.php index 0b8d95a2d97..15a6176d40c 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 <thomas@tanghus.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -174,6 +175,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 +188,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'; } @@ -217,31 +223,37 @@ 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, OC_VObject $card, $uri=null){ + if(is_null($card)){ + OC_Log::write('contacts','OC_Contacts_VCard::add. No vCard supplied', OC_Log::ERROR); + return null; }; + OC_Contacts_App::$categories->loadFromVObject($card); + + 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 +267,56 @@ 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 self::add($id, $card, $uri); + } - 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 - * @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; } + + OC_Contacts_App::$categories->loadFromVObject($card); + + $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 +334,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); } /** @@ -352,14 +352,6 @@ class OC_Contacts_VCard{ } /** - * @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 * @param string $uri the uri of the card @@ -375,6 +367,43 @@ class OC_Contacts_VCard{ } /** + * @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;$i<count($array);$i++) { + if(substr($array[$i],-1,1)=="\\") { + if(isset($array[$i+1])) { + $array[$i] = substr($array[$i],0,count($array[$i])-2).$delimiter.$array[$i+1]; + unset($array[$i+1]); + } else { + $array[$i] = substr($array[$i],0,count($array[$i])-2).$delimiter; + } + $i = $i - 1; + } + } + $array = array_map('trim', $array); + return $array; + } + + /** * @brief Data structure of vCard * @param object $property * @return associative array @@ -412,8 +441,10 @@ class OC_Contacts_VCard{ $value = $property->value; //$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, 'value' => $value, diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php index e81597f23d6..af159ce9c60 100644 --- a/apps/contacts/templates/index.php +++ b/apps/contacts/templates/index.php @@ -1,5 +1,6 @@ <script type='text/javascript'> var totalurl = '<?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/addressbooks'; + var categories = <?php sort($_['categories']); echo json_encode($_['categories']); ?>; </script> <div id="controls"> <form> diff --git a/apps/contacts/templates/part.addcardform.php b/apps/contacts/templates/part.addcardform.php deleted file mode 100644 index 1ad4c18b35b..00000000000 --- a/apps/contacts/templates/part.addcardform.php +++ /dev/null @@ -1,138 +0,0 @@ -<form id="contacts_addcardform"> - <?php if(count($_['addressbooks'])==1): ?> - <input type="hidden" name="id" value="<?php echo $_['addressbooks'][0]['id']; ?>"> - <?php else: ?> - <fieldset class="inputs"> - <dl class="form"> - <dt> - <label for="id"><?php echo $l->t('Addressbook'); ?></label> - </dt> - <dd> - <select name="id" size="1"> - <?php echo html_select_options($_['addressbooks'], null, array('value'=>'id', 'label'=>'displayname')); ?> - </select> - </dd> - </dl> - </fieldset> - <?php endif; ?> - <fieldset class="inputs"> - <dl class="form"> - <dt> - <label for="n1"><?php echo $l->t('Given name'); ?></label> - </dd> - <dd> - <input id="n1" type="text" name="value[N][1]" value=""> - </dd> - <dt> - <label for="n0"><?php echo $l->t('Family name'); ?></label> - </dd> - <dd> - <input id="n0" type="text" name="value[N][0]" value=""> - </dd> - <dt> - <label for="n2"><?php echo $l->t('Additional names'); ?></label> - </dd> - <dd> - <input id="n2" type="text" name="value[N][2]" value=""> - <input type="hidden" name="value[N][4]" value=""> - <input type="hidden" name="value[N][5]" value=""> - </dd> - </dl> - </fieldset> - <fieldset class="inputs"> - <dl class="form"> - <dt> - <label for="fn"><?php echo $l->t('Display name'); ?></label> - </dd> - <dd> - <input id="fn" type="text" name="fn" placeholder="<?php echo $l->t('How you want the name displayed in the list'); ?>" value=""> - </dd> - <dt> - <label for="org"><?php echo $l->t('Organization'); ?></label> - </dt> - <dd> - <input id="org" type="text" name="value[ORG]" value=""> - </dd> - </dl> - </fieldset> - <fieldset class="inputs"> - <dl class="form"> - <dt> - <label for="email"><?php echo $l->t('Email'); ?></label> - </dt> - <dd> - <input id="email" type="email" name="value[EMAIL]" value=""> - </dd> - <dt> - <label for="tel"><?php echo $l->t('Telephone'); ?></label> - </dt> - <dd> - <input type="tel" id="tel" name="value[TEL]" value=""> - <select id="TEL" name="parameters[TEL][TYPE][]" multiple="multiple"> - <?php echo html_select_options($_['phone_types'], 'CELL') ?> - </select> - </dd> - </dl> - </fieldset> - <fieldset class="inputs"> - <legend><?php echo $l->t('Address'); ?></legend> - <dl class="form"> - <dt> - <label for="adr_type"><?php echo $l->t('Type'); ?></label> - </dt> - <dd> - <select id="adr_type" name="parameters[ADR][TYPE]" size="1"> - <?php echo html_select_options($_['adr_types'], 'HOME') ?> - </select> - </dd> - <dt> - <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label> - </dt> - <dd> - <input type="text" id="adr_pobox" name="value[ADR][0]" placeholder="<?php echo $l->t('Post Office box'); ?>" value=""> - </dd> - <dd> - <!-- dt> - <label class="label" for="adr_extended"><?php echo $l->t('Extended'); ?></label> - </dt> - <dd> - <input type="text" id="adr_extended" name="value[ADR][1]" value=""> - </dd --> - <dt> - <label for="adr_street"><?php echo $l->t('Street'); ?></label> - </dt> - <dd> - <input style="width: 12em;" type="text" id="adr_street" name="value[ADR][2]" placeholder="<?php echo $l->t('Street name and no.'); ?>" value=""> - <label for="adr_extended"><?php echo $l->t('Extended'); ?></label> - <input style="width: 7em;" type="text" id="adr_extended" name="value[ADR][1]" placeholder="<?php echo $l->t('Apart. no., floor'); ?>" value=""> - </dd> - <dt> - <label for="adr_city"><?php echo $l->t('City'); ?></label> - </dt> - <dd> - <input style="width: 12em;" type="text" id="adr_city" name="value[ADR][3]" value=""> - <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> - <input style="width: 5em;" type="text" id="adr_zipcode" name="value[ADR][5]" value=""> - </dd> - <dt> - <label for="adr_region"><?php echo $l->t('Region'); ?></label> - </dt> - <dd> - <input type="text" id="adr_region" name="value[ADR][4]" placeholder="<?php echo $l->t('E.g. state or province'); ?>" value=""> - </dd> - <!-- dt> - <label class="label" for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> - </dt> - <dd> - <input type="text" id="adr_zipcode" name="value[ADR][5]" value=""> - </dd --> - <dt> - <label for="adr_country"><?php echo $l->t('Country'); ?></label> - </dt> - <dd> - <input type="text" id="adr_country" name="value[ADR][6]" value=""> - </dd> - </dl> - </fieldset> - <input class="create" type="submit" name="submit" value="<?php echo $l->t('Create Contact'); ?>"> -</form> diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php index 5be20964f4b..a93069fa722 100644 --- a/apps/contacts/templates/part.contact.php +++ b/apps/contacts/templates/part.contact.php @@ -13,6 +13,8 @@ $id = isset($_['id']) ? $_['id'] : ''; <li><a data-type="TEL"><?php echo $l->t('Phone'); ?></a></li> <li><a data-type="EMAIL"><?php echo $l->t('Email'); ?></a></li> <li><a data-type="ADR"><?php echo $l->t('Address'); ?></a></li> + <li><a data-type="NOTE"><?php echo $l->t('Note'); ?></a></li> + <li><a data-type="CATEGORIES"><?php echo $l->t('Categories'); ?></a></li> </ul> </div> <img onclick="Contacts.UI.Card.export();" class="svg action" id="contacts_downloadcard" src="<?php echo image_path('', 'actions/download.svg'); ?>" title="<?php echo $l->t('Download contact');?>" /> @@ -21,8 +23,9 @@ $id = isset($_['id']) ? $_['id'] : ''; <div class="contactsection"> - <form style="display:none;" id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target"> + <form style="display:none;" id="file_upload_form" action="ajax/uploadphoto.php" method="post" enctype="multipart/form-data" target="file_upload_target" class="propertycontainer" data-element="PHOTO"> <fieldset id="photo" class="formfloat"> + <a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a> <div id="contacts_details_photo_wrapper" title="<?php echo $l->t('Click or drop to upload picture'); ?> (max <?php echo $_['uploadMaxHumanFilesize']; ?>)"> <!-- img style="padding: 1em;" id="contacts_details_photo" alt="Profile picture" src="photo.php?id=<?php echo $_['id']; ?>" / --> <progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress> @@ -45,16 +48,29 @@ $id = isset($_['id']) ? $_['id'] : ''; <dt><label for="fn"><?php echo $l->t('Display name'); ?></label></dt> <dd class="propertycontainer" data-element="FN"> <select id="fn_select" title="<?php echo $l->t('Format custom, Short name, Full name, Reverse or Reverse with comma'); ?>" style="width:16em;"> - </select><a id="edit_name" class="edit" title="<?php echo $l->t('Edit name details'); ?>"></a> + </select><a id="edit_name" class="action edit" title="<?php echo $l->t('Edit name details'); ?>"></a> </dd> <dt style="display:none;" id="org_label" data-element="ORG"><label for="org"><?php echo $l->t('Organization'); ?></label></dt> - <dd style="display:none;" class="propertycontainer" id="org_value" data-element="ORG"><input id="org" required="required" name="value[ORG]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Organization'); ?>" /><a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd style="display:none;" class="propertycontainer" id="org_value" data-element="ORG"><input id="org" required="required" name="value[ORG]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Organization'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt style="display:none;" id="nickname_label" data-element="NICKNAME"><label for="nickname"><?php echo $l->t('Nickname'); ?></label></dt> - <dd style="display:none;" class="propertycontainer" id="nickname_value" data-element="NICKNAME"><input id="nickname" required="required" name="value[NICKNAME]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Enter nickname'); ?>" /><a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd style="display:none;" class="propertycontainer" id="nickname_value" data-element="NICKNAME"><input id="nickname" required="required" name="value[NICKNAME]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Enter nickname'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> <dt style="display:none;" id="bday_label" data-element="BDAY"><label for="bday"><?php echo $l->t('Birthday'); ?></label></dt> - <dd style="display:none;" class="propertycontainer" id="bday_value" data-element="BDAY"><input id="bday" required="required" name="value" type="text" class="contacts_property" value="" placeholder="<?php echo $l->t('dd-mm-yyyy'); ?>" /><a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <dd style="display:none;" class="propertycontainer" id="bday_value" data-element="BDAY"><input id="bday" required="required" name="value" type="text" class="contacts_property" value="" placeholder="<?php echo $l->t('dd-mm-yyyy'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></dd> + <!-- dt id="categories_label" data-element="CATEGORIES"><label for="categories"><?php echo $l->t('Categories'); ?></label></dt> + <dd class="propertycontainer" id="categories_value" data-element="CATEGORIES"> + <select class="contacts_property" multiple="multiple" id="categories" name="value[]"> + <?php echo html_select_options($_['categories'], array(), array('combine'=>true)) ?> + </select> + <a class="action edit" onclick="$(this).tipsy('hide');OCCategories.edit();" title="<?php echo $l->t('Edit categories'); ?>"></a> + </dd --> + <dt style="display:none;" id="categories_label" data-element="CATEGORIES"><label for="categories"><?php echo $l->t('Categories'); ?></label></dt> + <dd style="display:none;" class="propertycontainer" id="categories_value" data-element="CATEGORIES"><input id="categories" required="required" name="value[CATEGORIES]" type="text" class="contacts_property" style="width:16em;" name="value" value="" placeholder="<?php echo $l->t('Categories'); ?>" /><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a><a class="action edit" onclick="$(this).tipsy('hide');OCCategories.edit();" title="<?php echo $l->t('Edit categories'); ?>"></a></dd> </dl> </fieldset> + <fieldset id="note" class="formfloat propertycontainer contactpart" style="display:none;" data-element="NOTE"> + <legend><?php echo $l->t('Note'); ?><a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'single');" title="<?php echo $l->t('Delete'); ?>"></a></legend> + <textarea class="contacts_property note" name="value" cols="60" rows="10"></textarea> + </fieldset> </form> </div> @@ -68,8 +84,8 @@ $id = isset($_['id']) ? $_['id'] : ''; <ul id="emaillist" class="propertylist"> <li class="template" style="white-space: nowrap; display: none;" data-element="EMAIL"> <input type="checkbox" class="contacts_property" name="parameters[TYPE][]" value="PREF" title="<?php echo $l->t('Preferred'); ?>" /> - <input type="email" required="required" class="nonempty contacts_property" style="width:15em;" name="value" value="" x-moz-errormessage="<?php echo $l->t('Please specify a valid email address.'); ?>" placeholder="<?php echo $l->t('Enter email address'); ?>" /><span class="listactions"><a onclick="Contacts.UI.mailTo(this)" class="mail" title="<?php echo $l->t('Mail to address'); ?>"></a> - <a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="<?php echo $l->t('Delete email address'); ?>"></a></span></li> + <input type="email" required="required" class="nonempty contacts_property" style="width:15em;" name="value" value="" x-moz-errormessage="<?php echo $l->t('Please specify a valid email address.'); ?>" placeholder="<?php echo $l->t('Enter email address'); ?>" /><span class="listactions"><a onclick="Contacts.UI.mailTo(this)" class="action mail" title="<?php echo $l->t('Mail to address'); ?>"></a> + <a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="<?php echo $l->t('Delete email address'); ?>"></a></span></li> </ul><!-- a id="add_email" class="add" title="<?php echo $l->t('Add email address'); ?>"></a --> </div> <!-- email addresses--> @@ -84,7 +100,7 @@ $id = isset($_['id']) ? $_['id'] : ''; <select multiple="multiple" name="parameters[TYPE][]"> <?php echo html_select_options($_['phone_types'], array()) ?> </select> - <a class="delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="<?php echo $l->t('Delete phone number'); ?>"></a></li> + <a class="action delete" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="<?php echo $l->t('Delete phone number'); ?>"></a></li> </ul><!-- a id="add_phone" class="add" title="<?php echo $l->t('Add phone number'); ?>"></a --> </div> <!-- Phone numbers --> @@ -96,7 +112,7 @@ $id = isset($_['id']) ? $_['id'] : ''; <dl class="addresscard template" style="display: none;" data-element="ADR"><dt> <input class="adr contacts_property" name="value" type="hidden" value="" /> <input type="hidden" class="adr_type contacts_property" name="parameters[TYPE][]" value="" /> - <span class="adr_type_label"></span><a class="globe" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.searchOSM(this);" title="<?php echo $l->t('View on map'); ?>"></a><a class="edit" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.Card.editAddress(this, false);" title="<?php echo $l->t('Edit address details'); ?>"></a><a class="delete" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="Delete address"></a> + <span class="adr_type_label"></span><a class="action globe" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.searchOSM(this);" title="<?php echo $l->t('View on map'); ?>"></a><a class="action edit" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.Card.editAddress(this, false);" title="<?php echo $l->t('Edit address details'); ?>"></a><a class="action delete" style="float:right;" onclick="$(this).tipsy('hide');Contacts.UI.Card.deleteProperty(this, 'list');" title="Delete address"></a> </dt><dd><ul class="addresslist"></ul></dd></dl> </fieldset> diff --git a/apps/contacts/templates/part.contactphoto.php b/apps/contacts/templates/part.contactphoto.php index 9e3f5876cd1..bcb2f75815c 100644 --- a/apps/contacts/templates/part.contactphoto.php +++ b/apps/contacts/templates/part.contactphoto.php @@ -2,8 +2,9 @@ $id = $_['id']; $wattr = isset($_['width'])?'width="'.$_['width'].'"':''; $hattr = isset($_['height'])?'height="'.$_['height'].'"':''; +$rand = isset($_['refresh'])?'&'.rand().'='.rand():''; ?> -<img class="loading" id="contacts_details_photo" <?php echo $wattr; ?> <?php echo $hattr; ?> src="<?php echo OC_Helper::linkToAbsolute('contacts', 'photo.php'); ?>?id=<?php echo $id; ?>&refresh=<?php echo rand(); ?>" /> +<img class="loading" id="contacts_details_photo" <?php echo $wattr; ?> <?php echo $hattr; ?> src="<?php echo OC_Helper::linkToAbsolute('contacts', 'photo.php'); ?>?id=<?php echo $id.$rand; ?>" /> <progress id="contacts_details_photo_progress" style="display:none;" value="0" max="100">0 %</progress> diff --git a/apps/contacts/templates/part.details.php b/apps/contacts/templates/part.details.php deleted file mode 100644 index 5badd816155..00000000000 --- a/apps/contacts/templates/part.details.php +++ /dev/null @@ -1,96 +0,0 @@ -<?php if(array_key_exists('FN',$_['details'])): ?> - <?php echo $this->inc('part.property.FN', array('property' => $_['details']['FN'][0])); ?> - <?php echo $this->inc('part.property.N', array('property' => $_['details']['N'][0])); ?> - <a href="export.php?contactid=<?php echo $_['id']; ?>"><img class="svg action" id="contacts_downloadcard" src="<?php echo image_path('', 'actions/download.svg'); ?>" title="<?php echo $l->t('Download contact');?>" /></a> - <img class="svg action" id="contacts_deletecard" src="<?php echo image_path('', 'actions/delete.svg'); ?>" title="<?php echo $l->t('Delete contact');?>" /> - - <?php if(isset($_['details']['PHOTO'])): // Emails first ?> - <img id="contacts_details_photo" src="photo.php?id=<?php echo $_['id']; ?>"> - <?php endif; ?> - - <ul id="contacts_details_list"> - <?php if(isset($_['details']['BDAY'])): // Emails first ?> - <?php echo $this->inc('part.property', array('property' => $_['details']['BDAY'][0])); ?> - <?php endif; ?> - - <?php if(isset($_['details']['ORG'])): // Emails first ?> - <?php echo $this->inc('part.property', array('property' => $_['details']['ORG'][0])); ?> - <?php endif; ?> - - <?php foreach(array('EMAIL','TEL','ADR') as $type): ?> - <?php if(isset($_['details'][$type])): // Emails first ?> - <?php foreach($_['details'][$type] as $property): ?> - <?php echo $this->inc('part.property',array('property' => $property )); ?> - <?php endforeach; ?> - <?php endif; ?> - <?php endforeach; ?> - <li class="contacts_property_add"> - <form id="contacts_addpropertyform"> - <input type="hidden" name="id" value="<?php echo $_['id']; ?>"> - <p class="contacts_property_name"> - <select name="name" size="1"> - <?php echo html_select_options($_['property_types'], 'EMAIL') ?> - </select> - <br> - <input id="contacts_addproperty_button" type="submit" value="<?php echo $l->t('Add'); ?>"> - </p> - <p class="contacts_property_data" id="contacts_generic"> - <input type="text" name="value" value=""> - </p> - </form> - <div id="contacts_addcontactsparts" style="display:none;"> - <ul class="contacts_property_data" id="contacts_addresspart"> - <li> - <label for="adr_type"><?php echo $l->t('Type'); ?></label> - <select id="adr_type" name="parameters[TYPE]" size="1"> - <?php echo html_select_options($_['adr_types'], 'HOME') ?> - </select> - </li> - <li> - <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label> - <input id="adr_pobox" type="text" name="value[0]" value=""> - </li> - <li> - <label for="adr_extended"><?php echo $l->t('Extended'); ?></label> - <input id="adr_extended" type="text" name="value[1]" value=""> - </li> - <li> - <label for="adr_street"><?php echo $l->t('Street'); ?></label> - <input id="adr_street" type="text" name="value[2]" value=""> - </li> - <li> - <label for="adr_city"><?php echo $l->t('City'); ?></label> - <input id="adr_city" type="text" name="value[3]" value=""> - </li> - <li> - <label for="adr_region"><?php echo $l->t('Region'); ?></label> - <input id="adr_region" type="text" name="value[4]" value=""> - </li> - <li> - <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> - <input id="adr_zipcode" type="text" name="value[5]" value=""> - </li> - <li> - <label for="adr_country"><?php echo $l->t('Country'); ?></label> - <input id="adr_country" type="text" name="value[6]" value=""> - </li> - </ul> - <p class="contacts_property_data" id="contacts_phonepart"> - <input type="text" name="value" value=""> - <select name="parameters[TYPE][]" multiple="multiple" data-placeholder="<?php echo $l->t('Type') ?>"> - <?php echo html_select_options($_['phone_types'], 'CELL') ?> - </select> - </p> - <p class="contacts_property_data" id="contacts_generic"> - <input type="text" name="value" value=""> - </p> - </div> - </li> - </ul> -<?php endif; ?> -<script language="Javascript"> -/* Re-tipsify ;-)*/ - $('#contacts_deletecard').tipsy({gravity: 'ne'}); - $('#contacts_downloadcard').tipsy({gravity: 'ne'}); - $('.button').tipsy(); -</script> diff --git a/apps/contacts/templates/part.edit_categories_dialog.php b/apps/contacts/templates/part.edit_categories_dialog.php new file mode 100644 index 00000000000..8997fa586bd --- /dev/null +++ b/apps/contacts/templates/part.edit_categories_dialog.php @@ -0,0 +1,16 @@ +<?php +$categories = isset($_['categories'])?$_['categories']:array(); +?> +<div id="edit_categories_dialog" title="<?php echo $l->t('Edit categories'); ?>"> +<!-- ?php print_r($types); ? --> + <form method="post" id="categoryform"> + <div class="scrollarea"> + <ul id="categorylist"> + <?php foreach($categories as $category) { ?> + <li><input type="checkbox" name="categories[]" value="<?php echo $category; ?>" /><?php echo $category; ?></li> + <?php } ?> + </ul> + </div> + <div class="bottombuttons"><input type="text" id="category_addinput" name="category" /><button id="category_addbutton" disabled="disabled"><?php echo $l->t('Add'); ?></button></div> + </form> +</div> diff --git a/apps/contacts/templates/part.messagebox.php b/apps/contacts/templates/part.messagebox.php deleted file mode 100644 index 5db10e7e6c5..00000000000 --- a/apps/contacts/templates/part.messagebox.php +++ /dev/null @@ -1,3 +0,0 @@ -<div id="messagebox"> -<div id="messagebox_msg"></div> -</di> diff --git a/apps/contacts/templates/part.no_contacts.php b/apps/contacts/templates/part.no_contacts.php deleted file mode 100644 index f58fdef09f0..00000000000 --- a/apps/contacts/templates/part.no_contacts.php +++ /dev/null @@ -1,8 +0,0 @@ -<div id="firstrun"> -You have no contacts in your list. - <div id="selections"> - <input type="button" value="Import contacts" onclick="Contacts.UI.Addressbooks.import()" /> - <input type="button" value="Add contact" onclick="Contacts.UI.Card.editNew()" /> - <input type="button" value="Edit addressbooks" onclick="Contacts.UI.Addressbooks.overview()" /> - </div> -</div>
\ No newline at end of file diff --git a/apps/contacts/templates/part.property.FN.php b/apps/contacts/templates/part.property.FN.php deleted file mode 100644 index c9e21c20e60..00000000000 --- a/apps/contacts/templates/part.property.FN.php +++ /dev/null @@ -1,9 +0,0 @@ - <p id="contacts_details_name" class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>"> - <?php echo htmlspecialchars($_['property']['value']); ?> - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> - </p> -<?php if (!isset($_['details'])): ?> -<script> -$('#leftcontent li.active a').text('<?php echo htmlspecialchars($_['property']['value']); ?>'); -</script> -<?php endif ?> diff --git a/apps/contacts/templates/part.property.N.php b/apps/contacts/templates/part.property.N.php deleted file mode 100644 index 73d599ad7b4..00000000000 --- a/apps/contacts/templates/part.property.N.php +++ /dev/null @@ -1,4 +0,0 @@ -<p id="contacts_details_name_n" class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>"> - (<?php echo $_['property']['value'][0].', '.$_['property']['value'][1].' '.$_['property']['value'][2]; ?>) - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> -</p> diff --git a/apps/contacts/templates/part.property.php b/apps/contacts/templates/part.property.php deleted file mode 100644 index 7b23fae45b5..00000000000 --- a/apps/contacts/templates/part.property.php +++ /dev/null @@ -1,86 +0,0 @@ -<li class="contacts_property" data-checksum="<?php echo $_['property']['checksum']; ?>"> - <?php if($_['property']['name'] == 'BDAY'): ?> - <p class="contacts_property_name"><?php echo $l->t('Birthday'); ?></p> - <p class="contacts_property_data"> - <?php echo $l->l('date',new DateTime($_['property']['value'])); ?> - <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span> - </p> - <?php elseif($_['property']['name'] == 'ORG'): ?> - <p class="contacts_property_name"><?php echo $l->t('Organization'); ?></p> - <p class="contacts_property_data"> - <?php echo htmlspecialchars($_['property']['value']); ?> - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> - <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span> - </p> - <?php elseif($_['property']['name'] == 'EMAIL'): ?> - <p class="contacts_property_name"><?php echo $l->t('Email'); ?></p> - <p class="contacts_property_data"> - <?php echo htmlspecialchars($_['property']['value']); ?> - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> - <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span> - </p> - <?php elseif($_['property']['name'] == 'TEL'): ?> - <p class="contacts_property_name"><?php echo (isset($_['property']['parameters']['PREF']) && $_['property']['parameters']['PREF']) ? $l->t('Preferred').' ' : '' ?><?php echo $l->t('Phone'); ?></p> - <p class="contacts_property_data"> - <?php echo htmlspecialchars($_['property']['value']); ?> - <?php if(isset($_['property']['parameters']['TYPE']) && !empty($_['property']['parameters']['TYPE'])): ?> -<?php - foreach($_['property']['parameters']['TYPE'] as $type) { - if (isset($_['phone_types'][strtoupper($type)])){ - $types[]=$_['phone_types'][strtoupper($type)]; - } - else{ - $types[]=$l->t(ucwords(strtolower($type))); - } - } - $label = join(' ', $types); -?> - (<?php echo $label; ?>) - <?php endif; ?> - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> - <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span> - </p> - <?php elseif($_['property']['name'] == 'ADR'): ?> - <p class="contacts_property_name"> - <?php echo $l->t('Address'); ?> - <?php if(isset($_['property']['parameters']['TYPE'])): ?> - <br> -<?php - $type = $_['property']['parameters']['TYPE']; - if (isset($_['adr_types'][strtoupper($type)])){ - $label=$_['adr_types'][strtoupper($type)]; - } - else{ - $label=$l->t(ucwords(strtolower($type))); - } -?> - (<?php echo $label; ?>) - <?php endif; ?> - </p> - <p class="contacts_property_data"> - <?php if(!empty($_['property']['value'][0])): ?> - <?php echo htmlspecialchars($_['property']['value'][0]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][1])): ?> - <?php echo htmlspecialchars($_['property']['value'][1]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][2])): ?> - <?php echo htmlspecialchars($_['property']['value'][2]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][3])): ?> - <?php echo htmlspecialchars($_['property']['value'][3]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][4])): ?> - <?php echo htmlspecialchars($_['property']['value'][4]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][5])): ?> - <?php echo htmlspecialchars($_['property']['value'][5]); ?><br> - <?php endif; ?> - <?php if(!empty($_['property']['value'][6])): ?> - <?php echo htmlspecialchars($_['property']['value'][6]); ?> - <?php endif; ?> - <span style="display:none;" data-use="edit"><img class="svg action" src="<?php echo image_path('', 'actions/rename.svg'); ?>" /></span> - <span style="display:none;" data-use="delete"><img class="svg action" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></span> - </p> - <?php endif; ?> -</li> diff --git a/apps/contacts/templates/part.setpropertyform.php b/apps/contacts/templates/part.setpropertyform.php deleted file mode 100644 index 93ade8faaa7..00000000000 --- a/apps/contacts/templates/part.setpropertyform.php +++ /dev/null @@ -1,91 +0,0 @@ - <form id="contacts_setpropertyform"> - <input type="hidden" name="checksum" value="<?php echo $_['property']['checksum']; ?>"> - <input type="hidden" name="id" value="<?php echo $_['id']; ?>"> - <?php if($_['property']['name']=='N'): ?> - <p class="contacts_property_name"> - <dl class="contacts_property_data form"> - <dt><label for="n1"><?php echo $l->t('Given name'); ?></label></dt> - <dd><input id="n1" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]); ?>"></dd> - <dt><label for="n0"><?php echo $l->t('Family name'); ?></dt> - <dd><input id="n0" type="text" name="value[0]" value="<?php echo htmlspecialchars($_['property']['value'][0]); ?>"></dd> - <dt><label for="n2"><?php echo $l->t('Additional names'); ?></dt> - <dd><input id="n2" type="text" name="value[2]" value="<?php echo htmlspecialchars($_['property']['value'][2]); ?>"> - <input id="n3" type="hidden" name="value[3]" value="<?php echo htmlspecialchars($_['property']['value'][3]); ?>"> - <input id="n4" type="hidden" name="value[4]" value="<?php echo htmlspecialchars($_['property']['value'][4]); ?>"> - </dd> - </dl> - </p> - <?php elseif($_['property']['name']=='FN'): ?> - <p class="contacts_property_data"><input id="fn" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p> - <?php elseif($_['property']['name']=='ADR'): ?> - <p class="contacts_property_name"><label for="adr_pobox"><?php echo $l->t('Address'); ?></label></p> - <dl class="contacts_property_data form" id="contacts_addresspart"> - <dt> - <label class="label" for="adr_type"><?php echo $l->t('Type'); ?></label> - </dt> - <dd> - <select id="adr_type" name="parameters[TYPE]" size="1"> - <?php echo html_select_options($_['adr_types'], strtoupper($_['property']['parameters']['TYPE'])) ?> - </select> - </dd> - <dt> - <label for="adr_pobox"><?php echo $l->t('PO Box'); ?></label> - </dt> - <dd> - <input id="adr_pobox" type="text" name="value[0]" value="<?php echo htmlspecialchars($_['property']['value'][0]) ?>"> - </dd> - <!-- dt> - <label for="adr_extended"><?php echo $l->t('Extended'); ?></label> - </dt> - <dd> - <input style="width: 7em;" id="adr_extended" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]) ?>"> - </dd --> - <dt> - <label for="adr_street"><?php echo $l->t('Street'); ?></label> - </dt> - <dd> - <input style="width: 12em;" id="adr_street" type="text" name="value[2]" value="<?php echo htmlspecialchars($_['property']['value'][2]) ?>"> - <label for="adr_extended"><?php echo $l->t('Extended'); ?></label><input style="width: 7em;" id="adr_extended" type="text" name="value[1]" value="<?php echo htmlspecialchars($_['property']['value'][1]) ?>"> - </dd> - <dt> - <label for="adr_city"><?php echo $l->t('City'); ?></label> - </dt> - <dd> - <input style="width: 12em;" id="adr_city" type="text" name="value[3]" value="<?php echo htmlspecialchars($_['property']['value'][3]) ?>"> - <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> - <input style="width: 5em;" id="adr_zipcode" type="text" name="value[5]" value="<?php echo htmlspecialchars($_['property']['value'][5]) ?>"> - </dd> - <dt> - <label for="adr_region"><?php echo $l->t('Region'); ?></label> - </dt> - <dd> - <input id="adr_region" type="text" name="value[4]" value="<?php echo htmlspecialchars($_['property']['value'][4]) ?>"> - </dd> - <!-- dt> - <label for="adr_zipcode"><?php echo $l->t('Zipcode'); ?></label> - </dt> - <dd> - <input style="width: 7em;" id="adr_zipcode" type="text" name="value[5]" value="<?php echo htmlspecialchars($_['property']['value'][5]) ?>"> - </dd --> - <dt> - <label for="adr_country"><?php echo $l->t('Country'); ?></label> - </dt> - <dd> - <input style="width: 25em;" id="adr_country" type="text" name="value[6]" value="<?php echo htmlspecialchars($_['property']['value'][6]) ?>"> - </dd> - </dl> - <?php elseif($_['property']['name']=='TEL'): ?> - <p class="contacts_property_name"><label for="tel"><?php echo $l->t('Phone'); ?></label></p> - <p class="contacts_property_data"><input id="tel" type="phone" name="value" value="<?php echo htmlspecialchars($_['property']['value']) ?>"> - <select id="tel_type<?php echo $_['property']['checksum'] ?>" name="parameters[TYPE][]" multiple="multiple" data-placeholder="<?php echo $l->t('Type') ?>"> - <?php echo html_select_options($_['phone_types'], isset($_['property']['parameters']['TYPE'])?$_['property']['parameters']['TYPE']:array()) ?> - </select></p> - <?php elseif($_['property']['name']=='EMAIL'): ?> - <p class="contacts_property_name"><label for="email"><?php echo $l->t('Email'); ?></label></p> - <p class="contacts_property_data"><input id="email" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p> - <?php elseif($_['property']['name']=='ORG'): ?> - <p class="contacts_property_name"><label for="org"><?php echo $l->t('Organization'); ?></label></p> - <p class="contacts_property_data"><input id="org" type="text" name="value" value="<?php echo htmlspecialchars($_['property']['value']); ?>"></p> - <?php endif; ?> - <input id="contacts_setproperty_button" type="submit" value="<?php echo $l->t('Update'); ?>"> - </form> 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 @@ -<form id="mediaform"> +<form id="contacts"> <fieldset class="personalblock"> <strong><?php echo $l->t('Contacts'); ?></strong><br /> - <?php echo $l->t('CardDAV syncing address:'); ?> - <?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?><br /> + <?php echo $l->t('CardDAV syncing addresses:'); ?> + <dl> + <dt><?php echo $l->t('Primary address (Kontact et al)'); ?></dt> + <dd><code><?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/</code></dd> + <dt><?php echo $l->t('iOS/OS X'); ?></dt> + <dd><code><?php echo OC_Helper::linkToAbsolute('contacts', 'carddav.php'); ?>/principals/<?php echo OC_User::getUser(); ?></code>/</dd> + </dl> </fieldset> </form> 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 @@ +<?php + +/** + * Copyright (c) 2011, Frank Karlitschek <karlitschek@kde.org> + * 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 @@ -<?php -/** - * Copyright (c) 2011, Frank Karlitschek <karlitschek@kde.org> - * 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 @@ <?php /** -* 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 <http://www.gnu.org/licenses/>. -* -*/ - -OC_APP::registerAdmin('external','settings'); - -OC_App::register( array( 'order' => 70, 'id' => 'external', 'name' => 'External' )); - -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", '' ))); - + * 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 <http://www.gnu.org/licenses/>. + * + */ + +OC::$CLASSPATH['OC_External'] = 'apps/external/lib/external.php'; +OC_Util::addStyle( 'external', 'style'); + +OC_APP::registerAdmin('external', 'settings'); + +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 @@ <?php /** -* 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 <http://www.gnu.org/licenses/>. -* -*/ - + * 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 <http://www.gnu.org/licenses/>. + * + */ 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,67 +1,56 @@ $(document).ready(function(){ + newSiteHtml = '<li><input type="text" class="site_name" name="site_name[]" value="" placeholder="Name" />\n\ + <input type="text" name="site_url[]" class="site_url" value="" placeholder="URL" />\n\ +<img class="svg action delete_button" src="'+OC.imagePath("core", "actions/delete") +'" title="Remove site" /></li>'; - - - $('#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){ - event.preventDefault(); - var post = $( "#s3name" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s3name .msg', data); }); - }); + $(this).tipsy('hide'); + $(this).parent().remove(); - $('#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); }); - }); + saveSites(); + } - $('#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); }); - }); + function saveSites() { + var post = $('#external').serialize(); + $.post( OC.filePath('external','ajax','setsites.php') , post, function(data) { + // OC.msg.finishedSaving('#site_name .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); }); - }); + function showDeleteButton(event) { + $(this).find('img.delete_button').fadeIn(100); + } - $('#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); }); - }); + function hideDeleteButton(event) { + $(this).find('img.delete_button').fadeOut(100); + } - $('#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); }); - }); + // Initialize events + $('input[name^=site_]').change(addSiteEventHandler); + $('img.delete_button').click(deleteButtonEventHandler); + $('img.delete_button').tipsy(); - $('#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); }); - }); + $('#external li').hover(showDeleteButton, hideDeleteButton); - $('#s5url').blur(function(event){ + $('#add_external_site').click(function(event) { event.preventDefault(); - var post = $( "#s5url" ).serialize(); - $.post( OC.filePath('external','ajax','seturls.php') , post, function(data){ OC.msg.finishedSaving('#s5url .msg', data); }); - }); + $('#external ul').append(newSiteHtml); + $('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); + + }); }); 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 @@ +<?php + +/** + * ownCloud - gallery application + * + * @author Bartek Przybylski + * @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +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 @@ <form id="external"> <fieldset class="personalblock"> <strong>External Sites</strong><br /> - <input type="text" name="s1name" id="s1name" value="<?php echo $_['s1name']; ?>" placeholder="<?php echo $l->t('Name');?>" /> - <input type="text" name="s1url" id="s1url" value="<?php echo $_['s1url']; ?>" placeholder="<?php echo $l->t('Url');?>" /> - <br /> - <input type="text" name="s2name" id="s2name" value="<?php echo $_['s2name']; ?>" placeholder="<?php echo $l->t('Name');?>" /> - <input type="text" name="s2url" id="s2url" value="<?php echo $_['s2url']; ?>" placeholder="<?php echo $l->t('Url');?>" /> - <br /> - <input type="text" name="s3name" id="s3name" value="<?php echo $_['s3name']; ?>" placeholder="<?php echo $l->t('Name');?>" /> - <input type="text" name="s3url" id="s3url" value="<?php echo $_['s3url']; ?>" placeholder="<?php echo $l->t('Url');?>" /> - <br /> - <input type="text" name="s4name" id="s4name" value="<?php echo $_['s4name']; ?>" placeholder="<?php echo $l->t('Name');?>" /> - <input type="text" name="s4url" id="s4url" value="<?php echo $_['s4url']; ?>" placeholder="<?php echo $l->t('Url');?>" /> - <br /> - <input type="text" name="s5name" id="s5name" value="<?php echo $_['s5name']; ?>" placeholder="<?php echo $l->t('Name');?>" /> - <input type="text" name="s5url" id="s5url" value="<?php echo $_['s5url']; ?>" placeholder="<?php echo $l->t('Url');?>" /> - <br /> + <ul class="external_sites"> + <?php + $sites = OC_External::getSites(); + for($i = 0; $i < sizeof($sites); $i++) { + echo '<li><input type="text" name="site_name[]" class="site_name" value="'.$sites[$i][0].'" placeholder="'.$l->t('Name').'" /> + <input type="text" class="site_url" name="site_url[]" value="'.$sites[$i][1].'" placeholder="'.$l->t('URL').'" /> + <img class="svg action delete_button" src="'.image_path("", "actions/delete.svg") .'" title="'.$l->t("Remove site").'" /> + </li>'; + } + ?> -<span class="msg"></span> + </ul> + + <input type="button" id="add_external_site" value="Add" /> + <span class="msg"></span> </fieldset> </form> diff --git a/apps/files_archive/appinfo/app.php b/apps/files_archive/appinfo/app.php new file mode 100644 index 00000000000..693c28d98a0 --- /dev/null +++ b/apps/files_archive/appinfo/app.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC::$CLASSPATH['OC_Archive'] = 'apps/files_archive/lib/archive.php'; +foreach(array('ZIP') as $type){ + OC::$CLASSPATH['OC_Archive_'.$type] = 'apps/files_archive/lib/'.strtolower($type).'.php'; +} + +OC::$CLASSPATH['OC_Filestorage_Archive']='apps/files_archive/lib/storage.php'; + +OC_Hook::connect('OC_Filesystem','get_mountpoint','OC_Filestorage_Archive','autoMount'); + +OC_Util::addScript( 'files_archive', 'archive' ); diff --git a/apps/files_archive/appinfo/info.xml b/apps/files_archive/appinfo/info.xml new file mode 100644 index 00000000000..df767d39f6b --- /dev/null +++ b/apps/files_archive/appinfo/info.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<info> + <id>files_archive</id> + <name>Archive support</name> + <description>Transparent opening of archives</description> + <version>0.1</version> + <licence>AGPL</licence> + <author>Robin Appelman</author> + <require>3</require> +</info> diff --git a/apps/files_archive/js/archive.js b/apps/files_archive/js/archive.js new file mode 100644 index 00000000000..ec316c7bf2c --- /dev/null +++ b/apps/files_archive/js/archive.js @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +$(document).ready(function() { + if(typeof FileActions!=='undefined'){ + FileActions.register('application/zip','Open','',function(filename){ + window.location='index.php?dir='+encodeURIComponent($('#dir').val()).replace(/%2F/g, '/')+'/'+encodeURIComponent(filename); + }); + FileActions.setDefault('application/zip','Open'); + } +}); diff --git a/apps/files_archive/lib/archive.php b/apps/files_archive/lib/archive.php new file mode 100644 index 00000000000..be89f894fb7 --- /dev/null +++ b/apps/files_archive/lib/archive.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class OC_Archive{ + /** + * open any of the supporeted archive types + * @param string path + * @return OC_Archive + */ + public static function open($path){ + $ext=substr($path,strrpos($path,'.')); + switch($ext){ + case '.zip': + return new OC_Archive_ZIP($path); + } + } + + abstract function __construct($source); + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + abstract function addFolder($path); + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + abstract function addFile($path,$source=''); + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + abstract function rename($source,$dest); + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + abstract function filesize($path); + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + abstract function mtime($path); + /** + * get the files in a folder + * @param path + * @return array + */ + abstract function getFolder($path); + /** + *get all files in the archive + * @return array + */ + abstract function getFiles(); + /** + * get the content of a file + * @param string path + * @return string + */ + abstract function getFile($path); + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + abstract function extractFile($path,$dest); + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + abstract function fileExists($path); + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + abstract function remove($path); + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + abstract function getStream($path,$mode); +} diff --git a/apps/files_archive/lib/storage.php b/apps/files_archive/lib/storage.php new file mode 100644 index 00000000000..72a96ca5a5d --- /dev/null +++ b/apps/files_archive/lib/storage.php @@ -0,0 +1,142 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Filestorage_Archive extends OC_Filestorage_Common{ + /** + * underlying local storage used for missing functions + * @var OC_Archive + */ + private $archive; + private $path; + private static $mounted=array(); + private static $enableAutomount=true; + private static $rootView; + + private function stripPath($path){//files should never start with / + if(substr($path,0,1)=='/'){ + $path=substr($path,1); + } + return $path; + } + + public function __construct($params){ + $this->archive=OC_Archive::open($params['archive']); + $this->path=$params['archive']; + } + + public function mkdir($path){ + $path=$this->stripPath($path); + return $this->archive->addFolder($path); + } + public function rmdir($path){ + $path=$this->stripPath($path); + return $this->archive->remove($path.'/'); + } + public function opendir($path){ + $path=$this->stripPath($path); + $content=$this->archive->getFolder($path); + foreach($content as &$file){ + if(substr($file,-1)=='/'){ + $file=substr($file,0,-1); + } + } + $id=md5($this->path.$path); + OC_FakeDirStream::$dirs[$id]=$content; + return opendir('fakedir://'.$id); + } + public function stat($path){ + $ctime=filectime($this->path); + $path=$this->stripPath($path); + if($path==''){ + $stat=stat($this->path); + }else{ + if($this->is_dir($path)){ + $stat=array('size'=>0); + $stat['mtime']=filemtime($this->path); + }else{ + $stat=array(); + $stat['mtime']=$this->archive->mtime($path); + $stat['size']=$this->archive->filesize($path); + } + } + $stat['ctime']=$ctime; + return $stat; + } + public function filetype($path){ + $path=$this->stripPath($path); + if($path==''){ + return 'dir'; + } + if(substr($path,-1)=='/'){ + return $this->archive->fileExists($path)?'dir':'file'; + }else{ + return $this->archive->fileExists($path.'/')?'dir':'file'; + } + } + public function is_readable($path){ + return is_readable($this->path); + } + public function is_writable($path){ + return is_writable($this->path); + } + public function file_exists($path){ + $path=$this->stripPath($path); + if($path==''){ + return file_exists($this->path); + } + return $this->archive->fileExists($path) or $this->archive->fileExists($path.'/'); + } + public function unlink($path){ + $path=$this->stripPath($path); + return $this->archive->remove($path); + } + public function fopen($path,$mode){ + $path=$this->stripPath($path); + return $this->archive->getStream($path,$mode); + } + public function free_space($path){ + return 0; + } + public function touch($path, $mtime=null){ + if(is_null($mtime)){ + $tmpFile=OC_Helper::tmpFile(); + $this->archive->extractFile($path,$tmpFile); + $this->archive->addfile($path,$tmpFile); + }else{ + return false;//not supported + } + } + + /** + * automount paths from file hooks + * @param aray params + */ + public static function autoMount($params){ + if(!self::$enableAutomount){ + return; + } + $path=$params['path']; + if(!self::$rootView){ + self::$rootView=new OC_FilesystemView(''); + } + self::$enableAutomount=false;//prevent recursion + $supported=array('zip'); + foreach($supported as $type){ + $ext='.'.$type.'/'; + if(($pos=strpos(strtolower($path),$ext))!==false){ + $archive=substr($path,0,$pos+strlen($ext)-1); + if(self::$rootView->file_exists($archive) and array_search($archive,self::$mounted)===false){ + $localArchive=self::$rootView->getLocalFile($archive); + OC_Filesystem::mount('OC_Filestorage_Archive',array('archive'=>$localArchive),$archive.'/'); + self::$mounted[]=$archive; + } + } + } + self::$enableAutomount=true; + } +} diff --git a/apps/files_archive/lib/zip.php b/apps/files_archive/lib/zip.php new file mode 100644 index 00000000000..eab101b3a5c --- /dev/null +++ b/apps/files_archive/lib/zip.php @@ -0,0 +1,182 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_Archive_ZIP extends OC_Archive{ + /** + * @var ZipArchive zip + */ + private $zip=null; + private $contents=array(); + private $success=false; + private $path; + + function __construct($source){ + $this->path=$source; + $this->zip=new ZipArchive(); + if($this->zip->open($source,ZipArchive::CREATE)){ + }else{ + OC_LOG::write('files_archive','Error while opening archive '.$source,OC_Log::WARN); + } + } + /** + * add an empty folder to the archive + * @param string path + * @return bool + */ + function addFolder($path){ + return $this->zip->addEmptyDir($path); + } + /** + * add a file to the archive + * @param string path + * @param string source either a local file or string data + * @return bool + */ + function addFile($path,$source=''){ + if(file_exists($source)){ + $result=$this->zip->addFile($source,$path); + }else{ + $result=$this->zip->addFromString($path,$source); + } + if($result){ + $this->zip->close();//close and reopen to save the zip + $this->zip->open($this->path); + } + return $result; + } + /** + * rename a file or folder in the archive + * @param string source + * @param string dest + * @return bool + */ + function rename($source,$dest){ + return $this->zip->renameName($source,$dest); + } + /** + * get the uncompressed size of a file in the archive + * @param string path + * @return int + */ + function filesize($path){ + $stat=$this->zip->statName($path); + return $stat['size']; + } + /** + * get the last modified time of a file in the archive + * @param string path + * @return int + */ + function mtime($path){ + $stat=$this->zip->statName($path); + return $stat['mtime']; + } + /** + * get the files in a folder + * @param path + * @return array + */ + function getFolder($path){ + $files=$this->getFiles(); + $folderContent=array(); + $pathLength=strlen($path); + foreach($files as $file){ + if(substr($file,0,$pathLength)==$path and $file!=$path){ + if(strrpos(substr($file,0,-1),'/')<=$pathLength){ + $folderContent[]=substr($file,$pathLength); + } + } + } + return $folderContent; + } + /** + *get all files in the archive + * @return array + */ + function getFiles(){ + if(count($this->contents)){ + return $this->contents; + } + $fileCount=$this->zip->numFiles; + $files=array(); + for($i=0;$i<$fileCount;$i++){ + $files[]=$this->zip->getNameIndex($i); + } + $this->contents=$files; + return $files; + } + /** + * get the content of a file + * @param string path + * @return string + */ + function getFile($path){ + return $this->zip->getFromName($path); + } + /** + * extract a single file from the archive + * @param string path + * @param string dest + * @return bool + */ + function extractFile($path,$dest){ + $fp = $this->zip->getStream($path); + file_put_contents($dest,$fp); + } + /** + * check if a file or folder exists in the archive + * @param string path + * @return bool + */ + function fileExists($path){ + return $this->zip->locateName($path)!==false; + } + /** + * remove a file or folder from the archive + * @param string path + * @return bool + */ + function remove($path){ + return $this->zip->deleteName($path); + } + /** + * get a file handler + * @param string path + * @param string mode + * @return resource + */ + function getStream($path,$mode){ + if($mode=='r' or $mode=='rb'){ + return $this->zip->getStream($path); + }else{//since we cant directly get a writable stream, make a temp copy of the file and put it back in the archive when the stream is closed + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->fileExists($path)){ + $this->extractFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + private static $tempFiles=array(); + /** + * write back temporary files + */ + function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->addFile(self::$tempFiles[$tmpFile],$tmpFile); + unlink($tmpFile); + } + } +} diff --git a/apps/files_archive/tests/archive.php b/apps/files_archive/tests/archive.php new file mode 100644 index 00000000000..2e26b5e03b5 --- /dev/null +++ b/apps/files_archive/tests/archive.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +abstract class Test_Archive extends UnitTestCase { + /** + * @var OC_Archive + */ + protected $instance; + + /** + * get the existing test archive + * @return OC_Archive + */ + abstract protected function getExisting(); + /** + * get a new archive for write testing + * @return OC_Archive + */ + abstract protected function getNew(); + + public function testGetFiles(){ + $this->instance=$this->getExisting(); + $allFiles=$this->instance->getFiles(); + $expected=array('lorem.txt','logo-wide.png','dir/','dir/lorem.txt'); + $this->assertEqual(4,count($allFiles)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$allFiles),'cant find '.$file.' in archive'); + $this->assertTrue($this->instance->fileExists($file)); + } + $this->assertFalse($this->instance->fileExists('non/existing/file')); + + $rootContent=$this->instance->getFolder(''); + $expected=array('lorem.txt','logo-wide.png','dir/'); + $this->assertEqual(3,count($rootContent)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$rootContent),'cant find '.$file.' in archive'); + } + + $dirContent=$this->instance->getFolder('dir/'); + $expected=array('lorem.txt'); + $this->assertEqual(1,count($dirContent)); + foreach($expected as $file){ + $this->assertNotIdentical(false,array_search($file,$dirContent),'cant find '.$file.' in archive'); + } + } + + public function testContent(){ + $this->instance=$this->getExisting(); + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $textFile=$dir.'/lorem.txt'; + $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt')); + + $tmpFile=OC_Helper::tmpFile('.txt'); + $this->instance->extractFile('lorem.txt',$tmpFile); + $this->assertEqual(file_get_contents($textFile),file_get_contents($tmpFile)); + } + + public function testWrite(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $textFile=$dir.'/lorem.txt'; + $this->instance=$this->getNew(); + $this->assertEqual(0,count($this->instance->getFiles())); + $this->instance->addFile('lorem.txt',$textFile); + $this->assertEqual(1,count($this->instance->getFiles())); + $this->assertTrue($this->instance->fileExists('lorem.txt')); + + $this->assertEqual(file_get_contents($textFile),$this->instance->getFile('lorem.txt')); + $this->instance->addFile('lorem.txt','foobar'); + $this->assertEqual('foobar',$this->instance->getFile('lorem.txt')); + } + + public function testReadStream(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $this->instance=$this->getExisting(); + $fh=$this->instance->getStream('lorem.txt','r'); + $this->assertTrue($fh); + $content=fread($fh,$this->instance->filesize('lorem.txt')); + fclose($fh); + $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$content); + } + public function testWriteStream(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + $this->instance=$this->getNew(); + $fh=$this->instance->getStream('lorem.txt','w'); + $source=fopen($dir.'/lorem.txt','r'); + OC_Helper::streamCopy($source,$fh); + fclose($source); + fclose($fh); + $this->assertTrue($this->instance->fileExists('lorem.txt')); + $this->assertEqual(file_get_contents($dir.'/lorem.txt'),$this->instance->getFile('lorem.txt')); + } +} diff --git a/apps/files_archive/tests/storage.php b/apps/files_archive/tests/storage.php new file mode 100644 index 00000000000..4d0a83356bd --- /dev/null +++ b/apps/files_archive/tests/storage.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_Archive_Zip extends Test_FileStorage { + /** + * @var string tmpDir + */ + private $tmpFile; + + public function setUp(){ + $this->tmpFile=OC_Helper::tmpFile('.zip'); + $this->instance=new OC_Filestorage_Archive(array('archive'=>$this->tmpFile)); + } + + public function tearDown(){ + unlink($this->tmpFile); + } +} + +?>
\ No newline at end of file diff --git a/apps/files_archive/tests/zip.php b/apps/files_archive/tests/zip.php new file mode 100644 index 00000000000..3ff713eda70 --- /dev/null +++ b/apps/files_archive/tests/zip.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +require_once('archive.php'); + +class Test_Archive_ZIP extends Test_Archive{ + protected function getExisting(){ + $dir=OC::$SERVERROOT.'/apps/files_archive/tests/data'; + return new OC_Archive_ZIP($dir.'/data.zip'); + } + + protected function getNew(){ + return new OC_Archive_ZIP(OC_Helper::tmpFile('.zip')); + } +} diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php index 0a593b98c4b..246d4f672db 100644 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -26,7 +26,7 @@ // - Crypt/decrypt button in the userinterface // - Setting if crypto should be on by default // - Add a setting "Don´t encrypt files larger than xx because of performance reasons" -// - Transparent decrypt/encrpt in filesystem.php. Autodetect if a file is encrypted (.encrypted extensio) +// - Transparent decrypt/encrypt in filesystem.php. Autodetect if a file is encrypted (.encrypted extension) // - Don't use a password directly as encryption key. but a key which is stored on the server and encrypted with the user password. -> password change faster // - IMPORTANT! Check if the block lenght of the encrypted data stays the same diff --git a/apps/files_remote/appinfo/app.php b/apps/files_remote/appinfo/app.php new file mode 100644 index 00000000000..02c1c3ae313 --- /dev/null +++ b/apps/files_remote/appinfo/app.php @@ -0,0 +1,11 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC::$CLASSPATH['OC_Filestorage_FTP']='apps/files_remote/lib/ftp.php'; +OC::$CLASSPATH['OC_Filestorage_DAV']='apps/files_remote/lib/webdav.php'; +OC::$CLASSPATH['OC_Filestorage_Google']='apps/files_remote/lib/google.php'; diff --git a/apps/files_remote/appinfo/info.xml b/apps/files_remote/appinfo/info.xml new file mode 100644 index 00000000000..0720b6095b9 --- /dev/null +++ b/apps/files_remote/appinfo/info.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<info> + <id>files_remote</id> + <name>Remote storage support</name> + <description>Mount remote storage sources</description> + <version>0.1</version> + <licence>AGPL</licence> + <author>Robin Appelman</author> + <require>3</require> +</info> diff --git a/apps/files_remote/lib/ftp.php b/apps/files_remote/lib/ftp.php new file mode 100644 index 00000000000..802446b4fd8 --- /dev/null +++ b/apps/files_remote/lib/ftp.php @@ -0,0 +1,157 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_FileStorage_FTP extends OC_Filestorage_Common{ + private $password; + private $user; + private $host; + private $secure; + private $root; + + private static $tempFiles=array(); + + public function __construct($params){ + $this->host=$params['host']; + $this->user=$params['user']; + $this->password=$params['password']; + $this->secure=isset($params['secure'])?(bool)$params['secure']:false; + $this->root=isset($params['root'])?$params['root']:'/'; + if(substr($this->root,0,1)!='/'){ + $this->root='/'.$this->root; + } + + //create the root folder if necesary + mkdir($this->constructUrl('')); + } + + /** + * construct the ftp url + * @param string path + * @return string + */ + public function constructUrl($path){ + $url='ftp'; + if($this->secure){ + $url.='s'; + } + $url.='://'.$this->user.':'.$this->password.'@'.$this->host.$this->root.$path; + return $url; + } + + public function mkdir($path){ + return mkdir($this->constructUrl($path)); + } + + public function rmdir($path){ + if($this->file_exists($path)){ + $succes=rmdir($this->constructUrl($path)); + clearstatcache(); + return $succes; + }else{ + return false; + } + } + + public function opendir($path){ + return opendir($this->constructUrl($path)); + } + + public function filetype($path){ + return filetype($this->constructUrl($path)); + } + + public function is_readable($path){ + return true;//not properly supported + } + + public function is_writable($path){ + return true;//not properly supported + } + + public function file_exists($path){ + return file_exists($this->constructUrl($path)); + } + + public function unlink($path){ + $succes=unlink($this->constructUrl($path)); + clearstatcache(); + return $succes; + } + + public function fopen($path,$mode){ + switch($mode){ + case 'r': + case 'rb': + case 'w': + case 'wb': + case 'a': + case 'ab': + //these are supported by the wrapper + $context = stream_context_create(array('ftp' => array('overwrite' => true))); + return fopen($this->constructUrl($path),$mode,false,$context); + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + //emulate these + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->file_exists($path)){ + $this->getFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + public function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->uploadFile($tmpFile,self::$tempFiles[$tmpFile]); + unlink($tmpFile); + } + } + + public function free_space($path){ + return 0; + } + + public function touch($path,$mtime=null){ + if(is_null($mtime)){ + $fh=$this->fopen($path,'a'); + fwrite($fh,''); + fclose($fh); + }else{ + return false;//not supported + } + } + + public function getFile($path,$target){ + return copy($this->constructUrl($path),$target); + } + + public function uploadFile($path,$target){ + return copy($path,$this->constructUrl($target)); + } + + public function rename($path1,$path2){ + return rename($this->constructUrl($path1),$this->constructUrl($path2)); + } + + public function stat($path){ + return stat($this->constructUrl($path)); + } +} diff --git a/apps/files_remote/lib/google.php b/apps/files_remote/lib/google.php new file mode 100644 index 00000000000..0d6db1987f8 --- /dev/null +++ b/apps/files_remote/lib/google.php @@ -0,0 +1,409 @@ +<?php + +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski mtgap@owncloud.com +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +require_once 'common.inc.php'; + +class OC_Filestorage_Google extends OC_Filestorage_Common { + + private $consumer; + private $oauth_token; + private $sig_method; + private $entries; + + public function __construct($arguments) { + $consumer_key = isset($arguments['consumer_key']) ? $arguments['consumer_key'] : 'anonymous'; + $consumer_secret = isset($arguments['consumer_secret']) ? $arguments['consumer_secret'] : 'anonymous'; + $this->consumer = new OAuthConsumer($consumer_key, $consumer_secret); + $this->oauth_token = new OAuthToken($arguments['token'], $arguments['token_secret']); + $this->sig_method = new OAuthSignatureMethod_HMAC_SHA1(); + $this->entries = array(); + } + + private function sendRequest($feedUri, $http_method, $isDownload = false, $postData = null) { + $feedUri = trim($feedUri); + // create an associative array from each key/value url query param pair. + $params = array(); + $pieces = explode('?', $feedUri); + if (isset($pieces[1])) { + $params = explode_assoc('=', '&', $pieces[1]); + } + // urlencode each url parameter key/value pair + $tempStr = $pieces[0]; + foreach ($params as $key => $value) { + $tempStr .= '&' . urlencode($key) . '=' . urlencode($value); + } + $feedUri = preg_replace('/&/', '?', $tempStr, 1); + $request = OAuthRequest::from_consumer_and_token($this->consumer, $this->oauth_token, $http_method, $feedUri, $params); + $request->sign_request($this->sig_method, $this->consumer, $this->oauth_token); + $auth_header = $request->to_header(); + $headers = array($auth_header, 'Content-Type: application/atom+xml', 'GData-Version: 3.0'); + $curl = curl_init($feedUri); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + switch ($http_method) { + case 'GET': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + break; + case 'POST': + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'PUT': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + break; + case 'DELETE': + $headers[] = 'If-Match: *'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $http_method); + break; + default: + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + } + if ($isDownload) { + $tmpFile = OC_Helper::tmpFile(); + $fp = fopen($tmpFile, 'w'); + curl_setopt($curl, CURLOPT_FILE, $fp); + curl_exec($curl); + curl_close($curl); + return $tmpFile; + } + $result = curl_exec($curl); + curl_close($curl); + $dom = new DOMDocument(); + $dom->loadXML($result); + return $dom; + } + + private function getResource($path) { + $file = basename($path); + if (array_key_exists($file, $this->entries)) { + return $this->entries[$file]; + } else { + // Strip the file extension; file could be a native Google Docs resource + if ($pos = strpos($file, '.')) { + $title = substr($file, 0, $pos); + $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$title, 'GET'); + // Check if request was successful and entry exists + if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) { + $this->entries[$file] = $entry; + return $entry; + } + } + $dom = $this->sendRequest('https://docs.google.com/feeds/default/private/full?showfolders=true&title='.$file, 'GET'); + // Check if request was successful and entry exists + if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) { + $this->entries[$file] = $entry; + return $entry; + } + return false; + } + } + + private function getExtension($entry) { + $mimetype = $this->getMimeType('', $entry); + switch ($mimetype) { + case 'httpd/unix-directory': + return ''; + case 'application/vnd.oasis.opendocument.text': + return 'odt'; + case 'application/vnd.oasis.opendocument.spreadsheet': + return 'ods'; + case 'application/vnd.oasis.opendocument.presentation': + return 'pptx'; + case 'text/html': + return 'html'; + default: + return 'html'; + } + } + + + public function mkdir($path) { + $dir = dirname($path); + // Check if path parent is root directory + if ($dir == '/' || $dir == '\.' || $dir == '.') { + $feedUri = 'https://docs.google.com/feeds/default/private/full'; + // Get parent content link + } else if ($dom = $this->getResource(basename($dir))) { + $feedUri = $dom->getElementsByTagName('content')->item(0)->getAttribute('src'); + } + if (isset($feedUri)) { + $title = basename($path); + // Construct post data + $postData = '<?xml version="1.0" encoding="UTF-8"?>'; + $postData .= '<entry xmlns="http://www.w3.org/2005/Atom">'; + $postData .= '<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#folder"/>'; + $postData .= '<title>'.$title.'</title>'; + $postData .= '</entry>'; + if ($dom = $this->sendRequest($feedUri, 'POST', $postData)) { + return true; + } + } + return false; + } + + public function rmdir($path) { + return $this->unlink($path); + } + + public function opendir($path) { + if ($path == '' || $path == '/') { + $next = 'https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents'; + } else { + if ($entry = $this->getResource($path)) { + $next = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); + } else { + return false; + } + } + $files = array(); + while ($next) { + $dom = $this->sendRequest($next, 'GET'); + $links = $dom->getElementsByTagName('link'); + foreach ($links as $link) { + if ($link->getAttribute('rel') == 'next') { + $next = $link->getAttribute('src'); + break; + } else { + $next = false; + } + } + $entries = $dom->getElementsByTagName('entry'); + foreach ($entries as $entry) { + $name = $entry->getElementsByTagName('title')->item(0)->nodeValue; + // Google Docs resources don't always include extensions in title + if (!strpos($name, '.')) { + $extension = $this->getExtension($entry); + if ($extension != '') { + $name .= '.'.$extension; + } + } + $files[] = $name; + // Cache entry for future use + $this->entries[$name] = $entry; + } + } + OC_FakeDirStream::$dirs['google'] = $files; + return opendir('fakedir://google'); + } + + public function stat($path) { + if ($path == '' || $path == '/') { + $stat['size'] = $this->free_space($path); + $stat['atime'] = time(); + $stat['mtime'] = time(); + $stat['ctime'] = time(); + } else if ($entry = $this->getResource($path)) { + // NOTE: Native resources don't have a file size + $stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue; +// if (isset($atime = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue)) +// $stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'lastViewed')->item(0)->nodeValue); + $stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue); + $stat['ctime'] = strtotime($entry->getElementsByTagName('published')->item(0)->nodeValue); + } + if (isset($stat)) { + return $stat; + } + return false; + } + + public function filetype($path) { + if ($path == '' || $path == '/') { + return 'dir'; + } else if ($entry = $this->getResource($path)) { + $categories = $entry->getElementsByTagName('category'); + foreach ($categories as $category) { + if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') { + $type = $category->getAttribute('label'); + if (strlen(strstr($type, 'folder')) > 0) { + return 'dir'; + } else { + return 'file'; + } + } + } + } + return false; + } + + public function is_readable($path) { + return true; + } + + public function is_writable($path) { + if ($path == '' || $path == '/') { + return true; + } else if ($entry = $this->getResource($path)) { + // Check if edit or edit-media links exist + $links = $entry->getElementsByTagName('link'); + foreach ($links as $link) { + if ($link->getAttribute('rel') == 'edit') { + return true; + } else if ($link->getAttribute('rel') == 'edit-media') { + return true; + } + } + } + return false; + } + + public function file_exists($path) { + if ($path == '' || $path == '/') { + return true; + } else if ($this->getResource($path)) { + return true; + } + return false; + } + + public function unlink($path) { + // Get resource self link to trash resource + if ($entry = $this->getResource($path)) { + $links = $entry->getElementsByTagName('link'); + foreach ($links as $link) { + if ($link->getAttribute('rel') == 'self') { + $feedUri = $link->getAttribute('href'); + } + } + } + if (isset($feedUri)) { + $this->sendRequest($feedUri, 'DELETE'); + return true; + } + return false; + } + + public function rename($path1, $path2) { + // TODO Add support for moving to different collections + // Get resource edit link to rename resource + if ($entry = $this->getResource($path1)) { + $etag = $entry->getElementsByTagName('entry')->item(0)->getAttribute('gd:etag'); + $links = $entry->getElementsByTagName('link'); + foreach ($links as $link) { + if ($link->getAttribute('rel') == 'edit') { + $feedUri = $link->getAttribute('href'); + } + } + } + if (isset($etag) && isset($feedUri)) { + $title = basename($path2); + // Construct post data + $postData = '<?xml version="1.0" encoding="UTF-8"?>'; + $postData .= '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gd="http://schemas.google.com/g/2005" gd:etag='.$etag.'>'; + $postData .= '<title>'.$title.'</title>'; + $postData .= '</entry>'; + $this->sendRequest($feedUri, 'PUT', $postData); + return true; + } + return false; + } + + public function fopen($path, $mode) { + if ($entry = $this->getResource($path)) { + switch ($mode) { + case 'r': + case 'rb': + $extension = $this->getExtension($entry); + $downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src'); + // TODO Non-native documents don't need these additional parameters + $downloadUri .= '&exportFormat='.$extension.'&format='.$extension; + $tmpFile = $this->sendRequest($downloadUri, 'GET', true); + return fopen($tmpFile, 'r'); + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + // TODO Edit documents + } + + } + return false; + } + + public function getMimeType($path, $entry = null) { + // Entry can be passed, because extension is required for opendir and the entry can't be cached without the extension + if ($entry == null) { + if ($path == '' || $path == '/') { + return 'httpd/unix-directory'; + } else { + $entry = $this->getResource($path); + } + } + if ($entry) { + $mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type'); + // Native Google Docs resources often default to text/html, but it may be more useful to default to a corresponding ODF mimetype + // Collections get reported as application/atom+xml, make sure it actually is a folder and fix the mimetype + if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml;type=feed') { + $categories = $entry->getElementsByTagName('category'); + foreach ($categories as $category) { + if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') { + $type = $category->getAttribute('label'); + if (strlen(strstr($type, 'folder')) > 0) { + return 'httpd/unix-directory'; + } else if (strlen(strstr($type, 'document')) > 0) { + return 'application/vnd.oasis.opendocument.text'; + } else if (strlen(strstr($type, 'spreadsheet')) > 0) { + return 'application/vnd.oasis.opendocument.spreadsheet'; + } else if (strlen(strstr($type, 'presentation')) > 0) { + return 'application/vnd.oasis.opendocument.presentation'; + } else if (strlen(strstr($type, 'drawing')) > 0) { + return 'application/vnd.oasis.opendocument.graphics'; + } else { + // If nothing matches return text/html, all native Google Docs resources can be exported as text/html + return 'text/html'; + } + } + } + } + return $mimetype; + } + return false; + } + + public function free_space($path) { + if ($dom = $this->sendRequest('https://docs.google.com/feeds/metadata/default', 'GET')) { + // NOTE: Native Google Docs resources don't count towards quota + $total = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesTotal')->item(0)->nodeValue; + $used = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005', 'quotaBytesUsed')->item(0)->nodeValue; + return $total - $used; + } + return false; + } + + public function touch($path, $mtime = null) { + + } + +}
\ No newline at end of file diff --git a/apps/files_remote/lib/webdav.php b/apps/files_remote/lib/webdav.php new file mode 100644 index 00000000000..7a2da5c8ec0 --- /dev/null +++ b/apps/files_remote/lib/webdav.php @@ -0,0 +1,293 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class OC_FileStorage_DAV extends OC_Filestorage_Common{ + private $password; + private $user; + private $host; + private $secure; + private $root; + /** + * @var Sabre_DAV_Client + */ + private $client; + + private static $tempFiles=array(); + + public function __construct($params){ + $this->host=$params['host']; + $this->user=$params['user']; + $this->password=$params['password']; + $this->secure=isset($params['secure'])?(bool)$params['secure']:false; + $this->root=isset($params['root'])?$params['root']:'/'; + if(substr($this->root,0,1)!='/'){ + $this->root='/'.$this->root; + } + if(substr($this->root,-1,1)!='/'){ + $this->root.='/'; + } + + $settings = array( + 'baseUri' => $this->createBaseUri(), + 'userName' => $this->user, + 'password' => $this->password, + ); + $this->client = new Sabre_DAV_Client($settings); + + //create the root folder if necesary + $this->mkdir(''); + } + + private function createBaseUri(){ + $baseUri='http'; + if($this->secure){ + $baseUri.'s'; + } + $baseUri.='://'.$this->host.$this->root; + return $baseUri; + } + + public function mkdir($path){ + $path=$this->cleanPath($path); + return $this->simpleResponse('MKCOL',$path,null,201); + } + + public function rmdir($path){ + $path=$this->cleanPath($path); + return $this->simpleResponse('DELETE',$path,null,204); + } + + public function opendir($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array(),1); + $stripLength=strlen($this->root)+strlen($path); + $id=md5('webdav'.$this->root.$path); + OC_FakeDirStream::$dirs[$id]=array(); + foreach($response as $file=>$data){ + //strip root and path + $file=trim(substr($file,$stripLength)); + $file=trim($file,'/'); + if($file){ + OC_FakeDirStream::$dirs[$id][]=$file; + } + } + return opendir('fakedir://'.$id); + }catch(Exception $e){ + return false; + } + } + + public function filetype($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}resourcetype')); + $responseType=$response["{DAV:}resourcetype"]->resourceType; + return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; + }catch(Exception $e){ + return false; + } + } + + public function is_readable($path){ + return true;//not properly supported + } + + public function is_writable($path){ + return true;//not properly supported + } + + public function file_exists($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}resourcetype')); + return true;//no 404 exception + }catch(Exception $e){ + return false; + } + } + + public function unlink($path){ + return $this->simpleResponse('DELETE',$path,null,204); + } + + public function fopen($path,$mode){ + $path=$this->cleanPath($path); + switch($mode){ + case 'r': + case 'rb': + //straight up curl instead of sabredav here, sabredav put's the entire get result in memory + $curl = curl_init(); + $fp = fopen('php://temp', 'r+'); + curl_setopt($curl,CURLOPT_USERPWD,$this->user.':'.$this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$path); + curl_setopt($curl, CURLOPT_FILE, $fp); + + curl_exec ($curl); + curl_close ($curl); + rewind($fp); + return $fp; + case 'w': + case 'wb': + case 'a': + case 'ab': + case 'r+': + case 'w+': + case 'wb+': + case 'a+': + case 'x': + case 'x+': + case 'c': + case 'c+': + //emulate these + if(strrpos($path,'.')!==false){ + $ext=substr($path,strrpos($path,'.')); + }else{ + $ext=''; + } + $tmpFile=OC_Helper::tmpFile($ext); + OC_CloseStreamWrapper::$callBacks[$tmpFile]=array($this,'writeBack'); + if($this->file_exists($path)){ + $this->getFile($path,$tmpFile); + } + self::$tempFiles[$tmpFile]=$path; + return fopen('close://'.$tmpFile,$mode); + } + } + + public function writeBack($tmpFile){ + if(isset(self::$tempFiles[$tmpFile])){ + $this->uploadFile($tmpFile,self::$tempFiles[$tmpFile]); + unlink($tmpFile); + } + } + + public function free_space($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}quota-available-bytes')); + if(isset($response['{DAV:}quota-available-bytes'])){ + return (int)$response['{DAV:}quota-available-bytes']; + }else{ + return 0; + } + }catch(Exception $e){ + return 0; + } + } + + public function touch($path,$mtime=null){ + if(is_null($mtime)){ + $mtime=time(); + } + $path=$this->cleanPath($path); + $this->client->proppatch($path, array('{DAV:}lastmodified' => $mtime,)); + } + + public function getFile($path,$target){ + $source=$this->fopen($path,'r'); + file_put_contents($target,$source); + } + + public function uploadFile($path,$target){ + $source=fopen($path,'r'); + + $curl = curl_init(); + curl_setopt($curl,CURLOPT_USERPWD,$this->user.':'.$this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$target); + curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); + curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer + curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); + curl_setopt($curl, CURLOPT_PUT, true); + curl_exec ($curl); + curl_close ($curl); + } + + public function rename($path1,$path2){ + $path1=$this->cleanPath($path1); + $path2=$this->root.$this->cleanPath($path2); + try{ + $response=$this->client->request('MOVE',$path1,null,array('Destination'=>$path2)); + return true; + }catch(Exception $e){ + echo $e; + echo 'fail'; + var_dump($response); + return false; + } + } + + public function copy($path1,$path2){ + $path1=$this->cleanPath($path1); + $path2=$this->root.$this->cleanPath($path2); + try{ + $response=$this->client->request('COPY',$path1,null,array('Destination'=>$path2)); + return true; + }catch(Exception $e){ + echo $e; + echo 'fail'; + var_dump($response); + return false; + } + } + + public function stat($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}getlastmodified','{DAV:}getcontentlength')); + if(isset($response['{DAV:}getlastmodified']) and isset($response['{DAV:}getcontentlength'])){ + return array( + 'mtime'=>strtotime($response['{DAV:}getlastmodified']), + 'size'=>(int)$response['{DAV:}getcontentlength'], + 'ctime'=>-1, + ); + }else{ + return array(); + } + }catch(Exception $e){ + return array(); + } + } + + public function getMimeType($path){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->propfind($path, array('{DAV:}getcontenttype','{DAV:}resourcetype')); + $responseType=$response["{DAV:}resourcetype"]->resourceType; + $type=(count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; + if($type=='dir'){ + return 'httpd/unix-directory'; + }elseif(isset($response['{DAV:}getcontenttype'])){ + return $response['{DAV:}getcontenttype']; + }else{ + return false; + } + }catch(Exception $e){ + return false; + } + } + + private function cleanPath($path){ + if(substr($path,0,1)=='/'){ + return substr($path,1); + }else{ + return $path; + } + } + + private function simpleResponse($method,$path,$body,$expected){ + $path=$this->cleanPath($path); + try{ + $response=$this->client->request($method,$path,$body); + return $response['statusCode']==$expected; + }catch(Exception $e){ + return false; + } + } +} + diff --git a/apps/files_remote/tests/config.php b/apps/files_remote/tests/config.php new file mode 100644 index 00000000000..9b40d2b98cf --- /dev/null +++ b/apps/files_remote/tests/config.php @@ -0,0 +1,22 @@ +<?php +return array( + 'ftp'=>array( + 'host'=>'localhost', + 'user'=>'test', + 'password'=>'test', + 'root'=>'/test', + ), + 'webdav'=>array( + 'host'=>'localhost', + 'user'=>'test', + 'password'=>'test', + 'root'=>'/owncloud/files/webdav.php', + ), + 'google'=>array( + 'consumer_key'=>'anonymous', + 'consumer_secret'=>'anonymous', + 'token'=>'test', + 'token_secret'=>'test', + 'root'=>'/google', + ) +); diff --git a/apps/files_remote/tests/ftp.php b/apps/files_remote/tests/ftp.php new file mode 100644 index 00000000000..03633b7c0d1 --- /dev/null +++ b/apps/files_remote/tests/ftp.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_FTP extends Test_FileStorage { + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['ftp']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_FTP($this->config['ftp']); + } + + public function tearDown(){ + OC_Helper::rmdirr($this->instance->constructUrl('')); + } +} diff --git a/apps/files_remote/tests/google.php b/apps/files_remote/tests/google.php new file mode 100644 index 00000000000..b49f9e4647c --- /dev/null +++ b/apps/files_remote/tests/google.php @@ -0,0 +1,38 @@ +<?php + +/** +* ownCloud +* +* @author Michael Gapczynski +* @copyright 2012 Michael Gapczynski mtgap@owncloud.com +* +* 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 <http://www.gnu.org/licenses/>. +*/ + +class Test_Filestorage_Google extends Test_FileStorage { + + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['google']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_Google($this->config['google']); + } + + public function tearDown(){ + $this->instance->rmdir('/'); + } +}
\ No newline at end of file diff --git a/apps/files_remote/tests/webdav.php b/apps/files_remote/tests/webdav.php new file mode 100644 index 00000000000..219fff8852d --- /dev/null +++ b/apps/files_remote/tests/webdav.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class Test_Filestorage_DAV extends Test_FileStorage { + private $config; + private $id; + + public function setUp(){ + $id=uniqid(); + $this->config=include('apps/files_remote/tests/config.php'); + $this->config['webdav']['root'].='/'.$id;//make sure we have an new empty folder to work in + $this->instance=new OC_Filestorage_DAV($this->config['webdav']); + } + + public function tearDown(){ + $this->instance->rmdir('/'); + } +} diff --git a/apps/files_texteditor/ajax/savefile.php b/apps/files_texteditor/ajax/savefile.php index 589428d1862..57a948478f5 100644 --- a/apps/files_texteditor/ajax/savefile.php +++ b/apps/files_texteditor/ajax/savefile.php @@ -28,7 +28,7 @@ require_once('../../../lib/base.php'); OC_JSON::checkLoggedIn(); // Get paramteres -$filecontents = htmlspecialchars_decode($_POST['filecontents']); +$filecontents = $_POST['filecontents']; $path = isset($_POST['path']) ? $_POST['path'] : ''; $mtime = isset($_POST['mtime']) ? $_POST['mtime'] : ''; diff --git a/apps/files_texteditor/css/style.css b/apps/files_texteditor/css/style.css index e260ab0dd46..6a4392a08e9 100644 --- a/apps/files_texteditor/css/style.css +++ b/apps/files_texteditor/css/style.css @@ -5,7 +5,7 @@ left: 12.5em; } #editorwrapper{ - position: absoloute; + position: absolute; height: 0; width: 0; top: 41px; diff --git a/apps/files_texteditor/js/editor.js b/apps/files_texteditor/js/editor.js index e45652b6ef3..02d39b98430 100644 --- a/apps/files_texteditor/js/editor.js +++ b/apps/files_texteditor/js/editor.js @@ -11,37 +11,43 @@ function getFileExtension(file){ function setSyntaxMode(ext){ // Loads the syntax mode files and tells the editor var filetype = new Array(); - // Todo finish these - filetype["h"] = "c_cpp"; - filetype["c"] = "c_cpp"; - filetype["clj"] = "clojure"; - filetype["coffee"] = "coffee"; // coffescript can be compiled to javascript - filetype["coldfusion"] = "cfc"; - filetype["cpp"] = "c_cpp"; - filetype["cs"] = "csharp"; + // add file extensions like this: filetype["extension"] = "filetype": + filetype["h"] = "c_cpp"; + filetype["c"] = "c_cpp"; + filetype["clj"] = "clojure"; + filetype["coffee"] = "coffee"; // coffescript can be compiled to javascript + filetype["coldfusion"] = "cfc"; + filetype["cpp"] = "c_cpp"; + filetype["cs"] = "csharp"; filetype["css"] = "css"; - filetype["groovy"] = "groovy"; - filetype["haxe"] = "hx"; + filetype["groovy"] = "groovy"; + filetype["haxe"] = "hx"; filetype["html"] = "html"; - filetype["java"] = "java"; + filetype["java"] = "java"; filetype["js"] = "javascript"; - filetype["json"] = "json"; - filetype["latex"] = "latex"; - filetype["lua"] = "lua"; - filetype["markdown"] = "markdown"; // also: .md .markdown .mdown .mdwn - filetype["ml"] = "ocaml"; - filetype["mli"] = "ocaml"; + filetype["json"] = "json"; + filetype["latex"] = "latex"; + filetype["ly"] = "latex"; + filetype["ily"] = "latex"; + filetype["lua"] = "lua"; + filetype["markdown"] = "markdown"; + filetype["md"] = "markdown"; + filetype["mdown"] = "markdown"; + filetype["mdwn"] = "markdown"; + filetype["mkd"] = "markdown"; + filetype["ml"] = "ocaml"; + filetype["mli"] = "ocaml"; filetype["pl"] = "perl"; filetype["php"] = "php"; filetype["powershell"] = "ps1"; filetype["py"] = "python"; filetype["rb"] = "ruby"; - filetype["scad"] = "scad"; // seems to be something like 3d model files printed with e.g. reprap - filetype["scala"] = "scala"; - filetype["scss"] = "scss"; // "sassy css" - filetype["sql"] = "sql"; - filetype["svg"] = "svg"; - filetype["textile"] = "textile"; // related to markdown + filetype["scad"] = "scad"; // seems to be something like 3d model files printed with e.g. reprap + filetype["scala"] = "scala"; + filetype["scss"] = "scss"; // "sassy css" + filetype["sql"] = "sql"; + filetype["svg"] = "svg"; + filetype["textile"] = "textile"; // related to markdown filetype["xml"] = "xml"; if(filetype[ext]!=null){ @@ -142,7 +148,7 @@ function doFileSave(){ // Show saving spinner $("#editor_save").die('click',doFileSave); $('#save_result').remove(); - $('#editor_save').text(t('files_texteditor','Saving...'));//after('<img id="saving_icon" src="'+OC.filePath('core','img','loading.gif')+'"></img>'); + $('#editor_save').text(t('files_texteditor','Saving...')); // Get the data var filecontents = window.aceEditor.getSession().getValue(); // Send the data @@ -192,6 +198,7 @@ function showFileEditor(dir,filename){ $('#editor').attr('data-filename', filename); window.aceEditor = ace.edit("editor"); aceEditor.setShowPrintMargin(false); + aceEditor.getSession().setUseWrapMode(true); if(result.data.write=='false'){ aceEditor.setReadOnly(true); } diff --git a/apps/gallery/ajax/galleryOp.php b/apps/gallery/ajax/galleryOp.php index f07814056a3..b0433898cda 100644 --- a/apps/gallery/ajax/galleryOp.php +++ b/apps/gallery/ajax/galleryOp.php @@ -21,6 +21,7 @@ * */ +header('Content-type: text/html; charset=UTF-8') ; require_once('../../../lib/base.php'); OC_JSON::checkLoggedIn(); @@ -41,35 +42,28 @@ 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); } function handleGalleryScanning() { - OC_Gallery_Scanner::cleanup(); - OC_JSON::success(array('albums' => OC_Gallery_Scanner::scan('/'))); + OC_DB::beginTransaction(); + set_time_limit(0); + OC_Gallery_Album::cleanup(); + $eventSource = new OC_EventSource(); + OC_Gallery_Scanner::scan($eventSource); + $eventSource->close(); + OC_DB::commit(); } function handleFilescan($cleanup) { if ($cleanup) OC_Gallery_Album::cleanup(); - $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '').'/'; - $pathlist = OC_Gallery_Scanner::find_paths($root); + $pathlist = OC_Gallery_Scanner::find_paths(); sort($pathlist); OC_JSON::success(array('paths' => $pathlist)); } -function handlePartialCreate($path) { - if (empty($path)) OC_JSON::error(array('cause' => 'No path specified')); - if (!OC_Filesystem::is_dir($path)) OC_JSON::error(array('cause' => 'Invalid path given')); - - $album = OC_Gallery_Album::find(OC_User::getUser(), null, $path); - $albums = array(); - OC_Gallery_Scanner::scanDir($path, $albums); - OC_JSON::success(array('album_details' => $albums)); -} - function handleStoreSettings($root, $order) { if (!OC_Filesystem::file_exists($root)) { OC_JSON::error(array('cause' => 'No such file or directory')); @@ -81,13 +75,84 @@ function handleStoreSettings($root, $order) { } $current_root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/'); - $root = trim(rtrim($root, '/')); + $root = trim($root); + $root = rtrim($root, '/').'/'; $rescan = $current_root==$root?'no':'yes'; OC_Preferences::setValue(OC_User::getUser(), 'gallery', 'root', $root); OC_Preferences::setValue(OC_User::getUser(), 'gallery', 'order', $order); OC_JSON::success(array('rescan' => $rescan)); } +function handleGetGallery($path) { + $a = array(); + $root = OC_Preferences::getValue(OC_User::getUser(),'gallery', 'root', '/'); + $path = utf8_decode(rtrim($root.$path,'/')); + if($path == '') $path = '/'; + $pathLen = strlen($path); + $result = OC_Gallery_Album::find(OC_User::getUser(), null, $path); + $album_details = $result->fetchRow(); + + $result = OC_Gallery_Album::find(OC_User::getUser(), null, null, $path); + + while ($r = $result->fetchRow()) { + $album_name = $r['album_name']; + $size=OC_Gallery_Album::getAlbumSize($r['album_id']); + // this is a fallback mechanism and seems expensive + if ($size == 0) $size = OC_Gallery_Album::getIntermediateGallerySize($r['album_path']); + + $a[] = array('name' => utf8_encode($album_name), 'numOfItems' => min($size, 10),'path'=>substr($r['album_path'], $pathLen)); + } + + $result = OC_Gallery_Photo::find($album_details['album_id']); + + $p = array(); + + while ($r = $result->fetchRow()) { + $p[] = utf8_encode($r['file_path']); + } + + $r = OC_Gallery_Sharing::getEntryByAlbumId($album_details['album_id']); + $shared = false; + $recursive = false; + $token = ''; + if ($row = $r->fetchRow()) { + $shared = true; + $recursive = ($row['recursive'] == 1)? true : false; + $token = $row['token']; + } + + OC_JSON::success(array('albums'=>$a, 'photos'=>$p, 'shared' => $shared, 'recursive' => $recursive, 'token' => $token)); +} + +function handleShare($path, $share, $recursive) { + $recursive = $recursive == 'true' ? 1 : 0; + $owner = OC_User::getUser(); + $r = OC_Gallery_Album::find($owner, null, $path); + if ($row = $r->fetchRow()) { + $albumId = $row['album_id']; + } else { + OC_JSON::error(array('cause' => 'Couldn\'t find requested gallery')); + exit; + } + + if ($share == false) { + OC_Gallery_Sharing::remove($albumId); + OC_JSON::success(array('sharing' => false)); + } else { // share, yeah \o/ + $r = OC_Gallery_Sharing::getEntryByAlbumId($albumId); + if (($row = $r->fetchRow())) { // update entry + OC_Gallery_Sharing::updateSharingByToken($row['token'], $recursive); + OC_JSON::success(array('sharing' => true, 'token' => $row['token'], 'recursive' => $recursive == 1 ? true : false )); + } else { // and new sharing entry + $date = new DateTime(); + $token = md5($owner . $date->getTimestamp()); + OC_Gallery_Sharing::addShared($token, intval($albumId), $recursive); + OC_JSON::success(array('sharing' => true, 'token' => $token, 'recursive' => $recursive == 1 ? true : false )); + } + } +} + + if ($_GET['operation']) { switch($_GET['operation']) { case 'rename': @@ -104,15 +169,15 @@ if ($_GET['operation']) { case 'scan': handleGalleryScanning(); break; - case 'filescan': - handleFilescan($_GET['cleanup']); - break; - case 'partial_create': - handlePartialCreate(urldecode($_GET['path'])); - break; case 'store_settings': handleStoreSettings($_GET['root'], $_GET['order']); break; + case 'get_gallery': + handleGetGallery($_GET['path']); + break; + case 'share': + handleShare($_GET['path'], $_GET['share'] == 'true' ? true : false, $_GET['recursive']); + break; default: OC_JSON::error(array('cause' => 'Unknown operation')); } diff --git a/apps/gallery/ajax/getAlbums.php b/apps/gallery/ajax/getAlbums.php deleted file mode 100644 index be87af2abd3..00000000000 --- a/apps/gallery/ajax/getAlbums.php +++ /dev/null @@ -1,41 +0,0 @@ -<?php - -/** -* ownCloud - gallery application -* -* @author Bartek Przybylski -* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com -* -* 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 <http://www.gnu.org/licenses/>. -* -*/ - -require_once('../../../lib/base.php'); -OC_JSON::checkLoggedIn(); -OC_JSON::checkAppEnabled('gallery'); - -$a = array(); - -$result = OC_Gallery_Album::find(OC_User::getUser()); - -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'); -} - -OC_JSON::success(array('albums'=>$a)); - -?> diff --git a/apps/gallery/ajax/sharing.php b/apps/gallery/ajax/sharing.php new file mode 100644 index 00000000000..fba85fa34ee --- /dev/null +++ b/apps/gallery/ajax/sharing.php @@ -0,0 +1,115 @@ +<?php + +/** +* ownCloud - gallery application +* +* @author Bartek Przybylski +* @copyright 2012 Bartek Przybylski bartek@alefzero.eu +* +* 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 <http://www.gnu.org/licenses/>. +* +*/ + +require_once('../../../lib/base.php'); + +if (!isset($_GET['token']) || !isset($_GET['operation'])) { + OC_JSON::error(array('cause' => 'Not enought arguments')); + exit; +} + +$operation = $_GET['operation']; +$token = $_GET['token']; + +if (!OC_Gallery_Sharing::isTokenValid($token)) { + OC_JSON::error(array('cause' => 'Given token is not valid')); + exit; +} + +function handleGetGallery($token, $path) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $apath = OC_Gallery_Sharing::getPath($token); + + if ($path == false) + $root = $apath; + else + $root = rtrim($apath,'/').$path; + + $r = OC_Gallery_Album::find($owner, null, $root); + $albums = array(); + $photos = array(); + $albumId = -1; + if ($row = $r->fetchRow()) { + $albumId = $row['album_id']; + } + if ($albumId != -1) { + + if (OC_Gallery_Sharing::isRecursive($token)) { + $r = OC_Gallery_Album::find($owner, null, null, $root); + while ($row = $r->fetchRow()) + $albums[] = $row['album_name']; + } + + $r = OC_Gallery_Photo::find($albumId); + while ($row = $r->fetchRow()) + $photos[] = $row['file_path']; + } + + OC_JSON::success(array('albums' => $albums, 'photos' => $photos)); +} + +function handleGetThumbnail($token, $imgpath) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $image = OC_Gallery_Photo::getThumbnail($imgpath, $owner); + if ($image) { + OC_Response::enableCaching(3600 * 24); // 24 hour + $image->show(); + } +} + +function handleGetAlbumThumbnail($token, $albumname) +{ + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $file = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'.$albumname.'.png'; + $image = new OC_Image($file); + if ($image->valid()) { + $image->centerCrop(); + $image->resize(200); + $image->fixOrientation(); + OC_Response::enableCaching(3600 * 24); // 24 hour + $image->show(); + } +} + +function handleGetPhoto($token, $photo) { + $owner = OC_Gallery_Sharing::getTokenOwner($token); + $file = OC_Config::getValue( "datadirectory", OC::$SERVERROOT."/data" ).'/'.$owner.'/files'.urldecode($photo); + header('Content-Type: '.OC_Image::getMimeTypeForFile($file)); + OC_Response::sendFile($file); +} + +switch ($operation) { + case 'get_gallery': + handleGetGallery($token, isset($_GET['path'])? $_GET['path'] : false); + break; + case 'get_thumbnail': + handleGetThumbnail($token, urldecode($_GET['img'])); + break; + case 'get_album_thumbnail': + handleGetAlbumThumbnail($token, urldecode($_GET['albumname'])); + break; + case 'get_photo': + handleGetPhoto($token, urldecode($_GET['photo'])); + break; +} + diff --git a/apps/gallery/appinfo/app.php b/apps/gallery/appinfo/app.php index 1e5e27d408f..3e7e38301cf 100644 --- a/apps/gallery/appinfo/app.php +++ b/apps/gallery/appinfo/app.php @@ -24,6 +24,7 @@ OC::$CLASSPATH['OC_Gallery_Album'] = 'apps/gallery/lib/album.php'; OC::$CLASSPATH['OC_Gallery_Photo'] = 'apps/gallery/lib/photo.php'; OC::$CLASSPATH['OC_Gallery_Scanner'] = 'apps/gallery/lib/scanner.php'; +OC::$CLASSPATH['OC_Gallery_Sharing'] = 'apps/gallery/lib/sharing.php'; OC::$CLASSPATH['OC_Gallery_Hooks_Handlers'] = 'apps/gallery/lib/hooks_handlers.php'; $l = new OC_L10N('gallery'); diff --git a/apps/gallery/appinfo/database.xml b/apps/gallery/appinfo/database.xml index db88e4c1b5a..e3b13f7e93c 100644 --- a/apps/gallery/appinfo/database.xml +++ b/apps/gallery/appinfo/database.xml @@ -11,9 +11,9 @@ <name>album_id</name> <type>integer</type> <default>0</default> - <notnull>true</notnull> - <autoincrement>1</autoincrement> - <length>4</length> + <notnull>true</notnull> + <autoincrement>1</autoincrement> + <length>4</length> </field> <field> <name>uid_owner</name> @@ -27,12 +27,18 @@ <notnull>true</notnull> <length>100</length> </field> - <field> - <name>album_path</name> - <type>text</type> - <notnull>true</notnull> - <length>100</length> - </field> + <field> + <name>album_path</name> + <type>text</type> + <notnull>true</notnull> + <length>100</length> + </field> + <field> + <name>parent_path</name> + <type>text</type> + <notnull>true</notnull> + <length>100</length> + </field> </declaration> </table> <table> @@ -42,16 +48,16 @@ <name>photo_id</name> <type>integer</type> <default>0</default> - <notnull>true</notnull> - <autoincrement>1</autoincrement> - <length>4</length> + <notnull>true</notnull> + <autoincrement>1</autoincrement> + <length>4</length> </field> <field> <name>album_id</name> <type>integer</type> <default>0</default> - <notnull>true</notnull> - <length>4</length> + <notnull>true</notnull> + <length>4</length> </field> <field> <name>file_path</name> @@ -61,4 +67,28 @@ </field> </declaration> </table> + <table> + <name>*dbprefix*gallery_sharing</name> + <declaration> + <field> + <name>token</name> + <type>text</type> + <notnull>true</notnull> + <length>64</length> + </field> + <field> + <name>gallery_id</name> + <type>integer</type> + <default>0</default> + <notnull>true</notnull> + <length>4</length> + </field> + <field> + <name>recursive</name> + <type>integer</type> + <notnull>true</notnull> + <length>1</length> + </field> + </declaration> + </table> </database> 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 @@ <info> <id>gallery</id> <name>Gallery</name> - <version>0.3</version> + <version>0.4</version> <licence>AGPL</licence> <author>Bartek Przybylski</author> <require>2</require> diff --git a/apps/gallery/css/sharing.css b/apps/gallery/css/sharing.css new file mode 100644 index 00000000000..eaac82ebd60 --- /dev/null +++ b/apps/gallery/css/sharing.css @@ -0,0 +1,8 @@ +body { background-color: #eee; margin: 0; padding: 0;} +#gallery_list { height: 100%; width: 80%; background-color: white; margin: 0 auto; box-shadow: 0 0 8px #888; } +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; cursor: pointer; -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_box:hover { color: black; } +div.gallery_box h1 {font-size: 17px; font-weight: normal;} +div#breadcrumb { border: 0; width: 70%; margin: 0 auto; padding: 25px 0; font-family: Verdana; text-align: center;} +span.breadcrumbelement { margin: 10px; margin-right: 0; cursor: pointer;} +span.inside { background-image: url('../img/breadcrumb.png'); padding-left: 20px; background-position: left; background-repeat: no-repeat;} diff --git a/apps/gallery/css/styles.css b/apps/gallery/css/styles.css index da94f9ac9e5..fbf54e43db2 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_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 { 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; } +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; } @@ -15,3 +16,5 @@ div.gallery_control_overlay a { color:white; } #g-settings {position: absolute; left 13.5em; top: 0;} input[type=button] { -webkit-transition: opacity 0.5s ease-in-out; -moz-transition: opacity 0.5s ease-in-out; -o-transition: opacity 0.5s ease-in-out; opacity: 1} input[type=button]:disabled { opacity: 0.5 } +.ui-dialog tr {background-color: #eee;} +.ui-dialog input {width: 90%;} diff --git a/apps/gallery/img/breadcrumb.png b/apps/gallery/img/breadcrumb.png Binary files differnew file mode 100644 index 00000000000..a252a751554 --- /dev/null +++ b/apps/gallery/img/breadcrumb.png diff --git a/apps/gallery/img/loading.gif b/apps/gallery/img/loading.gif Binary files differnew file mode 100644 index 00000000000..5b33f7e54f4 --- /dev/null +++ b/apps/gallery/img/loading.gif diff --git a/apps/gallery/index.php b/apps/gallery/index.php index 822a5b8e143..7de7c094142 100644 --- a/apps/gallery/index.php +++ b/apps/gallery/index.php @@ -4,7 +4,7 @@ * ownCloud - gallery application * * @author Bartek Przybylski -* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com +* @copyright 2012 Bartek Przybylski bartek@alefzero.eu * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -29,9 +29,6 @@ OC_App::setActiveNavigationEntry( 'gallery_index' ); if (!file_exists(OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery')) { mkdir(OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery'); - $f = fopen(OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/.htaccess', 'w'); - fwrite($f, "allow from all"); - fclose($f); } if (!isset($_GET['view'])) { diff --git a/apps/gallery/js/album_cover.js b/apps/gallery/js/album_cover.js index 4ddac2f2111..061bbcd0b47 100644 --- a/apps/gallery/js/album_cover.js +++ b/apps/gallery/js/album_cover.js @@ -1,190 +1,153 @@ var actual_cover; -$(document).ready(function() { - $.getJSON('ajax/getAlbums.php', function(r) { - if (r.status == 'success') { - for (var i in r.albums) { - var a = r.albums[i]; - Albums.add(a.name, a.numOfItems); - } - 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'}) - }); - } else { - alert('Error occured: no such layer `gallery_list`'); - } - } else { - alert('Error occured: ' + r.message); - } - }); -}); +var paths = []; +var crumbCount = 0; +$(document).ready(returnToElement(0)); -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 class="gallery_album_box"><a href="?view='+r.name+'"><img class="gallery_album_cover"/></a><h1>'+r.name+'</h1></div>'; - $('div#gallery_list').append(v); - } - }); - } +function returnToElement(num) { + while (crumbCount != num) { + $('#g-album-navigation .last').remove(); + $('#g-album-navigation .crumb :last').parent().addClass('last'); + crumbCount--; + paths.pop(); + } + var p=''; + for (var i in paths) p += paths[i]+'/'; + $('#g-album-loading').show(); + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: p }, albumClickHandler); } -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) { - - 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) { +function albumClick(title) { + paths.push(title); + crumbCount++; + var p = ''; + for (var i in paths) p += paths[i]+'/'; + $('#g-album-loading').show(); + $.getJSON(OC.filePath('gallery','ajax','galleryOp.php'), {operation: 'get_gallery', path: p }, function(r) { + albumClickHandler(r); + if ($('#g-album-navigation :last-child')) + $('#g-album-navigation :last-child').removeClass('last'); + $('#g-album-navigation').append('<div class="crumb last real" style="background-image:url(\''+OC.imagePath('core','breadcrumb')+'\')"><a href=\"javascript:returnToElement('+crumbCount+');\">'+decodeURIComponent(escape(title))+'</a></div>'); + }); +} - if (r.status == 'success') { - Albums.add(r.album_details.albumName, r.album_details.imagesCount); - } +function constructSharingPath() { + return document.location.protocol + '//' + document.location.host + OC.linkTo('gallery', 'sharing.php') + '?token=' + Albums.token; +} - albumCounter++; - $('#scanprogressbar').progressbar({ value: (albumCounter/totalAlbums)*100 }); - if (albumCounter == totalAlbums) { - $('#scanprogressbar').fadeOut(); - var targetDiv = document.getElementById('gallery_list'); - if (targetDiv) { - targetDiv.innerHTML = ''; - Albums.display(targetDiv); - } else { - alert('Error occured: no such layer `gallery_list`'); - } - $('#g-scan-button').attr('disabled', null); - } - }); +function shareGallery() { + var existing_token = ''; + if (Albums.token) + existing_token = constructSharingPath(); + var form_fields = [{text: 'Share', name: 'share', type: 'checkbox', value: Albums.shared}, + {text: 'Share recursive', name: 'recursive', type: 'checkbox', value: Albums.recursive}, + {text: 'Shared gallery address', name: 'address', type: 'text', value: existing_token}]; + OC.dialogs.form(form_fields, t('gallery', 'Share gallery'), function(values){ + var p = ''; + for (var i in paths) p += '/'+paths[i]; + if (p == '') p = '/'; + $.getJSON(OC.filePath('gallery', 'ajax', 'galleryOp.php'), {operation: 'share', path: p, share: values[0].value, recursive: values[1].value}, function(r) { + if (r.status == 'success') { + Albums.shared = r.sharing; + if (Albums.shared) { + Albums.token = r.token; + Albums.recursive = r.recursive; + } else { + Albums.token = ''; + Albums.recursive = false; + } + var actual_addr = ''; + if (Albums.token) + actual_addr = constructSharingPath(); + $('input[name="address"]').val(actual_addr); + } else { + OC.dialogs.alert(t('gallery', 'Error: ') + r.cause, t('gallery', 'Internal error')); } - } else { - alert('Error occured: ' + r.message); - } + }); }); } -function galleryRemove(albumName) { - // a workaround for a flaw in the demo system (http://dev.jqueryui.com/ticket/4375), ignore! - $( "#dialog:ui-dialog" ).dialog( "destroy" ); - $('#albumName', $("#dialog-confirm")).text(albumName); - - $( '#dialog-confirm' ).dialog({ - resizable: false, - height:150, - buttons: [{ - text: t('gallery', 'OK'), - click: function() { - $.getJSON("ajax/galleryOp.php", {operation: "remove", name: albumName}, function(r) { - if (r.status == "success") { - $(".gallery_album_box").filterAttr('data-album',albumName).remove(); - Albums.remove(albumName); - } else { - alert("Error: " + r.cause); - } - $('#dialog-confirm').dialog('close'); - }); - }}, - { - text: t('gallery', 'Cancel'), - click: function() { - $( this ).dialog( 'close' ); - }}] - }); +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, a.path, a.shared, a.recursive, a.token); + } + for (var i in r.photos) { + Albums.photos.push(r.photos[i]); + } + Albums.shared = r.shared; + if (Albums.shared) { + Albums.recursive = r.recursive; + Albums.token = r.token; + } else { + Albums.recursive = false; + Albums.token = ''; + } + 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).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.cause, t('gallery', 'Internal error')); + } + $('#g-album-loading').hide(); } -function galleryRename(name) { - $('#name', $('#dialog-form')).val(name); - $( "#dialog-form" ).dialog({ - height: 140, - width: 350, - modal: false, - buttons: [{ - text: t('gallery', 'Change name'), - click: function() { - var newname = $('#name', $('#dialog-form')).val(); - if (newname == name || newname == '') { - $(this).dialog("close"); - return; - } - if (Albums.find(newname)) { - alert("Album ", newname, " exists"); - $(this).dialog("close"); - return; - } - $.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); - } else { - alert("Error: " + r.cause); - } - $('#dialog-form').dialog('close'); - }); +var albumCounter = 0; +var totalAlbums = 0; - } - }, - { - text: t('gallery', 'Cancel'), - click: function() { - $( this ).dialog('close'); - } - } - ], - }); +function scanForAlbums(cleanup) { + Scanner.scanAlbums(); + return; } 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 adecd24cc75..1fb38a5546c 100644 --- a/apps/gallery/js/albums.js +++ b/apps/gallery/js/albums.js @@ -1,89 +1,101 @@ 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(), - // 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 = '<div class="gallery_album_box"><div class="dummy"></div><a class="view"><div class="gallery_album_cover"></div></a><h1></h1><div class="gallery_album_decoration"><a><img src="img/share.png" title="Share"></a><a class="rename"><img src="img/rename.png" title="Rename"></a><a class="remove"><img src="img/delete.png" title="Delete"></a></div></div>'; - for (var i in Albums.albums) { - var a = Albums.albums[i]; - var local=$(displayTemplate); - local.attr('data-album',a.name); - $(".gallery_album_decoration a.rename", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - galleryRename(event.data.name); - }); - $(".gallery_album_decoration a.remove", local).bind('click', {name: a.name},function(event){ - event.preventDefault(); - 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); - } - }, - 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(), + shared: false, + recursive: false, + token: '', + // 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 = '<div class="gallery_box album"><div class="dummy"></div><a class="view"><div class="gallery_album_cover"></div></a><h1></h1></div>'; + 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(event) { + var albumMetadata = Albums.find(this.title); + if (albumMetadata == undefined) { + return; + } + var x = Math.floor(event.offsetX/(this.offsetWidth/albumMetadata.numOfCovers)); + x *= this.offsetWidth; + if (x < 0 || isNaN(x)) x=0; + $(this).css('background-position', -x+'px 0'); + }); + $(element).append(local); + } + var photoDisplayTemplate = '<div class="gallery_box"><div class="dummy"></div><div><a rel="images" href="'+OC.linkTo('files','download.php')+'?file=URLPATH"><img src="'+OC.filePath('gallery','ajax','thumbnail.php')+'?img=IMGPATH"></a></div></div>'; + 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 = ''; - } - } diff --git a/apps/gallery/js/scanner.js b/apps/gallery/js/scanner.js new file mode 100644 index 00000000000..804ee9d229b --- /dev/null +++ b/apps/gallery/js/scanner.js @@ -0,0 +1,34 @@ +Scanner={ + albumsFound:0, + eventSource:null, + albumsScanned:0, + scanAlbums:function(callback){ + $('#scanprogressbar').progressbar({value:0}); + $('#scanprogressbar').fadeIn(); + $('#scan input.start').hide(); + $('#scan input.stop').show(); + Scanner.albumsScanned=0; + Scanner.eventSource=new OC.EventSource(OC.linkTo('gallery', 'ajax/galleryOp.php'),{operation:'scan'}); + Scanner.eventSource.listen('count', function(total){Scanner.albumsFound=total;}); + Scanner.eventSource.listen('scanned', function(data) { + Scanner.albumsScanned++; + var progress=(Scanner.albumsScanned/Scanner.albumsFound)*100; + $('#scanprogressbar').progressbar('value',progress); + }); + Scanner.eventSource.listen('done', function(count){ + $('#scan input.start').show(); + $('#scan input.stop').hide(); + $('#scanprogressbar').fadeOut(); + returnToElement(0); + }); + if (callback) + callback(); + }, + stop:function() { + Scanner.eventSource.close(); + $('#scan input.start').show(); + $('#scan input.stop').hide(); + $('#scanprogressbar').fadeOut(); + } +} + diff --git a/apps/gallery/js/sharing.js b/apps/gallery/js/sharing.js new file mode 100644 index 00000000000..340d1b9b274 --- /dev/null +++ b/apps/gallery/js/sharing.js @@ -0,0 +1,57 @@ +$(document).ready(function() { + $.getJSON('ajax/sharing.php', {operation: 'get_gallery', token: TOKEN}, albumClickHandler); +}); + +var paths = []; +var counter = 0; + +function returnTo(num) { + while (num != counter) { + paths.pop(); + $('.breadcrumbelement:last').remove(); + counter--; + } + path = ''; + for (var e in paths) path += '/' + paths[e]; + $.getJSON('ajax/sharing.php', {operation: 'get_gallery', token: TOKEN, path: path}, function(r) { + albumClickHandler(r); + }); +} + +function albumClickHandler(r) { + var element = $('div#gallery_list'); + element.html(''); + var album_template = '<div class="gallery_box"><div><a rel="images"><img src="ajax/sharing.php?token='+TOKEN+'&operation=get_album_thumbnail&albumname=IMGPATH"></a></div><h1></h1></div>'; + + for (var i in r.albums) { + var a = r.albums[i]; + var local = $(album_template.replace('IMGPATH', encodeURIComponent(a))); + local.attr('title', a); + $('h1', local).html(a); + element.append(local); + } + + $('div.gallery_box').each(function(i, element) { + $(element).click(function() { + paths.push($(this).attr('title')); + path = ''; + for (var e in paths) path += '/' + paths[e]; + $.getJSON('ajax/sharing.php', {operation: 'get_gallery', token: TOKEN, path: path}, function(r) { + var name = paths[paths.length-1]; + counter++; + var d = '<span class="breadcrumbelement" onclick="javascript:returnTo('+counter+');return false;">'+name+'</span>'; + d = $(d).addClass('inside'); + $('#breadcrumb').append(d); + albumClickHandler(r); + }); + }); + }); + + var pat = ''; + for (var a in paths) pat += '/'+paths[a]; + var photo_template = '<div class="gallery_box"><div><a rel="images" href="*HREF*" target="_blank"><img src="ajax/sharing.php?token='+TOKEN+'&operation=get_thumbnail&img=IMGPATH"></a></div></div>'; + for (var a in r.photos) { + var local = photo_template.replace('IMGPATH', encodeURIComponent(r.photos[a])).replace('*HREF*', 'ajax/sharing.php?token='+TOKEN+'&operation=get_photo&photo='+encodeURIComponent(r.photos[a])); + element.append(local); + } +} diff --git a/apps/gallery/lib/album.php b/apps/gallery/lib/album.php index d1405333ac7..ef361a37913 100644 --- a/apps/gallery/lib/album.php +++ b/apps/gallery/lib/album.php @@ -4,97 +4,113 @@ * ownCloud - gallery application * * @author Bartek Przybylski -* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com -* +* @copyright 2012 Bartek Przybylski <bartek@alefzero.eu> +* * 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 +* 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 <http://www.gnu.org/licenses/>. -* +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* */ +require_once('base.php'); + 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)); + $stmt = OC_DB::prepare('INSERT INTO *PREFIX*gallery_albums (uid_owner, album_name, album_path, parent_path) VALUES (?, ?, ?, ?)'); + $stmt->execute(array($owner, $name, $path, self::getParentPath($path))); } - - 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)); + + public static function cleanup() { + $albums = self::find(OC_User::getUser()); + while ($r = $albums->fetchRow()) { + OC_Gallery_Photo::removeByAlbumId($r['album_id']); + self::remove(OC_User::getUser(), $r['album_name']); + } } - public static function cleanup() { - $albums = self::find(OC_User::getUser()); - while ($r = $albums->fetchRow()) { - OC_Gallery_Photo::removeByAlbumId($r['album_id']); - self::remove(OC_User::getUser(), $r['album_name']); - } - } - - public static function remove($owner, $name=null) { - $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner = ?'; + public static function getParentPath($path) { + return $path === '/' ? '' : dirname($path); + } + + public static function remove($owner, $name=null, $path=null, $parent=null) { + $sql = 'DELETE FROM *PREFIX*gallery_albums WHERE uid_owner LIKE ?'; $args = array($owner); if (!is_null($name)){ - $sql .= ' AND album_name = ?'; + $sql .= ' AND album_name LIKE ?'; $args[] = $name; } + if (!is_null($path)){ + $sql .= ' AND album_path LIKE ?'; + $args[] = $path; + } + if (!is_null($parent)){ + $sql .= ' AND parent_path LIKE ?'; + $args[] = $parent; + } $stmt = OC_DB::prepare($sql); return $stmt->execute($args); } - public static function removeByPath($path, $owner) { - $album = self::find($owner, null, $path); - $album = $album->fetchRow(); - self::remove($owner, $album['album_name']); - OC_Gallery_Photo::removeByAlbumId($album['album_id']); - // find and remove any gallery which might be stored lower in dir hierarchy - $path = $path.'/%'; - $stmt = OC_DB::prepare('SELECT * FROM *PREFIX*gallery_albums WHERE album_path LIKE ? AND uid_owner = ?'); - $result = $stmt->execute(array($path, $owner)); - while (($album = $result->fetchRow())) { - OC_Gallery_Photo::removeByAlbumId($album['album_id']); - self::remove($owner, $album['album_name']); - } - } + public static function removeByName($owner, $name) { self::remove($ownmer, $name); } + public static function removeByPath($owner, $path) { self::remove($owner, null, $path); } + public static function removeByParentPath($owner, $parent) { self::remove($owner, null, null, $parent); } - 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)){ $sql .= ' AND album_name = ?'; $args[] = $name; - } - if (!is_null($path)){ - $sql .= ' AND album_path = ?'; - $args[] = $path; - } - $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC'); - $sql .= ' ORDER BY album_name ' . $order; + } + if (!is_null($path)){ + $sql .= ' AND album_path = ?'; + $args[] = $path; + } + if (!is_null($parent)){ + $sql .= ' AND parent_path = ?'; + $args[] = $parent; + } + $order = OC_Preferences::getValue($owner, 'gallery', 'order', 'ASC'); + $sql .= ' ORDER BY album_name ' . $order; $stmt = OC_DB::prepare($sql); return $stmt->execute($args); } - public static function changePath($oldname, $newname, $owner) { - $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_path=? WHERE uid_owner=? AND album_path=?'); - $stmt->execute(array($newname, $owner, $oldname)); - } + public static function changePath($oldname, $newname, $owner) { + $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_albums SET album_path=? WHERE uid_owner=? AND album_path=?'); + $stmt->execute(array($newname, $owner, $oldname)); + } - public static function changeThumbnailPath($oldname, $newname) { - require_once('../../../lib/base.php'); - $thumbpath = OC::$CONFIG_DATADIRECTORY.'/../gallery/'; - rename($thumbpath.$oldname.'.png', $thumbpath.$newname.'.png'); - } + public static function changeThumbnailPath($oldname, $newname) { + require_once('../../../lib/base.php'); + $thumbpath = OC::$CONFIG_DATADIRECTORY.'/../gallery/'; + 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']; + } + + public static function getIntermediateGallerySize($path) { + $path .= '%'; + $sql = 'SELECT COUNT(*) as size FROM *PREFIX*gallery_photos photos, *PREFIX*gallery_albums albums WHERE photos.album_id = albums.album_id AND uid_owner = ? AND file_path LIKE ?'; + $stmt = OC_DB::prepare($sql); + $result = $stmt->execute(array(OC_User::getUser(), $path))->fetchRow(); + return $result['size']; + } } ?> diff --git a/apps/gallery/lib/hooks_handlers.php b/apps/gallery/lib/hooks_handlers.php index 046866e5c5d..2788337bbe8 100644 --- a/apps/gallery/lib/hooks_handlers.php +++ b/apps/gallery/lib/hooks_handlers.php @@ -21,9 +21,9 @@ * */ -OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OC_Gallery_Hooks_Handlers", "addPhotoFromPath"); -OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, "OC_Gallery_Hooks_Handlers", "removePhoto"); -OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, "OC_Gallery_Hooks_Handlers", "renamePhoto"); +//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_write, "OC_Gallery_Hooks_Handlers", "addPhotoFromPath"); +//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_delete, "OC_Gallery_Hooks_Handlers", "removePhoto"); +//OC_Hook::connect(OC_Filesystem::CLASSNAME, OC_Filesystem::signal_post_rename, "OC_Gallery_Hooks_Handlers", "renamePhoto"); require_once(OC::$CLASSPATH['OC_Gallery_Album']); require_once(OC::$CLASSPATH['OC_Gallery_Photo']); @@ -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; @@ -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); @@ -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/photo.php b/apps/gallery/lib/photo.php index 872ecc9488a..3bb6f9129fa 100644 --- a/apps/gallery/lib/photo.php +++ b/apps/gallery/lib/photo.php @@ -13,11 +13,11 @@ * * 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 +* 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 <http://www.gnu.org/licenses/>. +* License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ @@ -46,51 +46,58 @@ class OC_Gallery_Photo { return $stmt->execute(array($owner, $album_name)); } - public static function removeByPath($path) { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE file_path LIKE ?'); - $stmt->execute(array($path)); - } + public static function removeByPath($path) { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE file_path LIKE ?'); + $stmt->execute(array($path)); + } - public static function removeById($id) { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE photo_id = ?'); - $stmt->execute(array($id)); - } + public static function removeById($id) { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE photo_id = ?'); + $stmt->execute(array($id)); + } - public static function removeByAlbumId($albumid) { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE album_id = ?'); - $stmt->execute(array($albumid)); - } + public static function removeByAlbumId($albumid) { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos WHERE album_id = ?'); + $stmt->execute(array($albumid)); + } - public static function changePath($oldAlbumId, $newAlbumId, $oldpath, $newpath) { - $stmt = OC_DB::prepare("UPDATE *PREFIX*gallery_photos SET file_path = ?, album_id = ? WHERE album_id = ? and file_path = ?"); - $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath)); - } + public static function changePath($oldAlbumId, $newAlbumId, $oldpath, $newpath) { + $stmt = OC_DB::prepare("UPDATE *PREFIX*gallery_photos SET file_path = ?, album_id = ? WHERE album_id = ? and file_path = ?"); + $stmt->execute(array($newpath, $newAlbumId, $oldAlbumId, $oldpath)); + } - public static function getThumbnail($image_name) { - $save_dir = OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/'; + public static function getThumbnail($image_name, $owner = null) { + if (!$owner) $owner = OC_User::getUser(); + $save_dir = OC_Config::getValue("datadirectory").'/'. $owner .'/gallery/'; $save_dir .= dirname($image_name). '/'; - $thumb_file = $save_dir . $image_name; + $image_path = $image_name; + $thumb_file = $save_dir . basename($image_name); + if (!is_dir($save_dir)) { + mkdir($save_dir, 0777, true); + } if (file_exists($thumb_file)) { $image = new OC_Image($thumb_file); } else { - $imagePath = OC_Filesystem::getLocalFile($image_name); - if(!file_exists($imagePath)) { + $image_path = OC_Filesystem::getLocalFile($image_path); + if(!file_exists($image_path)) { return null; } - $image = new OC_Image($imagePath); + $image = new OC_Image($image_path); if ($image->valid()) { - $image->centerCrop(); - $image->resize(200); + $image->centerCrop(200); $image->fixOrientation(); - if (!is_dir($save_dir)) { - mkdir($save_dir, 0777, true); - } $image->save($thumb_file); } } if ($image->valid()) { return $image; + }else{ + $image->destroy(); } return null; } + + public static function getGalleryRoot() { + return OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', ''); + } } diff --git a/apps/gallery/lib/scanner.php b/apps/gallery/lib/scanner.php index 64efb006ad1..0317f943e5d 100644 --- a/apps/gallery/lib/scanner.php +++ b/apps/gallery/lib/scanner.php @@ -4,7 +4,7 @@ * ownCloud - gallery application * * @author Bartek Przybylski -* @copyright 2012 Bartek Przybylski bart.p.pl@gmail.com +* @copyright 2012 Bartek Przybylski <bartek@alefzero.eu> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -13,111 +13,132 @@ * * 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 +* 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 <http://www.gnu.org/licenses/>. +* License along with this library. If not, see <http://www.gnu.org/licenses/>. * */ -require_once('base.php'); // base lib -require_once('images_utils.php'); - class OC_Gallery_Scanner { - public static function scan($root) { - $albums = array(); - self::scanDir($root, $albums); - return $albums; - } - - public static function cleanUp() { - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_albums'); - $stmt->execute(array()); - $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_photos'); - $stmt->execute(array()); - } + public static function getGalleryRoot() { + return OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); + } + public static function getScanningRoot() { + return OC_Filesystem::getRoot().self::getGalleryRoot(); + } - 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; - } + public static function cleanUp() { + OC_Gallery_Album::cleanup(); + } - public static function scanDir($path, &$albums) { - $current_album = array('name'=> $path, 'imagesCount' => 0, 'images' => array()); - $current_album['name'] = self::createName($current_album['name']); + public static function createName($name) { + $name = basename($name); + return $name == '.' ? '' : $name; + } - 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; - if (self::isPhoto($path.'/'.$filename)) { - $current_album['images'][] = $filepath; - } - } - } - $current_album['imagesCount'] = count($current_album['images']); - $albums['imagesCount'] = $current_album['imagesCount']; - $albums['albumName'] = $current_album['name']; + // Scan single dir relative to gallery root + public static function scan($eventSource) { + $paths = self::findPaths(); + $eventSource->send('count', count($paths)+1); + $owner = OC_User::getUser(); + foreach ($paths as $path) { + $name = self::createName($path); + $images = self::findFiles($path); - $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); - $result = OC_Gallery_Album::find(OC_User::getUser(), $current_album['name']); - } - $albumId = $result->fetchRow(); - $albumId = $albumId['album_id']; - foreach ($current_album['images'] as $img) { - $result = OC_Gallery_Photo::find($albumId, $img); - if ($result->numRows() == 0) { - OC_Gallery_Photo::create($albumId, $img); - } - } - if (count($current_album['images'])) { - self::createThumbnail($current_album['name'],$current_album['images']); - } - } + $result = OC_Gallery_Album::find($owner, null, $path); + // don't duplicate galleries with same path + if (!($albumId = $result->fetchRow())) { + OC_Gallery_Album::create($owner, $name, $path); + $result = OC_Gallery_Album::find($owner, $name, $path); + $albumId = $result->fetchRow(); + } + $albumId = $albumId['album_id']; + foreach ($images as $img) { + $result = OC_Gallery_Photo::find($albumId, $img); + if (!$result->fetchRow()) + OC_Gallery_Photo::create($albumId, $img); + } + if (count($images)) + self::createThumbnails($name, $images); + $eventSource->send('scanned', ''); + } + self::createIntermediateAlbums(); + $eventSource->send('scanned', ''); + $eventSource->send('done', 1); + } - public static function createThumbnail($albumName, $files) { - $file_count = min(count($files), 10); - $thumbnail = imagecreatetruecolor($file_count*200, 200); - for ($i = 0; $i < $file_count; $i++) { - $image = OC_Gallery_Photo::getThumbnail($files[$i]); - if ($image && $image->valid()) { - imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200); - } - } - imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png'); - } + public static function createThumbnails($albumName, $files) { + // create gallery thumbnail + $file_count = min(count($files), 10); + $thumbnail = imagecreatetruecolor($file_count*200, 200); + for ($i = 0; $i < $file_count; $i++) { + $image = OC_Gallery_Photo::getThumbnail($files[$i]); + if ($image && $image->valid()) { + imagecopyresampled($thumbnail, $image->resource(), $i*200, 0, 0, 0, 200, 200, 200, 200); + $image->destroy(); + } + } + imagepng($thumbnail, OC_Config::getValue("datadirectory").'/'. OC_User::getUser() .'/gallery/' . $albumName.'.png'); + imagedestroy($thumbnail); + } - public static function isPhoto($filename) { - $ext = strtolower(substr($filename, strrpos($filename, '.')+1)); - return $ext=='png' || $ext=='jpeg' || $ext=='jpg' || $ext=='gif'; - } + public static function createIntermediateAlbums() { + $paths = self::findPaths(); + for ($i = 1; $i < count($paths); $i++) { + $prevLen = strlen($paths[$i-1]); + if (strncmp($paths[$i-1], $paths[$i], $prevLen)==0) { + $s = substr($paths[$i], $prevLen); + if (strrpos($s, '/') != 0) { + $a = explode('/', trim($s, '/')); + $p = $paths[$i-1]; + foreach ($a as $e) { + $p .= ($p == '/'?'':'/').$e; + OC_Gallery_Album::create(OC_User::getUser(), $e, $p); + $arr = OC_FileCache::searchByMime('image','', OC_Filesystem::getRoot().$p); + $step = floor(count($arr)/10); + if ($step == 0) $step = 1; + $na = array(); + for ($j = 0; $j < count($arr); $j+=$step) { + $na[] = $p.$arr[$j]; + } + if (count($na)) + self::createThumbnails($e, $na); + } + } + } + } + } - public static function find_paths($path) { - $ret = array(); - $dirres; - $addpath = FALSE; - if (($dirres = OC_Filesystem::opendir($path)) == FALSE) return $ret; + public static function isPhoto($filename) { + $ext = strtolower(substr($filename, strrpos($filename, '.')+1)); + return $ext=='png' || $ext=='jpeg' || $ext=='jpg' || $ext=='gif'; + } - while (($file = readdir($dirres)) != FALSE) { - if ($file[0] == '.') continue; - if (OC_Filesystem::is_dir($path.$file)) - $ret = array_merge($ret, self::find_paths($path.$file.'/')); - if (self::isPhoto($path.$file)) $addpath = TRUE; - } + public static function findFiles($path) { + $images = OC_FileCache::searchByMime('image','', OC_Filesystem::getRoot().$path); + $new = array(); + foreach ($images as $i) + if (strpos($i, '/',1) === FALSE) + $new[] = $path.$i; + return $new; + } - if ($addpath) $ret[] = urlencode($path); - - return $ret; - } + public static function findPaths() { + $images=OC_FileCache::searchByMime('image','', self::getScanningRoot()); + $paths=array(); + foreach($images as $image){ + $path=dirname($image); + $path = self::getGalleryRoot().($path=='.'?'':$path); + if ($path !== '/') $path=rtrim($path,'/'); + if(array_search($path,$paths)===false){ + $paths[]=$path; + } + } + sort($paths); + return $paths; + } } -?> + diff --git a/apps/gallery/lib/sharing.php b/apps/gallery/lib/sharing.php new file mode 100644 index 00000000000..60f108bd6c6 --- /dev/null +++ b/apps/gallery/lib/sharing.php @@ -0,0 +1,89 @@ +<?php + +/** +* ownCloud - gallery application +* +* @author Bartek Przybylski +* @copyright 2012 Bartek Przybylski bartek@alefzero.eu +* +* 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 <http://www.gnu.org/licenses/>. +* +*/ + +class OC_Gallery_Sharing { + private static function getEntries($token) { + $sql = 'SELECT * FROM *PREFIX*gallery_sharing WHERE token = ?'; + $stmt = OC_DB::prepare($sql); + return $stmt->execute(array($token)); + } + + public static function isTokenValid($token) { + $r = self::getEntries($token); + $row = $r->fetchRow(); + return $row != null; + } + + public static function isRecursive($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) return $row['recursive'] == 1; + return false; + } + + public static function getTokenOwner($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) { + $galleryId = $row['gallery_id']; + $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $r = $stmt->execute(array($galleryId)); + if ($row = $r->fetchRow()) + return $row['uid_owner']; + } + return false; + } + + public static function getPath($token) { + $r = self::getEntries($token); + if ($row = $r->fetchRow()) { + $galleryId = $row['gallery_id']; + $sql = 'SELECT * FROM *PREFIX*gallery_albums WHERE album_id = ?'; + $stmt = OC_DB::prepare($sql); + $r = $stmt->execute(array($galleryId)); + if ($row = $r->fetchRow()) + return $row['album_path']; + } + } + + public static function updateSharingByToken($token, $recursive) { + $stmt = OC_DB::prepare('UPDATE *PREFIX*gallery_sharing SET recursive = ? WHERE token = ?'); + $stmt->execute(array($recursive, $token)); + } + + public static function getEntryByAlbumId($album_id) { + $stmt = OC_DB::prepare('SELECT * FROM *PREFIX*gallery_sharing WHERE gallery_id = ?'); + return $stmt->execute(array($album_id)); + } + + public static function addShared($token, $albumId, $recursive) { + $sql = 'INSERT INTO *PREFIX*gallery_sharing (token, gallery_id, recursive) VALUES (?, ?, ?)'; + $stmt = OC_DB::prepare($sql); + $stmt->execute(array($token, $albumId, $recursive)); + } + + public static function remove($albumId) { + $stmt = OC_DB::prepare('DELETE FROM *PREFIX*gallery_sharing WHERE gallery_id = ?'); + $stmt->execute(array($albumId)); + } +} + diff --git a/apps/gallery/sharing.php b/apps/gallery/sharing.php new file mode 100644 index 00000000000..d7430becf43 --- /dev/null +++ b/apps/gallery/sharing.php @@ -0,0 +1,47 @@ +<?php + +/** +* ownCloud - gallery application +* +* @author Bartek Przybylski +* @copyright 2012 Bartek Przybylski bartek@alefzero.eu +* +* 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 <http://www.gnu.org/licenses/>. +* +*/ + +if (!isset($_GET['token']) || empty($_GET['token'])) { + exit; +} + +require_once('../../lib/base.php'); + +OC_Util::checkAppEnabled('gallery'); + +?> +<!doctype html> +<html> + <head> + <link rel="stylesheet" href="css/sharing.css" type="text/css"/> + <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script> + <script src="js/sharing.js" type="text/javascript"></script> + <script> + var TOKEN = '<?php echo $_GET['token']; ?>'; + </script> + </head> + <body> + <div id="breadcrumb"><span class="breadcrumbelement" onclick="javascript:returnTo(0);return false;">Shared gallery</span></div> + <div id="gallery_list"></div> + </body> +</html> diff --git a/apps/gallery/templates/index.php b/apps/gallery/templates/index.php index 1b8d53e82d4..c6373d3b0a2 100644 --- a/apps/gallery/templates/index.php +++ b/apps/gallery/templates/index.php @@ -1,30 +1,43 @@ <?php OC_Util::addStyle('gallery', 'styles'); OC_Util::addScript('gallery', 'albums'); +OC_Util::addScript('gallery', 'scanner'); 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'); ?> <div id="controls"> - <div id="scan"> - <div id="scanprogressbar"></div> - <input type="button" id="g-scan-button" value="<?php echo $l->t('Rescan');?>" onclick="javascript:scanForAlbums();" /> - </div> - <div id="g-settings"> - <input type="button" id="g-settings-button" value="<?php echo $l->t('Settings');?>" onclick="javascript:settings();"/> - </div> + <div id="scan"> + <div id="scanprogressbar"></div> + <input type="button" class="start" value="<?php echo $l->t('Rescan');?>" onclick="javascript:scanForAlbums();" /> + <input type="button" class="stop" style="display:none" value="<?php echo $l->t('Stop');?>" onclick="javascript:Scanner.stop();" /> + <input type="button" id="g-share-button" value="<?php echo $l->t('Share'); ?>" onclick="javascript:shareGallery();" /> + <input type="button" id="g-settings-button" value="<?php echo $l->t('Settings');?>" onclick="javascript:settings();"/> + </div> + <div id="g-album-navigation"> + <div class="crumb last" style="background-image:url('<?php echo OC::$WEBROOT;?>/core/img/breadcrumb.png')"> + <a href="javascript:returnToElement(0);">main</a> + </div> + </div> + <div id="g-album-loading" class="crumb" style="display:none"> + <img src="img/loading.gif"> + </div> </div> <div id="gallery_list"> </div> <div id="dialog-confirm" title="<?php echo $l->t('Remove confirmation');?>" style="display: none"> - <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><?php echo $l->t('Do you want to remove album');?> <span id="albumName"></span>?</p> + <p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><?php echo $l->t('Do you want to remove album');?> <span id="albumName"></span>?</p> </div> <div id="dialog-form" title="<?php echo $l->t('Change album name');?>" style="display:none"> <form> <fieldset> - <label for="name"><?php echo $l->t('New album name');?></label> + <label for="name"><?php echo $l->t('New album name');?></label> <input type="text" name="name" id="name" class="text ui-widget-content ui-corner-all" /> </fieldset> </form> @@ -32,23 +45,23 @@ $l = new OC_L10N('gallery'); <div id="g-dialog-settings" title="<?php echo $l->t('Settings');?>" style="display:none"> <form> - <fieldset><?php $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC');?> - <label for="name"><?php echo $l->t('Scanning root');?></label> - <input type="text" name="g-scanning-root" id="g-scanning-root" class="text ui-widget-content ui-corner-all" value="<?php echo $root;?>" /><br/> + <fieldset><?php $root = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'root', '/'); $order = OC_Preferences::getValue(OC_User::getUser(), 'gallery', 'order', 'ASC');?> + <label for="name"><?php echo $l->t('Scanning root');?></label> + <input type="text" name="g-scanning-root" id="g-scanning-root" class="text ui-widget-content ui-corner-all" value="<?php echo $root;?>" /><br/> - <label for="sort"><?php echo $l->t('Default sorting'); ?></label> - <select id="g-display-order"> - <option value="ASC"<?php echo $order=='ASC'?'selected':'';?>><?php echo $l->t('Ascending'); ?></option> - <option value="DESC"<?php echo $order=='DESC'?'selected':'';?>><?php echo $l->t('Descending'); ?></option> - </select><br/> + <label for="sort"><?php echo $l->t('Default sorting'); ?></label> + <select id="g-display-order"> + <option value="ASC"<?php echo $order=='ASC'?'selected':'';?>><?php echo $l->t('Ascending'); ?></option> + <option value="DESC"<?php echo $order=='DESC'?'selected':'';?>><?php echo $l->t('Descending'); ?></option> + </select><br/> <!-- - <label for="sort"><?php echo $l->t('Thumbnails size'); ?></label> - <select> - <option value="100">100px</option> - <option value="150">150px</option> - <option value="200">200px</option> - </select> - --> + <label for="sort"><?php echo $l->t('Thumbnails size'); ?></label> + <select> + <option value="100">100px</option> + <option value="150">150px</option> + <option value="200">200px</option> + </select> + --> </fieldset> </form> </div> diff --git a/apps/media/js/scanner.js b/apps/media/js/scanner.js index 6c991b60d52..a9321f99964 100644 --- a/apps/media/js/scanner.js +++ b/apps/media/js/scanner.js @@ -38,7 +38,7 @@ Scanner={ $('#scancount').show(); }, stop:function(){ - Scanner.close(); + Scanner.eventSource.close(); }, }; |