summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/ajax/upload.php51
-rw-r--r--apps/files/css/files.css11
-rw-r--r--apps/files/js/file-upload.js9
-rw-r--r--apps/files/templates/index.php1
-rw-r--r--apps/files_encryption/files/error.php29
-rwxr-xr-xapps/files_encryption/lib/crypt.php16
-rwxr-xr-xapps/files_encryption/lib/helper.php20
-rw-r--r--apps/files_encryption/lib/stream.php12
-rw-r--r--apps/files_encryption/templates/invalid_private_key.php2
-rw-r--r--apps/files_encryption/templates/settings-admin.php5
-rw-r--r--apps/files_encryption/templates/settings-personal.php8
-rw-r--r--apps/files_trashbin/templates/index.php1
-rw-r--r--apps/files_versions/ajax/preview.php13
-rw-r--r--apps/files_versions/lib/versions.php140
-rw-r--r--core/ajax/vcategories/add.php42
-rw-r--r--core/ajax/vcategories/addToFavorites.php38
-rw-r--r--core/ajax/vcategories/delete.php40
-rw-r--r--core/ajax/vcategories/edit.php34
-rw-r--r--core/ajax/vcategories/favorites.php30
-rw-r--r--core/ajax/vcategories/removeFromFavorites.php38
-rw-r--r--core/css/jquery.ocdialog.css1
-rw-r--r--core/css/styles.css24
-rw-r--r--core/js/oc-vcategories.js216
-rw-r--r--core/js/oc-vcategories.txt33
-rw-r--r--core/js/tags.js353
-rw-r--r--core/routes.php50
-rw-r--r--core/tags/controller.php114
-rw-r--r--core/templates/edit_categories_dialog.php19
-rw-r--r--core/templates/tags.html14
-rw-r--r--lib/private/connector/sabre/exception/entitytoolarge.php22
-rw-r--r--lib/private/connector/sabre/exception/unsupportedmediatype.php22
-rw-r--r--lib/private/connector/sabre/file.php16
-rw-r--r--lib/public/files/entitytoolargeexception.php11
-rw-r--r--lib/public/files/invalidcontentexception.php11
-rw-r--r--lib/public/files/invalidpathexception.php11
-rw-r--r--settings/js/personal.js7
-rw-r--r--settings/templates/personal.php28
37 files changed, 811 insertions, 681 deletions
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index 0920bf62109..45fb17de94a 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -110,30 +110,35 @@ if (strpos($dir, '..') === false) {
|| (isset($_POST['resolution']) && $_POST['resolution']==='replace')
) {
// upload and overwrite file
- if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
-
- // updated max file size after upload
- $storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
-
- $meta = \OC\Files\Filesystem::getFileInfo($target);
- if ($meta === false) {
- $error = $l->t('Upload failed. Could not get file info.');
+ try
+ {
+ if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
+
+ // updated max file size after upload
+ $storageStats = \OCA\Files\Helper::buildFileStorageStatistics($dir);
+
+ $meta = \OC\Files\Filesystem::getFileInfo($target);
+ if ($meta === false) {
+ $error = $l->t('Upload failed. Could not get file info.');
+ } else {
+ $result[] = array('status' => 'success',
+ 'mime' => $meta['mimetype'],
+ 'mtime' => $meta['mtime'],
+ 'size' => $meta['size'],
+ 'id' => $meta['fileid'],
+ 'name' => basename($target),
+ 'originalname' => $files['tmp_name'][$i],
+ 'uploadMaxFilesize' => $maxUploadFileSize,
+ 'maxHumanFilesize' => $maxHumanFileSize,
+ 'permissions' => $meta['permissions'],
+ );
+ }
+
} else {
- $result[] = array('status' => 'success',
- 'mime' => $meta['mimetype'],
- 'mtime' => $meta['mtime'],
- 'size' => $meta['size'],
- 'id' => $meta['fileid'],
- 'name' => basename($target),
- 'originalname' => $files['tmp_name'][$i],
- 'uploadMaxFilesize' => $maxUploadFileSize,
- 'maxHumanFilesize' => $maxHumanFileSize,
- 'permissions' => $meta['permissions'],
- );
+ $error = $l->t('Upload failed. Could not find uploaded file');
}
-
- } else {
- $error = $l->t('Upload failed. Could not find uploaded file');
+ } catch(Exception $ex) {
+ $error = $ex->getMessage();
}
} else {
@@ -164,5 +169,5 @@ if ($error === false) {
OCP\JSON::encodedPrint($result);
exit();
} else {
- OCP\JSON::error(array('data' => array_merge(array('message' => $error), $storageStats)));
+ OCP\JSON::error(array(array('data' => array_merge(array('message' => $error), $storageStats))));
}
diff --git a/apps/files/css/files.css b/apps/files/css/files.css
index cbf34279f54..c4a231551b1 100644
--- a/apps/files/css/files.css
+++ b/apps/files/css/files.css
@@ -105,8 +105,6 @@ table th#headerDate, table td.date {
box-sizing: border-box;
position: relative;
min-width: 11em;
- display: block;
- height: 51px;
}
/* Multiselect bar */
@@ -161,8 +159,6 @@ table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0
}
.modified {
position: relative;
- top: 11px;
- left: 5px;
}
/* TODO fix usability bug (accidental file/folder selection) */
@@ -178,6 +174,9 @@ table td.filename .nametext {
table td.filename .uploadtext { font-weight:normal; margin-left:.5em; }
table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
+.ie8 input[type="checkbox"]{
+ padding: 0;
+}
/* File checkboxes */
#fileList tr td.filename>input[type="checkbox"]:first-child {
@@ -253,9 +252,7 @@ table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }
#fileList a.action.delete {
position: absolute;
right: 0;
- top: 0;
- margin: 0;
- padding: 15px 14px 19px !important;
+ padding: 9px 14px 19px !important;
}
a.action>img { max-height:16px; max-width:16px; vertical-align:text-bottom; }
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index f1ef485fc3d..c03e9037cec 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -345,7 +345,7 @@ $(document).ready(function() {
} else if (result[0].status !== 'success') {
//delete data.jqXHR;
data.textStatus = 'servererror';
- data.errorThrown = result.data.message; // error message has been translated on server
+ data.errorThrown = result[0].data.message; // error message has been translated on server
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
fu._trigger('fail', e, data);
}
@@ -523,8 +523,10 @@ $(document).ready(function() {
function(result){
if (result.status == 'success') {
var date=new Date();
- FileList.addFile(name,0,date,false,hidden);
- var tr=$('tr').filterAttr('data-file',name);
+ // TODO: ideally addFile should be able to receive
+ // all attributes and set them automatically,
+ // and also auto-load the preview
+ var tr = FileList.addFile(name,0,date,false,hidden);
tr.attr('data-size',result.data.size);
tr.attr('data-mime',result.data.mime);
tr.attr('data-id', result.data.id);
@@ -533,6 +535,7 @@ $(document).ready(function() {
lazyLoadPreview(path, result.data.mime, function(previewpath){
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
});
+ FileActions.display(tr.find('td.filename'));
} else {
OC.dialogs.alert(result.data.message, t('core', 'Error'));
}
diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php
index ebdca097e74..32a59f1e1a6 100644
--- a/apps/files/templates/index.php
+++ b/apps/files/templates/index.php
@@ -1,4 +1,3 @@
-<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}table td{position:static !important;}</style><![endif]-->
<div id="controls">
<?php print_unescaped($_['breadcrumb']); ?>
<div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?> <?php if (isset($_['files']) and count($_['files'])==0):?>emptycontent<?php endif; ?>">
diff --git a/apps/files_encryption/files/error.php b/apps/files_encryption/files/error.php
index ac0c0269164..61574edf509 100644
--- a/apps/files_encryption/files/error.php
+++ b/apps/files_encryption/files/error.php
@@ -5,26 +5,39 @@ if (!isset($_)) { //also provide standalone error page
$l = OC_L10N::get('files_encryption');
- if (isset($_GET['i']) && $_GET['i'] === '0') {
- $errorMsg = $l->t('Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app.');
- $init = '0';
+ if (isset($_GET['errorCode'])) {
+ $errorCode = $_GET['errorCode'];
+ switch ($errorCode) {
+ case \OCA\Encryption\Crypt::ENCRYPTION_NOT_INITIALIZED_ERROR:
+ $errorMsg = $l->t('Encryption app not initialized! Maybe the encryption app was re-enabled during your session. Please try to log out and log back in to initialize the encryption app.');
+ break;
+ case \OCA\Encryption\Crypt::ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR:
+ $errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
+ break;
+ case \OCA\Encryption\Crypt::ENCRYPTION_NO_SHARE_KEY_FOUND:
+ $errorMsg = $l->t('Can not decrypt this file, probably this is a shared file. Please ask the file owner to reshare the file with you.');
+ break;
+ default:
+ $errorMsg = $l->t("Unknown error please check your system settings or contact your administrator");
+ break;
+ }
} else {
- $errorMsg = $l->t('Your private key is not valid! Likely your password was changed outside the ownCloud system (e.g. your corporate directory). You can update your private key password in your personal settings to recover access to your encrypted files.');
- $init = '1';
+ $errorCode = \OCA\Encryption\Crypt::ENCRYPTION_UNKNOWN_ERROR;
+ $errorMsg = $l->t("Unknown error please check your system settings or contact your administrator");
}
if (isset($_GET['p']) && $_GET['p'] === '1') {
- header('HTTP/1.0 404 ' . $errorMsg);
+ header('HTTP/1.0 403 ' . $errorMsg);
}
// check if ajax request
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
\OCP\JSON::error(array('data' => array('message' => $errorMsg)));
} else {
- header('HTTP/1.0 404 ' . $errorMsg);
+ header('HTTP/1.0 403 ' . $errorMsg);
$tmpl = new OC_Template('files_encryption', 'invalid_private_key', 'guest');
$tmpl->assign('message', $errorMsg);
- $tmpl->assign('init', $init);
+ $tmpl->assign('errorCode', $errorCode);
$tmpl->printPage();
}
diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php
index c009718160a..9155d238c77 100755
--- a/apps/files_encryption/lib/crypt.php
+++ b/apps/files_encryption/lib/crypt.php
@@ -33,6 +33,12 @@ require_once __DIR__ . '/../3rdparty/Crypt_Blowfish/Blowfish.php';
class Crypt {
+ const ENCRYPTION_UNKNOWN_ERROR = -1;
+ const ENCRYPTION_NOT_INITIALIZED_ERROR = 1;
+ const ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR = 2;
+ const ENCRYPTION_NO_SHARE_KEY_FOUND = 3;
+
+
/**
* @brief return encryption mode client or server side encryption
* @param string $user name (use system wide setting if name=null)
@@ -183,8 +189,8 @@ class Crypt {
// Fetch all file metadata from DB
$metadata = \OC\Files\Filesystem::getFileInfo($relPath, '');
- // If a file is flagged with encryption in DB, but isn't a
- // valid content + IV combination, it's probably using the
+ // If a file is flagged with encryption in DB, but isn't a
+ // valid content + IV combination, it's probably using the
// legacy encryption system
if (isset($metadata['encrypted'])
&& $metadata['encrypted'] === true
@@ -388,7 +394,7 @@ class Crypt {
*/
public static function multiKeyEncrypt($plainContent, array $publicKeys) {
- // openssl_seal returns false without errors if $plainContent
+ // openssl_seal returns false without errors if $plainContent
// is empty, so trigger our own error
if (empty($plainContent)) {
@@ -405,7 +411,7 @@ class Crypt {
$i = 0;
- // Ensure each shareKey is labelled with its
+ // Ensure each shareKey is labelled with its
// corresponding userId
foreach ($publicKeys as $userId => $publicKey) {
@@ -476,7 +482,7 @@ class Crypt {
}
- // We encode the iv purely for string manipulation
+ // We encode the iv purely for string manipulation
// purposes - it gets decoded before use
$iv = base64_encode($random);
diff --git a/apps/files_encryption/lib/helper.php b/apps/files_encryption/lib/helper.php
index ebfc00157f7..a754f9f28c4 100755
--- a/apps/files_encryption/lib/helper.php
+++ b/apps/files_encryption/lib/helper.php
@@ -235,16 +235,28 @@ class Helper {
/**
* @brief redirect to a error page
*/
- public static function redirectToErrorPage($session) {
-
- $init = $session->getInitialized();
+ public static function redirectToErrorPage($session, $errorCode = null) {
+
+ if ($errorCode === null) {
+ $init = $session->getInitialized();
+ switch ($init) {
+ case \OCA\Encryption\Session::INIT_EXECUTED:
+ $errorCode = \OCA\Encryption\Crypt::ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR;
+ break;
+ case \OCA\Encryption\Session::NOT_INITIALIZED:
+ $errorCode = \OCA\Encryption\Crypt::ENCRYPTION_NOT_INITIALIZED_ERROR;
+ break;
+ default:
+ $errorCode = \OCA\Encryption\Crypt::ENCRYPTION_UNKNOWN_ERROR;
+ }
+ }
$location = \OC_Helper::linkToAbsolute('apps/files_encryption/files', 'error.php');
$post = 0;
if(count($_POST) > 0) {
$post = 1;
}
- header('Location: ' . $location . '?p=' . $post . '&i=' . $init);
+ header('Location: ' . $location . '?p=' . $post . '&errorCode=' . $errorCode);
exit();
}
diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php
index b25ba7bb677..5ce5caf80ce 100644
--- a/apps/files_encryption/lib/stream.php
+++ b/apps/files_encryption/lib/stream.php
@@ -254,16 +254,20 @@ class Stream {
// If a keyfile already exists
if ($this->encKeyfile) {
+ $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath);
+
// if there is no valid private key return false
if ($this->privateKey === false) {
-
// if private key is not valid redirect user to a error page
- \OCA\Encryption\Helper::redirectToErrorPage();
-
+ \OCA\Encryption\Helper::redirectToErrorPage($this->session);
return false;
}
- $shareKey = Keymanager::getShareKey($this->rootView, $this->userId, $this->relPath);
+ if ($shareKey === false) {
+ // if no share key is available redirect user to a error page
+ \OCA\Encryption\Helper::redirectToErrorPage($this->session, \OCA\Encryption\Crypt::ENCRYPTION_NO_SHARE_KEY_FOUND);
+ return false;
+ }
$this->plainKey = Crypt::multiKeyDecrypt($this->encKeyfile, $shareKey, $this->privateKey);
diff --git a/apps/files_encryption/templates/invalid_private_key.php b/apps/files_encryption/templates/invalid_private_key.php
index 9af65f831b4..a3cae60b1da 100644
--- a/apps/files_encryption/templates/invalid_private_key.php
+++ b/apps/files_encryption/templates/invalid_private_key.php
@@ -4,7 +4,7 @@
<?php p($_['message']); ?>
<br/>
- <?php if($_['init']): ?>
+ <?php if($_['errorCode'] === \OCA\Encryption\Crypt::ENCRYPTION_PRIVATE_KEY_NOT_VALID_ERROR): ?>
<?php>p($l->t('Go directly to your ')); ?> <a href="<?php echo $location?>"><?php p($l->t('personal settings')); ?>.</a>
<?php endif; ?>
<br/>
diff --git a/apps/files_encryption/templates/settings-admin.php b/apps/files_encryption/templates/settings-admin.php
index 3a6adc09f4b..231a68b6a58 100644
--- a/apps/files_encryption/templates/settings-admin.php
+++ b/apps/files_encryption/templates/settings-admin.php
@@ -1,10 +1,7 @@
<form id="encryption">
<fieldset class="personalblock">
- <p>
- <strong><?php p($l->t('Encryption')); ?></strong>
- <br/>
- </p>
+ <h2><?php p($l->t('Encryption')); ?></h2>
<p>
<?php p($l->t("Enable recovery key (allow to recover users files in case of password loss):")); ?>
diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php
index ff04556dd53..a4ed89b8a49 100644
--- a/apps/files_encryption/templates/settings-personal.php
+++ b/apps/files_encryption/templates/settings-personal.php
@@ -1,8 +1,6 @@
<form id="encryption">
<fieldset class="personalblock">
- <legend>
- <?php p( $l->t( 'Encryption' ) ); ?>
- </legend>
+ <h2><?php p( $l->t( 'Encryption' ) ); ?></h2>
<?php if ( ! $_["privateKeySet"] && $_["initialized"] ): ?>
<p>
@@ -38,9 +36,8 @@
</p>
<?php endif; ?>
- <br />
-
<?php if ( $_["recoveryEnabled"] && $_["privateKeySet"] ): ?>
+ <br />
<p>
<label for="userEnableRecovery"><?php p( $l->t( "Enable password recovery:" ) ); ?></label>
<br />
@@ -65,6 +62,5 @@
</p>
<?php endif; ?>
- <br />
</fieldset>
</form>
diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php
index 9b01a2589a5..15ba074e45e 100644
--- a/apps/files_trashbin/templates/index.php
+++ b/apps/files_trashbin/templates/index.php
@@ -1,4 +1,3 @@
-<!--[if IE 8]><style>input[type="checkbox"]{padding:0;}table td{position:static !important;}</style><![endif]-->
<div id="controls">
<?php print_unescaped($_['breadcrumb']); ?>
<div id="file_action_panel"></div>
diff --git a/apps/files_versions/ajax/preview.php b/apps/files_versions/ajax/preview.php
index c24134df534..62bcc03f522 100644
--- a/apps/files_versions/ajax/preview.php
+++ b/apps/files_versions/ajax/preview.php
@@ -12,25 +12,32 @@ if(!\OC_App::isEnabled('files_versions')){
}
$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
+$user = array_key_exists('user', $_GET) ? $_GET['user'] : '';
$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
+if($user === '') {
+ \OC_Response::setStatus(400); //400 Bad Request
+ \OC_Log::write('versions-preview', 'No user parameter was passed', \OC_Log::DEBUG);
+ exit;
+}
+
if($file === '' && $version === '') {
\OC_Response::setStatus(400); //400 Bad Request
- \OC_Log::write('core-preview', 'No file parameter was passed', \OC_Log::DEBUG);
+ \OC_Log::write('versions-preview', 'No file parameter was passed', \OC_Log::DEBUG);
exit;
}
if($maxX === 0 || $maxY === 0) {
\OC_Response::setStatus(400); //400 Bad Request
- \OC_Log::write('core-preview', 'x and/or y set to 0', \OC_Log::DEBUG);
+ \OC_Log::write('versions-preview', 'x and/or y set to 0', \OC_Log::DEBUG);
exit;
}
try{
- $preview = new \OC\Preview(\OC_User::getUser(), 'files_versions');
+ $preview = new \OC\Preview($user, 'files_versions');
$preview->setFile($file.'.v'.$version);
$preview->setMaxX($maxX);
$preview->setMaxY($maxY);
diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php
index fc8d0365c71..225611374a6 100644
--- a/apps/files_versions/lib/versions.php
+++ b/apps/files_versions/lib/versions.php
@@ -19,6 +19,7 @@ class Storage {
const DEFAULTENABLED=true;
const DEFAULTMAXSIZE=50; // unit: percentage; 50% of available disk space/quota
+ const VERSIONS_ROOT = 'files_versions/';
private static $max_versions_per_interval = array(
//first 10sec, one version every 2sec
@@ -238,60 +239,38 @@ class Storage {
* @param $filename file to find versions of, relative to the user files dir
* @returns array
*/
- public static function getVersions($uid, $filename ) {
- if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
- $versions_fileview = new \OC\Files\View('/' . $uid . '/files_versions');
- $versionsName = $versions_fileview->getLocalFile($filename).'.v';
- $escapedVersionName = preg_replace('/(\*|\?|\[)/', '[$1]', $versionsName);
-
- $versions = array();
- // fetch for old versions
- $matches = glob($escapedVersionName.'*');
-
- if ( !$matches ) {
- return $versions;
- }
-
- sort( $matches );
-
- $files_view = new \OC\Files\View('/'.$uid.'/files');
- $local_file = $files_view->getLocalFile($filename);
- $local_file_md5 = \md5_file( $local_file );
-
- foreach( $matches as $ma ) {
- $parts = explode( '.v', $ma );
- $version = ( end( $parts ) );
- $key = $version.'#'.$filename;
- $versions[$key]['cur'] = 0;
- $versions[$key]['version'] = $version;
- $versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
- $versions[$key]['path'] = $filename;
- $versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $filename, 'version' => $version));
- $versions[$key]['size'] = $versions_fileview->filesize($filename.'.v'.$version);
-
- // if file with modified date exists, flag it in array as currently enabled version
- ( \md5_file( $ma ) == $local_file_md5 ? $versions[$key]['fileMatch'] = 1 : $versions[$key]['fileMatch'] = 0 );
-
- }
-
- // newest versions first
- $versions = array_reverse( $versions );
-
- foreach( $versions as $key => $value ) {
- // flag the first matched file in array (which will have latest modification date) as current version
- if ( $value['fileMatch'] ) {
- $value['cur'] = 1;
- break;
+ public static function getVersions($uid, $filename) {
+ $versions = array();
+ // fetch for old versions
+ $view = new \OC\Files\View('/' . $uid . '/' . self::VERSIONS_ROOT);
+
+ $pathinfo = pathinfo($filename);
+
+ $files = $view->getDirectoryContent($pathinfo['dirname']);
+
+ $versionedFile = $pathinfo['basename'];
+
+ foreach ($files as $file) {
+ if ($file['type'] === 'file') {
+ $pos = strrpos($file['path'], '.v');
+ $currentFile = substr($file['name'], 0, strrpos($file['name'], '.v'));
+ if ($currentFile === $versionedFile) {
+ $version = substr($file['path'], $pos + 2);
+ $key = $version . '#' . $filename;
+ $versions[$key]['cur'] = 0;
+ $versions[$key]['version'] = $version;
+ $versions[$key]['humanReadableTimestamp'] = self::getHumanReadableTimestamp($version);
+ $versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $filename, 'version' => $version, 'user' => $uid));
+ $versions[$key]['path'] = $filename;
+ $versions[$key]['size'] = $file['size'];
}
}
-
- return( $versions );
-
- } else {
- // if versioning isn't enabled then return an empty array
- return( array() );
}
+ // sort with newest version first
+ krsort($versions);
+
+ return $versions;
}
/**
@@ -366,48 +345,45 @@ class Storage {
* @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename
*/
private static function getAllVersions($uid) {
- if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
- $versions_fileview = new \OC\Files\View('/'.$uid.'/files_versions');
- $versionsRoot = $versions_fileview->getLocalFolder('');
+ $view = new \OC\Files\View('/' . $uid . '/');
+ $dirs = array(self::VERSIONS_ROOT);
- $iterator = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($versionsRoot),
- \RecursiveIteratorIterator::CHILD_FIRST
- );
+ while (!empty($dirs)) {
+ $dir = array_pop($dirs);
+ $files = $view->getDirectoryContent($dir);
- $versions = array();
-
- foreach ($iterator as $path) {
- if ( preg_match('/^.+\.v(\d+)$/', $path, $match) ) {
- $relpath = substr($path, strlen($versionsRoot)-1);
- $versions[$match[1].'#'.$relpath] = array('path' => $relpath, 'timestamp' => $match[1]);
+ foreach ($files as $file) {
+ if ($file['type'] === 'dir') {
+ array_push($dirs, $file['path']);
+ } else {
+ $versionsBegin = strrpos($file['path'], '.v');
+ $relPathStart = strlen(self::VERSIONS_ROOT);
+ $version = substr($file['path'], $versionsBegin + 2);
+ $relpath = substr($file['path'], $relPathStart, $versionsBegin - $relPathStart);
+ $key = $version . '#' . $relpath;
+ $versions[$key] = array('path' => $relpath, 'timestamp' => $version);
}
}
+ }
- ksort($versions);
-
- $i = 0;
-
- $result = array();
-
- foreach( $versions as $key => $value ) {
- $i++;
- $size = $versions_fileview->filesize($value['path']);
- $filename = substr($value['path'], 0, -strlen($value['timestamp'])-2);
+ ksort($versions);
- $result['all'][$key]['version'] = $value['timestamp'];
- $result['all'][$key]['path'] = $filename;
- $result['all'][$key]['size'] = $size;
+ $result = array();
- $filename = substr($value['path'], 0, -strlen($value['timestamp'])-2);
- $result['by_file'][$filename][$key]['version'] = $value['timestamp'];
- $result['by_file'][$filename][$key]['path'] = $filename;
- $result['by_file'][$filename][$key]['size'] = $size;
+ foreach ($versions as $key => $value) {
+ $size = $view->filesize($value['path']);
+ $filename = $value['path'];
- }
+ $result['all'][$key]['version'] = $value['timestamp'];
+ $result['all'][$key]['path'] = $filename;
+ $result['all'][$key]['size'] = $size;
- return $result;
+ $result['by_file'][$filename][$key]['version'] = $value['timestamp'];
+ $result['by_file'][$filename][$key]['path'] = $filename;
+ $result['by_file'][$filename][$key]['size'] = $size;
}
+
+ return $result;
}
/**
diff --git a/core/ajax/vcategories/add.php b/core/ajax/vcategories/add.php
deleted file mode 100644
index 16a1461be08..00000000000
--- a/core/ajax/vcategories/add.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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.
- */
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/add.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/add.php: '.$msg, OC_Log::DEBUG);
-}
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-
-$l = OC_L10N::get('core');
-
-$category = isset($_POST['category']) ? strip_tags($_POST['category']) : null;
-$type = isset($_POST['type']) ? $_POST['type'] : null;
-
-if(is_null($type)) {
- bailOut($l->t('Category type not provided.'));
-}
-
-if(is_null($category)) {
- bailOut($l->t('No category to add?'));
-}
-
-debug(print_r($category, true));
-
-$categories = new OC_VCategories($type);
-if($categories->hasCategory($category)) {
- bailOut($l->t('This category already exists: %s', array($category)));
-} else {
- $categories->add($category, true);
-}
-
-OC_JSON::success(array('data' => array('categories'=>$categories->categories())));
diff --git a/core/ajax/vcategories/addToFavorites.php b/core/ajax/vcategories/addToFavorites.php
deleted file mode 100644
index 52f62d5fc6b..00000000000
--- a/core/ajax/vcategories/addToFavorites.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?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.
- */
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG);
-}
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-
-$l = OC_L10N::get('core');
-
-$id = isset($_POST['id']) ? strip_tags($_POST['id']) : null;
-$type = isset($_POST['type']) ? $_POST['type'] : null;
-
-if(is_null($type)) {
- bailOut($l->t('Object type not provided.'));
-}
-
-if(is_null($id)) {
- bailOut($l->t('%s ID not provided.', $type));
-}
-
-$categories = new OC_VCategories($type);
-if(!$categories->addToFavorites($id, $type)) {
- bailOut($l->t('Error adding %s to favorites.', $id));
-}
-
-OC_JSON::success();
diff --git a/core/ajax/vcategories/delete.php b/core/ajax/vcategories/delete.php
deleted file mode 100644
index dfec3785743..00000000000
--- a/core/ajax/vcategories/delete.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?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.
- */
-
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/delete.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/delete.php: '.$msg, OC_Log::DEBUG);
-}
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-
-$l = OC_L10N::get('core');
-
-$type = isset($_POST['type']) ? $_POST['type'] : null;
-$categories = isset($_POST['categories']) ? $_POST['categories'] : null;
-
-if(is_null($type)) {
- bailOut($l->t('Object type not provided.'));
-}
-
-debug('The application using category type "'
- . $type
- . '" uses the default file for deletion. OC_VObjects will not be updated.');
-
-if(is_null($categories)) {
- bailOut($l->t('No categories selected for deletion.'));
-}
-
-$vcategories = new OC_VCategories($type);
-$vcategories->delete($categories);
-OC_JSON::success(array('data' => array('categories'=>$vcategories->categories())));
diff --git a/core/ajax/vcategories/edit.php b/core/ajax/vcategories/edit.php
deleted file mode 100644
index 0387b17576c..00000000000
--- a/core/ajax/vcategories/edit.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
- */
-
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/edit.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/edit.php: '.$msg, OC_Log::DEBUG);
-}
-
-OC_JSON::checkLoggedIn();
-
-$l = OC_L10N::get('core');
-
-$type = isset($_GET['type']) ? $_GET['type'] : null;
-
-if(is_null($type)) {
- bailOut($l->t('Category type not provided.'));
-}
-
-$tmpl = new OCP\Template("core", "edit_categories_dialog");
-
-$vcategories = new OC_VCategories($type);
-$categories = $vcategories->categories();
-debug(print_r($categories, true));
-$tmpl->assign('categories', $categories);
-$tmpl->printpage();
diff --git a/core/ajax/vcategories/favorites.php b/core/ajax/vcategories/favorites.php
deleted file mode 100644
index db4244d601a..00000000000
--- a/core/ajax/vcategories/favorites.php
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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.
- */
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG);
-}
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-
-$type = isset($_GET['type']) ? $_GET['type'] : null;
-
-if(is_null($type)) {
- $l = OC_L10N::get('core');
- bailOut($l->t('Object type not provided.'));
-}
-
-$categories = new OC_VCategories($type);
-$ids = $categories->getFavorites($type);
-
-OC_JSON::success(array('ids' => $ids));
diff --git a/core/ajax/vcategories/removeFromFavorites.php b/core/ajax/vcategories/removeFromFavorites.php
deleted file mode 100644
index 78a528caa86..00000000000
--- a/core/ajax/vcategories/removeFromFavorites.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?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.
- */
-function bailOut($msg) {
- OC_JSON::error(array('data' => array('message' => $msg)));
- OC_Log::write('core', 'ajax/vcategories/removeFromFavorites.php: '.$msg, OC_Log::DEBUG);
- exit();
-}
-function debug($msg) {
- OC_Log::write('core', 'ajax/vcategories/removeFromFavorites.php: '.$msg, OC_Log::DEBUG);
-}
-
-OCP\JSON::checkLoggedIn();
-OCP\JSON::callCheck();
-
-$l = OC_L10N::get('core');
-
-$id = isset($_POST['id']) ? strip_tags($_POST['id']) : null;
-$type = isset($_POST['type']) ? $_POST['type'] : null;
-
-if(is_null($type)) {
- bailOut($l->t('Object type not provided.'));
-}
-
-if(is_null($id)) {
- bailOut($l->t('%s ID not provided.', array($type)));
-}
-
-$categories = new OC_VCategories($type);
-if(!$categories->removeFromFavorites($id, $type)) {
- bailOut($l->t('Error removing %s from favorites.', array($id)));
-}
-
-OC_JSON::success();
diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css
index aa72eaf8474..236968e3245 100644
--- a/core/css/jquery.ocdialog.css
+++ b/core/css/jquery.ocdialog.css
@@ -29,6 +29,7 @@
bottom: 0;
display: block;
margin-top: 10px;
+ width: 100%;
}
.oc-dialog-close {
diff --git a/core/css/styles.css b/core/css/styles.css
index 728fd47bc9f..1a521019d98 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -753,15 +753,21 @@ span.ui-icon {float: left; margin: 3px 7px 30px 0;}
height: 16px;
}
-
-/* ---- CATEGORIES ---- */
-#categoryform .scrollarea { position:absolute; left:10px; top:10px; right:10px; bottom:50px; overflow:auto; border:1px solid #ddd; background:#f8f8f8; }
-#categoryform .bottombuttons { position:absolute; bottom:10px;}
-#categoryform .bottombuttons * { float:left;}
-/*#categorylist { border:1px solid #ddd;}*/
-#categorylist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
-#categorylist li:hover, #categorylist li:active { background:#eee; }
-#category_addinput { width:10em; }
+/* ---- TAGS ---- */
+#tagsdialog .content {
+ width: 100%; height: 280px;
+}
+#tagsdialog .scrollarea {
+ overflow:auto; border:1px solid #ddd;
+ width: 100%; height: 240px;
+}
+#tagsdialog .bottombuttons {
+ width: 100%; height: 30px;
+}
+#tagsdialog .bottombuttons * { float:left;}
+#tagsdialog .taglist li { background:#f8f8f8; padding:.3em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 500ms; -moz-transition:background-color 500ms; -o-transition:background-color 500ms; transition:background-color 500ms; }
+#tagsdialog .taglist li:hover, #tagsdialog .taglist li:active { background:#eee; }
+#tagsdialog .addinput { width: 90%; clear: both; }
/* ---- APP SETTINGS ---- */
.popup { background-color:white; border-radius:10px 10px 10px 10px; box-shadow:0 0 20px #888; color:#333; padding:10px; position:fixed !important; z-index:100; }
diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js
deleted file mode 100644
index c297a24680d..00000000000
--- a/core/js/oc-vcategories.js
+++ /dev/null
@@ -1,216 +0,0 @@
-var OCCategories= {
- category_favorites:'_$!<Favorite>!$_',
- edit:function(type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- $('body').append('<div id="category_dialog"></div>');
- $('#category_dialog').load(
- OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?type=' + type, function(response) {
- try {
- var jsondata = jQuery.parseJSON(response);
- if(response.status == 'error') {
- OC.dialogs.alert(response.data.message, t('core', 'Error'));
- return;
- }
- } catch(e) {
- var setEnabled = function(d, enable) {
- if(enable) {
- d.css('cursor', 'default').find('input,button:not(#category_addbutton)')
- .prop('disabled', false).css('cursor', 'default');
- } else {
- d.css('cursor', 'wait').find('input,button:not(#category_addbutton)')
- .prop('disabled', true).css('cursor', 'wait');
- }
- };
- var dlg = $('#edit_categories_dialog').dialog({
- modal: true,
- height: 350, minHeight:200, width: 250, minWidth: 200,
- buttons: {
- 'Close': function() {
- $(this).dialog('close');
- },
- 'Delete':function() {
- var categories = $('#categorylist').find('input:checkbox').serialize();
- setEnabled(dlg, false);
- OCCategories.doDelete(categories, function() {
- setEnabled(dlg, true);
- });
- },
- 'Rescan':function() {
- setEnabled(dlg, false);
- OCCategories.rescan(function() {
- setEnabled(dlg, true);
- });
- }
- },
- close : function(event, ui) {
- $(this).dialog('destroy').remove();
- $('#category_dialog').remove();
- },
- open : function(event, ui) {
- $('#category_addinput').on('input',function() {
- if($(this).val().length > 0) {
- $('#category_addbutton').removeAttr('disabled');
- }
- });
- $('#categoryform').submit(function() {
- OCCategories.add($('#category_addinput').val());
- $('#category_addinput').val('');
- $('#category_addbutton').attr('disabled', 'disabled');
- return false;
- });
- $('#category_addbutton').on('click',function(e) {
- e.preventDefault();
- if($('#category_addinput').val().length > 0) {
- OCCategories.add($('#category_addinput').val());
- $('#category_addinput').val('');
- }
- });
- }
- });
- }
- });
- },
- _processDeleteResult:function(jsondata) {
- if(jsondata.status == 'success') {
- OCCategories._update(jsondata.data.categories);
- } else {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- },
- favorites:function(type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- $.getJSON(OC.filePath('core', 'ajax', 'categories/favorites.php'), {type: type},function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- if(jsondata.status === 'success') {
- OCCategories._update(jsondata.data.categories);
- } else {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- }
- });
- },
- addToFavorites:function(id, type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- $.post(OC.filePath('core', 'ajax', 'vcategories/addToFavorites.php'), {id:id, type:type}, function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- if(jsondata.status !== 'success') {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- }
- });
- },
- removeFromFavorites:function(id, type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- $.post(OC.filePath('core', 'ajax', 'vcategories/removeFromFavorites.php'), {id:id, type:type}, function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- if(jsondata.status !== 'success') {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- }
- });
- },
- doDelete:function(categories, type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- if(categories == '' || categories == undefined) {
- OC.dialogs.alert(t('core', 'No categories selected for deletion.'), t('core', 'Error'));
- return false;
- }
- var self = this;
- var q = categories + '&type=' + type;
- if(this.app) {
- q += '&app=' + this.app;
- $.post(OC.filePath(this.app, 'ajax', 'categories/delete.php'), q, function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- self._processDeleteResult(jsondata);
- }
- });
- } else {
- $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), q, function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- self._processDeleteResult(jsondata);
- }
- });
- }
- },
- add:function(category, type, cb) {
- if(!type && !this.type) {
- throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
- }
- type = type ? type : this.type;
- $.post(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'type':type},function(jsondata) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- if(jsondata.status === 'success') {
- OCCategories._update(jsondata.data.categories);
- } else {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- }
- });
- },
- rescan:function(app, cb) {
- if(!app && !this.app) {
- throw { name: 'MissingParameter', message: t('core', 'The app name is not specified.') };
- }
- app = app ? app : this.app;
- $.getJSON(OC.filePath(app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr) {
- if(typeof cb == 'function') {
- cb(jsondata);
- } else {
- if(jsondata.status === 'success') {
- OCCategories._update(jsondata.data.categories);
- } else {
- OC.dialogs.alert(jsondata.data.message, t('core', 'Error'));
- }
- }
- }).error(function(xhr){
- if (xhr.status == 404) {
- var errormessage = t('core', 'The required file {file} is not installed!',
- {file: OC.filePath(app, 'ajax', 'categories/rescan.php')}, t('core', 'Error'));
- if(typeof cb == 'function') {
- cb({status:'error', data:{message:errormessage}});
- } else {
- OC.dialogs.alert(errormessage, t('core', 'Error'));
- }
- }
- });
- },
- _update:function(categories) {
- var categorylist = $('#categorylist');
- categorylist.find('li').remove();
- for(var category in categories) {
- var item = '<li><input type="checkbox" name="categories" value="' + categories[category] + '" />' + categories[category] + '</li>';
- $(item).appendTo(categorylist);
- }
- if(typeof OCCategories.changed === 'function') {
- OCCategories.changed(categories);
- }
- }
-}
-
diff --git a/core/js/oc-vcategories.txt b/core/js/oc-vcategories.txt
deleted file mode 100644
index 31216f80bd3..00000000000
--- a/core/js/oc-vcategories.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-Using OCCategories
-
-This 'class' is meant for any apps that uses OC_VObjects with the CATEGORIES field e.g.
-Contacts and Calendar. It provides an editor UI for adding/deleting and rescanning categories
-and basic ajax functions for adding and deleting.
-To use the mass updating of OC_VObjects that /lib/vcategories.php provides, the app must implement
-its own ajax functions in /apps/$(APP)/ajax/categories/rescan.php and /apps/$(APP)/ajax/categories/delete.php
-See examples in /apps/contacts/ajax/categories and the inline docs in /lib/vcategories.php.
-
-In your app make sure you load the script and stylesheet:
-
-OC_Util::addScript('','oc-vcategories');
-OC_Util::addStyle('','oc-vcategories');
-
-Set the app specific values in your javascript file. This is what I've used for the Contacts app:
-
- OCCategories.app = 'contacts';
- OCCategories.changed = Contacts.UI.Card.categoriesChanged;
-
-If OCCategories.changed is set that function will be called each time the categories have been changed
-in the editor (add/delete/rescan) to allow the app to update the UI accordingly. The only argument to the function
-is an array of the updated categories e.g.:
-
-OCCategories.changed = function(categories) {
- for(var category in categories) {
- console.log(categories[category]);
- }
-}
-
-To show the categories editor call:
-
- OCCategories.edit()
-
diff --git a/core/js/tags.js b/core/js/tags.js
new file mode 100644
index 00000000000..16dd3d4bf97
--- /dev/null
+++ b/core/js/tags.js
@@ -0,0 +1,353 @@
+OC.Tags= {
+ edit:function(type, cb) {
+ if(!type && !this.type) {
+ throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') };
+ }
+ type = type ? type : this.type;
+ var self = this;
+ $.when(this._getTemplate()).then(function($tmpl) {
+ if(self.$dialog) {
+ self.$dialog.ocdialog('close');
+ }
+ self.$dialog = $tmpl.octemplate({
+ addText: t('core', 'Enter new')
+ });
+ $('body').append(self.$dialog);
+
+ self.$dialog.ready(function() {
+ self.$taglist = self.$dialog.find('.taglist');
+ self.$taginput = self.$dialog.find('.addinput');
+ self.$taglist.on('change', 'input:checkbox', function(event) {
+ self._handleChanges(self.$taglist, self.$taginput);
+ });
+ self.$taginput.on('input', function(event) {
+ self._handleChanges(self.$taglist, self.$taginput);
+ });
+ self.deleteButton = {
+ text: t('core', 'Delete'),
+ click: function() {self._deleteTags(self, type, self._selectedIds())},
+ };
+ self.addButton = {
+ text: t('core', 'Add'),
+ click: function() {self._addTag(self, type, self.$taginput.val())},
+ };
+
+ self._fillTagList(type, self.$taglist);
+ });
+
+ self.$dialog.ocdialog({
+ title: t('core', 'Edit tags'),
+ closeOnEscape: true,
+ width: 250,
+ height: 'auto',
+ modal: true,
+ //buttons: buttonlist,
+ close: function(event, ui) {
+ try {
+ $(this).ocdialog('destroy').remove();
+ } catch(e) {console.warn(e);}
+ self.$dialog = null;
+ }
+ });
+ })
+ .fail(function(status, error) {
+ // If the method is called while navigating away
+ // from the page, it is probably not needed ;)
+ if(status !== 0) {
+ alert(t('core', 'Error loading dialog template: {error}', {error: error}));
+ }
+ });
+ },
+ /**
+ * @param string type
+ * @return jQuery.Promise which resolves with an array of ids
+ */
+ getIdsForTag:function(type, tag) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_ids_for_tag', {type: type});
+ $.getJSON(url, {tag: tag}, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response.ids);
+ } else {
+ defer.reject(response);
+ }
+ });
+ return defer.promise();
+ },
+ /**
+ * @param string type
+ * @return jQuery.Promise which resolves with an array of ids
+ */
+ getFavorites:function(type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_favorites', {type: type});
+ $.getJSON(url, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response.ids);
+ } else {
+ defer.reject(response);
+ }
+ });
+ return defer.promise();
+ },
+ /**
+ * @param string type
+ * @return jQuery.Promise which resolves with an array of id/name objects
+ */
+ getTags:function(type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_tags', {type: type});
+ $.getJSON(url, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response.tags);
+ } else {
+ defer.reject(response);
+ }
+ });
+ return defer.promise();
+ },
+ /**
+ * @param int id
+ * @param string type
+ * @return jQuery.Promise
+ */
+ tagAs:function(id, tag, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_tag', {type: type, id: id});
+ $.post(url, {tag: tag}, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response);
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ /**
+ * @param int id
+ * @param string type
+ * @return jQuery.Promise
+ */
+ unTag:function(id, tag, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_untag', {type: type, id: id});
+ $.post(url, {tag: tag}, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response);
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ /**
+ * @param int id
+ * @param string type
+ * @return jQuery.Promise
+ */
+ addToFavorites:function(id, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_favorite', {type: type, id: id});
+ $.post(url, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response);
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ /**
+ * @param int id
+ * @param string type
+ * @return jQuery.Promise
+ */
+ removeFromFavorites:function(id, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_unfavorite', {type: type, id: id});
+ $.post(url, function(response) {
+ if(response.status === 'success') {
+ defer.resolve();
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ /**
+ * @param string tag
+ * @param string type
+ * @return jQuery.Promise which resolves with an object with the name and the new id
+ */
+ addTag:function(tag, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_add', {type: type});
+ $.post(url,{tag:tag}, function(response) {
+ if(typeof cb == 'function') {
+ cb(response);
+ }
+ if(response.status === 'success') {
+ defer.resolve({id:response.id, name: tag});
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ /**
+ * @param array tags
+ * @param string type
+ * @return jQuery.Promise
+ */
+ deleteTags:function(tags, type) {
+ if(!type && !this.type) {
+ throw new Error('The object type is not specified.');
+ }
+ type = type ? type : this.type;
+ var defer = $.Deferred(),
+ self = this,
+ url = OC.Router.generate('core_tags_delete', {type: type});
+ if(!tags || !tags.length) {
+ throw new Error(t('core', 'No tags selected for deletion.'));
+ }
+ var self = this;
+ $.post(url, {tags:tags}, function(response) {
+ if(response.status === 'success') {
+ defer.resolve(response.tags);
+ } else {
+ defer.reject(response);
+ }
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ return defer.promise();
+ },
+ _update:function(tags, type) {
+ if(!this.$dialog) {
+ return;
+ }
+ var $taglist = this.$dialog.find('.taglist'),
+ self = this;
+ $taglist.empty();
+ $.each(tags, function(idx, tag) {
+ var $item = self.$listTmpl.octemplate({id: tag.id, name: tag.name});
+ $item.appendTo($taglist);
+ });
+ $(this).trigger('change', {type: type, tags: tags});
+ if(typeof this.changed === 'function') {
+ this.changed(tags);
+ }
+ },
+ _getTemplate: function() {
+ var defer = $.Deferred();
+ if(!this.$template) {
+ var self = this;
+ $.get(OC.filePath('core', 'templates', 'tags.html'), function(tmpl) {
+ self.$template = $(tmpl);
+ self.$listTmpl = self.$template.find('.taglist li:first-child').detach();
+ defer.resolve(self.$template);
+ })
+ .fail(function(jqXHR, textStatus, errorThrown) {
+ defer.reject(jqXHR.status, errorThrown);
+ });
+ } else {
+ defer.resolve(this.$template);
+ }
+ return defer.promise();
+ },
+ _fillTagList: function(type) {
+ var self = this;
+ $.when(this.getTags(type))
+ .then(function(tags) {
+ self._update(tags, type);
+ })
+ .fail(function(response) {
+ console.warn(response);
+ });
+ },
+ _selectedIds: function() {
+ return $.map(this.$taglist.find('input:checked'), function(b) {return $(b).val();});
+ },
+ _handleChanges: function($list, $input) {
+ var ids = this._selectedIds();
+ var buttons = [];
+ if($input.val().length) {
+ buttons.push(this.addButton);
+ }
+ if(ids.length) {
+ buttons.push(this.deleteButton);
+ }
+ this.$dialog.ocdialog('option', 'buttons', buttons);
+ },
+ _deleteTags: function(self, type, ids) {
+ $.when(self.deleteTags(ids, type))
+ .then(function() {
+ self._fillTagList(type);
+ self.$dialog.ocdialog('option', 'buttons', []);
+ })
+ .fail(function(response) {
+ console.warn(response);
+ });
+ },
+ _addTag: function(self, type, tag) {
+ $.when(self.addTag(tag, type))
+ .then(function(tag) {
+ self._fillTagList(type);
+ self.$taginput.val('').trigger('input');
+ })
+ .fail(function(response) {
+ console.warn(response);
+ });
+ }
+}
+
diff --git a/core/routes.php b/core/routes.php
index 57e25c0f1f7..5009243d59f 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -23,19 +23,43 @@ $this->create('core_ajax_share', '/core/ajax/share.php')
// Translations
$this->create('core_ajax_translations', '/core/ajax/translations.php')
->actionInclude('core/ajax/translations.php');
-// VCategories
-$this->create('core_ajax_vcategories_add', '/core/ajax/vcategories/add.php')
- ->actionInclude('core/ajax/vcategories/add.php');
-$this->create('core_ajax_vcategories_delete', '/core/ajax/vcategories/delete.php')
- ->actionInclude('core/ajax/vcategories/delete.php');
-$this->create('core_ajax_vcategories_addtofavorites', '/core/ajax/vcategories/addToFavorites.php')
- ->actionInclude('core/ajax/vcategories/addToFavorites.php');
-$this->create('core_ajax_vcategories_removefromfavorites', '/core/ajax/vcategories/removeFromFavorites.php')
- ->actionInclude('core/ajax/vcategories/removeFromFavorites.php');
-$this->create('core_ajax_vcategories_favorites', '/core/ajax/vcategories/favorites.php')
- ->actionInclude('core/ajax/vcategories/favorites.php');
-$this->create('core_ajax_vcategories_edit', '/core/ajax/vcategories/edit.php')
- ->actionInclude('core/ajax/vcategories/edit.php');
+// Tags
+$this->create('core_tags_tags', '/tags/{type}')
+ ->get()
+ ->action('OC\Core\Tags\Controller', 'getTags')
+ ->requirements(array('type'));
+$this->create('core_tags_favorites', '/tags/{type}/favorites')
+ ->get()
+ ->action('OC\Core\Tags\Controller', 'getFavorites')
+ ->requirements(array('type'));
+$this->create('core_tags_ids_for_tag', '/tags/{type}/ids')
+ ->get()
+ ->action('OC\Core\Tags\Controller', 'getIdsForTag')
+ ->requirements(array('type'));
+$this->create('core_tags_favorite', '/tags/{type}/favorite/{id}/')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'favorite')
+ ->requirements(array('type', 'id'));
+$this->create('core_tags_unfavorite', '/tags/{type}/unfavorite/{id}/')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'unFavorite')
+ ->requirements(array('type', 'id'));
+$this->create('core_tags_tag', '/tags/{type}/tag/{id}/')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'tagAs')
+ ->requirements(array('type', 'id'));
+$this->create('core_tags_untag', '/tags/{type}/untag/{id}/')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'unTag')
+ ->requirements(array('type', 'id'));
+$this->create('core_tags_add', '/tags/{type}/add')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'addTag')
+ ->requirements(array('type'));
+$this->create('core_tags_delete', '/tags/{type}/delete')
+ ->post()
+ ->action('OC\Core\Tags\Controller', 'deleteTags')
+ ->requirements(array('type'));
// oC JS config
$this->create('js_config', '/core/js/config.js')
->actionInclude('core/js/config.php');
diff --git a/core/tags/controller.php b/core/tags/controller.php
new file mode 100644
index 00000000000..c790d43345d
--- /dev/null
+++ b/core/tags/controller.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Core\Tags;
+
+class Controller {
+ protected static function getTagger($type) {
+ \OC_JSON::checkLoggedIn();
+ \OC_JSON::callCheck();
+
+ try {
+ $tagger = \OC::$server->getTagManager()->load($type);
+ return $tagger;
+ } catch(\Exception $e) {
+ \OCP\Util::writeLog('core', __METHOD__ . ' Exception: ' . $e->getMessage(), \OCP\Util::ERROR);
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error loading tags')));
+ exit;
+ }
+ }
+
+ public static function getTags($args) {
+ $tagger = self::getTagger($args['type']);
+ \OC_JSON::success(array('tags'=> $tagger->getTags()));
+ }
+
+ public static function getFavorites($args) {
+ $tagger = self::getTagger($args['type']);
+ \OC_JSON::success(array('ids'=> $tagger->getFavorites()));
+ }
+
+ public static function getIdsForTag($args) {
+ $tagger = self::getTagger($args['type']);
+ \OC_JSON::success(array('ids'=> $tagger->getIdsForTag($_GET['tag'])));
+ }
+
+ public static function addTag($args) {
+ $tagger = self::getTagger($args['type']);
+
+ $id = $tagger->add(strip_tags($_POST['tag']));
+ if($id === false) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Tag already exists')));
+ } else {
+ \OC_JSON::success(array('id'=> $id));
+ }
+ }
+
+ public static function deleteTags($args) {
+ $tags = $_POST['tags'];
+ if(!is_array($tags)) {
+ $tags = array($tags);
+ }
+
+ $tagger = self::getTagger($args['type']);
+
+ if(!$tagger->delete($tags)) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error deleting tag(s)')));
+ } else {
+ \OC_JSON::success();
+ }
+ }
+
+ public static function tagAs($args) {
+ $tagger = self::getTagger($args['type']);
+
+ if(!$tagger->tagAs($args['id'], $_POST['tag'])) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error tagging')));
+ } else {
+ \OC_JSON::success();
+ }
+ }
+
+ public static function unTag($args) {
+ $tagger = self::getTagger($args['type']);
+
+ if(!$tagger->unTag($args['id'], $_POST['tag'])) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error untagging')));
+ } else {
+ \OC_JSON::success();
+ }
+ }
+
+ public static function favorite($args) {
+ $tagger = self::getTagger($args['type']);
+
+ if(!$tagger->addToFavorites($args['id'])) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error favoriting')));
+ } else {
+ \OC_JSON::success();
+ }
+ }
+
+ public static function unFavorite($args) {
+ $tagger = self::getTagger($args['type']);
+
+ if(!$tagger->removeFromFavorites($args['id'])) {
+ $l = new \OC_L10n('core');
+ \OC_JSON::error(array('message'=> $l->t('Error unfavoriting')));
+ } else {
+ \OC_JSON::success();
+ }
+ }
+
+}
diff --git a/core/templates/edit_categories_dialog.php b/core/templates/edit_categories_dialog.php
deleted file mode 100644
index ea155bdf0ba..00000000000
--- a/core/templates/edit_categories_dialog.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-$categories = isset($_['categories'])?$_['categories']:array();
-?>
-<div id="edit_categories_dialog" title="<?php p($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 p($category); ?>" /><?php p($category); ?></li>
- <?php endforeach; ?>
- </ul>
- </div>
- <div class="bottombuttons">
- <input type="text" id="category_addinput" name="category" />
- <button id="category_addbutton" disabled="disabled"><?php p($l->t('Add')); ?></button>
- </div>
- </form>
-</div>
diff --git a/core/templates/tags.html b/core/templates/tags.html
new file mode 100644
index 00000000000..ae3d072b381
--- /dev/null
+++ b/core/templates/tags.html
@@ -0,0 +1,14 @@
+<div id="tagsdialog">
+ <div class="content">
+ <div class="scrollarea">
+ <ul class="taglist">
+ <li><input type="checkbox" name="ids[]" id="tag_{id}" value="{name}" />
+ <label for="tag_{id}">{name}</label>
+ </li>
+ </ul>
+ </div>
+ <div class="bottombuttons">
+ <input type="text" class="addinput" name="tag" placeholder="{addText}" />
+ </div>
+ </div>
+</div>
diff --git a/lib/private/connector/sabre/exception/entitytoolarge.php b/lib/private/connector/sabre/exception/entitytoolarge.php
new file mode 100644
index 00000000000..2bda51f2f3e
--- /dev/null
+++ b/lib/private/connector/sabre/exception/entitytoolarge.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * Entity Too Large
+ *
+ * This exception is thrown whenever a user tries to upload a file which exceeds hard limitations
+ *
+ */
+class OC_Connector_Sabre_Exception_EntityTooLarge extends Sabre_DAV_Exception {
+
+ /**
+ * Returns the HTTP status code for this exception
+ *
+ * @return int
+ */
+ public function getHTTPCode() {
+
+ return 413;
+
+ }
+
+}
diff --git a/lib/private/connector/sabre/exception/unsupportedmediatype.php b/lib/private/connector/sabre/exception/unsupportedmediatype.php
new file mode 100644
index 00000000000..95d6a8cc651
--- /dev/null
+++ b/lib/private/connector/sabre/exception/unsupportedmediatype.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * Unsupported Media Type
+ *
+ * This exception is thrown whenever a user tries to upload a file which holds content which is not allowed
+ *
+ */
+class OC_Connector_Sabre_Exception_UnsupportedMediaType extends Sabre_DAV_Exception {
+
+ /**
+ * Returns the HTTP status code for this exception
+ *
+ * @return int
+ */
+ public function getHTTPCode() {
+
+ return 415;
+
+ }
+
+}
diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php
index 037dba7f37b..667f7407f75 100644
--- a/lib/private/connector/sabre/file.php
+++ b/lib/private/connector/sabre/file.php
@@ -98,7 +98,21 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
throw new Sabre_DAV_Exception();
}
} catch (\OCP\Files\NotPermittedException $e) {
- throw new Sabre_DAV_Exception_Forbidden();
+ // a more general case - due to whatever reason the content could not be written
+ throw new Sabre_DAV_Exception_Forbidden($e->getMessage());
+
+ } catch (\OCP\Files\EntityTooLargeException $e) {
+ // the file is too big to be stored
+ throw new OC_Connector_Sabre_Exception_EntityTooLarge($e->getMessage());
+
+ } catch (\OCP\Files\InvalidContentException $e) {
+ // the file content is not permitted
+ throw new OC_Connector_Sabre_Exception_UnsupportedMediaType($e->getMessage());
+
+ } catch (\OCP\Files\InvalidPathException $e) {
+ // the path for the file was not valid
+ // TODO: find proper http status code for this case
+ throw new Sabre_DAV_Exception_Forbidden($e->getMessage());
}
// rename to correct path
diff --git a/lib/public/files/entitytoolargeexception.php b/lib/public/files/entitytoolargeexception.php
new file mode 100644
index 00000000000..3dff41bca02
--- /dev/null
+++ b/lib/public/files/entitytoolargeexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Müller <thomas.mueller@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class EntityTooLargeException extends \Exception {}
diff --git a/lib/public/files/invalidcontentexception.php b/lib/public/files/invalidcontentexception.php
new file mode 100644
index 00000000000..184ec4d06d6
--- /dev/null
+++ b/lib/public/files/invalidcontentexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Müller <thomas.mueller@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class InvalidContentException extends \Exception {}
diff --git a/lib/public/files/invalidpathexception.php b/lib/public/files/invalidpathexception.php
new file mode 100644
index 00000000000..36090ae5b48
--- /dev/null
+++ b/lib/public/files/invalidpathexception.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2013 Thomas Müller <thomas.mueller@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP\Files;
+
+class InvalidPathException extends \Exception {}
diff --git a/settings/js/personal.js b/settings/js/personal.js
index 3fdc2907c46..cdf7d0e9631 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -31,7 +31,7 @@ function changeDisplayName(){
// Ajax foo
$.post( 'ajax/changedisplayname.php', post, function(data){
if( data.status === "success" ){
- $('#oldDisplayName').text($('#displayName').val());
+ $('#oldDisplayName').val($('#displayName').val());
// update displayName on the top right expand button
$('#expandDisplayName').text($('#displayName').val());
updateAvatar();
@@ -171,11 +171,6 @@ $(document).ready(function(){
}
});
- $("#languageinput").chosen();
- // Show only the not selectable optgroup
- // Choosen only shows optgroup-labels if there are options in the optgroup
- $(".languagedivider").hide();
-
$("#languageinput").change( function(){
// Serialize the data
var post = $( "#languageinput" ).serialize();
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 47227d6ea0f..1be7be578d3 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -104,19 +104,27 @@ if($_['passwordChangeSupported']) {
<form>
<fieldset class="personalblock">
<h2><?php p($l->t('Language'));?></h2>
- <select id="languageinput" class="chzen-select" name="lang" data-placeholder="<?php p($l->t('Language'));?>">
- <option value="<?php p($_['activelanguage']['code']);?>"><?php p($_['activelanguage']['name']);?></option>
- <?php foreach($_['commonlanguages'] as $language):?>
- <option value="<?php p($language['code']);?>"><?php p($language['name']);?></option>
- <?php endforeach;?>
- <optgroup label="––––––––––"><option class="languagedivider">-</option></optgroup>
- <?php foreach($_['languages'] as $language):?>
- <option value="<?php p($language['code']);?>"><?php p($language['name']);?></option>
- <?php endforeach;?>
+ <select id="languageinput" name="lang" data-placeholder="<?php p($l->t('Language'));?>">
+ <option value="<?php p($_['activelanguage']['code']);?>">
+ <?php p($_['activelanguage']['name']);?>
+ </option>
+ <?php foreach($_['commonlanguages'] as $language):?>
+ <option value="<?php p($language['code']);?>">
+ <?php p($language['name']);?>
+ </option>
+ <?php endforeach;?>
+ <optgroup label="––––––––––"></optgroup>
+ <?php foreach($_['languages'] as $language):?>
+ <option value="<?php p($language['code']);?>">
+ <?php p($language['name']);?>
+ </option>
+ <?php endforeach;?>
</select>
<?php if (OC_Util::getEditionString() === ''): ?>
<a href="https://www.transifex.com/projects/p/owncloud/team/<?php p($_['activelanguage']['code']);?>/"
- target="_blank"><em><?php p($l->t('Help translate'));?></em></a>
+ target="_blank">
+ <em><?php p($l->t('Help translate'));?></em>
+ </a>
<?php endif; ?>
</fieldset>
</form>