diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..1021eae0f647c565bd23fff175e56e1b94a8804c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +## Submitting issues + +If you have questions about how to use ownCloud, please direct these to the [mailing list][mailinglist] or our [forum][forum]. We are also available on [IRC][irc]. + +### Guidelines +* Report the issue using our [template][template], it includes all the informations we need to track down the issue. +* This repository is *only* for issues within the ownCloud core code. Issues in other compontents should be reported in their own repositores: + - [Android client](https://github.com/owncloud/android/issues) + - [iOS client](https://github.com/owncloud/ios-issues/issues) + - [Desktop client](https://github.com/owncloud/mirall/issues) + - [ownCloud apps](https://github.com/owncloud/apps/issues) (e.g. Calendar, Contacts...) +* Search the existing issues first, it's likely that your issue was already reported. + +If your issue appears to be a bug, and hasn't been reported, open a new issue. + +Help us to maximize the effort we can spend fixing issues and adding new features, by not reporting duplicate issues. + +[template]: https://raw.github.com/owncloud/core/master/issue_template.md +[mailinglist]: https://mail.kde.org/mailman/listinfo/owncloud +[forum]: http://forum.owncloud.org/ +[irc]: http://webchat.freenode.net/?channels=owncloud&uio=d4 + +## Contributing to Source Code + +Thanks for wanting to contribute source code to ownCloud. That's great! + +Before we're able to merge your code into the ownCloud core, you need to sign our [Contributor Agreement][agreement]. + +Please read the [Developer Manuals][devmanual] to get useful infos like how to create your first application or how to test the ownCloud code with phpunit. + +[agreement]: http://owncloud.org/about/contributor-agreement/ +[devmanual]: http://owncloud.org/dev/ + +## Translations +Please submit translations via [Transifex][transifex]. + +[transifex]: https://www.transifex.com/projects/p/owncloud/ diff --git a/apps/files/admin.php b/apps/files/admin.php index 80fd4f4e4a595a129b873cf29683a0839c19b757..f747f8645f6ca62bc63bace5d3d90a2846a46026 100644 --- a/apps/files/admin.php +++ b/apps/files/admin.php @@ -30,11 +30,8 @@ OCP\User::checkAdminUser(); $htaccessWorking=(getenv('htaccessWorking')=='true'); $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); -$upload_max_filesize_possible = OCP\Util::computerFileSize(get_cfg_var('upload_max_filesize')); $post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); -$post_max_size_possible = OCP\Util::computerFileSize(get_cfg_var('post_max_size')); $maxUploadFilesize = OCP\Util::humanFileSize(min($upload_max_filesize, $post_max_size)); -$maxUploadFilesizePossible = OCP\Util::humanFileSize(min($upload_max_filesize_possible, $post_max_size_possible)); if($_POST && OC_Util::isCallRegistered()) { if(isset($_POST['maxUploadSize'])) { if(($setMaxSize = OC_Files::setUploadLimit(OCP\Util::computerFileSize($_POST['maxUploadSize']))) !== false) { @@ -60,7 +57,9 @@ $htaccessWritable=is_writable(OC::$SERVERROOT.'/.htaccess'); $tmpl = new OCP\Template( 'files', 'admin' ); $tmpl->assign( 'uploadChangable', $htaccessWorking and $htaccessWritable ); $tmpl->assign( 'uploadMaxFilesize', $maxUploadFilesize); -$tmpl->assign( 'maxPossibleUploadSize', $maxUploadFilesizePossible); +// max possible makes only sense on a 32 bit system +$tmpl->assign( 'displayMaxPossibleUploadSize', PHP_INT_SIZE===4); +$tmpl->assign( 'maxPossibleUploadSize', OCP\Util::humanFileSize(PHP_INT_MAX)); $tmpl->assign( 'allowZipDownload', $allowZipDownload); $tmpl->assign( 'maxZipInputSize', $maxZipInputSize); return $tmpl->fetchPage(); diff --git a/apps/files/ajax/autocomplete.php b/apps/files/ajax/autocomplete.php deleted file mode 100644 index b32ba7c3d5bd620b87571e8b158176bebf283e3e..0000000000000000000000000000000000000000 --- a/apps/files/ajax/autocomplete.php +++ /dev/null @@ -1,54 +0,0 @@ -$item, 'label'=>$item, 'name'=>$item); - } - } - } - } - } -} -OCP\JSON::encodedPrint($files); diff --git a/apps/files/ajax/delete.php b/apps/files/ajax/delete.php index 6532b76df210940a94554db44bd50ac9e884d781..575b8c8d9eac9a15187f5364db8337fac846ef28 100644 --- a/apps/files/ajax/delete.php +++ b/apps/files/ajax/delete.php @@ -14,15 +14,18 @@ $files = json_decode($files); $filesWithError = ''; $success = true; //Now delete -foreach($files as $file) { - if( !OC_Files::delete( $dir, $file )) { +foreach ($files as $file) { + if (!OC_Files::delete($dir, $file)) { $filesWithError .= $file . "\n"; $success = false; } } -if($success) { - OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $files ))); +// get array with updated storage stats (e.g. max file size) after upload +$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir); + +if ($success) { + OCP\JSON::success(array("data" => array_merge(array("dir" => $dir, "files" => $files), $storageStats))); } else { - OCP\JSON::error(array("data" => array( "message" => "Could not delete:\n" . $filesWithError ))); + OCP\JSON::error(array("data" => array_merge(array("message" => "Could not delete:\n" . $filesWithError), $storageStats))); } diff --git a/apps/files/ajax/getstoragestats.php b/apps/files/ajax/getstoragestats.php new file mode 100644 index 0000000000000000000000000000000000000000..7a2b642a9bd11296f64bc16afd1fb559dbde2443 --- /dev/null +++ b/apps/files/ajax/getstoragestats.php @@ -0,0 +1,9 @@ + \OCA\files\lib\Helper::buildFileStorageStatistics('/'))); diff --git a/apps/files/ajax/move.php b/apps/files/ajax/move.php index 5612716b7e4692f50b2c598ed26fef54fae34125..4ebc3f42d9f60e3a61ba5e0a341b5b285d107c69 100644 --- a/apps/files/ajax/move.php +++ b/apps/files/ajax/move.php @@ -11,14 +11,15 @@ $dir = stripslashes($_GET["dir"]); $file = stripslashes($_GET["file"]); $target = stripslashes(rawurldecode($_GET["target"])); +$l=OC_L10N::get('files'); if(OC_Filesystem::file_exists($target . '/' . $file)) { - OCP\JSON::error(array("data" => array( "message" => "Could not move $file - File with this name already exists" ))); + OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s - File with this name already exists", array($file)) ))); exit; } if(OC_Files::move($dir, $file, $target, $file)) { OCP\JSON::success(array("data" => array( "dir" => $dir, "files" => $file ))); } else { - OCP\JSON::error(array("data" => array( "message" => "Could not move $file" ))); + OCP\JSON::error(array("data" => array( "message" => $l->t("Could not move %s", array($file)) ))); } diff --git a/apps/files/ajax/rename.php b/apps/files/ajax/rename.php index 45448279fa161d46137c2bddee952060eaa6a584..89b4d4bba7310015c2a6f99004b9c0809cd3c3f7 100644 --- a/apps/files/ajax/rename.php +++ b/apps/files/ajax/rename.php @@ -12,9 +12,9 @@ $file = stripslashes($_GET["file"]); $newname = stripslashes($_GET["newname"]); // Delete -if( OC_Files::move( $dir, $file, $dir, $newname )) { +if( $newname !== '.' and OC_Files::move( $dir, $file, $dir, $newname )) { OCP\JSON::success(array("data" => array( "dir" => $dir, "file" => $file, "newname" => $newname ))); -} -else{ - OCP\JSON::error(array("data" => array( "message" => "Unable to rename file" ))); +} else { + $l=OC_L10N::get('files'); + OCP\JSON::error(array("data" => array( "message" => $l->t("Unable to rename file") ))); } diff --git a/apps/files/ajax/scan.php b/apps/files/ajax/scan.php index 5cd9572d7f99eb3328cfb53edff52f6d98b9834a..a819578e3092fd221572a44222883b0a4e58aa1a 100644 --- a/apps/files/ajax/scan.php +++ b/apps/files/ajax/scan.php @@ -6,13 +6,14 @@ $force=isset($_GET['force']) and $_GET['force']=='true'; $dir=isset($_GET['dir'])?$_GET['dir']:''; $checkOnly=isset($_GET['checkonly']) and $_GET['checkonly']=='true'; +$eventSource=false; if(!$checkOnly) { $eventSource=new OC_EventSource(); } session_write_close(); -//create the file cache if necesary +//create the file cache if necessary if($force or !OC_FileCache::inCache('')) { if(!$checkOnly) { OCP\DB::beginTransaction(); diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php index e7823bc4ffbb4432406fbb67f5a0829daa3afba8..415524be6293aa40a9add10121facc6c7403bcb9 100644 --- a/apps/files/ajax/upload.php +++ b/apps/files/ajax/upload.php @@ -8,64 +8,73 @@ OCP\JSON::setContentTypeHeader('text/plain'); OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); +$l = OC_L10N::get('files'); + +// get array with current storage stats (e.g. max file size) +$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir); if (!isset($_FILES['files'])) { - OCP\JSON::error(array('data' => array( 'message' => 'No file was uploaded. Unknown error' ))); + OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('No file was uploaded. Unknown error')), $storageStats))); exit(); } + foreach ($_FILES['files']['error'] as $error) { if ($error != 0) { - $l=OC_L10N::get('files'); $errors = array( - UPLOAD_ERR_OK=>$l->t('There is no error, the file uploaded with success'), - UPLOAD_ERR_INI_SIZE=>$l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ') - .ini_get('upload_max_filesize'), - UPLOAD_ERR_FORM_SIZE=>$l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified' - .' in the HTML form'), - UPLOAD_ERR_PARTIAL=>$l->t('The uploaded file was only partially uploaded'), - UPLOAD_ERR_NO_FILE=>$l->t('No file was uploaded'), - UPLOAD_ERR_NO_TMP_DIR=>$l->t('Missing a temporary folder'), - UPLOAD_ERR_CANT_WRITE=>$l->t('Failed to write to disk'), + UPLOAD_ERR_OK => $l->t('There is no error, the file uploaded with success'), + UPLOAD_ERR_INI_SIZE => $l->t('The uploaded file exceeds the upload_max_filesize directive in php.ini: ') + . ini_get('upload_max_filesize'), + UPLOAD_ERR_FORM_SIZE => $l->t('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified' + . ' in the HTML form'), + UPLOAD_ERR_PARTIAL => $l->t('The uploaded file was only partially uploaded'), + UPLOAD_ERR_NO_FILE => $l->t('No file was uploaded'), + UPLOAD_ERR_NO_TMP_DIR => $l->t('Missing a temporary folder'), + UPLOAD_ERR_CANT_WRITE => $l->t('Failed to write to disk'), ); - OCP\JSON::error(array('data' => array( 'message' => $errors[$error] ))); + OCP\JSON::error(array('data' => array_merge(array('message' => $errors[$error]), $storageStats))); exit(); } } -$files=$_FILES['files']; +$files = $_FILES['files']; $dir = $_POST['dir']; -$error=''; +$error = ''; -$totalSize=0; -foreach($files['size'] as $size) { - $totalSize+=$size; +$totalSize = 0; +foreach ($files['size'] as $size) { + $totalSize += $size; } -if($totalSize>OC_Filesystem::free_space($dir)) { - OCP\JSON::error(array('data' => array( 'message' => 'Not enough space available' ))); +if ($totalSize > OC_Filesystem::free_space($dir)) { + OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Not enough storage available')), $storageStats))); exit(); } -$result=array(); -if(strpos($dir, '..') === false) { - $fileCount=count($files['name']); - for($i=0;$i<$fileCount;$i++) { +$result = array(); +if (strpos($dir, '..') === false) { + $fileCount = count($files['name']); + for ($i = 0; $i < $fileCount; $i++) { $target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]); // $path needs to be normalized - this failed within drag'n'drop upload to a sub-folder $target = OC_Filesystem::normalizePath($target); - if(is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) { + if (is_uploaded_file($files['tmp_name'][$i]) and OC_Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) { $meta = OC_FileCache::get($target); $id = OC_FileCache::getId($target); - $result[]=array( 'status' => 'success', - 'mime'=>$meta['mimetype'], - 'size'=>$meta['size'], - 'id'=>$id, - 'name'=>basename($target)); + + // updated max file size after upload + $storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir); + + $result[] = array_merge(array('status' => 'success', + 'mime' => $meta['mimetype'], + 'size' => $meta['size'], + 'id' => $id, + 'name' => basename($target)), $storageStats + ); } } OCP\JSON::encodedPrint($result); exit(); } else { - $error='invalid dir'; + $error = $l->t('Invalid directory.'); } -OCP\JSON::error(array('data' => array('error' => $error, 'file' => $fileName))); +OCP\JSON::error(array('data' => array_merge(array('message' => $error), $storageStats))); diff --git a/apps/files/appinfo/remote.php b/apps/files/appinfo/remote.php index 1713bcc22ce97302f510aef1dea5f13d42674b1d..6a78a1e0d753640eb42103be96ebe08abb59663f 100644 --- a/apps/files/appinfo/remote.php +++ b/apps/files/appinfo/remote.php @@ -45,6 +45,7 @@ $server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend, 'ownCloud')); $server->addPlugin(new Sabre_DAV_Locks_Plugin($lockBackend)); $server->addPlugin(new Sabre_DAV_Browser_Plugin(false)); // Show something in the Browser, but no upload $server->addPlugin(new OC_Connector_Sabre_QuotaPlugin()); +$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin()); // And off we go! $server->exec(); diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php index 043782a9c04c5cdb5cb9958b0b848ba6f8994f93..307a4d0320d1b9527dcf7c48a62f1e9d36752cdf 100644 --- a/apps/files/appinfo/routes.php +++ b/apps/files/appinfo/routes.php @@ -8,4 +8,7 @@ $this->create('download', 'download{file}') ->requirements(array('file' => '.*')) - ->actionInclude('files/download.php'); \ No newline at end of file + ->actionInclude('files/download.php'); +// oC JS config +$this->create('publicListView', 'js/publiclistview.js') + ->actionInclude('files/js/publiclistview.php'); \ No newline at end of file diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 99c39f0acdba2868c3d3e484026d5dff689e4d54..0c97b009b88ef289393189ad354c814432932c0d 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -21,25 +21,25 @@ #new>ul>li { height:20px; margin:.3em; padding-left:2em; padding-bottom:0.1em; background-repeat:no-repeat; cursor:pointer; } #new>ul>li>p { cursor:pointer; } -#new>ul>li>input { padding:0.3em; margin:-0.3em; } +#new>ul>li>form>input { padding:0.3em; margin:-0.3em; } -#upload { +#upload { height:27px; padding:0; margin-left:0.2em; overflow:hidden; } #upload a { position:relative; display:block; width:100%; height:27px; - cursor:pointer; z-index:1000; + cursor:pointer; z-index:10; background-image:url('%webroot%/core/img/actions/upload.svg'); background-repeat:no-repeat; background-position:7px 6px; } .file_upload_target { display:none; } .file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; } -#file_upload_start { +#file_upload_start { left:0; top:0; width:28px; height:27px; padding:0; font-size:1em; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; - z-index:-1; position:relative; cursor:pointer; overflow:hidden; + z-index:20; position:relative; cursor:pointer; overflow:hidden; } #uploadprogresswrapper { position:absolute; right:13.5em; top:0em; } diff --git a/apps/files/index.php b/apps/files/index.php index b64bde44cc0def096f927d3bc586c1208525ac9e..2c6b689b0c9d3b1518249a02fd6382534a467fb1 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -28,6 +28,7 @@ OCP\User::checkLoggedIn(); OCP\Util::addStyle('files', 'files'); OCP\Util::addscript('files', 'jquery.iframe-transport'); OCP\Util::addscript('files', 'jquery.fileupload'); +OCP\Util::addscript('files', 'jquery-visibility'); OCP\Util::addscript('files', 'files'); OCP\Util::addscript('files', 'filelist'); OCP\Util::addscript('files', 'fileactions'); @@ -38,36 +39,36 @@ OCP\App::setActiveNavigationEntry('files_index'); $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; // Redirect if directory does not exist if (!OC_Filesystem::is_dir($dir . '/')) { - header('Location: ' . $_SERVER['SCRIPT_NAME'] . ''); - exit(); + header('Location: ' . $_SERVER['SCRIPT_NAME'] . ''); + exit(); } $files = array(); foreach (OC_Files::getdirectorycontent($dir) as $i) { - $i['date'] = OCP\Util::formatDate($i['mtime']); - if ($i['type'] == 'file') { - $fileinfo = pathinfo($i['name']); - $i['basename'] = $fileinfo['filename']; - if (!empty($fileinfo['extension'])) { - $i['extension'] = '.' . $fileinfo['extension']; - } else { - $i['extension'] = ''; - } - } - if ($i['directory'] == '/') { - $i['directory'] = ''; - } - $files[] = $i; + $i['date'] = OCP\Util::formatDate($i['mtime']); + if ($i['type'] == 'file') { + $fileinfo = pathinfo($i['name']); + $i['basename'] = $fileinfo['filename']; + if (!empty($fileinfo['extension'])) { + $i['extension'] = '.' . $fileinfo['extension']; + } else { + $i['extension'] = ''; + } + } + if ($i['directory'] == '/') { + $i['directory'] = ''; + } + $files[] = $i; } // Make breadcrumb $breadcrumb = array(); $pathtohere = ''; foreach (explode('/', $dir) as $i) { - if ($i != '') { - $pathtohere .= '/' . $i; - $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); - } + if ($i != '') { + $pathtohere .= '/' . $i; + $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); + } } // make breadcrumb und filelist markup @@ -79,25 +80,22 @@ $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); $breadcrumbNav->assign('breadcrumb', $breadcrumb, false); $breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir=', false); -$upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize')); -$post_max_size = OCP\Util::computerFileSize(ini_get('post_max_size')); -$maxUploadFilesize = min($upload_max_filesize, $post_max_size); - -$freeSpace = OC_Filesystem::free_space($dir); -$freeSpace = max($freeSpace, 0); -$maxUploadFilesize = min($maxUploadFilesize, $freeSpace); +$maxUploadFilesize=OCP\Util::maxUploadFilesize($dir); $permissions = OCP\PERMISSION_READ; if (OC_Filesystem::isUpdatable($dir . '/')) { - $permissions |= OCP\PERMISSION_UPDATE; + $permissions |= OCP\PERMISSION_UPDATE; } if (OC_Filesystem::isDeletable($dir . '/')) { - $permissions |= OCP\PERMISSION_DELETE; + $permissions |= OCP\PERMISSION_DELETE; } if (OC_Filesystem::isSharable($dir . '/')) { - $permissions |= OCP\PERMISSION_SHARE; + $permissions |= OCP\PERMISSION_SHARE; } +// information about storage capacities +$storageInfo=OC_Helper::getStorageInfo(); + $tmpl = new OCP\Template('files', 'index', 'user'); $tmpl->assign('fileList', $list->fetchPage(), false); $tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage(), false); @@ -108,4 +106,5 @@ $tmpl->assign('files', $files); $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize)); $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); +$tmpl->assign('usedSpacePercent', (int)$storageInfo['relative']); $tmpl->printPage(); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 80b9c01f83887176e554ebb72ef29513a88ede99..f5ee363a4c82e7fd2da9107c6105a03eb98482f5 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -70,23 +70,23 @@ var FileActions = { } parent.children('a.name').append(''); var defaultAction = FileActions.getDefault(FileActions.getCurrentMimeType(), FileActions.getCurrentType(), FileActions.getCurrentPermissions()); - + var actionHandler = function (event) { event.stopPropagation(); event.preventDefault(); FileActions.currentFile = event.data.elem; var file = FileActions.getCurrentFile(); - + event.data.actionFunc(file); }; - + $.each(actions, function (name, action) { // NOTE: Temporary fix to prevent rename action in root of Shared directory if (name === 'Rename' && $('#dir').val() === '/Shared') { return true; } - + if ((name === 'Download' || action !== defaultAction) && name !== 'Delete') { var img = FileActions.icons[name]; if (img.call) { @@ -97,16 +97,16 @@ var FileActions = { html += ' '; } html += t('files', name) + ''; - + var element = $(html); element.data('action', name); //alert(element); element.on('click',{a:null, elem:parent, actionFunc:actions[name]},actionHandler); parent.find('a.name>span.fileactions').append(element); } - + }); - + if (actions['Delete']) { var img = FileActions.icons['Delete']; if (img.call) { diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 96dd0323d29a4b463ca96d2f6c789fc63a0deb91..04b7d92e2c35065af78f9a98dc8565c19e9d88fe 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -149,10 +149,9 @@ var FileList={ event.stopPropagation(); event.preventDefault(); var newname=input.val(); - if (Files.containsInvalidCharacters(newname)) { + if (!Files.isFileNameValid(newname)) { return false; - } - if (newname != name) { + } else if (newname != name) { if (FileList.checkName(name, newname, false)) { newname = name; } else { @@ -185,6 +184,13 @@ var FileList={ td.children('a.name').show(); return false; }); + input.keyup(function(event){ + if (event.keyCode == 27) { + tr.data('renaming',false); + form.remove(); + td.children('a.name').show(); + } + }); input.click(function(event){ event.stopPropagation(); event.preventDefault(); @@ -195,15 +201,14 @@ var FileList={ }, checkName:function(oldName, newName, isNewFile) { if (isNewFile || $('tr').filterAttr('data-file', newName).length > 0) { - if (isNewFile) { - $('#notification').html(t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+''+t('files', 'replace')+''+t('files', 'suggest name')+''+t('files', 'cancel')+''); - } else { - $('#notification').html(t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+''+t('files', 'replace')+''+t('files', 'cancel')+''); - } $('#notification').data('oldName', oldName); $('#notification').data('newName', newName); $('#notification').data('isNewFile', isNewFile); - $('#notification').fadeIn(); + if (isNewFile) { + OC.Notification.showHtml(t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+''+t('files', 'replace')+''+t('files', 'suggest name')+''+t('files', 'cancel')+''); + } else { + OC.Notification.showHtml(t('files', '{new_name} already exists', {new_name: escapeHTML(newName)})+''+t('files', 'replace')+''+t('files', 'cancel')+''); + } return true; } else { return false; @@ -245,11 +250,10 @@ var FileList={ FileList.finishReplace(); }; if (isNewFile) { - $('#notification').html(t('files', 'replaced {new_name}', {new_name: newName})+''+t('files', 'undo')+''); + OC.Notification.showHtml(t('files', 'replaced {new_name}', {new_name: newName})+''+t('files', 'undo')+''); } else { - $('#notification').html(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+''+t('files', 'undo')+''); + OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+''+t('files', 'undo')+''); } - $('#notification').fadeIn(); }, finishReplace:function() { if (!FileList.replaceCanceled && FileList.replaceOldName && FileList.replaceNewName) { @@ -279,11 +283,10 @@ var FileList={ } else { // NOTE: Temporary fix to change the text to unshared for files in root of Shared folder if ($('#dir').val() == '/Shared') { - $('#notification').html(t('files', 'unshared {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+''); + OC.Notification.showHtml(t('files', 'unshared {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+''); } else { - $('#notification').html(t('files', 'deleted {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+''); + OC.Notification.showHtml(t('files', 'deleted {files}', {'files': escapeHTML(files)})+''+t('files', 'undo')+''); } - $('#notification').fadeIn(); } }, finishDelete:function(ready,sync){ @@ -296,7 +299,7 @@ var FileList={ data: {dir:$('#dir').val(),files:fileNames}, complete: function(data){ boolOperationFinished(data, function(){ - $('#notification').fadeOut('400'); + OC.Notification.hide(); $.each(FileList.deleteFiles,function(index,file){ FileList.remove(file); }); @@ -356,16 +359,16 @@ $(document).ready(function(){ FileList.replaceIsNewFile = null; } FileList.lastAction = null; - $('#notification').fadeOut('400'); + OC.Notification.hide(); }); $('#notification .replace').live('click', function() { - $('#notification').fadeOut('400', function() { - FileList.replace($('#notification').data('oldName'), $('#notification').data('newName'), $('#notification').data('isNewFile')); - }); + OC.Notification.hide(function() { + FileList.replace($('#notification').data('oldName'), $('#notification').data('newName'), $('#notification').data('isNewFile')); + }); }); $('#notification .suggest').live('click', function() { $('tr').filterAttr('data-file', $('#notification').data('oldName')).show(); - $('#notification').fadeOut('400'); + OC.Notification.hide(); }); $('#notification .cancel').live('click', function() { if ($('#notification').data('isNewFile')) { diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 6a37d9e7f538fdebcb0760d81b80da01019e2ee9..6486468eafd4b231f3489064a430e6f99fd515e1 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -26,21 +26,65 @@ Files={ }); procesSelection(); }, - containsInvalidCharacters:function (name) { + updateMaxUploadFilesize:function(response) { + if(response == undefined) { + return; + } + if(response.data !== undefined && response.data.uploadMaxFilesize !== undefined) { + $('#max_upload').val(response.data.uploadMaxFilesize); + $('#upload.button').attr('original-title', response.data.maxHumanFilesize); + $('#usedSpacePercent').val(response.data.usedSpacePercent); + Files.displayStorageWarnings(); + } + if(response[0] == undefined) { + return; + } + if(response[0].uploadMaxFilesize !== undefined) { + $('#max_upload').val(response[0].uploadMaxFilesize); + $('#upload.button').attr('original-title', response[0].maxHumanFilesize); + $('#usedSpacePercent').val(response[0].usedSpacePercent); + Files.displayStorageWarnings(); + } + + }, + isFileNameValid:function (name) { + if (name === '.') { + OC.Notification.show(t('files', '\'.\' is an invalid file name.')); + return false; + } + if (name.length == 0) { + OC.Notification.show(t('files', 'File name cannot be empty.')); + return false; + } + + // check for invalid characters var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*']; for (var i = 0; i < invalid_characters.length; i++) { if (name.indexOf(invalid_characters[i]) != -1) { - $('#notification').text(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.")); - $('#notification').fadeIn(); - return true; + OC.Notification.show(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed.")); + return false; } } - $('#notification').fadeOut(); - return false; + OC.Notification.hide(); + return true; + }, + displayStorageWarnings: function() { + if (!OC.Notification.isHidden()) { + return; + } + + var usedSpacePercent = $('#usedSpacePercent').val(); + if (usedSpacePercent > 98) { + OC.Notification.show(t('files', 'Your storage is full, files can not be updated or synced anymore!')); + return; + } + if (usedSpacePercent > 90) { + OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)', {usedSpacePercent: usedSpacePercent})); + } } }; $(document).ready(function() { - Files.bindKeyboardShortcuts(document, jQuery); + Files.bindKeyboardShortcuts(document, jQuery); $('#fileList tr').each(function(){ //little hack to set unescape filenames in attribute $(this).attr('data-file',decodeURIComponent($(this).attr('data-file'))); @@ -75,8 +119,8 @@ $(document).ready(function() { // Sets the file link behaviour : $('td.filename a').live('click',function(event) { - event.preventDefault(); if (event.ctrlKey || event.shiftKey) { + event.preventDefault(); if (event.shiftKey) { var last = $(lastChecked).parent().parent().prevAll().length; var first = $(this).parent().parent().prevAll().length; @@ -118,6 +162,7 @@ $(document).ready(function() { var permissions = $(this).parent().parent().data('permissions'); var action=FileActions.getDefault(mime,type, permissions); if(action){ + event.preventDefault(); action(filename); } } @@ -171,8 +216,7 @@ $(document).ready(function() { $('.download').click('click',function(event) { var files=getSelectedFiles('name').join(';'); var dir=$('#dir').val()||'/'; - $('#notification').text(t('files','generating ZIP-file, it may take some time.')); - $('#notification').fadeIn(); + OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.')); // use special download URL if provided, e.g. for public shared files if ( (downloadURL = document.getElementById("downloadURL")) ) { window.location=downloadURL.value+"&download&files="+files; @@ -234,12 +278,12 @@ $(document).ready(function() { } }); }else{ - var dropTarget = $(e.originalEvent.target).closest('tr'); - if(dropTarget && dropTarget.attr('data-type') === 'dir') { // drag&drop upload to folder - var dirName = dropTarget.attr('data-file') - } + var dropTarget = $(e.originalEvent.target).closest('tr'); + if(dropTarget && dropTarget.attr('data-type') === 'dir') { // drag&drop upload to folder + var dirName = dropTarget.attr('data-file') + } - var date=new Date(); + var date=new Date(); if(files){ for(var i=0;i0){ @@ -292,26 +336,27 @@ $(document).ready(function() { var jqXHR = $('#file_upload_start').fileupload('send', {files: files[i], formData: function(form) { var formArray = form.serializeArray(); - // array index 0 contains the max files size - // array index 1 contains the request token - // array index 2 contains the directory + // array index 0 contains the max files size + // array index 1 contains the request token + // array index 2 contains the directory formArray[2]['value'] = dirName; return formArray; }}).success(function(result, textStatus, jqXHR) { var response; response=jQuery.parseJSON(result); if(response[0] == undefined || response[0].status != 'success') { - $('#notification').text(t('files', response.data.message)); - $('#notification').fadeIn(); + OC.Notification.show(t('files', response.data.message)); } + Files.updateMaxUploadFilesize(response); var file=response[0]; - // TODO: this doesn't work if the file name has been changed server side + // TODO: this doesn't work if the file name has been changed server side delete uploadingFiles[dirName][file.name]; - if ($.assocArraySize(uploadingFiles[dirName]) == 0) { - delete uploadingFiles[dirName]; - } + if ($.assocArraySize(uploadingFiles[dirName]) == 0) { + delete uploadingFiles[dirName]; + } + //TODO update file upload size limit - var uploadtext = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName).find('.uploadtext') + var uploadtext = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName).find('.uploadtext') var currentUploads = parseInt(uploadtext.attr('currentUploads')); currentUploads -= 1; uploadtext.attr('currentUploads', currentUploads); @@ -339,9 +384,8 @@ $(document).ready(function() { } else { uploadtext.text(t('files', '{count} files uploading', {count: currentUploads})); } - $('#notification').hide(); - $('#notification').text(t('files', 'Upload cancelled.')); - $('#notification').fadeIn(); + delete uploadingFiles[dirName][fileName]; + OC.Notification.show(t('files', 'Upload cancelled.')); } }); //TODO test with filenames containing slashes @@ -354,6 +398,8 @@ $(document).ready(function() { .success(function(result, textStatus, jqXHR) { var response; response=jQuery.parseJSON(result); + Files.updateMaxUploadFilesize(response); + if(response[0] != undefined && response[0].status == 'success') { var file=response[0]; delete uploadingFiles[file.name]; @@ -362,21 +408,21 @@ $(document).ready(function() { if(size==t('files','Pending')){ $('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size); } + //TODO update file upload size limit FileList.loadingDone(file.name, file.id); } else { - $('#notification').text(t('files', response.data.message)); - $('#notification').fadeIn(); + Files.cancelUpload(this.files[0].name); + OC.Notification.show(t('files', response.data.message)); $('#fileList > tr').not('[data-mime]').fadeOut(); $('#fileList > tr').not('[data-mime]').remove(); } - }) - .error(function(jqXHR, textStatus, errorThrown) { - if(errorThrown === 'abort') { - $('#notification').hide(); - $('#notification').text(t('files', 'Upload cancelled.')); - $('#notification').fadeIn(); - } - }); + }) + .error(function(jqXHR, textStatus, errorThrown) { + if(errorThrown === 'abort') { + Files.cancelUpload(this.files[0].name); + OC.Notification.show(t('files', 'Upload cancelled.')); + } + }); uploadingFiles[uniqueName] = jqXHR; } } @@ -384,6 +430,7 @@ $(document).ready(function() { data.submit().success(function(data, status) { // in safari data is a string response = jQuery.parseJSON(typeof data === 'string' ? data : data[0].body.innerText); + Files.updateMaxUploadFilesize(response); if(response[0] != undefined && response[0].status == 'success') { var file=response[0]; delete uploadingFiles[file.name]; @@ -392,10 +439,11 @@ $(document).ready(function() { if(size==t('files','Pending')){ $('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size); } + //TODO update file upload size limit FileList.loadingDone(file.name, file.id); } else { - $('#notification').text(t('files', response.data.message)); - $('#notification').fadeIn(); + //TODO Files.cancelUpload(/*where do we get the filename*/); + OC.Notification.show(t('files', response.data.message)); $('#fileList > tr').not('[data-mime]').fadeOut(); $('#fileList > tr').not('[data-mime]').remove(); } @@ -434,7 +482,7 @@ $(document).ready(function() { // http://stackoverflow.com/a/6700/11236 var size = 0, key; for (key in obj) { - if (obj.hasOwnProperty(key)) size++; + if (obj.hasOwnProperty(key)) size++; } return size; }; @@ -477,7 +525,7 @@ $(document).ready(function() { $('#new').removeClass('active'); $('#new li').each(function(i,element){ if($(element).children('p').length==0){ - $(element).children('input').remove(); + $(element).children('form').remove(); $(element).append('

'+$(element).data('text')+'

'); } }); @@ -496,7 +544,7 @@ $(document).ready(function() { $('#new li').each(function(i,element){ if($(element).children('p').length==0){ - $(element).children('input').remove(); + $(element).children('form').remove(); $(element).append('

'+$(element).data('text')+'

'); } }); @@ -505,23 +553,30 @@ $(document).ready(function() { var text=$(this).children('p').text(); $(this).data('text',text); $(this).children('p').remove(); + var form=$('
'); var input=$(''); - $(this).append(input); + form.append(input); + $(this).append(form); input.focus(); - input.change(function(){ - if (type != 'web' && Files.containsInvalidCharacters($(this).val())) { - return; - } else if( type == 'folder' && $('#dir').val() == '/' && $(this).val() == 'Shared') { - $('#notification').text(t('files','Invalid folder name. Usage of "Shared" is reserved by Owncloud')); - $('#notification').fadeIn(); - return; + form.submit(function(event){ + event.stopPropagation(); + event.preventDefault(); + var newname=input.val(); + if(type == 'web' && newname.length == 0) { + OC.Notification.show(t('files', 'URL cannot be empty.')); + return false; + } else if (type != 'web' && !Files.isFileNameValid(newname)) { + return false; + } else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') { + OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by Owncloud')); + return false; } if (FileList.lastAction) { FileList.lastAction(); } - var name = getUniqueName($(this).val()); - if (name != $(this).val()) { - FileList.checkName(name, $(this).val(), true); + var name = getUniqueName(newname); + if (newname != name) { + FileList.checkName(name, newname, true); var hidden = true; } else { var hidden = false; @@ -565,7 +620,7 @@ $(document).ready(function() { break; case 'web': if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){ - name='http://'.name; + name='http://'+name; } var localName=name; if(localName.substr(localName.length-1,1)=='/'){//strip / @@ -604,8 +659,8 @@ $(document).ready(function() { }); break; } - var li=$(this).parent(); - $(this).remove(); + var li=form.parent(); + form.remove(); li.append('

'+li.data('text')+'

'); $('#new>a').click(); }); @@ -683,6 +738,36 @@ $(document).ready(function() { }); resizeBreadcrumbs(true); + + // display storage warnings + setTimeout ( "Files.displayStorageWarnings()", 100 ); + OC.Notification.setDefault(Files.displayStorageWarnings); + + // file space size sync + function update_storage_statistics() { + $.getJSON(OC.filePath('files','ajax','getstoragestats.php'),function(response) { + Files.updateMaxUploadFilesize(response); + }); + } + + // start on load - we ask the server every 5 minutes + var update_storage_statistics_interval = 5*60*1000; + var update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval); + + // Use jquery-visibility to de-/re-activate file stats sync + if ($.support.pageVisibility) { + $(document).on({ + 'show.visibility': function() { + if (!update_storage_statistics_interval_id) { + update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval); + } + }, + 'hide.visibility': function() { + clearInterval(update_storage_statistics_interval_id); + update_storage_statistics_interval_id = 0; + } + }); + } }); function scanFiles(force,dir){ @@ -712,6 +797,7 @@ scanFiles.scanning=false; function boolOperationFinished(data, callback) { result = jQuery.parseJSON(data.responseText); + Files.updateMaxUploadFilesize(result); if(result.status == 'success'){ callback.call(); } else { diff --git a/apps/files/js/jquery-visibility.js b/apps/files/js/jquery-visibility.js new file mode 100644 index 0000000000000000000000000000000000000000..a824bf6873076b284def2bd5a47c1d6ae52a5611 --- /dev/null +++ b/apps/files/js/jquery-visibility.js @@ -0,0 +1,32 @@ +/*! http://mths.be/visibility v1.0.5 by @mathias */ +(function (window, document, $, undefined) { + + var prefix, + property, +// In Opera, `'onfocusin' in document == true`, hence the extra `hasFocus` check to detect IE-like behavior + eventName = 'onfocusin' in document && 'hasFocus' in document ? 'focusin focusout' : 'focus blur', + prefixes = ['', 'moz', 'ms', 'o', 'webkit'], + $support = $.support, + $event = $.event; + + while ((property = prefix = prefixes.pop()) != undefined) { + property = (prefix ? prefix + 'H' : 'h') + 'idden'; + if ($support.pageVisibility = typeof document[property] == 'boolean') { + eventName = prefix + 'visibilitychange'; + break; + } + } + + $(/blur$/.test(eventName) ? window : document).on(eventName, function (event) { + var type = event.type, + originalEvent = event.originalEvent, + toElement = originalEvent.toElement; +// If it’s a `{focusin,focusout}` event (IE), `fromElement` and `toElement` should both be `null` or `undefined`; +// else, the page visibility hasn’t changed, but the user just clicked somewhere in the doc. +// In IE9, we need to check the `relatedTarget` property instead. + if (!/^focus./.test(type) || (toElement == undefined && originalEvent.fromElement == undefined && originalEvent.relatedTarget == undefined)) { + $event.trigger((property && document[property] || /^(?:blur|focusout)$/.test(type) ? 'hide' : 'show') + '.visibility'); + } + }); + +}(this, document, jQuery)); diff --git a/apps/files/js/publiclistview.php b/apps/files/js/publiclistview.php new file mode 100644 index 0000000000000000000000000000000000000000..f1c67aabb485e11a84dc835d0a3f344385f1d5ba --- /dev/null +++ b/apps/files/js/publiclistview.php @@ -0,0 +1,20 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// Set the content type to Javascript +header("Content-type: text/javascript"); + +// Disallow caching +header("Cache-Control: no-cache, must-revalidate"); +header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); + +if ( array_key_exists('disableSharing', $_) && $_['disableSharing'] == true ) { + echo "var disableSharing = true;"; +} else { + echo "var disableSharing = false;"; +} diff --git a/apps/files/l10n/ar.php b/apps/files/l10n/ar.php index 5740d54f8b1b13c3015ac0451c7ef1353783c24f..d468b102875329f039250b33766a18900df76ef9 100644 --- a/apps/files/l10n/ar.php +++ b/apps/files/l10n/ar.php @@ -1,4 +1,5 @@ "إرفع", "There is no error, the file uploaded with success" => "تم ترفيع الملفات بنجاح.", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "حجم الملف الذي تريد ترفيعه أعلى مما MAX_FILE_SIZE يسمح به في واجهة ال HTML.", "The uploaded file was only partially uploaded" => "تم ترفيع جزء من الملفات الذي تريد ترفيعها فقط", @@ -16,7 +17,6 @@ "New" => "جديد", "Text file" => "ملف", "Folder" => "مجلد", -"Upload" => "إرفع", "Nothing in here. Upload something!" => "لا يوجد شيء هنا. إرفع بعض الملفات!", "Download" => "تحميل", "Upload too large" => "حجم الترفيع أعلى من المسموح", diff --git a/apps/files/l10n/bg_BG.php b/apps/files/l10n/bg_BG.php index b527b0e027fc107f006de14811ab7aaeb2f0bb0c..a8c2dc97e00417e081b9cc49aabf23892454a406 100644 --- a/apps/files/l10n/bg_BG.php +++ b/apps/files/l10n/bg_BG.php @@ -1,28 +1,22 @@ "Файлът е качен успешно", -"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Файлът който се опитвате да качите надвишава стойностите в MAX_FILE_SIZE в HTML формата.", -"The uploaded file was only partially uploaded" => "Файлът е качен частично", -"No file was uploaded" => "Фахлът не бе качен", -"Missing a temporary folder" => "Липсва временната папка", -"Failed to write to disk" => "Грешка при запис на диска", +"Upload" => "Качване", +"Missing a temporary folder" => "Липсва временна папка", "Files" => "Файлове", "Delete" => "Изтриване", -"Upload Error" => "Грешка при качване", -"Upload cancelled." => "Качването е отменено.", +"Rename" => "Преименуване", +"replace" => "препокриване", +"cancel" => "отказ", +"undo" => "възтановяване", +"Upload cancelled." => "Качването е спряно.", "Name" => "Име", "Size" => "Размер", "Modified" => "Променено", -"Maximum upload size" => "Макс. размер за качване", -"0 is unlimited" => "0 означава без ограничение", +"Maximum upload size" => "Максимален размер за качване", +"0 is unlimited" => "Ползвайте 0 за без ограничения", "Save" => "Запис", -"New" => "Нов", -"Text file" => "Текстов файл", +"New" => "Ново", "Folder" => "Папка", -"Upload" => "Качване", -"Cancel upload" => "Отказване на качването", -"Nothing in here. Upload something!" => "Няма нищо, качете нещо!", +"Nothing in here. Upload something!" => "Няма нищо тук. Качете нещо.", "Download" => "Изтегляне", -"Upload too large" => "Файлът е прекалено голям", -"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Файловете които се опитвате да качите са по-големи от позволеното за сървъра.", -"Files are being scanned, please wait." => "Файловете се претърсват, изчакайте." +"Upload too large" => "Файлът който сте избрали за качване е прекалено голям" ); diff --git a/apps/files/l10n/bn_BD.php b/apps/files/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..e8e19c6898f0ab31eafc74c42df47b234685031a --- /dev/null +++ b/apps/files/l10n/bn_BD.php @@ -0,0 +1,70 @@ + "আপলোড", +"Could not move %s - File with this name already exists" => "%s কে স্থানান্তর করা সম্ভব হলো না - এই নামের ফাইল বিদ্যমান", +"Could not move %s" => "%s কে স্থানান্তর করা সম্ভব হলো না", +"Unable to rename file" => "ফাইলের নাম পরিবর্তন করা সম্ভব হলো না", +"No file was uploaded. Unknown error" => "কোন ফাইল আপলোড করা হয় নি। সমস্যা অজ্ঞাত।", +"There is no error, the file uploaded with success" => "কোন সমস্যা নেই, ফাইল আপলোড সুসম্পন্ন হয়েছে", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "আপলোড করা ফাইলটি php.ini তে বর্ণিত upload_max_filesize নির্দেশিত আয়তন অতিক্রম করছেঃ", +"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "আপলোড করা ফাইলটি HTML ফর্মে নির্ধারিত MAX_FILE_SIZE নির্দেশিত সর্বোচ্চ আকার অতিক্রম করেছে ", +"The uploaded file was only partially uploaded" => "আপলোড করা ফাইলটি আংশিক আপলোড করা হয়েছে", +"No file was uploaded" => "কোন ফাইল আপলোড করা হয় নি", +"Missing a temporary folder" => "অস্থায়ী ফোল্ডার খোয়া গিয়েছে", +"Failed to write to disk" => "ডিস্কে লিখতে ব্যর্থ", +"Not enough space available" => "যথেষ্ঠ পরিমাণ স্থান নেই", +"Invalid directory." => "ভুল ডিরেক্টরি", +"Files" => "ফাইল", +"Unshare" => "ভাগাভাগি বাতিল ", +"Delete" => "মুছে ফেল", +"Rename" => "পূনঃনামকরণ", +"{new_name} already exists" => "{new_name} টি বিদ্যমান", +"replace" => "প্রতিস্থাপন", +"suggest name" => "নাম সুপারিশ করুন", +"cancel" => "বাতিল", +"replaced {new_name}" => "{new_name} প্রতিস্থাপন করা হয়েছে", +"undo" => "ক্রিয়া প্রত্যাহার", +"replaced {new_name} with {old_name}" => "{new_name} কে {old_name} নামে প্রতিস্থাপন করা হয়েছে", +"unshared {files}" => "{files} ভাগাভাগি বাতিল কর", +"deleted {files}" => "{files} মুছে ফেলা হয়েছে", +"'.' is an invalid file name." => "টি একটি অননুমোদিত নাম।", +"File name cannot be empty." => "ফাইলের নামটি ফাঁকা রাখা যাবে না।", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "নামটি সঠিক নয়, '\\', '/', '<', '>', ':', '\"', '|', '?' এবং '*' অনুমোদিত নয়।", +"Unable to upload your file as it is a directory or has 0 bytes" => "আপনার ফাইলটি আপলোড করা সম্ভব হলো না, কেননা এটি হয় একটি ফোল্ডার কিংবা এর আকার ০ বাইট", +"Upload Error" => "আপলোড করতে সমস্যা ", +"Close" => "বন্ধ", +"Pending" => "মুলতুবি", +"1 file uploading" => "১টি ফাইল আপলোড করা হচ্ছে", +"{count} files uploading" => "{count} টি ফাইল আপলোড করা হচ্ছে", +"Upload cancelled." => "আপলোড বাতিল করা হয়েছে।", +"File upload is in progress. Leaving the page now will cancel the upload." => "ফাইল আপলোড চলমান। এই পৃষ্ঠা পরিত্যাগ করলে আপলোড বাতিল করা হবে।", +"URL cannot be empty." => "URL ফাঁকা রাখা যাবে না।", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "ফোল্ডারের নামটি সঠিক নয়। 'ভাগাভাগি করা' শুধুমাত্র Owncloud এর জন্য সংরক্ষিত।", +"{count} files scanned" => "{count} টি ফাইল স্ক্যান করা হয়েছে", +"error while scanning" => "স্ক্যান করার সময় সমস্যা দেখা দিয়েছে", +"Name" => "নাম", +"Size" => "আকার", +"Modified" => "পরিবর্তিত", +"1 folder" => "১টি ফোল্ডার", +"{count} folders" => "{count} টি ফোল্ডার", +"1 file" => "১টি ফাইল", +"{count} files" => "{count} টি ফাইল", +"File handling" => "ফাইল হ্যার্ডলিং", +"Maximum upload size" => "আপলোডের সর্বোচ্চ আকার", +"max. possible: " => "অনুমোদিত সর্বোচ্চ আকার", +"Needed for multi-file and folder downloads." => "একাধিক ফাইল এবং ফোল্ডার ডাউনলোড করার জন্য আবশ্যক।", +"Enable ZIP-download" => "ZIP ডাউনলোড সক্রিয় কর", +"0 is unlimited" => "০ এর অর্থ অসীম", +"Maximum input size for ZIP files" => "ZIP ফাইলের ইনপুটের সর্বোচ্চ আকার", +"Save" => "সংরক্ষন কর", +"New" => "নতুন", +"Text file" => "টেক্সট ফাইল", +"Folder" => "ফোল্ডার", +"From link" => " লিংক থেকে", +"Cancel upload" => "আপলোড বাতিল কর", +"Nothing in here. Upload something!" => "এখানে কিছুই নেই। কিছু আপলোড করুন !", +"Download" => "ডাউনলোড", +"Upload too large" => "আপলোডের আকারটি অনেক বড়", +"The files you are trying to upload exceed the maximum size for file uploads on this server." => "আপনি এই সার্ভারে আপলোড করার জন্য অনুমোদিত ফাইলের সর্বোচ্চ আকারের চেয়ে বৃহদাকার ফাইল আপলোড করার চেষ্টা করছেন ", +"Files are being scanned, please wait." => "ফাইলগুলো স্ক্যান করা হচ্ছে, দয়া করে অপেক্ষা করুন।", +"Current scanning" => "বর্তমান স্ক্যানিং" +); diff --git a/apps/files/l10n/ca.php b/apps/files/l10n/ca.php index 0866d97bd7486dc9bc41db4783d4cf5219b35aa4..b35a9299de03bdb9202f046aae5988b9cdc09bfa 100644 --- a/apps/files/l10n/ca.php +++ b/apps/files/l10n/ca.php @@ -1,4 +1,9 @@ "Puja", +"Could not move %s - File with this name already exists" => "No s'ha pogut moure %s - Ja hi ha un fitxer amb aquest nom", +"Could not move %s" => " No s'ha pogut moure %s", +"Unable to rename file" => "No es pot canviar el nom del fitxer", +"No file was uploaded. Unknown error" => "No s'ha carregat cap fitxer. Error desconegut", "There is no error, the file uploaded with success" => "El fitxer s'ha pujat correctament", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "L’arxiu que voleu carregar supera el màxim definit en la directiva upload_max_filesize del php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "El fitxer de pujada excedeix la directiva MAX_FILE_SIZE especificada al formulari HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "El fitxer no s'ha pujat", "Missing a temporary folder" => "S'ha perdut un fitxer temporal", "Failed to write to disk" => "Ha fallat en escriure al disc", +"Not enough space available" => "No hi ha prou espai disponible", +"Invalid directory." => "Directori no vàlid.", "Files" => "Fitxers", "Unshare" => "Deixa de compartir", "Delete" => "Suprimeix", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "s'ha substituït {old_name} per {new_name}", "unshared {files}" => "no compartits {files}", "deleted {files}" => "eliminats {files}", +"'.' is an invalid file name." => "'.' és un nom no vàlid per un fitxer.", +"File name cannot be empty." => "El nom del fitxer no pot ser buit.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "El nóm no és vàlid, '\\', '/', '<', '>', ':', '\"', '|', '?' i '*' no estan permesos.", -"generating ZIP-file, it may take some time." => "s'estan generant fitxers ZIP, pot trigar una estona.", +"Your download is being prepared. This might take some time if the files are big." => "S'està preparant la baixada. Pot trigar una estona si els fitxers són grans.", "Unable to upload your file as it is a directory or has 0 bytes" => "No es pot pujar el fitxer perquè és una carpeta o té 0 bytes", "Upload Error" => "Error en la pujada", "Close" => "Tanca", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} fitxers en pujada", "Upload cancelled." => "La pujada s'ha cancel·lat.", "File upload is in progress. Leaving the page now will cancel the upload." => "Hi ha una pujada en curs. Si abandoneu la pàgina la pujada es cancel·larà.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "El nom de la carpeta no és vàlid. L'ús de \"Compartit\" està reservat per a OwnCloud", +"URL cannot be empty." => "La URL no pot ser buida", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nom de carpeta no vàlid. L'ús de 'Shared' està reservat per Owncloud", "{count} files scanned" => "{count} fitxers escannejats", "error while scanning" => "error durant l'escaneig", "Name" => "Nom", @@ -51,7 +61,6 @@ "Text file" => "Fitxer de text", "Folder" => "Carpeta", "From link" => "Des d'enllaç", -"Upload" => "Puja", "Cancel upload" => "Cancel·la la pujada", "Nothing in here. Upload something!" => "Res per aquí. Pugeu alguna cosa!", "Download" => "Baixa", diff --git a/apps/files/l10n/cs_CZ.php b/apps/files/l10n/cs_CZ.php index 12eb79a1a10b4ac5816fee63a5eb319a271d5f69..a8d82ba51112723f87f1018db9c99380f384d59c 100644 --- a/apps/files/l10n/cs_CZ.php +++ b/apps/files/l10n/cs_CZ.php @@ -1,4 +1,9 @@ "Odeslat", +"Could not move %s - File with this name already exists" => "Nelze přesunout %s - existuje soubor se stejným názvem", +"Could not move %s" => "Nelze přesunout %s", +"Unable to rename file" => "Nelze přejmenovat soubor", +"No file was uploaded. Unknown error" => "Soubor nebyl odeslán. Neznámá chyba", "There is no error, the file uploaded with success" => "Soubor byl odeslán úspěšně", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Odesílaný soubor přesahuje velikost upload_max_filesize povolenou v php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Odeslaný soubor přesáhl svou velikostí parametr MAX_FILE_SIZE specifikovaný v formuláři HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Žádný soubor nebyl odeslán", "Missing a temporary folder" => "Chybí adresář pro dočasné soubory", "Failed to write to disk" => "Zápis na disk selhal", +"Not enough space available" => "Nedostatek dostupného místa", +"Invalid directory." => "Neplatný adresář", "Files" => "Soubory", "Unshare" => "Zrušit sdílení", "Delete" => "Smazat", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "nahrazeno {new_name} s {old_name}", "unshared {files}" => "sdílení zrušeno pro {files}", "deleted {files}" => "smazáno {files}", +"'.' is an invalid file name." => "'.' je neplatným názvem souboru.", +"File name cannot be empty." => "Název souboru nemůže být prázdný řetězec.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Neplatný název, znaky '\\', '/', '<', '>', ':', '\"', '|', '?' a '*' nejsou povoleny.", -"generating ZIP-file, it may take some time." => "generuji ZIP soubor, může to nějakou dobu trvat.", +"Your download is being prepared. This might take some time if the files are big." => "Vaše soubory ke stažení se připravují. Pokud jsou velké může to chvíli trvat.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nelze odeslat Váš soubor, protože je to adresář nebo má velikost 0 bajtů", "Upload Error" => "Chyba odesílání", "Close" => "Zavřít", @@ -29,7 +38,8 @@ "{count} files uploading" => "odesílám {count} souborů", "Upload cancelled." => "Odesílání zrušeno.", "File upload is in progress. Leaving the page now will cancel the upload." => "Probíhá odesílání souboru. Opuštění stránky vyústí ve zrušení nahrávání.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Neplatný název složky. Použití názvu \"Shared\" je rezervováno pro interní úžití službou Owncloud.", +"URL cannot be empty." => "URL nemůže být prázdná", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Neplatný název složky. Použití 'Shared' je rezervováno pro vnitřní potřeby Owncloud", "{count} files scanned" => "prozkoumáno {count} souborů", "error while scanning" => "chyba při prohledávání", "Name" => "Název", @@ -51,7 +61,6 @@ "Text file" => "Textový soubor", "Folder" => "Složka", "From link" => "Z odkazu", -"Upload" => "Odeslat", "Cancel upload" => "Zrušit odesílání", "Nothing in here. Upload something!" => "Žádný obsah. Nahrajte něco.", "Download" => "Stáhnout", diff --git a/apps/files/l10n/da.php b/apps/files/l10n/da.php index 05404d27af701c590cd13a03c4acdca05f2e49a9..010af12e960548c07a0a657e4aba495e286b76ee 100644 --- a/apps/files/l10n/da.php +++ b/apps/files/l10n/da.php @@ -1,4 +1,6 @@ "Upload", +"No file was uploaded. Unknown error" => "Ingen fil blev uploadet. Ukendt fejl.", "There is no error, the file uploaded with success" => "Der er ingen fejl, filen blev uploadet med success", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Den uploadede fil overstiger upload_max_filesize direktivet i php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Den uploadede fil overskrider MAX_FILE_SIZE -direktivet som er specificeret i HTML-formularen", @@ -20,7 +22,6 @@ "unshared {files}" => "ikke delte {files}", "deleted {files}" => "slettede {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ugyldigt navn, '\\', '/', '<', '>', ':' | '?', '\"', '', og '*' er ikke tilladt.", -"generating ZIP-file, it may take some time." => "genererer ZIP-fil, det kan tage lidt tid.", "Unable to upload your file as it is a directory or has 0 bytes" => "Kunne ikke uploade din fil, da det enten er en mappe eller er tom", "Upload Error" => "Fejl ved upload", "Close" => "Luk", @@ -29,7 +30,7 @@ "{count} files uploading" => "{count} filer uploades", "Upload cancelled." => "Upload afbrudt.", "File upload is in progress. Leaving the page now will cancel the upload." => "Fil upload kører. Hvis du forlader siden nu, vil uploadet blive annuleret.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Ugyldigt mappenavn. Brug af \"Shared\" er forbeholdt Owncloud", +"URL cannot be empty." => "URLen kan ikke være tom.", "{count} files scanned" => "{count} filer skannet", "error while scanning" => "fejl under scanning", "Name" => "Navn", @@ -51,7 +52,6 @@ "Text file" => "Tekstfil", "Folder" => "Mappe", "From link" => "Fra link", -"Upload" => "Upload", "Cancel upload" => "Fortryd upload", "Nothing in here. Upload something!" => "Her er tomt. Upload noget!", "Download" => "Download", diff --git a/apps/files/l10n/de.php b/apps/files/l10n/de.php index 8073ee28da5af2c06639a900991565d2f77977b4..c851f7df2a701782a0720a7b48f8132c17aecdb5 100644 --- a/apps/files/l10n/de.php +++ b/apps/files/l10n/de.php @@ -1,4 +1,9 @@ "Hochladen", +"Could not move %s - File with this name already exists" => "Konnte %s nicht verschieben - Datei mit diesem Namen existiert bereits.", +"Could not move %s" => "Konnte %s nicht verschieben", +"Unable to rename file" => "Konnte Datei nicht umbenennen", +"No file was uploaded. Unknown error" => "Keine Datei hochgeladen. Unbekannter Fehler", "There is no error, the file uploaded with success" => "Datei fehlerfrei hochgeladen.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Die hochgeladene Datei überschreitet die upload_max_filesize Vorgabe in php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Die Größe der hochzuladenden Datei überschreitet die MAX_FILE_SIZE-Richtlinie, die im HTML-Formular angegeben wurde", @@ -6,6 +11,8 @@ "No file was uploaded" => "Es wurde keine Datei hochgeladen.", "Missing a temporary folder" => "Temporärer Ordner fehlt.", "Failed to write to disk" => "Fehler beim Schreiben auf die Festplatte", +"Not enough space available" => "Nicht genug Speicherplatz verfügbar", +"Invalid directory." => "Ungültiges Verzeichnis", "Files" => "Dateien", "Unshare" => "Nicht mehr freigeben", "Delete" => "Löschen", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "{old_name} ersetzt durch {new_name}", "unshared {files}" => "Freigabe von {files} aufgehoben", "deleted {files}" => "{files} gelöscht", +"'.' is an invalid file name." => "'.' ist kein gültiger Dateiname", +"File name cannot be empty." => "Der Dateiname darf nicht leer sein", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ungültiger Name, '\\', '/', '<', '>', ':', '\"', '|', '?' und '*' sind nicht zulässig.", -"generating ZIP-file, it may take some time." => "Erstelle ZIP-Datei. Dies kann eine Weile dauern.", +"Your download is being prepared. This might take some time if the files are big." => "Dein Download wird vorbereitet. Dies kann bei größeren Dateien etwas dauern.", "Unable to upload your file as it is a directory or has 0 bytes" => "Deine Datei kann nicht hochgeladen werden, da sie entweder ein Verzeichnis oder 0 Bytes groß ist.", "Upload Error" => "Fehler beim Upload", "Close" => "Schließen", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} Dateien werden hochgeladen", "Upload cancelled." => "Upload abgebrochen.", "File upload is in progress. Leaving the page now will cancel the upload." => "Dateiupload läuft. Wenn Du die Seite jetzt verlässt, wird der Upload abgebrochen.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Ungültiger Ordnername. Die Verwendung von \"Shared\" ist ownCloud vorbehalten.", +"URL cannot be empty." => "Die URL darf nicht leer sein", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Ungültiger Verzeichnisname. Die Nutzung von \"Shared\" ist ownCloud vorbehalten.", "{count} files scanned" => "{count} Dateien wurden gescannt", "error while scanning" => "Fehler beim Scannen", "Name" => "Name", @@ -51,7 +61,6 @@ "Text file" => "Textdatei", "Folder" => "Ordner", "From link" => "Von einem Link", -"Upload" => "Hochladen", "Cancel upload" => "Upload abbrechen", "Nothing in here. Upload something!" => "Alles leer. Lade etwas hoch!", "Download" => "Herunterladen", diff --git a/apps/files/l10n/de_DE.php b/apps/files/l10n/de_DE.php index 6a9730e94b0b2b9befd90acf9cee068c80cfc08b..281685b78dfd3cb7a7c67c94636b68211e96129a 100644 --- a/apps/files/l10n/de_DE.php +++ b/apps/files/l10n/de_DE.php @@ -1,4 +1,9 @@ "Hochladen", +"Could not move %s - File with this name already exists" => "Konnte %s nicht verschieben - Datei mit diesem Namen existiert bereits", +"Could not move %s" => "Konnte %s nicht verschieben", +"Unable to rename file" => "Konnte Datei nicht umbenennen", +"No file was uploaded. Unknown error" => "Keine Datei hochgeladen. Unbekannter Fehler", "There is no error, the file uploaded with success" => "Es sind keine Fehler aufgetreten. Die Datei wurde erfolgreich hochgeladen.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Die hochgeladene Datei überschreitet die upload_max_filesize Vorgabe in php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Die Größe der hochzuladenden Datei überschreitet die MAX_FILE_SIZE-Richtlinie, die im HTML-Formular angegeben wurde", @@ -6,6 +11,8 @@ "No file was uploaded" => "Es wurde keine Datei hochgeladen.", "Missing a temporary folder" => "Der temporäre Ordner fehlt.", "Failed to write to disk" => "Fehler beim Schreiben auf die Festplatte", +"Not enough space available" => "Nicht genügend Speicherplatz verfügbar", +"Invalid directory." => "Ungültiges Verzeichnis.", "Files" => "Dateien", "Unshare" => "Nicht mehr freigeben", "Delete" => "Löschen", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "{old_name} wurde ersetzt durch {new_name}", "unshared {files}" => "Freigabe für {files} beendet", "deleted {files}" => "{files} gelöscht", +"'.' is an invalid file name." => "'.' ist kein gültiger Dateiname.", +"File name cannot be empty." => "Der Dateiname darf nicht leer sein.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ungültiger Name, '\\', '/', '<', '>', ':', '\"', '|', '?' und '*' sind nicht zulässig.", -"generating ZIP-file, it may take some time." => "Erstelle ZIP-Datei. Dies kann eine Weile dauern.", +"Your download is being prepared. This might take some time if the files are big." => "Ihr Download wird vorbereitet. Dies kann bei größeren Dateien einen Moment dauern.", "Unable to upload your file as it is a directory or has 0 bytes" => "Ihre Datei kann nicht hochgeladen werden, da sie entweder ein Verzeichnis oder 0 Bytes groß ist.", "Upload Error" => "Fehler beim Upload", "Close" => "Schließen", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} Dateien wurden hochgeladen", "Upload cancelled." => "Upload abgebrochen.", "File upload is in progress. Leaving the page now will cancel the upload." => "Der Dateiupload läuft. Wenn Sie die Seite jetzt verlassen, wird der Upload abgebrochen.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Ungültiger Ordnername. Die Verwendung von \"Shared\" ist ownCloud vorbehalten.", +"URL cannot be empty." => "Die URL darf nicht leer sein.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Ungültiger Verzeichnisname. Die Nutzung von \"Shared\" ist ownCloud vorbehalten", "{count} files scanned" => "{count} Dateien wurden gescannt", "error while scanning" => "Fehler beim Scannen", "Name" => "Name", @@ -51,7 +61,6 @@ "Text file" => "Textdatei", "Folder" => "Ordner", "From link" => "Von einem Link", -"Upload" => "Hochladen", "Cancel upload" => "Upload abbrechen", "Nothing in here. Upload something!" => "Alles leer. Bitte laden Sie etwas hoch!", "Download" => "Herunterladen", diff --git a/apps/files/l10n/el.php b/apps/files/l10n/el.php index ddbea421241fb5724ea4660aad3bd7888df82747..cc93943d286b3423b1fbe8aacc05c2af632338d9 100644 --- a/apps/files/l10n/el.php +++ b/apps/files/l10n/el.php @@ -1,4 +1,9 @@ "Αποστολή", +"Could not move %s - File with this name already exists" => "Αδυναμία μετακίνησης του %s - υπάρχει ήδη αρχείο με αυτό το όνομα", +"Could not move %s" => "Αδυναμία μετακίνησης του %s", +"Unable to rename file" => "Αδυναμία μετονομασίας αρχείου", +"No file was uploaded. Unknown error" => "Δεν ανέβηκε κάποιο αρχείο. Άγνωστο σφάλμα", "There is no error, the file uploaded with success" => "Δεν υπάρχει σφάλμα, το αρχείο εστάλει επιτυχώς", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Το απεσταλμένο αρχείο ξεπερνά την οδηγία upload_max_filesize στο php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Το αρχείο υπερβαίνει την οδηγία μέγιστου επιτρεπτού μεγέθους \"MAX_FILE_SIZE\" που έχει οριστεί στην HTML φόρμα", @@ -6,6 +11,8 @@ "No file was uploaded" => "Κανένα αρχείο δεν στάλθηκε", "Missing a temporary folder" => "Λείπει ο προσωρινός φάκελος", "Failed to write to disk" => "Αποτυχία εγγραφής στο δίσκο", +"Not enough space available" => "Δεν υπάρχει αρκετός διαθέσιμος χώρος", +"Invalid directory." => "Μη έγκυρος φάκελος.", "Files" => "Αρχεία", "Unshare" => "Διακοπή κοινής χρήσης", "Delete" => "Διαγραφή", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "αντικαταστάθηκε το {new_name} με {old_name}", "unshared {files}" => "μη διαμοιρασμένα {files}", "deleted {files}" => "διαγραμμένα {files}", +"'.' is an invalid file name." => "'.' είναι μη έγκυρο όνομα αρχείου.", +"File name cannot be empty." => "Το όνομα αρχείου δεν πρέπει να είναι κενό.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Μη έγκυρο όνομα, '\\', '/', '<', '>', ':', '\"', '|', '?' και '*' δεν επιτρέπονται.", -"generating ZIP-file, it may take some time." => "παραγωγή αρχείου ZIP, ίσως διαρκέσει αρκετά.", +"Your download is being prepared. This might take some time if the files are big." => "Η λήψη προετοιμάζεται. Αυτό μπορεί να πάρει ώρα εάν τα αρχεία έχουν μεγάλο μέγεθος.", "Unable to upload your file as it is a directory or has 0 bytes" => "Αδυναμία στην αποστολή του αρχείου σας αφού είναι φάκελος ή έχει 0 bytes", "Upload Error" => "Σφάλμα Αποστολής", "Close" => "Κλείσιμο", @@ -28,8 +37,9 @@ "1 file uploading" => "1 αρχείο ανεβαίνει", "{count} files uploading" => "{count} αρχεία ανεβαίνουν", "Upload cancelled." => "Η αποστολή ακυρώθηκε.", -"File upload is in progress. Leaving the page now will cancel the upload." => "Η αποστολή του αρχείου βρίσκεται σε εξέλιξη. Έξοδος από την σελίδα τώρα θα ακυρώσει την αποστολή.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Μη έγκυρο όνομα φακέλου. Η χρήση του \"Shared\" είναι δεσμευμένη από το Owncloud", +"File upload is in progress. Leaving the page now will cancel the upload." => "Η αποστολή του αρχείου βρίσκεται σε εξέλιξη. Το κλείσιμο της σελίδας θα ακυρώσει την αποστολή.", +"URL cannot be empty." => "Η URL δεν πρέπει να είναι κενή.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Μη έγκυρο όνομα φακέλου. Η χρήση του 'Κοινόχρηστος' χρησιμοποιείται από ο Owncloud", "{count} files scanned" => "{count} αρχεία ανιχνεύτηκαν", "error while scanning" => "σφάλμα κατά την ανίχνευση", "Name" => "Όνομα", @@ -51,12 +61,11 @@ "Text file" => "Αρχείο κειμένου", "Folder" => "Φάκελος", "From link" => "Από σύνδεσμο", -"Upload" => "Αποστολή", "Cancel upload" => "Ακύρωση αποστολής", "Nothing in here. Upload something!" => "Δεν υπάρχει τίποτα εδώ. Ανέβασε κάτι!", "Download" => "Λήψη", "Upload too large" => "Πολύ μεγάλο αρχείο προς αποστολή", -"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Τα αρχεία που προσπαθείτε να ανεβάσετε υπερβαίνουν το μέγιστο μέγεθος αποστολής αρχείων σε αυτόν το διακομιστή.", +"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Τα αρχεία που προσπαθείτε να ανεβάσετε υπερβαίνουν το μέγιστο μέγεθος αποστολής αρχείων σε αυτόν τον διακομιστή.", "Files are being scanned, please wait." => "Τα αρχεία σαρώνονται, παρακαλώ περιμένετε", "Current scanning" => "Τρέχουσα αναζήτηση " ); diff --git a/apps/files/l10n/eo.php b/apps/files/l10n/eo.php index bdde6d0feceac55915af470e8d0a491122e8a368..0aebf9c034eeb907bf9dd1a5b6c4cb62f7e295c7 100644 --- a/apps/files/l10n/eo.php +++ b/apps/files/l10n/eo.php @@ -1,4 +1,9 @@ "Alŝuti", +"Could not move %s - File with this name already exists" => "Ne eblis movi %s: dosiero kun ĉi tiu nomo jam ekzistas", +"Could not move %s" => "Ne eblis movi %s", +"Unable to rename file" => "Ne eblis alinomigi dosieron", +"No file was uploaded. Unknown error" => "Neniu dosiero alŝutiĝis. Nekonata eraro.", "There is no error, the file uploaded with success" => "Ne estas eraro, la dosiero alŝutiĝis sukcese", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "La dosiero alŝutita superas la regulon upload_max_filesize el php.ini: ", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "La dosiero alŝutita superas la regulon MAX_FILE_SIZE, kiu estas difinita en la HTML-formularo", @@ -6,6 +11,8 @@ "No file was uploaded" => "Neniu dosiero estas alŝutita", "Missing a temporary folder" => "Mankas tempa dosierujo", "Failed to write to disk" => "Malsukcesis skribo al disko", +"Not enough space available" => "Ne haveblas sufiĉa spaco", +"Invalid directory." => "Nevalida dosierujo.", "Files" => "Dosieroj", "Unshare" => "Malkunhavigi", "Delete" => "Forigi", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "anstataŭiĝis {new_name} per {old_name}", "unshared {files}" => "malkunhaviĝis {files}", "deleted {files}" => "foriĝis {files}", +"'.' is an invalid file name." => "'.' ne estas valida dosiernomo.", +"File name cannot be empty." => "Dosiernomo devas ne malpleni.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nevalida nomo: “\\”, “/”, “<”, “>”, “:”, “\"”, “|”, “?” kaj “*” ne permesatas.", -"generating ZIP-file, it may take some time." => "generanta ZIP-dosiero, ĝi povas daŭri iom da tempo", +"Your download is being prepared. This might take some time if the files are big." => "Via elŝuto pretiĝatas. Ĉi tio povas daŭri iom da tempo se la dosieroj grandas.", "Unable to upload your file as it is a directory or has 0 bytes" => "Ne eblis alŝuti vian dosieron ĉar ĝi estas dosierujo aŭ havas 0 duumokojn", "Upload Error" => "Alŝuta eraro", "Close" => "Fermi", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} dosieroj alŝutatas", "Upload cancelled." => "La alŝuto nuliĝis.", "File upload is in progress. Leaving the page now will cancel the upload." => "Dosieralŝuto plenumiĝas. Lasi la paĝon nun nuligus la alŝuton.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nevalida nomo de dosierujo. Uzo de “Shared” rezervitas de Owncloud", +"URL cannot be empty." => "URL ne povas esti malplena.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nevalida dosierujnomo. Uzo de “Shared” rezervatas de Owncloud.", "{count} files scanned" => "{count} dosieroj skaniĝis", "error while scanning" => "eraro dum skano", "Name" => "Nomo", @@ -51,7 +61,6 @@ "Text file" => "Tekstodosiero", "Folder" => "Dosierujo", "From link" => "El ligilo", -"Upload" => "Alŝuti", "Cancel upload" => "Nuligi alŝuton", "Nothing in here. Upload something!" => "Nenio estas ĉi tie. Alŝutu ion!", "Download" => "Elŝuti", diff --git a/apps/files/l10n/es.php b/apps/files/l10n/es.php index 40b9ea9f23f8084733e5c5371abf26d356a37f59..c76431ef3833110f37b7aaa25beb72f38f5da083 100644 --- a/apps/files/l10n/es.php +++ b/apps/files/l10n/es.php @@ -1,4 +1,9 @@ "Subir", +"Could not move %s - File with this name already exists" => "No se puede mover %s - Ya existe un archivo con ese nombre", +"Could not move %s" => "No se puede mover %s", +"Unable to rename file" => "No se puede renombrar el archivo", +"No file was uploaded. Unknown error" => "Fallo no se subió el fichero", "There is no error, the file uploaded with success" => "No se ha producido ningún error, el archivo se ha subido con éxito", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "El archivo que intentas subir sobrepasa el tamaño definido por la variable upload_max_filesize en php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "El archivo que intentas subir sobrepasa el tamaño definido por la variable MAX_FILE_SIZE especificada en el formulario HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "No se ha subido ningún archivo", "Missing a temporary folder" => "Falta un directorio temporal", "Failed to write to disk" => "La escritura en disco ha fallado", +"Not enough space available" => "No hay suficiente espacio disponible", +"Invalid directory." => "Directorio invalido.", "Files" => "Archivos", "Unshare" => "Dejar de compartir", "Delete" => "Eliminar", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "reemplazado {new_name} con {old_name}", "unshared {files}" => "{files} descompartidos", "deleted {files}" => "{files} eliminados", +"'.' is an invalid file name." => "'.' es un nombre de archivo inválido.", +"File name cannot be empty." => "El nombre de archivo no puede estar vacío.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nombre Invalido, \"\\\", \"/\", \"<\", \">\", \":\", \"\", \"|\" \"?\" y \"*\" no están permitidos ", -"generating ZIP-file, it may take some time." => "generando un fichero ZIP, puede llevar un tiempo.", +"Your download is being prepared. This might take some time if the files are big." => "Tu descarga esta siendo preparada. Esto puede tardar algun tiempo si los archivos son muy grandes.", "Unable to upload your file as it is a directory or has 0 bytes" => "No ha sido posible subir tu archivo porque es un directorio o tiene 0 bytes", "Upload Error" => "Error al subir el archivo", "Close" => "cerrrar", @@ -29,7 +38,8 @@ "{count} files uploading" => "Subiendo {count} archivos", "Upload cancelled." => "Subida cancelada.", "File upload is in progress. Leaving the page now will cancel the upload." => "La subida del archivo está en proceso. Salir de la página ahora cancelará la subida.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nombre de la carpeta invalido. El uso de \"Shared\" esta reservado para Owncloud", +"URL cannot be empty." => "La URL no puede estar vacía.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nombre de carpeta invalido. El uso de \"Shared\" esta reservado para Owncloud", "{count} files scanned" => "{count} archivos escaneados", "error while scanning" => "error escaneando", "Name" => "Nombre", @@ -51,7 +61,6 @@ "Text file" => "Archivo de texto", "Folder" => "Carpeta", "From link" => "Desde el enlace", -"Upload" => "Subir", "Cancel upload" => "Cancelar subida", "Nothing in here. Upload something!" => "Aquí no hay nada. ¡Sube algo!", "Download" => "Descargar", diff --git a/apps/files/l10n/es_AR.php b/apps/files/l10n/es_AR.php index e514d8de59aa200ec1b741cef360bf65071f57df..418844007b206a1f488abfa009add45277cf539c 100644 --- a/apps/files/l10n/es_AR.php +++ b/apps/files/l10n/es_AR.php @@ -1,4 +1,9 @@ "Subir", +"Could not move %s - File with this name already exists" => "No se pudo mover %s - Un archivo con este nombre ya existe", +"Could not move %s" => "No se pudo mover %s ", +"Unable to rename file" => "No fue posible cambiar el nombre al archivo", +"No file was uploaded. Unknown error" => "El archivo no fue subido. Error desconocido", "There is no error, the file uploaded with success" => "No se han producido errores, el archivo se ha subido con éxito", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "El archivo que intentás subir excede el tamaño definido por upload_max_filesize en el php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "El archivo que intentás subir sobrepasa el tamaño definido por la variable MAX_FILE_SIZE especificada en el formulario HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "El archivo no fue subido", "Missing a temporary folder" => "Falta un directorio temporal", "Failed to write to disk" => "Error al escribir en el disco", +"Not enough space available" => "No hay suficiente espacio disponible", +"Invalid directory." => "Directorio invalido.", "Files" => "Archivos", "Unshare" => "Dejar de compartir", "Delete" => "Borrar", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "reemplazado {new_name} con {old_name}", "unshared {files}" => "{files} se dejaron de compartir", "deleted {files}" => "{files} borrados", +"'.' is an invalid file name." => "'.' es un nombre de archivo inválido.", +"File name cannot be empty." => "El nombre del archivo no puede quedar vacío.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nombre invalido, '\\', '/', '<', '>', ':', '\"', '|', '?' y '*' no están permitidos.", -"generating ZIP-file, it may take some time." => "generando un archivo ZIP, puede llevar un tiempo.", +"Your download is being prepared. This might take some time if the files are big." => "Tu descarga esta siendo preparada. Esto puede tardar algun tiempo si los archivos son muy grandes.", "Unable to upload your file as it is a directory or has 0 bytes" => "No fue posible subir el archivo porque es un directorio o porque su tamaño es 0 bytes", "Upload Error" => "Error al subir el archivo", "Close" => "Cerrar", @@ -29,7 +38,8 @@ "{count} files uploading" => "Subiendo {count} archivos", "Upload cancelled." => "La subida fue cancelada", "File upload is in progress. Leaving the page now will cancel the upload." => "La subida del archivo está en proceso. Si salís de la página ahora, la subida se cancelará.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nombre del directorio inválido. Usar \"Shared\" está reservado por ownCloud.", +"URL cannot be empty." => "La URL no puede estar vacía", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nombre de carpeta inválido. El uso de 'Shared' está reservado por ownCloud", "{count} files scanned" => "{count} archivos escaneados", "error while scanning" => "error mientras se escaneaba", "Name" => "Nombre", @@ -51,7 +61,6 @@ "Text file" => "Archivo de texto", "Folder" => "Carpeta", "From link" => "Desde enlace", -"Upload" => "Subir", "Cancel upload" => "Cancelar subida", "Nothing in here. Upload something!" => "No hay nada. ¡Subí contenido!", "Download" => "Descargar", diff --git a/apps/files/l10n/et_EE.php b/apps/files/l10n/et_EE.php index 0fddbfdca466c2b1084b76ce4099fb5b2b493fed..8305cf0edead39a4af2ab937968839585694c001 100644 --- a/apps/files/l10n/et_EE.php +++ b/apps/files/l10n/et_EE.php @@ -1,4 +1,6 @@ "Lae üles", +"No file was uploaded. Unknown error" => "Ühtegi faili ei laetud üles. Tundmatu viga", "There is no error, the file uploaded with success" => "Ühtegi viga pole, fail on üles laetud", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Üles laetud faili suurus ületab HTML vormis määratud upload_max_filesize suuruse", "The uploaded file was only partially uploaded" => "Fail laeti üles ainult osaliselt", @@ -19,7 +21,6 @@ "unshared {files}" => "jagamata {files}", "deleted {files}" => "kustutatud {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Vigane nimi, '\\', '/', '<', '>', ':', '\"', '|', '?' ja '*' pole lubatud.", -"generating ZIP-file, it may take some time." => "ZIP-faili loomine, see võib veidi aega võtta.", "Unable to upload your file as it is a directory or has 0 bytes" => "Sinu faili üleslaadimine ebaõnnestus, kuna see on kaust või selle suurus on 0 baiti", "Upload Error" => "Üleslaadimise viga", "Close" => "Sulge", @@ -28,7 +29,7 @@ "{count} files uploading" => "{count} faili üleslaadimist", "Upload cancelled." => "Üleslaadimine tühistati.", "File upload is in progress. Leaving the page now will cancel the upload." => "Faili üleslaadimine on töös. Lehelt lahkumine katkestab selle üleslaadimise.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Vigane kausta nimi. Nime \"Jagatud\" kasutamine on Owncloudi poolt broneeritud ", +"URL cannot be empty." => "URL ei saa olla tühi.", "{count} files scanned" => "{count} faili skännitud", "error while scanning" => "viga skännimisel", "Name" => "Nimi", @@ -50,7 +51,6 @@ "Text file" => "Tekstifail", "Folder" => "Kaust", "From link" => "Allikast", -"Upload" => "Lae üles", "Cancel upload" => "Tühista üleslaadimine", "Nothing in here. Upload something!" => "Siin pole midagi. Lae midagi üles!", "Download" => "Lae alla", diff --git a/apps/files/l10n/eu.php b/apps/files/l10n/eu.php index 0b223b93d8cc59b2b68b0bce9c16daa7598202cb..a1cb5632121758810d4b791d61cb2e92949b27f1 100644 --- a/apps/files/l10n/eu.php +++ b/apps/files/l10n/eu.php @@ -1,4 +1,9 @@ "Igo", +"Could not move %s - File with this name already exists" => "Ezin da %s mugitu - Izen hau duen fitxategia dagoeneko existitzen da", +"Could not move %s" => "Ezin dira fitxategiak mugitu %s", +"Unable to rename file" => "Ezin izan da fitxategia berrizendatu", +"No file was uploaded. Unknown error" => "Ez da fitxategirik igo. Errore ezezaguna", "There is no error, the file uploaded with success" => "Ez da arazorik izan, fitxategia ongi igo da", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Igotako fitxategiak php.ini fitxategian ezarritako upload_max_filesize muga gainditu du:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Igotako fitxategiaren tamaina HTML inprimakiko MAX_FILESIZE direktiban adierazitakoa baino handiagoa da", @@ -6,6 +11,8 @@ "No file was uploaded" => "Ez da fitxategirik igo", "Missing a temporary folder" => "Aldi baterako karpeta falta da", "Failed to write to disk" => "Errore bat izan da diskoan idazterakoan", +"Not enough space available" => "Ez dago leku nahikorik.", +"Invalid directory." => "Baliogabeko karpeta.", "Files" => "Fitxategiak", "Unshare" => "Ez elkarbanatu", "Delete" => "Ezabatu", @@ -19,8 +26,9 @@ "replaced {new_name} with {old_name}" => " {new_name}-k {old_name} ordezkatu du", "unshared {files}" => "elkarbanaketa utzita {files}", "deleted {files}" => "ezabatuta {files}", +"'.' is an invalid file name." => "'.' ez da fitxategi izen baliogarria.", +"File name cannot be empty." => "Fitxategi izena ezin da hutsa izan.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "IZen aliogabea, '\\', '/', '<', '>', ':', '\"', '|', '?' eta '*' ez daude baimenduta.", -"generating ZIP-file, it may take some time." => "ZIP-fitxategia sortzen ari da, denbora har dezake", "Unable to upload your file as it is a directory or has 0 bytes" => "Ezin da zure fitxategia igo, karpeta bat da edo 0 byt ditu", "Upload Error" => "Igotzean errore bat suertatu da", "Close" => "Itxi", @@ -29,7 +37,8 @@ "{count} files uploading" => "{count} fitxategi igotzen", "Upload cancelled." => "Igoera ezeztatuta", "File upload is in progress. Leaving the page now will cancel the upload." => "Fitxategien igoera martxan da. Orria orain uzteak igoera ezeztatutko du.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Karpeta izen baliogabea. \"Shared\" karpetaren erabilera Owncloudek erreserbatuta dauka", +"URL cannot be empty." => "URLa ezin da hutsik egon.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Baliogabeako karpeta izena. 'Shared' izena Owncloudek erreserbatzen du", "{count} files scanned" => "{count} fitxategi eskaneatuta", "error while scanning" => "errore bat egon da eskaneatzen zen bitartean", "Name" => "Izena", @@ -51,7 +60,6 @@ "Text file" => "Testu fitxategia", "Folder" => "Karpeta", "From link" => "Estekatik", -"Upload" => "Igo", "Cancel upload" => "Ezeztatu igoera", "Nothing in here. Upload something!" => "Ez dago ezer. Igo zerbait!", "Download" => "Deskargatu", diff --git a/apps/files/l10n/fa.php b/apps/files/l10n/fa.php index 8284593e886f941d945ce074cdb095dc98434284..ec8b5cdec4ec1b390c4925ad854c6892ea14a380 100644 --- a/apps/files/l10n/fa.php +++ b/apps/files/l10n/fa.php @@ -1,4 +1,6 @@ "بارگذاری", +"No file was uploaded. Unknown error" => "هیچ فایلی آپلود نشد.خطای ناشناس", "There is no error, the file uploaded with success" => "هیچ خطایی وجود ندارد فایل با موفقیت بار گذاری شد", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "حداکثر حجم مجاز برای بارگذاری از طریق HTML \nMAX_FILE_SIZE", "The uploaded file was only partially uploaded" => "مقدار کمی از فایل بارگذاری شده", @@ -6,12 +8,12 @@ "Missing a temporary folder" => "یک پوشه موقت گم شده است", "Failed to write to disk" => "نوشتن بر روی دیسک سخت ناموفق بود", "Files" => "فایل ها", +"Unshare" => "لغو اشتراک", "Delete" => "پاک کردن", "Rename" => "تغییرنام", "replace" => "جایگزین", "cancel" => "لغو", "undo" => "بازگشت", -"generating ZIP-file, it may take some time." => "در حال ساخت فایل فشرده ممکن است زمان زیادی به طول بیانجامد", "Unable to upload your file as it is a directory or has 0 bytes" => "ناتوان در بارگذاری یا فایل یک پوشه است یا 0بایت دارد", "Upload Error" => "خطا در بار گذاری", "Close" => "بستن", @@ -31,7 +33,6 @@ "New" => "جدید", "Text file" => "فایل متنی", "Folder" => "پوشه", -"Upload" => "بارگذاری", "Cancel upload" => "متوقف کردن بار گذاری", "Nothing in here. Upload something!" => "اینجا هیچ چیز نیست.", "Download" => "بارگیری", diff --git a/apps/files/l10n/fi_FI.php b/apps/files/l10n/fi_FI.php index 772dabbb392f0eb570167625df17ef1fd3558aa1..fac93b1246bc8c79fe6a604470cc02ad76905846 100644 --- a/apps/files/l10n/fi_FI.php +++ b/apps/files/l10n/fi_FI.php @@ -1,10 +1,17 @@ "Lähetä", +"Could not move %s - File with this name already exists" => "Kohteen %s siirto ei onnistunut - Tiedosto samalla nimellä on jo olemassa", +"Could not move %s" => "Kohteen %s siirto ei onnistunut", +"Unable to rename file" => "Tiedoston nimeäminen uudelleen ei onnistunut", +"No file was uploaded. Unknown error" => "Tiedostoa ei lähetetty. Tuntematon virhe", "There is no error, the file uploaded with success" => "Ei virheitä, tiedosto lähetettiin onnistuneesti", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Lähetetty tiedosto ylittää HTML-lomakkeessa määritetyn MAX_FILE_SIZE-arvon ylärajan", "The uploaded file was only partially uploaded" => "Tiedoston lähetys onnistui vain osittain", "No file was uploaded" => "Yhtäkään tiedostoa ei lähetetty", "Missing a temporary folder" => "Väliaikaiskansiota ei ole olemassa", "Failed to write to disk" => "Levylle kirjoitus epäonnistui", +"Not enough space available" => "Tilaa ei ole riittävästi", +"Invalid directory." => "Virheellinen kansio.", "Files" => "Tiedostot", "Unshare" => "Peru jakaminen", "Delete" => "Poista", @@ -14,14 +21,17 @@ "suggest name" => "ehdota nimeä", "cancel" => "peru", "undo" => "kumoa", +"'.' is an invalid file name." => "'.' on virheellinen nimi tiedostolle.", +"File name cannot be empty." => "Tiedoston nimi ei voi olla tyhjä.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Virheellinen nimi, merkit '\\', '/', '<', '>', ':', '\"', '|', '?' ja '*' eivät ole sallittuja.", -"generating ZIP-file, it may take some time." => "luodaan ZIP-tiedostoa, tämä saattaa kestää hetken.", +"Your download is being prepared. This might take some time if the files are big." => "Lataustasi valmistellaan. Tämä saattaa kestää hetken, jos tiedostot ovat suuria kooltaan.", "Unable to upload your file as it is a directory or has 0 bytes" => "Tiedoston lähetys epäonnistui, koska sen koko on 0 tavua tai kyseessä on kansio", "Upload Error" => "Lähetysvirhe.", "Close" => "Sulje", "Pending" => "Odottaa", "Upload cancelled." => "Lähetys peruttu.", "File upload is in progress. Leaving the page now will cancel the upload." => "Tiedoston lähetys on meneillään. Sivulta poistuminen nyt peruu tiedoston lähetyksen.", +"URL cannot be empty." => "Verkko-osoite ei voi olla tyhjä", "Name" => "Nimi", "Size" => "Koko", "Modified" => "Muutettu", @@ -40,7 +50,7 @@ "New" => "Uusi", "Text file" => "Tekstitiedosto", "Folder" => "Kansio", -"Upload" => "Lähetä", +"From link" => "Linkistä", "Cancel upload" => "Peru lähetys", "Nothing in here. Upload something!" => "Täällä ei ole mitään. Lähetä tänne jotakin!", "Download" => "Lataa", diff --git a/apps/files/l10n/fr.php b/apps/files/l10n/fr.php index 86d476873d075a96f3a326cbd67a16c388c42a8e..2e4ae6382072392f670121a8c8a70673ffa78601 100644 --- a/apps/files/l10n/fr.php +++ b/apps/files/l10n/fr.php @@ -1,4 +1,9 @@ "Envoyer", +"Could not move %s - File with this name already exists" => "Impossible de déplacer %s - Un fichier possédant ce nom existe déjà", +"Could not move %s" => "Impossible de déplacer %s", +"Unable to rename file" => "Impossible de renommer le fichier", +"No file was uploaded. Unknown error" => "Aucun fichier n'a été chargé. Erreur inconnue", "There is no error, the file uploaded with success" => "Aucune erreur, le fichier a été téléversé avec succès", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Le fichier envoyé dépasse la valeur upload_max_filesize située dans le fichier php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Le fichier téléversé excède la valeur de MAX_FILE_SIZE spécifiée dans le formulaire HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Aucun fichier n'a été téléversé", "Missing a temporary folder" => "Il manque un répertoire temporaire", "Failed to write to disk" => "Erreur d'écriture sur le disque", +"Not enough space available" => "Espace disponible insuffisant", +"Invalid directory." => "Dossier invalide.", "Files" => "Fichiers", "Unshare" => "Ne plus partager", "Delete" => "Supprimer", @@ -14,13 +21,15 @@ "replace" => "remplacer", "suggest name" => "Suggérer un nom", "cancel" => "annuler", -"replaced {new_name}" => "{new_name} a été replacé", +"replaced {new_name}" => "{new_name} a été remplacé", "undo" => "annuler", "replaced {new_name} with {old_name}" => "{new_name} a été remplacé par {old_name}", "unshared {files}" => "Fichiers non partagés : {files}", "deleted {files}" => "Fichiers supprimés : {files}", +"'.' is an invalid file name." => "'.' n'est pas un nom de fichier valide.", +"File name cannot be empty." => "Le nom de fichier ne peut être vide.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nom invalide, les caractères '\\', '/', '<', '>', ':', '\"', '|', '?' et '*' ne sont pas autorisés.", -"generating ZIP-file, it may take some time." => "Fichier ZIP en cours d'assemblage ; cela peut prendre du temps.", +"Your download is being prepared. This might take some time if the files are big." => "Votre téléchargement est cours de préparation. Ceci peut nécessiter un certain temps si les fichiers sont volumineux.", "Unable to upload your file as it is a directory or has 0 bytes" => "Impossible de charger vos fichiers car il s'agit d'un dossier ou le fichier fait 0 octet.", "Upload Error" => "Erreur de chargement", "Close" => "Fermer", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} fichiers téléversés", "Upload cancelled." => "Chargement annulé.", "File upload is in progress. Leaving the page now will cancel the upload." => "L'envoi du fichier est en cours. Quitter cette page maintenant annulera l'envoi du fichier.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nom de répertoire invalide. \"Shared\" est réservé par ownCloud", +"URL cannot be empty." => "L'URL ne peut-être vide", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nom de dossier invalide. L'utilisation du mot 'Shared' est réservée à Owncloud", "{count} files scanned" => "{count} fichiers indexés", "error while scanning" => "erreur lors de l'indexation", "Name" => "Nom", @@ -51,10 +61,9 @@ "Text file" => "Fichier texte", "Folder" => "Dossier", "From link" => "Depuis le lien", -"Upload" => "Envoyer", "Cancel upload" => "Annuler l'envoi", "Nothing in here. Upload something!" => "Il n'y a rien ici ! Envoyez donc quelque chose :)", -"Download" => "Téléchargement", +"Download" => "Télécharger", "Upload too large" => "Fichier trop volumineux", "The files you are trying to upload exceed the maximum size for file uploads on this server." => "Les fichiers que vous essayez d'envoyer dépassent la taille maximale permise par ce serveur.", "Files are being scanned, please wait." => "Les fichiers sont en cours d'analyse, veuillez patienter.", diff --git a/apps/files/l10n/gl.php b/apps/files/l10n/gl.php index 5c50e3764cf95008518443c6c769a567da033e1d..d24680eaa8697f225f227651f1f3e8bf42d08553 100644 --- a/apps/files/l10n/gl.php +++ b/apps/files/l10n/gl.php @@ -1,4 +1,9 @@ "Enviar", +"Could not move %s - File with this name already exists" => "Non se moveu %s - Xa existe un ficheiro con ese nome.", +"Could not move %s" => "Non se puido mover %s", +"Unable to rename file" => "Non se pode renomear o ficheiro", +"No file was uploaded. Unknown error" => "Non se subiu ningún ficheiro. Erro descoñecido.", "There is no error, the file uploaded with success" => "Non hai erros. O ficheiro enviouse correctamente", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "O ficheiro subido excede a directiva indicada polo tamaño_máximo_de_subida de php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "O ficheiro enviado supera a directiva MAX_FILE_SIZE que foi indicada no formulario HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Non se enviou ningún ficheiro", "Missing a temporary folder" => "Falta un cartafol temporal", "Failed to write to disk" => "Erro ao escribir no disco", +"Not enough space available" => "O espazo dispoñíbel é insuficiente", +"Invalid directory." => "O directorio é incorrecto.", "Files" => "Ficheiros", "Unshare" => "Deixar de compartir", "Delete" => "Eliminar", @@ -19,8 +26,9 @@ "replaced {new_name} with {old_name}" => "substituír {new_name} polo {old_name}", "unshared {files}" => "{files} sen compartir", "deleted {files}" => "{files} eliminados", +"'.' is an invalid file name." => "'.' é un nonme de ficheiro non válido", +"File name cannot be empty." => "O nome de ficheiro non pode estar baldeiro", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome non válido, '\\', '/', '<', '>', ':', '\"', '|', '?' e '*' non se permiten.", -"generating ZIP-file, it may take some time." => "xerando un ficheiro ZIP, o que pode levar un anaco.", "Unable to upload your file as it is a directory or has 0 bytes" => "Non se puido subir o ficheiro pois ou é un directorio ou ten 0 bytes", "Upload Error" => "Erro na subida", "Close" => "Pechar", @@ -29,7 +37,8 @@ "{count} files uploading" => "{count} ficheiros subíndose", "Upload cancelled." => "Subida cancelada.", "File upload is in progress. Leaving the page now will cancel the upload." => "A subida do ficheiro está en curso. Saír agora da páxina cancelará a subida.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nome de cartafol non válido. O uso de \"compartido\" está reservado exclusivamente para ownCloud", +"URL cannot be empty." => "URL non pode quedar baleiro.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nome de cartafol non válido. O uso de 'Shared' está reservado por Owncloud", "{count} files scanned" => "{count} ficheiros escaneados", "error while scanning" => "erro mentres analizaba", "Name" => "Nome", @@ -51,7 +60,6 @@ "Text file" => "Ficheiro de texto", "Folder" => "Cartafol", "From link" => "Dende a ligazón", -"Upload" => "Enviar", "Cancel upload" => "Cancelar a subida", "Nothing in here. Upload something!" => "Nada por aquí. Envía algo.", "Download" => "Descargar", diff --git a/apps/files/l10n/he.php b/apps/files/l10n/he.php index 4c73493211d615d6554ec38923cf85dc03e4076d..8acc544cf5f9898e71a50a4fd85433c0f95d8069 100644 --- a/apps/files/l10n/he.php +++ b/apps/files/l10n/he.php @@ -1,4 +1,6 @@ "העלאה", +"No file was uploaded. Unknown error" => "לא הועלה קובץ. טעות בלתי מזוהה.", "There is no error, the file uploaded with success" => "לא אירעה תקלה, הקבצים הועלו בהצלחה", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "הקבצים שנשלחו חורגים מהגודל שצוין בהגדרה upload_max_filesize שבקובץ php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "הקובץ שהועלה חרג מההנחיה MAX_FILE_SIZE שצוינה בטופס ה־HTML", @@ -20,7 +22,6 @@ "unshared {files}" => "בוטל שיתופם של {files}", "deleted {files}" => "{files} נמחקו", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "השם שגוי, אסור להשתמש בתווים '\\', '/', '<', '>', ':', '\"', '|', '?' ו־'*'.", -"generating ZIP-file, it may take some time." => "יוצר קובץ ZIP, אנא המתן.", "Unable to upload your file as it is a directory or has 0 bytes" => "לא יכול להעלות את הקובץ מכיוון שזו תקיה או שמשקל הקובץ 0 בתים", "Upload Error" => "שגיאת העלאה", "Close" => "סגירה", @@ -29,7 +30,7 @@ "{count} files uploading" => "{count} קבצים נשלחים", "Upload cancelled." => "ההעלאה בוטלה.", "File upload is in progress. Leaving the page now will cancel the upload." => "מתבצעת כעת העלאת קבצים. עזיבה של העמוד תבטל את ההעלאה.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "שם התיקייה שגוי. השימוש בשם „Shared“ שמור לטובת Owncloud", +"URL cannot be empty." => "קישור אינו יכול להיות ריק.", "{count} files scanned" => "{count} קבצים נסרקו", "error while scanning" => "אירעה שגיאה במהלך הסריקה", "Name" => "שם", @@ -51,7 +52,6 @@ "Text file" => "קובץ טקסט", "Folder" => "תיקייה", "From link" => "מקישור", -"Upload" => "העלאה", "Cancel upload" => "ביטול ההעלאה", "Nothing in here. Upload something!" => "אין כאן שום דבר. אולי ברצונך להעלות משהו?", "Download" => "הורדה", diff --git a/apps/files/l10n/hr.php b/apps/files/l10n/hr.php index 4db4ac3f3e3c0a6ffa61efbd4a39657ba9d79b49..a9a7354d1d6b47cf701b1c505feda996cc4a8e0a 100644 --- a/apps/files/l10n/hr.php +++ b/apps/files/l10n/hr.php @@ -1,4 +1,5 @@ "Pošalji", "There is no error, the file uploaded with success" => "Datoteka je poslana uspješno i bez pogrešaka", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Poslana datoteka izlazi iz okvira MAX_FILE_SIZE direktive postavljene u HTML obrascu", "The uploaded file was only partially uploaded" => "Datoteka je poslana samo djelomično", @@ -13,7 +14,6 @@ "suggest name" => "predloži ime", "cancel" => "odustani", "undo" => "vrati", -"generating ZIP-file, it may take some time." => "generiranje ZIP datoteke, ovo može potrajati.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nemoguće poslati datoteku jer je prazna ili je direktorij", "Upload Error" => "Pogreška pri slanju", "Close" => "Zatvori", @@ -36,7 +36,6 @@ "New" => "novo", "Text file" => "tekstualna datoteka", "Folder" => "mapa", -"Upload" => "Pošalji", "Cancel upload" => "Prekini upload", "Nothing in here. Upload something!" => "Nema ničega u ovoj mapi. Pošalji nešto!", "Download" => "Preuzmi", diff --git a/apps/files/l10n/hu_HU.php b/apps/files/l10n/hu_HU.php index 083d5a391e1d435b46bddf548e82f0e19710381f..21797809b694e2bfc705f198442bd64064739f9b 100644 --- a/apps/files/l10n/hu_HU.php +++ b/apps/files/l10n/hu_HU.php @@ -1,42 +1,71 @@ "Nincs hiba, a fájl sikeresen feltöltve.", -"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "A feltöltött fájl meghaladja a MAX_FILE_SIZE direktívát ami meghatározott a HTML form-ban.", -"The uploaded file was only partially uploaded" => "Az eredeti fájl csak részlegesen van feltöltve.", -"No file was uploaded" => "Nem lett fájl feltöltve.", -"Missing a temporary folder" => "Hiányzik az ideiglenes könyvtár", -"Failed to write to disk" => "Nem írható lemezre", +"Upload" => "Feltöltés", +"Could not move %s - File with this name already exists" => "%s áthelyezése nem sikerült - már létezik másik fájl ezzel a névvel", +"Could not move %s" => "Nem sikerült %s áthelyezése", +"Unable to rename file" => "Nem lehet átnevezni a fájlt", +"No file was uploaded. Unknown error" => "Nem történt feltöltés. Ismeretlen hiba", +"There is no error, the file uploaded with success" => "A fájlt sikerült feltölteni", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "A feltöltött fájl mérete meghaladja a php.ini állományban megadott upload_max_filesize paraméter értékét.", +"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "A feltöltött fájl mérete meghaladja a MAX_FILE_SIZE paramétert, ami a HTML formban került megadásra.", +"The uploaded file was only partially uploaded" => "Az eredeti fájlt csak részben sikerült feltölteni.", +"No file was uploaded" => "Nem töltődött fel semmi", +"Missing a temporary folder" => "Hiányzik egy ideiglenes mappa", +"Failed to write to disk" => "Nem sikerült a lemezre történő írás", +"Not enough space available" => "Nincs elég szabad hely", +"Invalid directory." => "Érvénytelen mappa.", "Files" => "Fájlok", -"Unshare" => "Nem oszt meg", +"Unshare" => "Megosztás visszavonása", "Delete" => "Törlés", -"replace" => "cserél", +"Rename" => "Átnevezés", +"{new_name} already exists" => "{new_name} már létezik", +"replace" => "írjuk fölül", +"suggest name" => "legyen más neve", "cancel" => "mégse", -"undo" => "visszavon", -"generating ZIP-file, it may take some time." => "ZIP-fájl generálása, ez eltarthat egy ideig.", +"replaced {new_name}" => "a(z) {new_name} állományt kicseréltük", +"undo" => "visszavonás", +"replaced {new_name} with {old_name}" => "{new_name} fájlt kicseréltük ezzel: {old_name}", +"unshared {files}" => "{files} fájl megosztása visszavonva", +"deleted {files}" => "{files} fájl törölve", +"'.' is an invalid file name." => "'.' fájlnév érvénytelen.", +"File name cannot be empty." => "A fájlnév nem lehet semmi.", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Érvénytelen elnevezés. Ezek a karakterek nem használhatók: '\\', '/', '<', '>', ':', '\"', '|', '?' és '*'", +"Your download is being prepared. This might take some time if the files are big." => "Készül a letöltendő állomány. Ez eltarthat egy ideig, ha nagyok a fájlok.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nem tölthető fel, mert mappa volt, vagy 0 byte méretű", "Upload Error" => "Feltöltési hiba", -"Close" => "Bezár", +"Close" => "Bezárás", "Pending" => "Folyamatban", -"Upload cancelled." => "Feltöltés megszakítva", +"1 file uploading" => "1 fájl töltődik föl", +"{count} files uploading" => "{count} fájl töltődik föl", +"Upload cancelled." => "A feltöltést megszakítottuk.", +"File upload is in progress. Leaving the page now will cancel the upload." => "Fájlfeltöltés van folyamatban. Az oldal elhagyása megszakítja a feltöltést.", +"URL cannot be empty." => "Az URL nem lehet semmi.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Érvénytelen mappanév. A név használata csak a Owncloud számára lehetséges.", +"{count} files scanned" => "{count} fájlt találtunk", +"error while scanning" => "Hiba a fájllista-ellenőrzés során", "Name" => "Név", "Size" => "Méret", "Modified" => "Módosítva", +"1 folder" => "1 mappa", +"{count} folders" => "{count} mappa", +"1 file" => "1 fájl", +"{count} files" => "{count} fájl", "File handling" => "Fájlkezelés", "Maximum upload size" => "Maximális feltölthető fájlméret", -"max. possible: " => "max. lehetséges", -"Needed for multi-file and folder downloads." => "Kötegelt file- vagy mappaletöltéshez szükséges", -"Enable ZIP-download" => "ZIP-letöltés engedélyezése", +"max. possible: " => "max. lehetséges: ", +"Needed for multi-file and folder downloads." => "Kötegelt fájl- vagy mappaletöltéshez szükséges", +"Enable ZIP-download" => "A ZIP-letöltés engedélyezése", "0 is unlimited" => "0 = korlátlan", -"Maximum input size for ZIP files" => "ZIP file-ok maximum mérete", +"Maximum input size for ZIP files" => "ZIP-fájlok maximális kiindulási mérete", "Save" => "Mentés", "New" => "Új", "Text file" => "Szövegfájl", "Folder" => "Mappa", -"Upload" => "Feltöltés", -"Cancel upload" => "Feltöltés megszakítása", -"Nothing in here. Upload something!" => "Töltsön fel egy fájlt.", +"From link" => "Feltöltés linkről", +"Cancel upload" => "A feltöltés megszakítása", +"Nothing in here. Upload something!" => "Itt nincs semmi. Töltsön fel valamit!", "Download" => "Letöltés", -"Upload too large" => "Feltöltés túl nagy", -"The files you are trying to upload exceed the maximum size for file uploads on this server." => "A fájlokat amit próbálsz feltölteni meghaladta a legnagyobb fájlméretet ezen a szerveren.", -"Files are being scanned, please wait." => "File-ok vizsgálata, kis türelmet", -"Current scanning" => "Aktuális vizsgálat" +"Upload too large" => "A feltöltés túl nagy", +"The files you are trying to upload exceed the maximum size for file uploads on this server." => "A feltöltendő állományok mérete meghaladja a kiszolgálón megengedett maximális méretet.", +"Files are being scanned, please wait." => "A fájllista ellenőrzése zajlik, kis türelmet!", +"Current scanning" => "Ellenőrzés alatt" ); diff --git a/apps/files/l10n/ia.php b/apps/files/l10n/ia.php index ada64cd7574ac43a4485a1bbdfaa5db0085173b6..a7babb27d9e8750558393bb5cb0a2f98bee65fc7 100644 --- a/apps/files/l10n/ia.php +++ b/apps/files/l10n/ia.php @@ -1,4 +1,5 @@ "Incargar", "The uploaded file was only partially uploaded" => "Le file incargate solmente esseva incargate partialmente", "No file was uploaded" => "Nulle file esseva incargate", "Missing a temporary folder" => "Manca un dossier temporari", @@ -13,7 +14,6 @@ "New" => "Nove", "Text file" => "File de texto", "Folder" => "Dossier", -"Upload" => "Incargar", "Nothing in here. Upload something!" => "Nihil hic. Incarga alcun cosa!", "Download" => "Discargar", "Upload too large" => "Incargamento troppo longe" diff --git a/apps/files/l10n/id.php b/apps/files/l10n/id.php index 1f8cb444d2641d1214173230543821a26ee305d5..46d9ad1a75af9369bb4196a6987eff251c2c2094 100644 --- a/apps/files/l10n/id.php +++ b/apps/files/l10n/id.php @@ -1,4 +1,5 @@ "Unggah", "There is no error, the file uploaded with success" => "Tidak ada galat, berkas sukses diunggah", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "File yang diunggah melampaui directive MAX_FILE_SIZE yang disebutan dalam form HTML.", "The uploaded file was only partially uploaded" => "Berkas hanya diunggah sebagian", @@ -11,12 +12,12 @@ "replace" => "mengganti", "cancel" => "batalkan", "undo" => "batal dikerjakan", -"generating ZIP-file, it may take some time." => "membuat berkas ZIP, ini mungkin memakan waktu.", "Unable to upload your file as it is a directory or has 0 bytes" => "Gagal mengunggah berkas anda karena berupa direktori atau mempunyai ukuran 0 byte", "Upload Error" => "Terjadi Galat Pengunggahan", "Close" => "tutup", "Pending" => "Menunggu", "Upload cancelled." => "Pengunggahan dibatalkan.", +"URL cannot be empty." => "tautan tidak boleh kosong", "Name" => "Nama", "Size" => "Ukuran", "Modified" => "Dimodifikasi", @@ -31,7 +32,6 @@ "New" => "Baru", "Text file" => "Berkas teks", "Folder" => "Folder", -"Upload" => "Unggah", "Cancel upload" => "Batal mengunggah", "Nothing in here. Upload something!" => "Tidak ada apa-apa di sini. Unggah sesuatu!", "Download" => "Unduh", diff --git a/apps/files/l10n/is.php b/apps/files/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..c3adf0984e5e6ae4854b7a9ba2bf7154b87ab8f1 --- /dev/null +++ b/apps/files/l10n/is.php @@ -0,0 +1,70 @@ + "Senda inn", +"Could not move %s - File with this name already exists" => "Gat ekki fært %s - Skrá með þessu nafni er þegar til", +"Could not move %s" => "Gat ekki fært %s", +"Unable to rename file" => "Gat ekki endurskýrt skrá", +"No file was uploaded. Unknown error" => "Engin skrá var send inn. Óþekkt villa.", +"There is no error, the file uploaded with success" => "Engin villa, innsending heppnaðist", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Innsend skrá er stærri en upload_max stillingin í php.ini:", +"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Innsenda skráin er stærri en MAX_FILE_SIZE sem skilgreint er í HTML sniðinu.", +"The uploaded file was only partially uploaded" => "Einungis hluti af innsendri skrá skilaði sér", +"No file was uploaded" => "Engin skrá skilaði sér", +"Missing a temporary folder" => "Vantar bráðabirgðamöppu", +"Failed to write to disk" => "Tókst ekki að skrifa á disk", +"Not enough space available" => "Ekki nægt pláss tiltækt", +"Invalid directory." => "Ógild mappa.", +"Files" => "Skrár", +"Unshare" => "Hætta deilingu", +"Delete" => "Eyða", +"Rename" => "Endurskýra", +"{new_name} already exists" => "{new_name} er þegar til", +"replace" => "yfirskrifa", +"suggest name" => "stinga upp á nafni", +"cancel" => "hætta við", +"replaced {new_name}" => "endurskýrði {new_name}", +"undo" => "afturkalla", +"replaced {new_name} with {old_name}" => "yfirskrifaði {new_name} með {old_name}", +"unshared {files}" => "Hætti við deilingu á {files}", +"deleted {files}" => "eyddi {files}", +"'.' is an invalid file name." => "'.' er ekki leyfilegt nafn.", +"File name cannot be empty." => "Nafn skráar má ekki vera tómt", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ógilt nafn, táknin '\\', '/', '<', '>', ':', '\"', '|', '?' og '*' eru ekki leyfð.", +"Unable to upload your file as it is a directory or has 0 bytes" => "Innsending á skrá mistókst, hugsanlega sendir þú möppu eða skráin er 0 bæti.", +"Upload Error" => "Villa við innsendingu", +"Close" => "Loka", +"Pending" => "Bíður", +"1 file uploading" => "1 skrá innsend", +"{count} files uploading" => "{count} skrár innsendar", +"Upload cancelled." => "Hætt við innsendingu.", +"File upload is in progress. Leaving the page now will cancel the upload." => "Innsending í gangi. Ef þú ferð af þessari síðu mun innsending misheppnast.", +"URL cannot be empty." => "Vefslóð má ekki vera tóm.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Óleyfilegt nafn á möppu. Nafnið 'Shared' er frátekið fyrir Owncloud", +"{count} files scanned" => "{count} skrár skimaðar", +"error while scanning" => "villa við skimun", +"Name" => "Nafn", +"Size" => "Stærð", +"Modified" => "Breytt", +"1 folder" => "1 mappa", +"{count} folders" => "{count} möppur", +"1 file" => "1 skrá", +"{count} files" => "{count} skrár", +"File handling" => "Meðhöndlun skrár", +"Maximum upload size" => "Hámarks stærð innsendingar", +"max. possible: " => "hámark mögulegt: ", +"Needed for multi-file and folder downloads." => "Nauðsynlegt til að sækja margar skrár og möppur í einu.", +"Enable ZIP-download" => "Virkja ZIP niðurhal.", +"0 is unlimited" => "0 er ótakmarkað", +"Maximum input size for ZIP files" => "Hámarks inntaksstærð fyrir ZIP skrár", +"Save" => "Vista", +"New" => "Nýtt", +"Text file" => "Texta skrá", +"Folder" => "Mappa", +"From link" => "Af tengli", +"Cancel upload" => "Hætta við innsendingu", +"Nothing in here. Upload something!" => "Ekkert hér. Settu eitthvað inn!", +"Download" => "Niðurhal", +"Upload too large" => "Innsend skrá er of stór", +"The files you are trying to upload exceed the maximum size for file uploads on this server." => "Skrárnar sem þú ert að senda inn eru stærri en hámarks innsendingarstærð á þessum netþjóni.", +"Files are being scanned, please wait." => "Verið er að skima skrár, vinsamlegast hinkraðu.", +"Current scanning" => "Er að skima" +); diff --git a/apps/files/l10n/it.php b/apps/files/l10n/it.php index 90b341712200916ae7df51bf19e3dacaa954f741..9e211ae21acf1cd174630e4f7ca5598582ff6877 100644 --- a/apps/files/l10n/it.php +++ b/apps/files/l10n/it.php @@ -1,4 +1,9 @@ "Carica", +"Could not move %s - File with this name already exists" => "Impossibile spostare %s - un file con questo nome esiste già", +"Could not move %s" => "Impossibile spostare %s", +"Unable to rename file" => "Impossibile rinominare il file", +"No file was uploaded. Unknown error" => "Nessun file è stato inviato. Errore sconosciuto", "There is no error, the file uploaded with success" => "Non ci sono errori, file caricato con successo", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Il file caricato supera la direttiva upload_max_filesize in php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Il file caricato supera il valore MAX_FILE_SIZE definito nel form HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Nessun file è stato caricato", "Missing a temporary folder" => "Cartella temporanea mancante", "Failed to write to disk" => "Scrittura su disco non riuscita", +"Not enough space available" => "Spazio disponibile insufficiente", +"Invalid directory." => "Cartella non valida.", "Files" => "File", "Unshare" => "Rimuovi condivisione", "Delete" => "Elimina", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "sostituito {new_name} con {old_name}", "unshared {files}" => "non condivisi {files}", "deleted {files}" => "eliminati {files}", +"'.' is an invalid file name." => "'.' non è un nome file valido.", +"File name cannot be empty." => "Il nome del file non può essere vuoto.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome non valido, '\\', '/', '<', '>', ':', '\"', '|', '?' e '*' non sono consentiti.", -"generating ZIP-file, it may take some time." => "creazione file ZIP, potrebbe richiedere del tempo.", +"Your download is being prepared. This might take some time if the files are big." => "Il tuo scaricamento è in fase di preparazione. Ciò potrebbe richiedere del tempo se i file sono grandi.", "Unable to upload your file as it is a directory or has 0 bytes" => "Impossibile inviare il file poiché è una cartella o ha dimensione 0 byte", "Upload Error" => "Errore di invio", "Close" => "Chiudi", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} file in fase di caricamentoe", "Upload cancelled." => "Invio annullato", "File upload is in progress. Leaving the page now will cancel the upload." => "Caricamento del file in corso. La chiusura della pagina annullerà il caricamento.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nome della cartella non valido. L'uso di \"Shared\" è riservato a ownCloud", +"URL cannot be empty." => "L'URL non può essere vuoto.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nome della cartella non valido. L'uso di 'Shared' è riservato da ownCloud", "{count} files scanned" => "{count} file analizzati", "error while scanning" => "errore durante la scansione", "Name" => "Nome", @@ -51,7 +61,6 @@ "Text file" => "File di testo", "Folder" => "Cartella", "From link" => "Da collegamento", -"Upload" => "Carica", "Cancel upload" => "Annulla invio", "Nothing in here. Upload something!" => "Non c'è niente qui. Carica qualcosa!", "Download" => "Scarica", diff --git a/apps/files/l10n/ja_JP.php b/apps/files/l10n/ja_JP.php index 7b8c3ca4778c4c5a2f3e22b8847aba80c8357287..548263f54a353314db15cebb4556658ab55509f5 100644 --- a/apps/files/l10n/ja_JP.php +++ b/apps/files/l10n/ja_JP.php @@ -1,4 +1,9 @@ "アップロード", +"Could not move %s - File with this name already exists" => "%s を移動できませんでした ― この名前のファイルはすでに存在します", +"Could not move %s" => "%s を移動できませんでした", +"Unable to rename file" => "ファイル名の変更ができません", +"No file was uploaded. Unknown error" => "ファイルは何もアップロードされていません。不明なエラー", "There is no error, the file uploaded with success" => "エラーはありません。ファイルのアップロードは成功しました", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "アップロードされたファイルはphp.ini の upload_max_filesize に設定されたサイズを超えています:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "アップロードされたファイルはHTMLのフォームに設定されたMAX_FILE_SIZEに設定されたサイズを超えています", @@ -6,6 +11,8 @@ "No file was uploaded" => "ファイルはアップロードされませんでした", "Missing a temporary folder" => "テンポラリフォルダが見つかりません", "Failed to write to disk" => "ディスクへの書き込みに失敗しました", +"Not enough space available" => "利用可能なスペースが十分にありません", +"Invalid directory." => "無効なディレクトリです。", "Files" => "ファイル", "Unshare" => "共有しない", "Delete" => "削除", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "{old_name} を {new_name} に置換", "unshared {files}" => "未共有 {files}", "deleted {files}" => "削除 {files}", +"'.' is an invalid file name." => "'.' は無効なファイル名です。", +"File name cannot be empty." => "ファイル名を空にすることはできません。", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "無効な名前、'\\', '/', '<', '>', ':', '\"', '|', '?', '*' は使用できません。", -"generating ZIP-file, it may take some time." => "ZIPファイルを生成中です、しばらくお待ちください。", +"Your download is being prepared. This might take some time if the files are big." => "ダウンロードの準備中です。ファイルサイズが大きい場合は少し時間がかかるかもしれません。", "Unable to upload your file as it is a directory or has 0 bytes" => "ディレクトリもしくは0バイトのファイルはアップロードできません", "Upload Error" => "アップロードエラー", "Close" => "閉じる", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} ファイルをアップロード中", "Upload cancelled." => "アップロードはキャンセルされました。", "File upload is in progress. Leaving the page now will cancel the upload." => "ファイル転送を実行中です。今このページから移動するとアップロードが中止されます。", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "無効なフォルダ名です。\"Shared\" の利用は ownCloud が予約済みです。", +"URL cannot be empty." => "URLは空にできません。", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "無効なフォルダ名です。'Shared' の利用は ownCloud が予約済みです。", "{count} files scanned" => "{count} ファイルをスキャン", "error while scanning" => "スキャン中のエラー", "Name" => "名前", @@ -51,7 +61,6 @@ "Text file" => "テキストファイル", "Folder" => "フォルダ", "From link" => "リンク", -"Upload" => "アップロード", "Cancel upload" => "アップロードをキャンセル", "Nothing in here. Upload something!" => "ここには何もありません。何かアップロードしてください。", "Download" => "ダウンロード", diff --git a/apps/files/l10n/ka_GE.php b/apps/files/l10n/ka_GE.php index 9a73abfbe3bfa764ea5d5203ae868ca39aaa5fa7..3f5a532f6bd91c599f8d337ce35e62f369838fd5 100644 --- a/apps/files/l10n/ka_GE.php +++ b/apps/files/l10n/ka_GE.php @@ -1,4 +1,5 @@ "ატვირთვა", "There is no error, the file uploaded with success" => "ჭოცდომა არ დაფიქსირდა, ფაილი წარმატებით აიტვირთა", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "ატვირთული ფაილი აჭარბებს MAX_FILE_SIZE დირექტივას, რომელიც მითითებულია HTML ფორმაში", "The uploaded file was only partially uploaded" => "ატვირთული ფაილი მხოლოდ ნაწილობრივ აიტვირთა", @@ -18,7 +19,6 @@ "replaced {new_name} with {old_name}" => "{new_name} შეცვლილია {old_name}–ით", "unshared {files}" => "გაზიარება მოხსნილი {files}", "deleted {files}" => "წაშლილი {files}", -"generating ZIP-file, it may take some time." => "ZIP-ფაილის გენერირება, ამას ჭირდება გარკვეული დრო.", "Unable to upload your file as it is a directory or has 0 bytes" => "თქვენი ფაილის ატვირთვა ვერ მოხერხდა. ის არის საქაღალდე და შეიცავს 0 ბაიტს", "Upload Error" => "შეცდომა ატვირთვისას", "Close" => "დახურვა", @@ -47,7 +47,6 @@ "New" => "ახალი", "Text file" => "ტექსტური ფაილი", "Folder" => "საქაღალდე", -"Upload" => "ატვირთვა", "Cancel upload" => "ატვირთვის გაუქმება", "Nothing in here. Upload something!" => "აქ არაფერი არ არის. ატვირთე რამე!", "Download" => "ჩამოტვირთვა", diff --git a/apps/files/l10n/ko.php b/apps/files/l10n/ko.php index 4b5d57dff9254616b276a16788cf8e7741db4f75..891b036761d60e713776b0ff8ec6610948db0922 100644 --- a/apps/files/l10n/ko.php +++ b/apps/files/l10n/ko.php @@ -1,4 +1,9 @@ "업로드", +"Could not move %s - File with this name already exists" => "%s 항목을 이동시키지 못하였음 - 파일 이름이 이미 존재함", +"Could not move %s" => "%s 항목을 이딩시키지 못하였음", +"Unable to rename file" => "파일 이름바꾸기 할 수 없음", +"No file was uploaded. Unknown error" => "파일이 업로드되지 않았습니다. 알 수 없는 오류입니다", "There is no error, the file uploaded with success" => "업로드에 성공하였습니다.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "업로드한 파일이 php.ini의 upload_max_filesize보다 큽니다:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "업로드한 파일이 HTML 문서에 지정한 MAX_FILE_SIZE보다 더 큼", @@ -6,6 +11,8 @@ "No file was uploaded" => "업로드된 파일 없음", "Missing a temporary folder" => "임시 폴더가 사라짐", "Failed to write to disk" => "디스크에 쓰지 못했습니다", +"Not enough space available" => "여유공간이 부족합니다", +"Invalid directory." => "올바르지 않은 디렉토리입니다.", "Files" => "파일", "Unshare" => "공유 해제", "Delete" => "삭제", @@ -19,8 +26,9 @@ "replaced {new_name} with {old_name}" => "{old_name}이(가) {new_name}(으)로 대체됨", "unshared {files}" => "{files} 공유 해제됨", "deleted {files}" => "{files} 삭제됨", +"'.' is an invalid file name." => "'.' 는 올바르지 않은 파일 이름 입니다.", +"File name cannot be empty." => "파일이름은 공란이 될 수 없습니다.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "폴더 이름이 올바르지 않습니다. 이름에 문자 '\\', '/', '<', '>', ':', '\"', '|', '? ', '*'는 사용할 수 없습니다.", -"generating ZIP-file, it may take some time." => "ZIP 파일을 생성하고 있습니다. 시간이 걸릴 수도 있습니다.", "Unable to upload your file as it is a directory or has 0 bytes" => "이 파일은 디렉터리이거나 비어 있기 때문에 업로드할 수 없습니다", "Upload Error" => "업로드 오류", "Close" => "닫기", @@ -29,7 +37,8 @@ "{count} files uploading" => "파일 {count}개 업로드 중", "Upload cancelled." => "업로드가 취소되었습니다.", "File upload is in progress. Leaving the page now will cancel the upload." => "파일 업로드가 진행 중입니다. 이 페이지를 벗어나면 업로드가 취소됩니다.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "폴더 이름이 올바르지 않습니다. \"Shared\" 폴더는 ownCloud에서 예약되었습니다.", +"URL cannot be empty." => "URL을 입력해야 합니다.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "폴더 이름이 유효하지 않습니다. ", "{count} files scanned" => "파일 {count}개 검색됨", "error while scanning" => "검색 중 오류 발생", "Name" => "이름", @@ -51,7 +60,6 @@ "Text file" => "텍스트 파일", "Folder" => "폴더", "From link" => "링크에서", -"Upload" => "업로드", "Cancel upload" => "업로드 취소", "Nothing in here. Upload something!" => "내용이 없습니다. 업로드할 수 있습니다!", "Download" => "다운로드", diff --git a/apps/files/l10n/ku_IQ.php b/apps/files/l10n/ku_IQ.php index 49995f8df86150a9feba03dc5c3bccc8a0a5c8fb..ddd2c1427880977ae46a63c7edf47b5b0d5e7732 100644 --- a/apps/files/l10n/ku_IQ.php +++ b/apps/files/l10n/ku_IQ.php @@ -1,8 +1,9 @@ "بارکردن", "Close" => "داخستن", +"URL cannot be empty." => "ناونیشانی به‌سته‌ر نابێت به‌تاڵ بێت.", "Name" => "ناو", "Save" => "پاشکه‌وتکردن", "Folder" => "بوخچه", -"Upload" => "بارکردن", "Download" => "داگرتن" ); diff --git a/apps/files/l10n/lb.php b/apps/files/l10n/lb.php index 229ec3f20244ab3b1772d8aa3b5b72da8a62aa2b..b041079f0d865ea0d86d853dcc0338e8f9724956 100644 --- a/apps/files/l10n/lb.php +++ b/apps/files/l10n/lb.php @@ -1,4 +1,5 @@ "Eroplueden", "There is no error, the file uploaded with success" => "Keen Feeler, Datei ass komplett ropgelueden ginn", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Déi ropgelueden Datei ass méi grouss wei d'MAX_FILE_SIZE Eegenschaft déi an der HTML form uginn ass", "The uploaded file was only partially uploaded" => "Déi ropgelueden Datei ass nëmmen hallef ropgelueden ginn", @@ -10,7 +11,6 @@ "replace" => "ersetzen", "cancel" => "ofbriechen", "undo" => "réckgängeg man", -"generating ZIP-file, it may take some time." => "Et gëtt eng ZIP-File generéiert, dëst ka bëssen daueren.", "Unable to upload your file as it is a directory or has 0 bytes" => "Kann deng Datei net eroplueden well et en Dossier ass oder 0 byte grouss ass.", "Upload Error" => "Fehler beim eroplueden", "Close" => "Zoumaachen", @@ -30,7 +30,6 @@ "New" => "Nei", "Text file" => "Text Fichier", "Folder" => "Dossier", -"Upload" => "Eroplueden", "Cancel upload" => "Upload ofbriechen", "Nothing in here. Upload something!" => "Hei ass näischt. Lued eppes rop!", "Download" => "Eroflueden", diff --git a/apps/files/l10n/lt_LT.php b/apps/files/l10n/lt_LT.php index fd9824e0c1990248214ae688c2d4b9ec2aa73ba4..22490f8e9fd01755c34936e5cd0605c72e47be5c 100644 --- a/apps/files/l10n/lt_LT.php +++ b/apps/files/l10n/lt_LT.php @@ -1,4 +1,5 @@ "Įkelti", "There is no error, the file uploaded with success" => "Klaidų nėra, failas įkeltas sėkmingai", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Įkeliamo failo dydis viršija MAX_FILE_SIZE parametrą, kuris yra nustatytas HTML formoje", "The uploaded file was only partially uploaded" => "Failas buvo įkeltas tik dalinai", @@ -18,7 +19,6 @@ "replaced {new_name} with {old_name}" => "pakeiskite {new_name} į {old_name}", "unshared {files}" => "nebesidalinti {files}", "deleted {files}" => "ištrinti {files}", -"generating ZIP-file, it may take some time." => "kuriamas ZIP archyvas, tai gali užtrukti šiek tiek laiko.", "Unable to upload your file as it is a directory or has 0 bytes" => "Neįmanoma įkelti failo - jo dydis gali būti 0 bitų arba tai katalogas", "Upload Error" => "Įkėlimo klaida", "Close" => "Užverti", @@ -47,7 +47,6 @@ "New" => "Naujas", "Text file" => "Teksto failas", "Folder" => "Katalogas", -"Upload" => "Įkelti", "Cancel upload" => "Atšaukti siuntimą", "Nothing in here. Upload something!" => "Čia tuščia. Įkelkite ką nors!", "Download" => "Atsisiųsti", diff --git a/apps/files/l10n/lv.php b/apps/files/l10n/lv.php index 333679849182284d32eed63979a177f2125d6162..589b7020c4a2abac40b83c4d7c0666c481013361 100644 --- a/apps/files/l10n/lv.php +++ b/apps/files/l10n/lv.php @@ -1,4 +1,5 @@ "Augšuplādet", "There is no error, the file uploaded with success" => "Viss kārtībā, augšupielāde veiksmīga", "No file was uploaded" => "Neviens fails netika augšuplādēts", "Missing a temporary folder" => "Trūkst pagaidu mapes", @@ -11,7 +12,6 @@ "suggest name" => "Ieteiktais nosaukums", "cancel" => "atcelt", "undo" => "vienu soli atpakaļ", -"generating ZIP-file, it may take some time." => "lai uzģenerētu ZIP failu, kāds brīdis ir jāpagaida", "Unable to upload your file as it is a directory or has 0 bytes" => "Nav iespējams augšuplādēt jūsu failu, jo tāds jau eksistē vai arī failam nav izmēra (0 baiti)", "Upload Error" => "Augšuplādēšanas laikā radās kļūda", "Pending" => "Gaida savu kārtu", @@ -30,7 +30,6 @@ "New" => "Jauns", "Text file" => "Teksta fails", "Folder" => "Mape", -"Upload" => "Augšuplādet", "Cancel upload" => "Atcelt augšuplādi", "Nothing in here. Upload something!" => "Te vēl nekas nav. Rīkojies, sāc augšuplādēt", "Download" => "Lejuplādēt", diff --git a/apps/files/l10n/mk.php b/apps/files/l10n/mk.php index 1d22746156e8dea4955bc3c7f0afb0623312006e..2916e86a94dae49f5e02544dde41746f094379a5 100644 --- a/apps/files/l10n/mk.php +++ b/apps/files/l10n/mk.php @@ -1,4 +1,6 @@ "Подигни", +"No file was uploaded. Unknown error" => "Ниту еден фајл не се вчита. Непозната грешка", "There is no error, the file uploaded with success" => "Нема грешка, датотеката беше подигната успешно", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Подигнатата датотека ја надминува upload_max_filesize директивата во php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Подигнатата датотеката ја надминува MAX_FILE_SIZE директивата која беше поставена во HTML формата", @@ -20,7 +22,6 @@ "unshared {files}" => "без споделување {files}", "deleted {files}" => "избришани {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Неправилно име. , '\\', '/', '<', '>', ':', '\"', '|', '?' и '*' не се дозволени.", -"generating ZIP-file, it may take some time." => "Се генерира ZIP фајлот, ќе треба извесно време.", "Unable to upload your file as it is a directory or has 0 bytes" => "Не може да се преземе вашата датотека бидејќи фолдерот во кој се наоѓа фајлот има големина од 0 бајти", "Upload Error" => "Грешка при преземање", "Close" => "Затвои", @@ -29,7 +30,7 @@ "{count} files uploading" => "{count} датотеки се подигаат", "Upload cancelled." => "Преземањето е прекинато.", "File upload is in progress. Leaving the page now will cancel the upload." => "Подигање на датотека е во тек. Напуштење на страницата ќе го прекине.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Неправилно име на папка. Користењето на „Shared“ е резервирано за Owncloud", +"URL cannot be empty." => "Адресата неможе да биде празна.", "{count} files scanned" => "{count} датотеки скенирани", "error while scanning" => "грешка при скенирање", "Name" => "Име", @@ -51,7 +52,6 @@ "Text file" => "Текстуална датотека", "Folder" => "Папка", "From link" => "Од врска", -"Upload" => "Подигни", "Cancel upload" => "Откажи прикачување", "Nothing in here. Upload something!" => "Тука нема ништо. Снимете нешто!", "Download" => "Преземи", diff --git a/apps/files/l10n/ms_MY.php b/apps/files/l10n/ms_MY.php index d7756698d0cca44dfb02607cc5dc37ca1c2ff4de..23a2783cd9a7e9323f1fbf28a52e26c79c5f9f2a 100644 --- a/apps/files/l10n/ms_MY.php +++ b/apps/files/l10n/ms_MY.php @@ -1,4 +1,6 @@ "Muat naik", +"No file was uploaded. Unknown error" => "Tiada fail dimuatnaik. Ralat tidak diketahui.", "There is no error, the file uploaded with success" => "Tiada ralat, fail berjaya dimuat naik.", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Fail yang dimuat naik melebihi MAX_FILE_SIZE yang dinyatakan dalam form HTML ", "The uploaded file was only partially uploaded" => "Sebahagian daripada fail telah dimuat naik. ", @@ -9,7 +11,6 @@ "Delete" => "Padam", "replace" => "ganti", "cancel" => "Batal", -"generating ZIP-file, it may take some time." => "sedang menghasilkan fail ZIP, mungkin mengambil sedikit masa.", "Unable to upload your file as it is a directory or has 0 bytes" => "Tidak boleh memuatnaik fail anda kerana mungkin ianya direktori atau saiz fail 0 bytes", "Upload Error" => "Muat naik ralat", "Close" => "Tutup", @@ -29,7 +30,6 @@ "New" => "Baru", "Text file" => "Fail teks", "Folder" => "Folder", -"Upload" => "Muat naik", "Cancel upload" => "Batal muat naik", "Nothing in here. Upload something!" => "Tiada apa-apa di sini. Muat naik sesuatu!", "Download" => "Muat turun", diff --git a/apps/files/l10n/nb_NO.php b/apps/files/l10n/nb_NO.php index e5615a1c29b7945c6dff8019271a7ec1362c6680..48b873e1ef0f903fde4fd9ec8c7616071dcb7d0d 100644 --- a/apps/files/l10n/nb_NO.php +++ b/apps/files/l10n/nb_NO.php @@ -1,4 +1,6 @@ "Last opp", +"No file was uploaded. Unknown error" => "Ingen filer ble lastet opp. Ukjent feil.", "There is no error, the file uploaded with success" => "Det er ingen feil. Filen ble lastet opp.", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Filstørrelsen overskrider maksgrensen på MAX_FILE_SIZE som ble oppgitt i HTML-skjemaet", "The uploaded file was only partially uploaded" => "Filopplastningen ble bare delvis gjennomført", @@ -17,7 +19,7 @@ "undo" => "angre", "replaced {new_name} with {old_name}" => "erstatt {new_name} med {old_name}", "deleted {files}" => "slettet {files}", -"generating ZIP-file, it may take some time." => "opprettet ZIP-fil, dette kan ta litt tid", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ugyldig navn, '\\', '/', '<', '>', ':', '\"', '|', '?' og '*' er ikke tillatt.", "Unable to upload your file as it is a directory or has 0 bytes" => "Kan ikke laste opp filen din siden det er en mappe eller den har 0 bytes", "Upload Error" => "Opplasting feilet", "Close" => "Lukk", @@ -26,6 +28,7 @@ "{count} files uploading" => "{count} filer laster opp", "Upload cancelled." => "Opplasting avbrutt.", "File upload is in progress. Leaving the page now will cancel the upload." => "Filopplasting pågår. Forlater du siden nå avbrytes opplastingen.", +"URL cannot be empty." => "URL-en kan ikke være tom.", "{count} files scanned" => "{count} filer lest inn", "error while scanning" => "feil under skanning", "Name" => "Navn", @@ -46,7 +49,7 @@ "New" => "Ny", "Text file" => "Tekstfil", "Folder" => "Mappe", -"Upload" => "Last opp", +"From link" => "Fra link", "Cancel upload" => "Avbryt opplasting", "Nothing in here. Upload something!" => "Ingenting her. Last opp noe!", "Download" => "Last ned", diff --git a/apps/files/l10n/nl.php b/apps/files/l10n/nl.php index 093a5430d53a36ab19f8d993c6e6235d9114f2e9..4a9685e06c97bd633287593e62dc1d2ac8bc034c 100644 --- a/apps/files/l10n/nl.php +++ b/apps/files/l10n/nl.php @@ -1,4 +1,9 @@ "Upload", +"Could not move %s - File with this name already exists" => "Kon %s niet verplaatsen - Er bestaat al een bestand met deze naam", +"Could not move %s" => "Kon %s niet verplaatsen", +"Unable to rename file" => "Kan bestand niet hernoemen", +"No file was uploaded. Unknown error" => "Er was geen bestand geladen. Onbekende fout", "There is no error, the file uploaded with success" => "Geen fout opgetreden, bestand successvol geupload.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Het geüploade bestand overscheidt de upload_max_filesize optie in php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Het geüploade bestand is groter dan de MAX_FILE_SIZE richtlijn die is opgegeven in de HTML-formulier", @@ -6,6 +11,8 @@ "No file was uploaded" => "Geen bestand geüpload", "Missing a temporary folder" => "Een tijdelijke map mist", "Failed to write to disk" => "Schrijven naar schijf mislukt", +"Not enough space available" => "Niet genoeg ruimte beschikbaar", +"Invalid directory." => "Ongeldige directory.", "Files" => "Bestanden", "Unshare" => "Stop delen", "Delete" => "Verwijder", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "verving {new_name} met {old_name}", "unshared {files}" => "delen gestopt {files}", "deleted {files}" => "verwijderde {files}", +"'.' is an invalid file name." => "'.' is een ongeldige bestandsnaam.", +"File name cannot be empty." => "Bestandsnaam kan niet leeg zijn.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Onjuiste naam; '\\', '/', '<', '>', ':', '\"', '|', '?' en '*' zijn niet toegestaan.", -"generating ZIP-file, it may take some time." => "aanmaken ZIP-file, dit kan enige tijd duren.", +"Your download is being prepared. This might take some time if the files are big." => "Uw download wordt voorbereid. Dit kan enige tijd duren bij grote bestanden.", "Unable to upload your file as it is a directory or has 0 bytes" => "uploaden van de file mislukt, het is of een directory of de bestandsgrootte is 0 bytes", "Upload Error" => "Upload Fout", "Close" => "Sluit", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} bestanden aan het uploaden", "Upload cancelled." => "Uploaden geannuleerd.", "File upload is in progress. Leaving the page now will cancel the upload." => "Bestandsupload is bezig. Wanneer de pagina nu verlaten wordt, stopt de upload.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Folder naam niet toegestaan. Het gebruik van \"Shared\" is aan Owncloud voorbehouden", +"URL cannot be empty." => "URL kan niet leeg zijn.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Ongeldige mapnaam. Gebruik van'Gedeeld' is voorbehouden aan Owncloud", "{count} files scanned" => "{count} bestanden gescanned", "error while scanning" => "Fout tijdens het scannen", "Name" => "Naam", @@ -51,7 +61,6 @@ "Text file" => "Tekstbestand", "Folder" => "Map", "From link" => "Vanaf link", -"Upload" => "Upload", "Cancel upload" => "Upload afbreken", "Nothing in here. Upload something!" => "Er bevindt zich hier niets. Upload een bestand!", "Download" => "Download", diff --git a/apps/files/l10n/nn_NO.php b/apps/files/l10n/nn_NO.php index 04e01a39cfc86c3b60e96e8ecec391f8e8a5884a..8abbe1b6cd3a53302c8a1bb5f38cea2c6f42f837 100644 --- a/apps/files/l10n/nn_NO.php +++ b/apps/files/l10n/nn_NO.php @@ -1,4 +1,5 @@ "Last opp", "There is no error, the file uploaded with success" => "Ingen feil, fila vart lasta opp", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Den opplasta fila er større enn variabelen MAX_FILE_SIZE i HTML-skjemaet", "The uploaded file was only partially uploaded" => "Fila vart berre delvis lasta opp", @@ -15,7 +16,6 @@ "New" => "Ny", "Text file" => "Tekst fil", "Folder" => "Mappe", -"Upload" => "Last opp", "Nothing in here. Upload something!" => "Ingenting her. Last noko opp!", "Download" => "Last ned", "Upload too large" => "For stor opplasting", diff --git a/apps/files/l10n/oc.php b/apps/files/l10n/oc.php index 36bbb433394c6b8095d851cb18d594ccf897ea75..87ec98e4cf870f2ee413d6cec68b0b7871aa3466 100644 --- a/apps/files/l10n/oc.php +++ b/apps/files/l10n/oc.php @@ -1,4 +1,5 @@ "Amontcarga", "There is no error, the file uploaded with success" => "Amontcargament capitat, pas d'errors", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Lo fichièr amontcargat es mai gròs que la directiva «MAX_FILE_SIZE» especifiada dins lo formulari HTML", "The uploaded file was only partially uploaded" => "Lo fichièr foguèt pas completament amontcargat", @@ -13,7 +14,6 @@ "suggest name" => "nom prepausat", "cancel" => "anulla", "undo" => "defar", -"generating ZIP-file, it may take some time." => "Fichièr ZIP a se far, aquò pòt trigar un briu.", "Unable to upload your file as it is a directory or has 0 bytes" => "Impossible d'amontcargar lo teu fichièr qu'es un repertòri o que ten pas que 0 octet.", "Upload Error" => "Error d'amontcargar", "Pending" => "Al esperar", @@ -35,7 +35,6 @@ "New" => "Nòu", "Text file" => "Fichièr de tèxte", "Folder" => "Dorsièr", -"Upload" => "Amontcarga", "Cancel upload" => " Anulla l'amontcargar", "Nothing in here. Upload something!" => "Pas res dedins. Amontcarga qualquaren", "Download" => "Avalcarga", diff --git a/apps/files/l10n/pl.php b/apps/files/l10n/pl.php index 8051eae8c429a161a6962d88b8a8b740bdc36edb..4166bac545d9c108566c22266d19f8830f6daeb1 100644 --- a/apps/files/l10n/pl.php +++ b/apps/files/l10n/pl.php @@ -1,4 +1,9 @@ "Prześlij", +"Could not move %s - File with this name already exists" => "Nie można było przenieść %s - Plik o takiej nazwie już istnieje", +"Could not move %s" => "Nie można było przenieść %s", +"Unable to rename file" => "Nie można zmienić nazwy pliku", +"No file was uploaded. Unknown error" => "Plik nie został załadowany. Nieznany błąd", "There is no error, the file uploaded with success" => "Przesłano plik", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Wgrany plik przekracza wartość upload_max_filesize zdefiniowaną w php.ini: ", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Rozmiar przesłanego pliku przekracza maksymalną wartość dyrektywy upload_max_filesize, zawartą formularzu HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Nie przesłano żadnego pliku", "Missing a temporary folder" => "Brak katalogu tymczasowego", "Failed to write to disk" => "Błąd zapisu na dysk", +"Not enough space available" => "Za mało miejsca", +"Invalid directory." => "Zła ścieżka.", "Files" => "Pliki", "Unshare" => "Nie udostępniaj", "Delete" => "Usuwa element", @@ -19,8 +26,9 @@ "replaced {new_name} with {old_name}" => "zastąpiony {new_name} z {old_name}", "unshared {files}" => "Udostępniane wstrzymane {files}", "deleted {files}" => "usunięto {files}", +"'.' is an invalid file name." => "'.' jest nieprawidłową nazwą pliku.", +"File name cannot be empty." => "Nazwa pliku nie może być pusta.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Niepoprawna nazwa, Znaki '\\', '/', '<', '>', ':', '\"', '|', '?' oraz '*'są niedozwolone.", -"generating ZIP-file, it may take some time." => "Generowanie pliku ZIP, może potrwać pewien czas.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nie można wczytać pliku jeśli jest katalogiem lub ma 0 bajtów", "Upload Error" => "Błąd wczytywania", "Close" => "Zamknij", @@ -29,7 +37,8 @@ "{count} files uploading" => "{count} przesyłanie plików", "Upload cancelled." => "Wczytywanie anulowane.", "File upload is in progress. Leaving the page now will cancel the upload." => "Wysyłanie pliku jest w toku. Teraz opuszczając stronę wysyłanie zostanie anulowane.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Błędna nazwa folderu. Nazwa \"Shared\" jest zarezerwowana dla Owncloud", +"URL cannot be empty." => "URL nie może być pusty.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nazwa folderu nieprawidłowa. Wykorzystanie \"Shared\" jest zarezerwowane przez Owncloud", "{count} files scanned" => "{count} pliki skanowane", "error while scanning" => "Wystąpił błąd podczas skanowania", "Name" => "Nazwa", @@ -51,7 +60,6 @@ "Text file" => "Plik tekstowy", "Folder" => "Katalog", "From link" => "Z linku", -"Upload" => "Prześlij", "Cancel upload" => "Przestań wysyłać", "Nothing in here. Upload something!" => "Brak zawartości. Proszę wysłać pliki!", "Download" => "Pobiera element", diff --git a/apps/files/l10n/pt_BR.php b/apps/files/l10n/pt_BR.php index 97e5c94fb31a7e8ea5888ef666dcf01a4ae26d9d..b199ded9fe0efb7df00059f3e52ff02fcc934b3f 100644 --- a/apps/files/l10n/pt_BR.php +++ b/apps/files/l10n/pt_BR.php @@ -1,4 +1,6 @@ "Carregar", +"No file was uploaded. Unknown error" => "Nenhum arquivo foi transferido. Erro desconhecido", "There is no error, the file uploaded with success" => "Não houve nenhum erro, o arquivo foi transferido com sucesso", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "O arquivo enviado excede a diretiva upload_max_filesize no php.ini: ", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "O arquivo carregado excede o MAX_FILE_SIZE que foi especificado no formulário HTML", @@ -20,7 +22,6 @@ "unshared {files}" => "{files} não compartilhados", "deleted {files}" => "{files} apagados", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome inválido, '\\', '/', '<', '>', ':', '\"', '|', '?' e '*' não são permitidos.", -"generating ZIP-file, it may take some time." => "gerando arquivo ZIP, isso pode levar um tempo.", "Unable to upload your file as it is a directory or has 0 bytes" => "Impossível enviar seus arquivo como diretório ou ele tem 0 bytes.", "Upload Error" => "Erro de envio", "Close" => "Fechar", @@ -29,7 +30,7 @@ "{count} files uploading" => "Enviando {count} arquivos", "Upload cancelled." => "Envio cancelado.", "File upload is in progress. Leaving the page now will cancel the upload." => "Upload em andamento. Sair da página agora resultará no cancelamento do envio.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nome de pasta inválido. O nome \"Shared\" é reservado pelo Owncloud", +"URL cannot be empty." => "URL não pode ficar em branco", "{count} files scanned" => "{count} arquivos scaneados", "error while scanning" => "erro durante verificação", "Name" => "Nome", @@ -51,7 +52,6 @@ "Text file" => "Arquivo texto", "Folder" => "Pasta", "From link" => "Do link", -"Upload" => "Carregar", "Cancel upload" => "Cancelar upload", "Nothing in here. Upload something!" => "Nada aqui.Carrege alguma coisa!", "Download" => "Baixar", diff --git a/apps/files/l10n/pt_PT.php b/apps/files/l10n/pt_PT.php index 8c90fd477143316bcbbb9600d2979535c03f0ffa..0ed13fa99839b83d09845ab917c25f805fced4ab 100644 --- a/apps/files/l10n/pt_PT.php +++ b/apps/files/l10n/pt_PT.php @@ -1,4 +1,9 @@ "Enviar", +"Could not move %s - File with this name already exists" => "Não foi possível mover o ficheiro %s - Já existe um ficheiro com esse nome", +"Could not move %s" => "Não foi possível move o ficheiro %s", +"Unable to rename file" => "Não foi possível renomear o ficheiro", +"No file was uploaded. Unknown error" => "Nenhum ficheiro foi carregado. Erro desconhecido", "There is no error, the file uploaded with success" => "Sem erro, ficheiro enviado com sucesso", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "O ficheiro enviado excede o limite permitido na directiva do php.ini upload_max_filesize", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "O ficheiro enviado excede o diretivo MAX_FILE_SIZE especificado no formulário HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "Não foi enviado nenhum ficheiro", "Missing a temporary folder" => "Falta uma pasta temporária", "Failed to write to disk" => "Falhou a escrita no disco", +"Not enough space available" => "Espaço em disco insuficiente!", +"Invalid directory." => "Directório Inválido", "Files" => "Ficheiros", "Unshare" => "Deixar de partilhar", "Delete" => "Apagar", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "substituido {new_name} por {old_name}", "unshared {files}" => "{files} não partilhado(s)", "deleted {files}" => "{files} eliminado(s)", +"'.' is an invalid file name." => "'.' não é um nome de ficheiro válido!", +"File name cannot be empty." => "O nome do ficheiro não pode estar vazio.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nome Inválido, os caracteres '\\', '/', '<', '>', ':', '\"', '|', '?' e '*' não são permitidos.", -"generating ZIP-file, it may take some time." => "a gerar o ficheiro ZIP, poderá demorar algum tempo.", +"Your download is being prepared. This might take some time if the files are big." => "O seu download está a ser preparado. Este processo pode demorar algum tempo se os ficheiros forem grandes.", "Unable to upload your file as it is a directory or has 0 bytes" => "Não é possível fazer o envio do ficheiro devido a ser uma pasta ou ter 0 bytes", "Upload Error" => "Erro no envio", "Close" => "Fechar", @@ -29,7 +38,8 @@ "{count} files uploading" => "A carregar {count} ficheiros", "Upload cancelled." => "O envio foi cancelado.", "File upload is in progress. Leaving the page now will cancel the upload." => "Envio de ficheiro em progresso. Irá cancelar o envio se sair da página agora.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nome de pasta inválido! O uso de \"Shared\" (Partilhado) está reservado pelo OwnCloud", +"URL cannot be empty." => "O URL não pode estar vazio.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Nome de pasta inválido. O Uso de 'shared' é reservado para o ownCloud", "{count} files scanned" => "{count} ficheiros analisados", "error while scanning" => "erro ao analisar", "Name" => "Nome", @@ -51,7 +61,6 @@ "Text file" => "Ficheiro de texto", "Folder" => "Pasta", "From link" => "Da ligação", -"Upload" => "Enviar", "Cancel upload" => "Cancelar envio", "Nothing in here. Upload something!" => "Vazio. Envie alguma coisa!", "Download" => "Transferir", diff --git a/apps/files/l10n/ro.php b/apps/files/l10n/ro.php index 34e8dc8a50ea909142267f6965396f44f2e2b43a..af9833e5c2d26f5d4f200583e5efb69a09190e25 100644 --- a/apps/files/l10n/ro.php +++ b/apps/files/l10n/ro.php @@ -1,30 +1,54 @@ "Încarcă", +"Could not move %s - File with this name already exists" => "Nu se poate de mutat %s - Fișier cu acest nume deja există", +"Could not move %s" => "Nu s-a putut muta %s", +"Unable to rename file" => "Nu s-a putut redenumi fișierul", +"No file was uploaded. Unknown error" => "Nici un fișier nu a fost încărcat. Eroare necunoscută", "There is no error, the file uploaded with success" => "Nicio eroare, fișierul a fost încărcat cu succes", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Fisierul incarcat depaseste upload_max_filesize permisi in php.ini: ", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Fișierul are o dimensiune mai mare decât variabile MAX_FILE_SIZE specificată în formularul HTML", "The uploaded file was only partially uploaded" => "Fișierul a fost încărcat doar parțial", "No file was uploaded" => "Niciun fișier încărcat", "Missing a temporary folder" => "Lipsește un dosar temporar", "Failed to write to disk" => "Eroare la scriere pe disc", +"Not enough space available" => "Nu este suficient spațiu disponibil", +"Invalid directory." => "Director invalid.", "Files" => "Fișiere", "Unshare" => "Anulează partajarea", "Delete" => "Șterge", "Rename" => "Redenumire", +"{new_name} already exists" => "{new_name} deja exista", "replace" => "înlocuire", "suggest name" => "sugerează nume", "cancel" => "anulare", +"replaced {new_name}" => "inlocuit {new_name}", "undo" => "Anulează ultima acțiune", -"generating ZIP-file, it may take some time." => "se generază fișierul ZIP, va dura ceva timp.", +"replaced {new_name} with {old_name}" => "{new_name} inlocuit cu {old_name}", +"unshared {files}" => "nedistribuit {files}", +"deleted {files}" => "Sterse {files}", +"'.' is an invalid file name." => "'.' este un nume invalid de fișier.", +"File name cannot be empty." => "Numele fișierului nu poate rămâne gol.", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nume invalid, '\\', '/', '<', '>', ':', '\"', '|', '?' si '*' nu sunt permise.", +"Your download is being prepared. This might take some time if the files are big." => "Se pregătește descărcarea. Aceasta poate să dureze ceva timp dacă fișierele sunt mari.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nu s-a putut încărca fișierul tău deoarece pare să fie un director sau are 0 bytes.", "Upload Error" => "Eroare la încărcare", "Close" => "Închide", "Pending" => "În așteptare", "1 file uploading" => "un fișier se încarcă", +"{count} files uploading" => "{count} fisiere incarcate", "Upload cancelled." => "Încărcare anulată.", "File upload is in progress. Leaving the page now will cancel the upload." => "Fișierul este în curs de încărcare. Părăsirea paginii va întrerupe încărcarea.", +"URL cannot be empty." => "Adresa URL nu poate fi goală.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Invalid folder name. Usage of 'Shared' is reserved by Ownclou", +"{count} files scanned" => "{count} fisiere scanate", "error while scanning" => "eroare la scanarea", "Name" => "Nume", "Size" => "Dimensiune", "Modified" => "Modificat", +"1 folder" => "1 folder", +"{count} folders" => "{count} foldare", +"1 file" => "1 fisier", +"{count} files" => "{count} fisiere", "File handling" => "Manipulare fișiere", "Maximum upload size" => "Dimensiune maximă admisă la încărcare", "max. possible: " => "max. posibil:", @@ -36,7 +60,7 @@ "New" => "Nou", "Text file" => "Fișier text", "Folder" => "Dosar", -"Upload" => "Încarcă", +"From link" => "de la adresa", "Cancel upload" => "Anulează încărcarea", "Nothing in here. Upload something!" => "Nimic aici. Încarcă ceva!", "Download" => "Descarcă", diff --git a/apps/files/l10n/ru.php b/apps/files/l10n/ru.php index 4b6d0a8b1511a14342b835b28ae0629a183e1f2d..cb17476b9f807ac5db3bd2af4277aa7452140773 100644 --- a/apps/files/l10n/ru.php +++ b/apps/files/l10n/ru.php @@ -1,4 +1,9 @@ "Загрузить", +"Could not move %s - File with this name already exists" => "Невозможно переместить %s - файл с таким именем уже существует", +"Could not move %s" => "Невозможно переместить %s", +"Unable to rename file" => "Невозможно переименовать файл", +"No file was uploaded. Unknown error" => "Файл не был загружен. Неизвестная ошибка", "There is no error, the file uploaded with success" => "Файл успешно загружен", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Файл превышает размер установленный upload_max_filesize в php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Файл превышает размер MAX_FILE_SIZE, указаный в HTML-форме", @@ -6,6 +11,8 @@ "No file was uploaded" => "Файл не был загружен", "Missing a temporary folder" => "Невозможно найти временную папку", "Failed to write to disk" => "Ошибка записи на диск", +"Not enough space available" => "Недостаточно свободного места", +"Invalid directory." => "Неправильный каталог.", "Files" => "Файлы", "Unshare" => "Отменить публикацию", "Delete" => "Удалить", @@ -19,8 +26,9 @@ "replaced {new_name} with {old_name}" => "заменено {new_name} на {old_name}", "unshared {files}" => "не опубликованные {files}", "deleted {files}" => "удаленные {files}", +"'.' is an invalid file name." => "'.' - неправильное имя файла.", +"File name cannot be empty." => "Имя файла не может быть пустым.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Неправильное имя, '\\', '/', '<', '>', ':', '\"', '|', '?' и '*' недопустимы.", -"generating ZIP-file, it may take some time." => "создание ZIP-файла, это может занять некоторое время.", "Unable to upload your file as it is a directory or has 0 bytes" => "Не удается загрузить файл размером 0 байт в каталог", "Upload Error" => "Ошибка загрузки", "Close" => "Закрыть", @@ -29,7 +37,8 @@ "{count} files uploading" => "{count} файлов загружается", "Upload cancelled." => "Загрузка отменена.", "File upload is in progress. Leaving the page now will cancel the upload." => "Файл в процессе загрузки. Покинув страницу вы прервёте загрузку.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Не правильное имя папки. Имя \"Shared\" резервировано в Owncloud", +"URL cannot be empty." => "Ссылка не может быть пустой.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Неправильное имя каталога. Имя 'Shared' зарезервировано.", "{count} files scanned" => "{count} файлов просканировано", "error while scanning" => "ошибка во время санирования", "Name" => "Название", @@ -51,7 +60,6 @@ "Text file" => "Текстовый файл", "Folder" => "Папка", "From link" => "Из ссылки", -"Upload" => "Загрузить", "Cancel upload" => "Отмена загрузки", "Nothing in here. Upload something!" => "Здесь ничего нет. Загрузите что-нибудь!", "Download" => "Скачать", diff --git a/apps/files/l10n/ru_RU.php b/apps/files/l10n/ru_RU.php index bb701aac002cd32b474ad0a4a986ed56d17478b5..4f8bd1d5b9552ef518205d1c2adaa2ebd5f50374 100644 --- a/apps/files/l10n/ru_RU.php +++ b/apps/files/l10n/ru_RU.php @@ -1,4 +1,6 @@ "Загрузить ", +"No file was uploaded. Unknown error" => "Файл не был загружен. Неизвестная ошибка", "There is no error, the file uploaded with success" => "Ошибка отсутствует, файл загружен успешно.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Размер загружаемого файла превышает upload_max_filesize директиву в php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Размер загруженного", @@ -20,7 +22,6 @@ "unshared {files}" => "Cовместное использование прекращено {файлы}", "deleted {files}" => "удалено {файлы}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Некорректное имя, '\\', '/', '<', '>', ':', '\"', '|', '?' и '*' не допустимы.", -"generating ZIP-file, it may take some time." => "Создание ZIP-файла, это может занять некоторое время.", "Unable to upload your file as it is a directory or has 0 bytes" => "Невозможно загрузить файл,\n так как он имеет нулевой размер или является директорией", "Upload Error" => "Ошибка загрузки", "Close" => "Закрыть", @@ -29,7 +30,7 @@ "{count} files uploading" => "{количество} загружено файлов", "Upload cancelled." => "Загрузка отменена", "File upload is in progress. Leaving the page now will cancel the upload." => "Процесс загрузки файла. Если покинуть страницу сейчас, загрузка будет отменена.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Некорректное имя папки. Нименование \"Опубликовано\" зарезервировано ownCloud", +"URL cannot be empty." => "URL не должен быть пустым.", "{count} files scanned" => "{количество} файлов отсканировано", "error while scanning" => "ошибка при сканировании", "Name" => "Имя", @@ -51,7 +52,6 @@ "Text file" => "Текстовый файл", "Folder" => "Папка", "From link" => "По ссылке", -"Upload" => "Загрузить ", "Cancel upload" => "Отмена загрузки", "Nothing in here. Upload something!" => "Здесь ничего нет. Загрузите что-нибудь!", "Download" => "Загрузить", diff --git a/apps/files/l10n/si_LK.php b/apps/files/l10n/si_LK.php index e256075896f9fd038efce43b84444cb03bb9dd21..8b276bdaa8ff5d59752f77acf0d70979818e4be8 100644 --- a/apps/files/l10n/si_LK.php +++ b/apps/files/l10n/si_LK.php @@ -1,4 +1,6 @@ "උඩුගත කිරීම", +"No file was uploaded. Unknown error" => "ගොනුවක් උඩුගත නොවුනි. නොහැඳිනු දෝෂයක්", "There is no error, the file uploaded with success" => "නිවැරදි ව ගොනුව උඩුගත කෙරිනි", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "උඩුගත කළ ගොනුවේ විශාලත්වය HTML පෝරමයේ නියම කළ ඇති MAX_FILE_SIZE විශාලත්වයට වඩා වැඩිය", "The uploaded file was only partially uploaded" => "උඩුගත කළ ගොනුවේ කොටසක් පමණක් උඩුගත විය", @@ -13,12 +15,12 @@ "suggest name" => "නමක් යෝජනා කරන්න", "cancel" => "අත් හරින්න", "undo" => "නිෂ්ප්‍රභ කරන්න", -"generating ZIP-file, it may take some time." => "ගොනුවක් සෑදෙමින් පවතී. කෙටි වේලාවක් ගත විය හැක", "Upload Error" => "උඩුගත කිරීමේ දෝශයක්", "Close" => "වසන්න", "1 file uploading" => "1 ගොනුවක් උඩගත කෙරේ", "Upload cancelled." => "උඩුගත කිරීම අත් හරින්න ලදී", "File upload is in progress. Leaving the page now will cancel the upload." => "උඩුගතකිරීමක් සිදුවේ. පිටුව හැර යාමෙන් එය නැවතෙනු ඇත", +"URL cannot be empty." => "යොමුව හිස් විය නොහැක", "error while scanning" => "පරීක්ෂා කිරීමේදී දෝෂයක්", "Name" => "නම", "Size" => "ප්‍රමාණය", @@ -37,7 +39,6 @@ "Text file" => "පෙළ ගොනුව", "Folder" => "ෆෝල්ඩරය", "From link" => "යොමුවෙන්", -"Upload" => "උඩුගත කිරීම", "Cancel upload" => "උඩුගත කිරීම අත් හරින්න", "Nothing in here. Upload something!" => "මෙහි කිසිවක් නොමැත. යමක් උඩුගත කරන්න", "Download" => "බාගත කිරීම", diff --git a/apps/files/l10n/sk_SK.php b/apps/files/l10n/sk_SK.php index 21d9710f6ba3f82b08f47df936770d194748af03..66163b1e53c3b232ec10e0e8fb04780cf70db8e6 100644 --- a/apps/files/l10n/sk_SK.php +++ b/apps/files/l10n/sk_SK.php @@ -1,4 +1,9 @@ "Odoslať", +"Could not move %s - File with this name already exists" => "Nie je možné presunúť %s - súbor s týmto menom už existuje", +"Could not move %s" => "Nie je možné presunúť %s", +"Unable to rename file" => "Nemožno premenovať súbor", +"No file was uploaded. Unknown error" => "Žiaden súbor nebol odoslaný. Neznáma chyba", "There is no error, the file uploaded with success" => "Nenastala žiadna chyba, súbor bol úspešne nahraný", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Nahraný súbor predčil konfiguračnú direktívu upload_max_filesize v súbore php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Nahrávaný súbor presiahol MAX_FILE_SIZE direktívu, ktorá bola špecifikovaná v HTML formulári", @@ -6,6 +11,8 @@ "No file was uploaded" => "Žiaden súbor nebol nahraný", "Missing a temporary folder" => "Chýbajúci dočasný priečinok", "Failed to write to disk" => "Zápis na disk sa nepodaril", +"Not enough space available" => "Nie je k dispozícii dostatok miesta", +"Invalid directory." => "Neplatný adresár", "Files" => "Súbory", "Unshare" => "Nezdielať", "Delete" => "Odstrániť", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "prepísaný {new_name} súborom {old_name}", "unshared {files}" => "zdieľanie zrušené pre {files}", "deleted {files}" => "zmazané {files}", +"'.' is an invalid file name." => "'.' je neplatné meno súboru.", +"File name cannot be empty." => "Meno súboru nemôže byť prázdne", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Nesprávne meno, '\\', '/', '<', '>', ':', '\"', '|', '?' a '*' nie sú povolené hodnoty.", -"generating ZIP-file, it may take some time." => "generujem ZIP-súbor, môže to chvíľu trvať.", +"Your download is being prepared. This might take some time if the files are big." => "Vaše sťahovanie sa pripravuje. Ak sú sťahované súbory veľké, môže to chvíľu trvať.", "Unable to upload your file as it is a directory or has 0 bytes" => "Nemôžem nahrať súbor lebo je to priečinok alebo má 0 bajtov.", "Upload Error" => "Chyba odosielania", "Close" => "Zavrieť", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} súborov odosielaných", "Upload cancelled." => "Odosielanie zrušené", "File upload is in progress. Leaving the page now will cancel the upload." => "Opustenie stránky zruší práve prebiehajúce odosielanie súboru.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Nesprávne meno adresára. Použitie slova \"Shared\" (Zdieľané) je vyhradené službou ownCloud.", +"URL cannot be empty." => "URL nemôže byť prázdne", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Neplatné meno adresára. Používanie mena 'Shared' je vyhradené len pre Owncloud", "{count} files scanned" => "{count} súborov prehľadaných", "error while scanning" => "chyba počas kontroly", "Name" => "Meno", @@ -51,7 +61,6 @@ "Text file" => "Textový súbor", "Folder" => "Priečinok", "From link" => "Z odkazu", -"Upload" => "Odoslať", "Cancel upload" => "Zrušiť odosielanie", "Nothing in here. Upload something!" => "Žiadny súbor. Nahrajte niečo!", "Download" => "Stiahnuť", diff --git a/apps/files/l10n/sl.php b/apps/files/l10n/sl.php index c5ee6c422d5c5b6038e2d4aa2fa7400b302fce75..34544e3401c210e688fc3399bafa2cb0b94e95c3 100644 --- a/apps/files/l10n/sl.php +++ b/apps/files/l10n/sl.php @@ -1,4 +1,6 @@ "Pošlji", +"No file was uploaded. Unknown error" => "Nobena datoteka ni naložena. Neznana napaka.", "There is no error, the file uploaded with success" => "Datoteka je uspešno naložena brez napak.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Naložena datoteka presega dovoljeno velikost. Le-ta je določena z vrstico upload_max_filesize v datoteki php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Naložena datoteka presega velikost, ki jo določa parameter MAX_FILE_SIZE v HTML obrazcu", @@ -20,7 +22,6 @@ "unshared {files}" => "odstranjeno iz souporabe {files}", "deleted {files}" => "izbrisano {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Neveljavno ime, znaki '\\', '/', '<', '>', ':', '\"', '|', '?' in '*' niso dovoljeni.", -"generating ZIP-file, it may take some time." => "Ustvarjanje datoteke ZIP. To lahko traja nekaj časa.", "Unable to upload your file as it is a directory or has 0 bytes" => "Pošiljanje ni mogoče, saj gre za mapo, ali pa je datoteka velikosti 0 bajtov.", "Upload Error" => "Napaka med nalaganjem", "Close" => "Zapri", @@ -29,7 +30,7 @@ "{count} files uploading" => "nalagam {count} datotek", "Upload cancelled." => "Pošiljanje je preklicano.", "File upload is in progress. Leaving the page now will cancel the upload." => "V teku je pošiljanje datoteke. Če zapustite to stran zdaj, bo pošiljanje preklicano.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Neveljavno ime datoteke. Uporaba mape \"Share\" je rezervirana za ownCloud.", +"URL cannot be empty." => "Naslov URL ne sme biti prazen.", "{count} files scanned" => "{count} files scanned", "error while scanning" => "napaka med pregledovanjem datotek", "Name" => "Ime", @@ -51,7 +52,6 @@ "Text file" => "Besedilna datoteka", "Folder" => "Mapa", "From link" => "Iz povezave", -"Upload" => "Pošlji", "Cancel upload" => "Prekliči pošiljanje", "Nothing in here. Upload something!" => "Tukaj ni ničesar. Naložite kaj!", "Download" => "Prejmi", diff --git a/apps/files/l10n/sr.php b/apps/files/l10n/sr.php index 48b258862b542ea824fd421fd076fa1f56b926d7..3da6e27373fa6f4d012c825dcaddb285382e5cd3 100644 --- a/apps/files/l10n/sr.php +++ b/apps/files/l10n/sr.php @@ -1,4 +1,5 @@ "Отпреми", "There is no error, the file uploaded with success" => "Није дошло до грешке. Датотека је успешно отпремљена.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Отпремљена датотека прелази смерницу upload_max_filesize у датотеци php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Отпремљена датотека прелази смерницу MAX_FILE_SIZE која је наведена у HTML обрасцу", @@ -20,7 +21,6 @@ "unshared {files}" => "укинуто дељење {files}", "deleted {files}" => "обрисано {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Неисправан назив. Следећи знакови нису дозвољени: \\, /, <, >, :, \", |, ? и *.", -"generating ZIP-file, it may take some time." => "правим ZIP датотеку…", "Unable to upload your file as it is a directory or has 0 bytes" => "Не могу да отпремим датотеку као фасциклу или она има 0 бајтова", "Upload Error" => "Грешка при отпремању", "Close" => "Затвори", @@ -29,7 +29,6 @@ "{count} files uploading" => "Отпремам {count} датотеке/а", "Upload cancelled." => "Отпремање је прекинуто.", "File upload is in progress. Leaving the page now will cancel the upload." => "Отпремање датотеке је у току. Ако сада напустите страницу, прекинућете отпремање.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Неисправан назив фасцикле. „Дељено“ користи Оунклауд.", "{count} files scanned" => "Скенирано датотека: {count}", "error while scanning" => "грешка при скенирању", "Name" => "Назив", @@ -51,7 +50,6 @@ "Text file" => "текстуална датотека", "Folder" => "фасцикла", "From link" => "Са везе", -"Upload" => "Отпреми", "Cancel upload" => "Прекини отпремање", "Nothing in here. Upload something!" => "Овде нема ничег. Отпремите нешто!", "Download" => "Преузми", diff --git a/apps/files/l10n/sr@latin.php b/apps/files/l10n/sr@latin.php index fddaf5840cea10fe137c9cdc119f8b1731d4dd07..117d437f0bb5624c1e22e207069918bb294ff47c 100644 --- a/apps/files/l10n/sr@latin.php +++ b/apps/files/l10n/sr@latin.php @@ -1,4 +1,5 @@ "Pošalji", "There is no error, the file uploaded with success" => "Nema greške, fajl je uspešno poslat", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Poslati fajl prevazilazi direktivu MAX_FILE_SIZE koja je navedena u HTML formi", "The uploaded file was only partially uploaded" => "Poslati fajl je samo delimično otpremljen!", @@ -12,7 +13,6 @@ "Modified" => "Zadnja izmena", "Maximum upload size" => "Maksimalna veličina pošiljke", "Save" => "Snimi", -"Upload" => "Pošalji", "Nothing in here. Upload something!" => "Ovde nema ničeg. Pošaljite nešto!", "Download" => "Preuzmi", "Upload too large" => "Pošiljka je prevelika", diff --git a/apps/files/l10n/sv.php b/apps/files/l10n/sv.php index bcc849242acc20b24d2a0ef08ce5b720e902ca14..7597f6908eb82ec00244aea1e57566155c60def9 100644 --- a/apps/files/l10n/sv.php +++ b/apps/files/l10n/sv.php @@ -1,4 +1,9 @@ "Ladda upp", +"Could not move %s - File with this name already exists" => "Kunde inte flytta %s - Det finns redan en fil med detta namn", +"Could not move %s" => "Kan inte flytta %s", +"Unable to rename file" => "Kan inte byta namn på filen", +"No file was uploaded. Unknown error" => "Ingen fil uppladdad. Okänt fel", "There is no error, the file uploaded with success" => "Inga fel uppstod. Filen laddades upp utan problem", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Den uppladdade filen överskrider upload_max_filesize direktivet php.ini:", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Den uppladdade filen överstiger MAX_FILE_SIZE direktivet som anges i HTML-formulär", @@ -6,6 +11,8 @@ "No file was uploaded" => "Ingen fil blev uppladdad", "Missing a temporary folder" => "Saknar en tillfällig mapp", "Failed to write to disk" => "Misslyckades spara till disk", +"Not enough space available" => "Inte tillräckligt med utrymme tillgängligt", +"Invalid directory." => "Felaktig mapp.", "Files" => "Filer", "Unshare" => "Sluta dela", "Delete" => "Radera", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "ersatt {new_name} med {old_name}", "unshared {files}" => "stoppad delning {files}", "deleted {files}" => "raderade {files}", +"'.' is an invalid file name." => "'.' är ett ogiltigt filnamn.", +"File name cannot be empty." => "Filnamn kan inte vara tomt.", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Ogiltigt namn, '\\', '/', '<', '>', ':', '\"', '|', '?' och '*' är inte tillåtet.", -"generating ZIP-file, it may take some time." => "genererar ZIP-fil, det kan ta lite tid.", +"Your download is being prepared. This might take some time if the files are big." => "Din nedladdning förbereds. Det kan ta tid om det är stora filer.", "Unable to upload your file as it is a directory or has 0 bytes" => "Kunde inte ladda upp dina filer eftersom det antingen är en mapp eller har 0 bytes.", "Upload Error" => "Uppladdningsfel", "Close" => "Stäng", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} filer laddas upp", "Upload cancelled." => "Uppladdning avbruten.", "File upload is in progress. Leaving the page now will cancel the upload." => "Filuppladdning pågår. Lämnar du sidan så avbryts uppladdningen.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Ogiltigt mappnamn. Ordet \"Delad\" är reserverat av ownCloud.", +"URL cannot be empty." => "URL kan inte vara tom.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Ogiltigt mappnamn. Användande av 'Shared' är reserverat av ownCloud", "{count} files scanned" => "{count} filer skannade", "error while scanning" => "fel vid skanning", "Name" => "Namn", @@ -51,7 +61,6 @@ "Text file" => "Textfil", "Folder" => "Mapp", "From link" => "Från länk", -"Upload" => "Ladda upp", "Cancel upload" => "Avbryt uppladdning", "Nothing in here. Upload something!" => "Ingenting här. Ladda upp något!", "Download" => "Ladda ner", diff --git a/apps/files/l10n/ta_LK.php b/apps/files/l10n/ta_LK.php index 9399089bc787cee13fd631a72cc2b7a9223fcfb7..d7a9313d9744ef15978cc522b8ff7f20eb43929b 100644 --- a/apps/files/l10n/ta_LK.php +++ b/apps/files/l10n/ta_LK.php @@ -1,4 +1,6 @@ "பதிவேற்றுக", +"No file was uploaded. Unknown error" => "ஒரு கோப்பும் பதிவேற்றப்படவில்லை. அறியப்படாத வழு", "There is no error, the file uploaded with success" => "இங்கு வழு இல்லை, கோப்பு வெற்றிகரமாக பதிவேற்றப்பட்டது", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "பதிவேற்றப்பட்ட கோப்பானது HTML படிவத்தில் குறிப்பிடப்பட்டுள்ள MAX_FILE_SIZE directive ஐ விட கூடியது", "The uploaded file was only partially uploaded" => "பதிவேற்றப்பட்ட கோப்பானது பகுதியாக மட்டுமே பதிவேற்றப்பட்டுள்ளது", @@ -19,7 +21,6 @@ "unshared {files}" => "பகிரப்படாதது {கோப்புகள்}", "deleted {files}" => "நீக்கப்பட்டது {கோப்புகள்}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "செல்லுபடியற்ற பெயர்,'\\', '/', '<', '>', ':', '\"', '|', '?' மற்றும் '*' ஆகியன அனுமதிக்கப்படமாட்டாது.", -"generating ZIP-file, it may take some time." => " ZIP கோப்பு உருவாக்கப்படுகின்றது, இது சில நேரம் ஆகலாம்.", "Unable to upload your file as it is a directory or has 0 bytes" => "அடைவு அல்லது 0 bytes ஐ கொண்டுள்ளதால் உங்களுடைய கோப்பை பதிவேற்ற முடியவில்லை", "Upload Error" => "பதிவேற்றல் வழு", "Close" => "மூடுக", @@ -28,7 +29,7 @@ "{count} files uploading" => "{எண்ணிக்கை} கோப்புகள் பதிவேற்றப்படுகின்றது", "Upload cancelled." => "பதிவேற்றல் இரத்து செய்யப்பட்டுள்ளது", "File upload is in progress. Leaving the page now will cancel the upload." => "கோப்பு பதிவேற்றம் செயல்பாட்டில் உள்ளது. இந்தப் பக்கத்திலிருந்து வெறியேறுவதானது பதிவேற்றலை இரத்து செய்யும்.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "செல்லுபடியற்ற கோப்புறை பெயர். \"பகிர்வின்\" பாவனை Owncloud இனால் ஒதுக்கப்பட்டுள்ளது", +"URL cannot be empty." => "URL வெறுமையாக இருக்கமுடியாது.", "{count} files scanned" => "{எண்ணிக்கை} கோப்புகள் வருடப்பட்டது", "error while scanning" => "வருடும் போதான வழு", "Name" => "பெயர்", @@ -50,7 +51,6 @@ "Text file" => "கோப்பு உரை", "Folder" => "கோப்புறை", "From link" => "இணைப்பிலிருந்து", -"Upload" => "பதிவேற்றுக", "Cancel upload" => "பதிவேற்றலை இரத்து செய்க", "Nothing in here. Upload something!" => "இங்கு ஒன்றும் இல்லை. ஏதாவது பதிவேற்றுக!", "Download" => "பதிவிறக்குக", diff --git a/apps/files/l10n/th_TH.php b/apps/files/l10n/th_TH.php index bad817ab006a13dee7466c8ef0b07bfbe3c6fcdd..43a905ea3bc5ae63dc1a5c37b39e1ca0393118b2 100644 --- a/apps/files/l10n/th_TH.php +++ b/apps/files/l10n/th_TH.php @@ -1,4 +1,9 @@ "อัพโหลด", +"Could not move %s - File with this name already exists" => "ไม่สามารถย้าย %s ได้ - ไฟล์ที่ใช้ชื่อนี้มีอยู่แล้ว", +"Could not move %s" => "ไม่สามารถย้าย %s ได้", +"Unable to rename file" => "ไม่สามารถเปลี่ยนชื่อไฟล์ได้", +"No file was uploaded. Unknown error" => "ยังไม่มีไฟล์ใดที่ถูกอัพโหลด เกิดข้อผิดพลาดที่ไม่ทราบสาเหตุ", "There is no error, the file uploaded with success" => "ไม่มีข้อผิดพลาดใดๆ ไฟล์ถูกอัพโหลดเรียบร้อยแล้ว", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "ขนาดไฟล์ที่อัพโหลดมีขนาดเกิน upload_max_filesize ที่ระบุไว้ใน php.ini", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "ไฟล์ที่อัพโหลดมีขนาดเกินคำสั่ง MAX_FILE_SIZE ที่ระบุเอาไว้ในรูปแบบคำสั่งในภาษา HTML", @@ -6,6 +11,8 @@ "No file was uploaded" => "ยังไม่มีไฟล์ที่ถูกอัพโหลด", "Missing a temporary folder" => "แฟ้มเอกสารชั่วคราวเกิดการสูญหาย", "Failed to write to disk" => "เขียนข้อมูลลงแผ่นดิสก์ล้มเหลว", +"Not enough space available" => "มีพื้นที่เหลือไม่เพียงพอ", +"Invalid directory." => "ไดเร็กทอรี่ไม่ถูกต้อง", "Files" => "ไฟล์", "Unshare" => "ยกเลิกการแชร์ข้อมูล", "Delete" => "ลบ", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "แทนที่ {new_name} ด้วย {old_name} แล้ว", "unshared {files}" => "ยกเลิกการแชร์แล้ว {files} ไฟล์", "deleted {files}" => "ลบไฟล์แล้ว {files} ไฟล์", +"'.' is an invalid file name." => "'.' เป็นชื่อไฟล์ที่ไม่ถูกต้อง", +"File name cannot be empty." => "ชื่อไฟล์ไม่สามารถเว้นว่างได้", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "ชื่อที่ใช้ไม่ถูกต้อง, '\\', '/', '<', '>', ':', '\"', '|', '?' และ '*' ไม่ได้รับอนุญาตให้ใช้งานได้", -"generating ZIP-file, it may take some time." => "กำลังสร้างไฟล์บีบอัด ZIP อาจใช้เวลาสักครู่", +"Your download is being prepared. This might take some time if the files are big." => "กำลังเตรียมดาวน์โหลดข้อมูล หากไฟล์มีขนาดใหญ่ อาจใช้เวลาสักครู่", "Unable to upload your file as it is a directory or has 0 bytes" => "ไม่สามารถอัพโหลดไฟล์ของคุณได้ เนื่องจากไฟล์ดังกล่าวเป็นไดเร็กทอรี่หรือมีขนาด 0 ไบต์", "Upload Error" => "เกิดข้อผิดพลาดในการอัพโหลด", "Close" => "ปิด", @@ -29,7 +38,8 @@ "{count} files uploading" => "กำลังอัพโหลด {count} ไฟล์", "Upload cancelled." => "การอัพโหลดถูกยกเลิก", "File upload is in progress. Leaving the page now will cancel the upload." => "การอัพโหลดไฟล์กำลังอยู่ในระหว่างดำเนินการ การออกจากหน้าเว็บนี้จะทำให้การอัพโหลดถูกยกเลิก", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "ชื่อโฟลเดอร์ที่ใช้ไม่ถูกต้อง การใช้งาน \"ถูกแชร์\" ถูกสงวนไว้เฉพาะ Owncloud เท่านั้น", +"URL cannot be empty." => "URL ไม่สามารถเว้นว่างได้", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "ชื่อโฟลเดอร์ไม่ถูกต้อง การใช้งาน 'แชร์' สงวนไว้สำหรับ Owncloud เท่านั้น", "{count} files scanned" => "สแกนไฟล์แล้ว {count} ไฟล์", "error while scanning" => "พบข้อผิดพลาดในระหว่างการสแกนไฟล์", "Name" => "ชื่อ", @@ -51,7 +61,6 @@ "Text file" => "ไฟล์ข้อความ", "Folder" => "แฟ้มเอกสาร", "From link" => "จากลิงก์", -"Upload" => "อัพโหลด", "Cancel upload" => "ยกเลิกการอัพโหลด", "Nothing in here. Upload something!" => "ยังไม่มีไฟล์ใดๆอยู่ที่นี่ กรุณาอัพโหลดไฟล์!", "Download" => "ดาวน์โหลด", diff --git a/apps/files/l10n/tr.php b/apps/files/l10n/tr.php index 061ed1f3ae28ee7aea4f48febf9741fbaf3913d9..6b390570f307dd2777becdd4ccd67d343909c039 100644 --- a/apps/files/l10n/tr.php +++ b/apps/files/l10n/tr.php @@ -1,10 +1,18 @@ "Yükle", +"Could not move %s - File with this name already exists" => "%s taşınamadı. Bu isimde dosya zaten var.", +"Could not move %s" => "%s taşınamadı", +"Unable to rename file" => "Dosya adı değiştirilemedi", +"No file was uploaded. Unknown error" => "Dosya yüklenmedi. Bilinmeyen hata", "There is no error, the file uploaded with success" => "Bir hata yok, dosya başarıyla yüklendi", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "php.ini dosyasında upload_max_filesize ile belirtilen dosya yükleme sınırı aşıldı.", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Yüklenen dosya HTML formundaki MAX_FILE_SIZE sınırını aşıyor", "The uploaded file was only partially uploaded" => "Yüklenen dosyanın sadece bir kısmı yüklendi", "No file was uploaded" => "Hiç dosya yüklenmedi", "Missing a temporary folder" => "Geçici bir klasör eksik", "Failed to write to disk" => "Diske yazılamadı", +"Not enough space available" => "Yeterli disk alanı yok", +"Invalid directory." => "Geçersiz dizin.", "Files" => "Dosyalar", "Unshare" => "Paylaşılmayan", "Delete" => "Sil", @@ -15,20 +23,32 @@ "cancel" => "iptal", "replaced {new_name}" => "değiştirilen {new_name}", "undo" => "geri al", +"replaced {new_name} with {old_name}" => "{new_name} ismi {old_name} ile değiştirildi", "unshared {files}" => "paylaşılmamış {files}", "deleted {files}" => "silinen {files}", -"generating ZIP-file, it may take some time." => "ZIP dosyası oluşturuluyor, biraz sürebilir.", +"'.' is an invalid file name." => "'.' geçersiz dosya adı.", +"File name cannot be empty." => "Dosya adı boş olamaz.", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Geçersiz isim, '\\', '/', '<', '>', ':', '\"', '|', '?' ve '*' karakterlerine izin verilmemektedir.", +"Your download is being prepared. This might take some time if the files are big." => "İndirmeniz hazırlanıyor. Dosya büyük ise biraz zaman alabilir.", "Unable to upload your file as it is a directory or has 0 bytes" => "Dosyanızın boyutu 0 byte olduğundan veya bir dizin olduğundan yüklenemedi", "Upload Error" => "Yükleme hatası", "Close" => "Kapat", "Pending" => "Bekliyor", "1 file uploading" => "1 dosya yüklendi", +"{count} files uploading" => "{count} dosya yükleniyor", "Upload cancelled." => "Yükleme iptal edildi.", "File upload is in progress. Leaving the page now will cancel the upload." => "Dosya yükleme işlemi sürüyor. Şimdi sayfadan ayrılırsanız işleminiz iptal olur.", +"URL cannot be empty." => "URL boş olamaz.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "Geçersiz dizin adı. Shared isminin kullanımı Owncloud tarafından rezerver edilmiştir.", +"{count} files scanned" => "{count} dosya tarandı", "error while scanning" => "tararamada hata oluşdu", "Name" => "Ad", "Size" => "Boyut", "Modified" => "Değiştirilme", +"1 folder" => "1 dizin", +"{count} folders" => "{count} dizin", +"1 file" => "1 dosya", +"{count} files" => "{count} dosya", "File handling" => "Dosya taşıma", "Maximum upload size" => "Maksimum yükleme boyutu", "max. possible: " => "mümkün olan en fazla: ", @@ -40,7 +60,7 @@ "New" => "Yeni", "Text file" => "Metin dosyası", "Folder" => "Klasör", -"Upload" => "Yükle", +"From link" => "Bağlantıdan", "Cancel upload" => "Yüklemeyi iptal et", "Nothing in here. Upload something!" => "Burada hiçbir şey yok. Birşeyler yükleyin!", "Download" => "İndir", diff --git a/apps/files/l10n/uk.php b/apps/files/l10n/uk.php index 00491bcc2d6d6ece35f01741d24d56e608387fde..f1279bc77c8d5653021b0ee84f511d6b369bc063 100644 --- a/apps/files/l10n/uk.php +++ b/apps/files/l10n/uk.php @@ -1,4 +1,6 @@ "Відвантажити", +"No file was uploaded. Unknown error" => "Не завантажено жодного файлу. Невідома помилка", "There is no error, the file uploaded with success" => "Файл успішно вивантажено без помилок.", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "Розмір звантаження перевищує upload_max_filesize параметра в php.ini: ", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Розмір відвантаженого файлу перевищує директиву MAX_FILE_SIZE вказану в HTML формі", @@ -20,7 +22,6 @@ "unshared {files}" => "неопубліковано {files}", "deleted {files}" => "видалено {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Невірне ім'я, '\\', '/', '<', '>', ':', '\"', '|', '?' та '*' не дозволені.", -"generating ZIP-file, it may take some time." => "Створення ZIP-файлу, це може зайняти певний час.", "Unable to upload your file as it is a directory or has 0 bytes" => "Неможливо завантажити ваш файл тому, що він тека або файл розміром 0 байт", "Upload Error" => "Помилка завантаження", "Close" => "Закрити", @@ -29,7 +30,7 @@ "{count} files uploading" => "{count} файлів завантажується", "Upload cancelled." => "Завантаження перервано.", "File upload is in progress. Leaving the page now will cancel the upload." => "Виконується завантаження файлу. Закриття цієї сторінки приведе до відміни завантаження.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Невірне ім'я каталогу. Використання \"Shared\" зарезервовано Owncloud", +"URL cannot be empty." => "URL не може бути пустим.", "{count} files scanned" => "{count} файлів проскановано", "error while scanning" => "помилка при скануванні", "Name" => "Ім'я", @@ -51,7 +52,6 @@ "Text file" => "Текстовий файл", "Folder" => "Папка", "From link" => "З посилання", -"Upload" => "Відвантажити", "Cancel upload" => "Перервати завантаження", "Nothing in here. Upload something!" => "Тут нічого немає. Відвантажте що-небудь!", "Download" => "Завантажити", diff --git a/apps/files/l10n/vi.php b/apps/files/l10n/vi.php index 4f58e623178cd2789afb17a87259c5fa7c943455..dcaf8900014881afe8d09d05213df6bb6c4a3354 100644 --- a/apps/files/l10n/vi.php +++ b/apps/files/l10n/vi.php @@ -1,4 +1,6 @@ "Tải lên", +"No file was uploaded. Unknown error" => "Không có tập tin nào được tải lên. Lỗi không xác định", "There is no error, the file uploaded with success" => "Không có lỗi, các tập tin đã được tải lên thành công", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "Kích thước những tập tin tải lên vượt quá MAX_FILE_SIZE đã được quy định", "The uploaded file was only partially uploaded" => "Tập tin tải lên mới chỉ tải lên được một phần", @@ -19,7 +21,6 @@ "unshared {files}" => "hủy chia sẽ {files}", "deleted {files}" => "đã xóa {files}", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "Tên không hợp lệ, '\\', '/', '<', '>', ':', '\"', '|', '?' và '*' thì không được phép dùng.", -"generating ZIP-file, it may take some time." => "Tạo tập tin ZIP, điều này có thể làm mất một chút thời gian", "Unable to upload your file as it is a directory or has 0 bytes" => "Không thể tải lên tập tin này do nó là một thư mục hoặc kích thước tập tin bằng 0 byte", "Upload Error" => "Tải lên lỗi", "Close" => "Đóng", @@ -28,7 +29,7 @@ "{count} files uploading" => "{count} tập tin đang tải lên", "Upload cancelled." => "Hủy tải lên", "File upload is in progress. Leaving the page now will cancel the upload." => "Tập tin tải lên đang được xử lý. Nếu bạn rời khỏi trang bây giờ sẽ hủy quá trình này.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "Tên thư mục không hợp lệ. Sử dụng \"Chia sẻ\" được dành riêng bởi Owncloud", +"URL cannot be empty." => "URL không được để trống.", "{count} files scanned" => "{count} tập tin đã được quét", "error while scanning" => "lỗi trong khi quét", "Name" => "Tên", @@ -50,7 +51,6 @@ "Text file" => "Tập tin văn bản", "Folder" => "Thư mục", "From link" => "Từ liên kết", -"Upload" => "Tải lên", "Cancel upload" => "Hủy upload", "Nothing in here. Upload something!" => "Không có gì ở đây .Hãy tải lên một cái gì đó !", "Download" => "Tải xuống", diff --git a/apps/files/l10n/zh_CN.GB2312.php b/apps/files/l10n/zh_CN.GB2312.php index ccf0efff0500330677ef09c69fa791defcc83fe2..4416ce9a4a2e4635dba77228e309eacbb958d934 100644 --- a/apps/files/l10n/zh_CN.GB2312.php +++ b/apps/files/l10n/zh_CN.GB2312.php @@ -1,4 +1,6 @@ "上传", +"No file was uploaded. Unknown error" => "没有上传文件。未知错误", "There is no error, the file uploaded with success" => "没有任何错误,文件上传成功了", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "上传的文件超过了HTML表单指定的MAX_FILE_SIZE", "The uploaded file was only partially uploaded" => "文件只有部分被上传", @@ -18,7 +20,6 @@ "replaced {new_name} with {old_name}" => "已用 {old_name} 替换 {new_name}", "unshared {files}" => "未分享的 {files}", "deleted {files}" => "已删除的 {files}", -"generating ZIP-file, it may take some time." => "正在生成ZIP文件,这可能需要点时间", "Unable to upload your file as it is a directory or has 0 bytes" => "不能上传你指定的文件,可能因为它是个文件夹或者大小为0", "Upload Error" => "上传错误", "Close" => "关闭", @@ -27,6 +28,7 @@ "{count} files uploading" => "{count} 个文件正在上传", "Upload cancelled." => "上传取消了", "File upload is in progress. Leaving the page now will cancel the upload." => "文件正在上传。关闭页面会取消上传。", +"URL cannot be empty." => "网址不能为空。", "{count} files scanned" => "{count} 个文件已扫描", "error while scanning" => "扫描出错", "Name" => "名字", @@ -48,7 +50,6 @@ "Text file" => "文本文档", "Folder" => "文件夹", "From link" => "来自链接", -"Upload" => "上传", "Cancel upload" => "取消上传", "Nothing in here. Upload something!" => "这里没有东西.上传点什么!", "Download" => "下载", diff --git a/apps/files/l10n/zh_CN.php b/apps/files/l10n/zh_CN.php index 8db652f003e31db998dff1f765217c9098566688..f8dedc118e0d93915c065d801199772ba9722813 100644 --- a/apps/files/l10n/zh_CN.php +++ b/apps/files/l10n/zh_CN.php @@ -1,4 +1,9 @@ "上传", +"Could not move %s - File with this name already exists" => "无法移动 %s - 同名文件已存在", +"Could not move %s" => "无法移动 %s", +"Unable to rename file" => "无法重命名文件", +"No file was uploaded. Unknown error" => "没有文件被上传。未知错误", "There is no error, the file uploaded with success" => "没有发生错误,文件上传成功。", "The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "上传文件大小已超过php.ini中upload_max_filesize所规定的值", "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "上传的文件超过了在HTML 表单中指定的MAX_FILE_SIZE", @@ -6,6 +11,8 @@ "No file was uploaded" => "文件没有上传", "Missing a temporary folder" => "缺少临时目录", "Failed to write to disk" => "写入磁盘失败", +"Not enough space available" => "没有足够可用空间", +"Invalid directory." => "无效文件夹。", "Files" => "文件", "Unshare" => "取消分享", "Delete" => "删除", @@ -19,8 +26,10 @@ "replaced {new_name} with {old_name}" => "已将 {old_name}替换成 {new_name}", "unshared {files}" => "取消了共享 {files}", "deleted {files}" => "删除了 {files}", +"'.' is an invalid file name." => "'.' 是一个无效的文件名。", +"File name cannot be empty." => "文件名不能为空。", "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "无效名称,'\\', '/', '<', '>', ':', '\"', '|', '?' 和 '*' 不被允许使用。", -"generating ZIP-file, it may take some time." => "正在生成 ZIP 文件,可能需要一些时间", +"Your download is being prepared. This might take some time if the files are big." => "下载正在准备中。如果文件较大可能会花费一些时间。", "Unable to upload your file as it is a directory or has 0 bytes" => "无法上传文件,因为它是一个目录或者大小为 0 字节", "Upload Error" => "上传错误", "Close" => "关闭", @@ -29,7 +38,8 @@ "{count} files uploading" => "{count} 个文件上传中", "Upload cancelled." => "上传已取消", "File upload is in progress. Leaving the page now will cancel the upload." => "文件正在上传中。现在离开此页会导致上传动作被取消。", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "无效的文件夹名称。”Shared“ 是 Owncloud 保留字符。", +"URL cannot be empty." => "URL不能为空", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "无效文件夹名。'共享' 是 Owncloud 预留的文件夹名。", "{count} files scanned" => "{count} 个文件已扫描。", "error while scanning" => "扫描时出错", "Name" => "名称", @@ -51,7 +61,6 @@ "Text file" => "文本文件", "Folder" => "文件夹", "From link" => "来自链接", -"Upload" => "上传", "Cancel upload" => "取消上传", "Nothing in here. Upload something!" => "这里还什么都没有。上传些东西吧!", "Download" => "下载", diff --git a/apps/files/l10n/zh_TW.php b/apps/files/l10n/zh_TW.php index 5333209eff79f1e4ac714096b5ab3cd5b83b33db..2bf15af1c426b764031fb8fc3f73e357007699f6 100644 --- a/apps/files/l10n/zh_TW.php +++ b/apps/files/l10n/zh_TW.php @@ -1,29 +1,46 @@ "上傳", +"Could not move %s - File with this name already exists" => "無法移動 %s - 同名的檔案已經存在", +"Could not move %s" => "無法移動 %s", +"Unable to rename file" => "無法重新命名檔案", +"No file was uploaded. Unknown error" => "沒有檔案被上傳。未知的錯誤。", "There is no error, the file uploaded with success" => "無錯誤,檔案上傳成功", -"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "上傳黨案的超過 HTML 表單中指定 MAX_FILE_SIZE 限制", -"The uploaded file was only partially uploaded" => "只有部分檔案被上傳", +"The uploaded file exceeds the upload_max_filesize directive in php.ini: " => "上傳的檔案大小超過 php.ini 當中 upload_max_filesize 參數的設定:", +"The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form" => "上傳的檔案大小超過 HTML 表單中 MAX_FILE_SIZE 的限制", +"The uploaded file was only partially uploaded" => "只有檔案的一部分被上傳", "No file was uploaded" => "無已上傳檔案", "Missing a temporary folder" => "遺失暫存資料夾", "Failed to write to disk" => "寫入硬碟失敗", +"Not enough space available" => "沒有足夠的可用空間", +"Invalid directory." => "無效的資料夾。", "Files" => "檔案", "Unshare" => "取消共享", "Delete" => "刪除", "Rename" => "重新命名", "{new_name} already exists" => "{new_name} 已經存在", "replace" => "取代", +"suggest name" => "建議檔名", "cancel" => "取消", "replaced {new_name}" => "已取代 {new_name}", "undo" => "復原", "replaced {new_name} with {old_name}" => "使用 {new_name} 取代 {old_name}", -"generating ZIP-file, it may take some time." => "產生壓縮檔, 它可能需要一段時間.", +"unshared {files}" => "已取消分享 {files}", +"deleted {files}" => "已刪除 {files}", +"'.' is an invalid file name." => "'.' 是不合法的檔名。", +"File name cannot be empty." => "檔名不能為空。", +"Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed." => "檔名不合法,不允許 '\\', '/', '<', '>', ':', '\"', '|', '?' 和 '*' 。", +"Your download is being prepared. This might take some time if the files are big." => "正在準備您的下載,若您的檔案較大,將會需要更多時間。", "Unable to upload your file as it is a directory or has 0 bytes" => "無法上傳您的檔案因為它可能是一個目錄或檔案大小為0", "Upload Error" => "上傳發生錯誤", "Close" => "關閉", +"Pending" => "等候中", "1 file uploading" => "1 個檔案正在上傳", "{count} files uploading" => "{count} 個檔案正在上傳", "Upload cancelled." => "上傳取消", -"File upload is in progress. Leaving the page now will cancel the upload." => "檔案上傳中. 離開此頁面將會取消上傳.", -"Invalid folder name. Usage of \"Shared\" is reserved by Owncloud" => "無效的資料夾名稱. \"Shared\" 名稱已被 Owncloud 所保留使用", +"File upload is in progress. Leaving the page now will cancel the upload." => "檔案上傳中。離開此頁面將會取消上傳。", +"URL cannot be empty." => "URL 不能為空白.", +"Invalid folder name. Usage of 'Shared' is reserved by Owncloud" => "無效的資料夾名稱,'Shared' 的使用被 Owncloud 保留", +"{count} files scanned" => "{count} 個檔案已掃描", "error while scanning" => "掃描時發生錯誤", "Name" => "名稱", "Size" => "大小", @@ -33,22 +50,22 @@ "1 file" => "1 個檔案", "{count} files" => "{count} 個檔案", "File handling" => "檔案處理", -"Maximum upload size" => "最大上傳容量", -"max. possible: " => "最大允許: ", -"Needed for multi-file and folder downloads." => "針對多檔案和目錄下載是必填的", +"Maximum upload size" => "最大上傳檔案大小", +"max. possible: " => "最大允許:", +"Needed for multi-file and folder downloads." => "針對多檔案和目錄下載是必填的。", "Enable ZIP-download" => "啟用 Zip 下載", "0 is unlimited" => "0代表沒有限制", -"Maximum input size for ZIP files" => "針對ZIP檔案最大輸入大小", +"Maximum input size for ZIP files" => "針對 ZIP 檔案最大輸入大小", "Save" => "儲存", "New" => "新增", "Text file" => "文字檔", "Folder" => "資料夾", -"Upload" => "上傳", +"From link" => "從連結", "Cancel upload" => "取消上傳", -"Nothing in here. Upload something!" => "沒有任何東西。請上傳內容!", +"Nothing in here. Upload something!" => "沒有任何東西。請上傳內容!", "Download" => "下載", "Upload too large" => "上傳過大", -"The files you are trying to upload exceed the maximum size for file uploads on this server." => "你試圖上傳的檔案已超過伺服器的最大容量限制。 ", +"The files you are trying to upload exceed the maximum size for file uploads on this server." => "您試圖上傳的檔案已超過伺服器的最大檔案大小限制。 ", "Files are being scanned, please wait." => "正在掃描檔案,請稍等。", "Current scanning" => "目前掃描" ); diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php new file mode 100644 index 0000000000000000000000000000000000000000..f2b1f142e9b81bd745393c19b22e3ee27783cda2 --- /dev/null +++ b/apps/files/lib/helper.php @@ -0,0 +1,20 @@ +t('Upload') . ' max. ' . $maxHumanFilesize; + + // information about storage capacities + $storageInfo = \OC_Helper::getStorageInfo(); + + return array('uploadMaxFilesize' => $maxUploadFilesize, + 'maxHumanFilesize' => $maxHumanFilesize, + 'usedSpacePercent' => (int)$storageInfo['relative']); + } +} diff --git a/apps/files/templates/admin.php b/apps/files/templates/admin.php index 0de12edcba577a2dbe3294751753e507260981fc..ad69b5519d9a616a354256f4aea247ce3428d5b0 100644 --- a/apps/files/templates/admin.php +++ b/apps/files/templates/admin.php @@ -6,7 +6,10 @@ '/> - (t('max. possible: '); echo $_['maxPossibleUploadSize'] ?>)
+ + (t('max. possible: '); echo $_['maxPossibleUploadSize'] ?>) + +

t('From link');?>

-
+
- - - +
@@ -52,7 +50,6 @@
-
t('Nothing in here. Upload something!')?>
@@ -117,3 +114,4 @@ + diff --git a/apps/files/templates/part.breadcrumb.php b/apps/files/templates/part.breadcrumb.php index f7b1a6076d894d1455e4770c3e48937e2e4f611c..7df2afc1f52ea6b8ef1c0f2f3b9495b418663c53 100644 --- a/apps/files/templates/part.breadcrumb.php +++ b/apps/files/templates/part.breadcrumb.php @@ -1,9 +1,10 @@ - -
svg" - data-dir='' - style='background-image:url("")'> - -
- +
svg" + data-dir='' + style='background-image:url("")'> + +
+ - - var publicListView = true; + + +200) $relative_date_color = 200; + $name = str_replace('+', '%20', urlencode($file['name'])); + $name = str_replace('%2F', '/', $name); + $directory = str_replace('+', '%20', urlencode($file['directory'])); + $directory = str_replace('%2F', '/', $directory); ?> + ' + data-permissions=''> + + style="background-image:url()" - var publicListView = false; + style="background-image:url()" - - - 200) $relative_date_color = 200; - $name = str_replace('+', '%20', urlencode($file['name'])); - $name = str_replace('%2F', '/', $name); - $directory = str_replace('+', '%20', urlencode($file['directory'])); - $directory = str_replace('%2F', '/', $directory); ?> - ' - data-permissions=''> - - style="background-image:url()" - - style="background-image:url()" - - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +use OCA\Encryption\Keymanager; + +OCP\JSON::checkAppEnabled('files_encryption'); +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + +$mode = $_POST['mode']; +$changePasswd = false; +$passwdChanged = false; + +if ( isset($_POST['newpasswd']) && isset($_POST['oldpasswd']) ) { + $oldpasswd = $_POST['oldpasswd']; + $newpasswd = $_POST['newpasswd']; + $changePasswd = true; + $passwdChanged = Keymanager::changePasswd($oldpasswd, $newpasswd); +} + +$query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" ); +$result = $query->execute(array(\OCP\User::getUser())); + +if ($result->fetchRow()){ + $query = OC_DB::prepare( 'UPDATE *PREFIX*encryption SET mode = ? WHERE uid = ?' ); +} else { + $query = OC_DB::prepare( 'INSERT INTO *PREFIX*encryption ( mode, uid ) VALUES( ?, ? )' ); +} + +if ( (!$changePasswd || $passwdChanged) && $query->execute(array($mode, \OCP\User::getUser())) ) { + OCP\JSON::success(); +} else { + OCP\JSON::error(); +} \ No newline at end of file diff --git a/apps/files_encryption/appinfo/app.php b/apps/files_encryption/appinfo/app.php index 2a30d0beb67af5316678d70e5c0e852b2c13a4f9..31b430d37a9fbc5c177abff55432689ba445d581 100644 --- a/apps/files_encryption/appinfo/app.php +++ b/apps/files_encryption/appinfo/app.php @@ -1,21 +1,37 @@ getPrivateKey( \OCP\USER::getUser() ) +&& OCP\User::isLoggedIn() +&& OCA\Encryption\Crypt::mode() == 'server' +) { + + // Force the user to re-log in if the encryption key isn't unlocked (happens when a user is logged in before the encryption app is enabled) OCP\User::logout(); - header("Location: ".OC::$WEBROOT.'/'); + + header( "Location: " . OC::$WEBROOT.'/' ); + exit(); + } -OCP\App::registerAdmin('files_encryption', 'settings'); \ No newline at end of file +OCP\App::registerAdmin( 'files_encryption', 'settings'); +OCP\App::registerPersonal( 'files_encryption', 'settings-personal' ); \ No newline at end of file diff --git a/apps/files_encryption/appinfo/database.xml b/apps/files_encryption/appinfo/database.xml new file mode 100644 index 0000000000000000000000000000000000000000..d294c35d63d0052e14cc188cebb3603822113aac --- /dev/null +++ b/apps/files_encryption/appinfo/database.xml @@ -0,0 +1,24 @@ + + + *dbname* + true + false + utf8 + + *dbprefix*encryption + + + uid + text + true + 64 + + + mode + text + true + 64 + + +
+
\ No newline at end of file diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml index 48a28fde78a9c42a8862834cb948fb5e52df11ae..39ea155488f4f1944a152cc4b85b49bd0394b5fb 100644 --- a/apps/files_encryption/appinfo/info.xml +++ b/apps/files_encryption/appinfo/info.xml @@ -2,10 +2,10 @@ files_encryption Encryption - Server side encryption of files. DEPRECATED. This app is no longer supported and will be replaced with an improved version in ownCloud 5. Only enable this features if you want to read old encrypted data. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP. + Server side encryption of files. Warning: You will lose your data if you enable this App and forget your password. Encryption is not yet compatible with LDAP. AGPL - Robin Appelman - 4.9 + Sam Tuke + 4 true diff --git a/apps/files_encryption/appinfo/version b/apps/files_encryption/appinfo/version index 2f4536184bcac31936bd15a5f9cf931dd526c022..7dff5b8921122a487162febe3c8e32effb7acb35 100644 --- a/apps/files_encryption/appinfo/version +++ b/apps/files_encryption/appinfo/version @@ -1 +1 @@ -0.2 \ No newline at end of file +0.2.1 \ No newline at end of file diff --git a/apps/files_encryption/hooks/hooks.php b/apps/files_encryption/hooks/hooks.php new file mode 100644 index 0000000000000000000000000000000000000000..c2f97247835331d63f189acb864f43616a147d3c --- /dev/null +++ b/apps/files_encryption/hooks/hooks.php @@ -0,0 +1,143 @@ +. + * + */ + +namespace OCA\Encryption; + +/** + * Class for hook specific logic + */ + +class Hooks { + + # TODO: use passphrase for encrypting private key that is separate to the login password + + /** + * @brief Startup encryption backend upon user login + * @note This method should never be called for users using client side encryption + */ + public static function login( $params ) { + +// if ( Crypt::mode( $params['uid'] ) == 'server' ) { + + # TODO: use lots of dependency injection here + + $view = new \OC_FilesystemView( '/' ); + + $util = new Util( $view, $params['uid'] ); + + if ( ! $util->ready() ) { + + \OC_Log::write( 'Encryption library', 'User account "' . $params['uid'] . '" is not ready for encryption; configuration started' , \OC_Log::DEBUG ); + + return $util->setupServerSide( $params['password'] ); + + } + + \OC_FileProxy::$enabled = false; + + $encryptedKey = Keymanager::getPrivateKey( $view, $params['uid'] ); + + \OC_FileProxy::$enabled = true; + + # TODO: dont manually encrypt the private keyfile - use the config options of openssl_pkey_export instead for better mobile compatibility + + $privateKey = Crypt::symmetricDecryptFileContent( $encryptedKey, $params['password'] ); + + $session = new Session(); + + $session->setPrivateKey( $privateKey, $params['uid'] ); + + $view1 = new \OC_FilesystemView( '/' . $params['uid'] ); + + // Set legacy encryption key if it exists, to support + // depreciated encryption system + if ( + $view1->file_exists( 'encryption.key' ) + && $legacyKey = $view1->file_get_contents( 'encryption.key' ) + ) { + + $_SESSION['legacyenckey'] = Crypt::legacyDecrypt( $legacyKey, $params['password'] ); + + } +// } + + return true; + + } + + /** + * @brief Change a user's encryption passphrase + * @param array $params keys: uid, password + */ + public static function setPassphrase( $params ) { + + // Only attempt to change passphrase if server-side encryption + // is in use (client-side encryption does not have access to + // the necessary keys) + if ( Crypt::mode() == 'server' ) { + + // Get existing decrypted private key + $privateKey = $_SESSION['privateKey']; + + // Encrypt private key with new user pwd as passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $privateKey, $params['password'] ); + + // Save private key + Keymanager::setPrivateKey( $encryptedPrivateKey ); + + # NOTE: Session does not need to be updated as the + # private key has not changed, only the passphrase + # used to decrypt it has changed + + } + + } + + /** + * @brief update the encryption key of the file uploaded by the client + */ + public static function updateKeyfile( $params ) { + + if ( Crypt::mode() == 'client' ) { + + if ( isset( $params['properties']['key'] ) ) { + + Keymanager::setFileKey( $params['path'], $params['properties']['key'] ); + + } else { + + \OC_Log::write( + 'Encryption library', "Client side encryption is enabled but the client doesn't provide a encryption key for the file!" + , \OC_Log::ERROR + ); + + error_log( "Client side encryption is enabled but the client doesn't provide an encryption key for the file!" ); + + } + + } + + } + +} + +?> \ No newline at end of file diff --git a/apps/files_encryption/js/settings-personal.js b/apps/files_encryption/js/settings-personal.js new file mode 100644 index 0000000000000000000000000000000000000000..1a53e99d2b4da326c10710ac2cb14617e3c68070 --- /dev/null +++ b/apps/files_encryption/js/settings-personal.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2012, Bjoern Schiessle + * This file is licensed under the Affero General Public License version 3 or later. + * See the COPYING-README file. + */ + +$(document).ready(function(){ + $('input[name=encryption_mode]').change(function(){ + var prevmode = document.getElementById('prev_encryption_mode').value + var client=$('input[value="client"]:checked').val() + ,server=$('input[value="server"]:checked').val() + ,user=$('input[value="user"]:checked').val() + ,none=$('input[value="none"]:checked').val() + if (client) { + $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'client' }); + if (prevmode == 'server') { + OC.dialogs.info(t('encryption', 'Please switch to your ownCloud client and change your encryption password to complete the conversion.'), t('encryption', 'switched to client side encryption')); + } + } else if (server) { + if (prevmode == 'client') { + OC.dialogs.form([{text:'Login password', name:'newpasswd', type:'password'},{text:'Encryption password used on the client', name:'oldpasswd', type:'password'}],t('encryption', 'Change encryption password to login password'), function(data) { + $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'server', newpasswd: data[0].value, oldpasswd: data[1].value }, function(result) { + if (result.status != 'success') { + document.getElementById(prevmode+'_encryption').checked = true; + OC.dialogs.alert(t('encryption', 'Please check your passwords and try again.'), t('encryption', 'Could not change your file encryption password to your login password')) + } else { + console.log("alles super"); + } + }, true); + }); + } else { + $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'server' }); + } + } else { + $.post(OC.filePath('files_encryption', 'ajax', 'mode.php'), { mode: 'none' }); + } + }) +}) \ No newline at end of file diff --git a/apps/files_encryption/js/settings.js b/apps/files_encryption/js/settings.js index 6fc70eba7f6af8c45592b2bd511b773d37755363..60563bde859cd59683bbb7706fb4c0992b3523f9 100644 --- a/apps/files_encryption/js/settings.js +++ b/apps/files_encryption/js/settings.js @@ -11,14 +11,36 @@ $(document).ready(function(){ onuncheck:blackListChange, createText:'...', }); - + function blackListChange(){ var blackList=$('#encryption_blacklist').val().join(','); OC.AppConfig.setValue('files_encryption','type_blacklist',blackList); } - $('#enable_encryption').change(function(){ - var checked=$('#enable_encryption').is(':checked'); - OC.AppConfig.setValue('files_encryption','enable_encryption',(checked)?'true':'false'); - }); -}); + //TODO: Handle switch between client and server side encryption + $('input[name=encryption_mode]').change(function(){ + var client=$('input[value="client"]:checked').val() + ,server=$('input[value="server"]:checked').val() + ,user=$('input[value="user"]:checked').val() + ,none=$('input[value="none"]:checked').val() + ,disable=false + if (client) { + OC.AppConfig.setValue('files_encryption','mode','client'); + disable = true; + } else if (server) { + OC.AppConfig.setValue('files_encryption','mode','server'); + disable = true; + } else if (user) { + OC.AppConfig.setValue('files_encryption','mode','user'); + disable = true; + } else { + OC.AppConfig.setValue('files_encryption','mode','none'); + } + if (disable) { + document.getElementById('server_encryption').disabled = true; + document.getElementById('client_encryption').disabled = true; + document.getElementById('user_encryption').disabled = true; + document.getElementById('none_encryption').disabled = true; + } + }) +}) \ No newline at end of file diff --git a/apps/files_encryption/l10n/ar.php b/apps/files_encryption/l10n/ar.php index 756a9d72799163ead8949eaaa973d848794d5a8a..f08585e485f18faf6d35e4b14b7ce831b1f88bbf 100644 --- a/apps/files_encryption/l10n/ar.php +++ b/apps/files_encryption/l10n/ar.php @@ -1,6 +1,5 @@ "التشفير", "Exclude the following file types from encryption" => "استبعد أنواع الملفات التالية من التشفير", -"None" => "لا شيء", -"Enable Encryption" => "تفعيل التشفير" +"None" => "لا شيء" ); diff --git a/apps/files_encryption/l10n/bg_BG.php b/apps/files_encryption/l10n/bg_BG.php new file mode 100644 index 0000000000000000000000000000000000000000..4ceee127af1be0674c4544f534712f0574cb637b --- /dev/null +++ b/apps/files_encryption/l10n/bg_BG.php @@ -0,0 +1,5 @@ + "Криптиране", +"Exclude the following file types from encryption" => "Изключване на следните файлови типове от криптирането", +"None" => "Няма" +); diff --git a/apps/files_encryption/l10n/bn_BD.php b/apps/files_encryption/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..29c486b8ca06e3d3db8609ba2ace6e8085833964 --- /dev/null +++ b/apps/files_encryption/l10n/bn_BD.php @@ -0,0 +1,5 @@ + "সংকেতায়ন", +"Exclude the following file types from encryption" => "সংকেতায়ন থেকে নিম্নোক্ত ধরণসমূহ বাদ দাও", +"None" => "কোনটিই নয়" +); diff --git a/apps/files_encryption/l10n/ca.php b/apps/files_encryption/l10n/ca.php index 8e087b34620b2c5415b72acfa78acc7e890fa591..56c81e747f7c823ae8b7e54d1040fc36196ba926 100644 --- a/apps/files_encryption/l10n/ca.php +++ b/apps/files_encryption/l10n/ca.php @@ -1,6 +1,16 @@ "Connecteu-vos al client ownCloud i canvieu la contrasenya d'encriptació per completar la conversió.", +"switched to client side encryption" => "s'ha commutat a l'encriptació per part del client", +"Change encryption password to login password" => "Canvia la contrasenya d'encriptació per la d'accés", +"Please check your passwords and try again." => "Comproveu les contrasenyes i proveu-ho de nou.", +"Could not change your file encryption password to your login password" => "No s'ha pogut canviar la contrasenya d'encriptació de fitxers per la d'accés", +"Choose encryption mode:" => "Escolliu el mode d'encriptació:", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Encriptació per part del client (més segura però fa impossible l'accés a les dades des de la interfície web)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Encriptació per part del servidor (permet accedir als fitxers des de la interfície web i des del client d'escriptori)", +"None (no encryption at all)" => "Cap (sense encriptació)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Important: quan seleccioneu un mode d'encriptació no hi ha manera de canviar-lo de nou", +"User specific (let the user decide)" => "Específic per usuari (permet que l'usuari ho decideixi)", "Encryption" => "Encriptatge", "Exclude the following file types from encryption" => "Exclou els tipus de fitxers següents de l'encriptatge", -"None" => "Cap", -"Enable Encryption" => "Activa l'encriptatge" +"None" => "Cap" ); diff --git a/apps/files_encryption/l10n/cs_CZ.php b/apps/files_encryption/l10n/cs_CZ.php index 9be2be98092114f5107515a396b958c5ebb4c41d..5948a9b82e802b9c5ac8ccbcd382b3f80fcb18a2 100644 --- a/apps/files_encryption/l10n/cs_CZ.php +++ b/apps/files_encryption/l10n/cs_CZ.php @@ -1,6 +1,16 @@ "Prosím přejděte na svého klienta ownCloud a nastavte šifrovací heslo pro dokončení konverze.", +"switched to client side encryption" => "přepnuto na šifrování na straně klienta", +"Change encryption password to login password" => "Změnit šifrovací heslo na přihlašovací", +"Please check your passwords and try again." => "Zkontrolujte, prosím, své heslo a zkuste to znovu.", +"Could not change your file encryption password to your login password" => "Nelze změnit šifrovací heslo na přihlašovací.", +"Choose encryption mode:" => "Vyberte režim šifrování:", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Šifrování na straně klienta (nejbezpečnější ale neumožňuje vám přistupovat k souborům z webového rozhraní)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Šifrování na straně serveru (umožňuje vám přistupovat k souborům pomocí webového rozhraní i aplikací)", +"None (no encryption at all)" => "Žádný (vůbec žádné šifrování)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Důležité: jak si jednou vyberete režim šifrování nelze jej opětovně změnit", +"User specific (let the user decide)" => "Definován uživatelem (umožní uživateli si vybrat)", "Encryption" => "Šifrování", "Exclude the following file types from encryption" => "Při šifrování vynechat následující typy souborů", -"None" => "Žádné", -"Enable Encryption" => "Povolit šifrování" +"None" => "Žádné" ); diff --git a/apps/files_encryption/l10n/da.php b/apps/files_encryption/l10n/da.php index 144c9f97084f6768bda1bce92d4515b50d05b1dd..1b4664ce1cb205cb93a83ad7b524a1750f84c4c4 100644 --- a/apps/files_encryption/l10n/da.php +++ b/apps/files_encryption/l10n/da.php @@ -1,6 +1,5 @@ "Kryptering", "Exclude the following file types from encryption" => "Ekskluder følgende filtyper fra kryptering", -"None" => "Ingen", -"Enable Encryption" => "Aktivér kryptering" +"None" => "Ingen" ); diff --git a/apps/files_encryption/l10n/de.php b/apps/files_encryption/l10n/de.php index d486a82322bb7f4c1e6f73ce9976d2ada7d60747..34c596dc4bbbea458d3fb660354638ac8000b91a 100644 --- a/apps/files_encryption/l10n/de.php +++ b/apps/files_encryption/l10n/de.php @@ -1,6 +1,5 @@ "Verschlüsselung", "Exclude the following file types from encryption" => "Die folgenden Dateitypen von der Verschlüsselung ausnehmen", -"None" => "Keine", -"Enable Encryption" => "Verschlüsselung aktivieren" +"None" => "Keine" ); diff --git a/apps/files_encryption/l10n/de_DE.php b/apps/files_encryption/l10n/de_DE.php index d486a82322bb7f4c1e6f73ce9976d2ada7d60747..261c52a75f729ae32232c5dc190048ae4b1a677d 100644 --- a/apps/files_encryption/l10n/de_DE.php +++ b/apps/files_encryption/l10n/de_DE.php @@ -1,6 +1,8 @@ "Wählen Sie die Verschlüsselungsart:", +"None (no encryption at all)" => "Keine (ohne Verschlüsselung)", +"User specific (let the user decide)" => "Benutzerspezifisch (der Benutzer kann entscheiden)", "Encryption" => "Verschlüsselung", "Exclude the following file types from encryption" => "Die folgenden Dateitypen von der Verschlüsselung ausnehmen", -"None" => "Keine", -"Enable Encryption" => "Verschlüsselung aktivieren" +"None" => "Keine" ); diff --git a/apps/files_encryption/l10n/el.php b/apps/files_encryption/l10n/el.php index 40a7c6a367253dcdbd759d67f4b8972a4b25d1ec..50b812c82dffe0647cb83db5cdcf47c045e8fccf 100644 --- a/apps/files_encryption/l10n/el.php +++ b/apps/files_encryption/l10n/el.php @@ -1,6 +1,9 @@ "Αλλαγή συνθηματικού κρυπτογράφησης στο συνθηματικό εισόδου ", +"Please check your passwords and try again." => "Παρακαλώ ελέγξτε το συνθηματικό σας και προσπαθήστε ξανά.", +"Could not change your file encryption password to your login password" => "Αδυναμία αλλαγής συνθηματικού κρυπτογράφησης αρχείων στο συνθηματικό εισόδου σας", +"Choose encryption mode:" => "Επιλογή κατάστασης κρυπτογράφησης:", "Encryption" => "Κρυπτογράφηση", "Exclude the following file types from encryption" => "Εξαίρεση των παρακάτω τύπων αρχείων από την κρυπτογράφηση", -"None" => "Καμία", -"Enable Encryption" => "Ενεργοποίηση Κρυπτογράφησης" +"None" => "Καμία" ); diff --git a/apps/files_encryption/l10n/eo.php b/apps/files_encryption/l10n/eo.php index af3c9ae98e4dcbf39f846429d0d4cddfd5406097..c6f82dcb8a02a4fcd85bd40d18ecc5893d4db644 100644 --- a/apps/files_encryption/l10n/eo.php +++ b/apps/files_encryption/l10n/eo.php @@ -1,6 +1,5 @@ "Ĉifrado", "Exclude the following file types from encryption" => "Malinkluzivigi la jenajn dosiertipojn el ĉifrado", -"None" => "Nenio", -"Enable Encryption" => "Kapabligi ĉifradon" +"None" => "Nenio" ); diff --git a/apps/files_encryption/l10n/es.php b/apps/files_encryption/l10n/es.php index b7e7601b35f8c5e609ad837d23b0055f6cecd1e8..1fea54ff35896029135f3a6be0f1dbe83460c977 100644 --- a/apps/files_encryption/l10n/es.php +++ b/apps/files_encryption/l10n/es.php @@ -1,6 +1,5 @@ "Cifrado", "Exclude the following file types from encryption" => "Excluir del cifrado los siguientes tipos de archivo", -"None" => "Ninguno", -"Enable Encryption" => "Habilitar cifrado" +"None" => "Ninguno" ); diff --git a/apps/files_encryption/l10n/es_AR.php b/apps/files_encryption/l10n/es_AR.php index a15c37e730eae89fb61754432cfefe8bc65331cc..31898f50fded15d743ad82281a287b4b8d67dfa7 100644 --- a/apps/files_encryption/l10n/es_AR.php +++ b/apps/files_encryption/l10n/es_AR.php @@ -1,6 +1,5 @@ "Encriptación", "Exclude the following file types from encryption" => "Exceptuar de la encriptación los siguientes tipos de archivo", -"None" => "Ninguno", -"Enable Encryption" => "Habilitar encriptación" +"None" => "Ninguno" ); diff --git a/apps/files_encryption/l10n/et_EE.php b/apps/files_encryption/l10n/et_EE.php index a7cd9395bf070721e490495b12cc1dfbf7b109b9..0c0ef2311457a00b792144ab61161441638a8252 100644 --- a/apps/files_encryption/l10n/et_EE.php +++ b/apps/files_encryption/l10n/et_EE.php @@ -1,6 +1,5 @@ "Krüpteerimine", "Exclude the following file types from encryption" => "Järgnevaid failitüüpe ära krüpteeri", -"None" => "Pole", -"Enable Encryption" => "Luba krüpteerimine" +"None" => "Pole" ); diff --git a/apps/files_encryption/l10n/eu.php b/apps/files_encryption/l10n/eu.php index 57b6a4927bfa6b6ad50e7f1bdd94826ff0f38586..2bb1a46954c1fad7c44bcff751a8c5acd3361fd7 100644 --- a/apps/files_encryption/l10n/eu.php +++ b/apps/files_encryption/l10n/eu.php @@ -1,6 +1,5 @@ "Enkriptazioa", "Exclude the following file types from encryption" => "Ez enkriptatu hurrengo fitxategi motak", -"None" => "Bat ere ez", -"Enable Encryption" => "Gaitu enkriptazioa" +"None" => "Bat ere ez" ); diff --git a/apps/files_encryption/l10n/fa.php b/apps/files_encryption/l10n/fa.php index 01582e48e60e4d685b2db79aa42e041585ffbdce..0cdee74f5a9615f1f64abd7aafff64bfc439d47e 100644 --- a/apps/files_encryption/l10n/fa.php +++ b/apps/files_encryption/l10n/fa.php @@ -1,6 +1,5 @@ "رمزگذاری", "Exclude the following file types from encryption" => "نادیده گرفتن فایل های زیر برای رمز گذاری", -"None" => "هیچ‌کدام", -"Enable Encryption" => "فعال کردن رمزگذاری" +"None" => "هیچ‌کدام" ); diff --git a/apps/files_encryption/l10n/fi_FI.php b/apps/files_encryption/l10n/fi_FI.php index 5796499a26ceb3cb6017378318f0b9ab268115fb..433ae890ef60d37738ac63ef54e5055c155e659d 100644 --- a/apps/files_encryption/l10n/fi_FI.php +++ b/apps/files_encryption/l10n/fi_FI.php @@ -1,6 +1,5 @@ "Salaus", "Exclude the following file types from encryption" => "Jätä seuraavat tiedostotyypit salaamatta", -"None" => "Ei mitään", -"Enable Encryption" => "Käytä salausta" +"None" => "Ei mitään" ); diff --git a/apps/files_encryption/l10n/fr.php b/apps/files_encryption/l10n/fr.php index c9367d1a31209bb806fec920731bc4b0169c4262..41e37134d4e68ebd3930a2d16f315f8c755894ea 100644 --- a/apps/files_encryption/l10n/fr.php +++ b/apps/files_encryption/l10n/fr.php @@ -1,6 +1,16 @@ "Veuillez vous connecter depuis votre client de synchronisation ownCloud et changer votre mot de passe de chiffrement pour finaliser la conversion.", +"switched to client side encryption" => "Mode de chiffrement changé en chiffrement côté client", +"Change encryption password to login password" => "Convertir le mot de passe de chiffrement en mot de passe de connexion", +"Please check your passwords and try again." => "Veuillez vérifier vos mots de passe et réessayer.", +"Could not change your file encryption password to your login password" => "Impossible de convertir votre mot de passe de chiffrement en mot de passe de connexion", +"Choose encryption mode:" => "Choix du type de chiffrement :", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Chiffrement côté client (plus sécurisé, mais ne permet pas l'accès à vos données depuis l'interface web)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Chiffrement côté serveur (vous permet d'accéder à vos fichiers depuis l'interface web et depuis le client de synchronisation)", +"None (no encryption at all)" => "Aucun (pas de chiffrement)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Important : Une fois le mode de chiffrement choisi, il est impossible de revenir en arrière", +"User specific (let the user decide)" => "Propre à l'utilisateur (laisse le choix à l'utilisateur)", "Encryption" => "Chiffrement", "Exclude the following file types from encryption" => "Ne pas chiffrer les fichiers dont les types sont les suivants", -"None" => "Aucun", -"Enable Encryption" => "Activer le chiffrement" +"None" => "Aucun" ); diff --git a/apps/files_encryption/l10n/gl.php b/apps/files_encryption/l10n/gl.php index 91d155ccad36424efee50b05203a6a5bd6fae413..42fcfce1cc082b118ca1c0f8cc48e84bb9fc17c1 100644 --- a/apps/files_encryption/l10n/gl.php +++ b/apps/files_encryption/l10n/gl.php @@ -1,6 +1,5 @@ "Cifrado", "Exclude the following file types from encryption" => "Excluír os seguintes tipos de ficheiro do cifrado", -"None" => "Nada", -"Enable Encryption" => "Activar o cifrado" +"None" => "Nada" ); diff --git a/apps/files_encryption/l10n/he.php b/apps/files_encryption/l10n/he.php new file mode 100644 index 0000000000000000000000000000000000000000..9adb6d2b92a782e6576facf5393158dc8eeafbee --- /dev/null +++ b/apps/files_encryption/l10n/he.php @@ -0,0 +1,5 @@ + "הצפנה", +"Exclude the following file types from encryption" => "הוצא את סוגי הקבצים הבאים מהצפנה", +"None" => "כלום" +); diff --git a/apps/files_encryption/l10n/hu_HU.php b/apps/files_encryption/l10n/hu_HU.php index 4352d8b7712bbe12ecde867342d4b4d0d8a8ac55..1ef1effd41e07274dfa6236226897b9a67861c4a 100644 --- a/apps/files_encryption/l10n/hu_HU.php +++ b/apps/files_encryption/l10n/hu_HU.php @@ -1,6 +1,5 @@ "Titkosítás", -"Exclude the following file types from encryption" => "A következő fájl típusok kizárása a titkosításból", -"None" => "Egyik sem", -"Enable Encryption" => "Titkosítás engedélyezése" +"Exclude the following file types from encryption" => "A következő fájltípusok kizárása a titkosításból", +"None" => "Egyik sem" ); diff --git a/apps/files_encryption/l10n/id.php b/apps/files_encryption/l10n/id.php index 824ae88304101a447abc016d949678621391d652..20f33b87829edaac7a24499a373c75344b060efc 100644 --- a/apps/files_encryption/l10n/id.php +++ b/apps/files_encryption/l10n/id.php @@ -1,6 +1,5 @@ "enkripsi", "Exclude the following file types from encryption" => "pengecualian untuk tipe file berikut dari enkripsi", -"None" => "tidak ada", -"Enable Encryption" => "aktifkan enkripsi" +"None" => "tidak ada" ); diff --git a/apps/files_encryption/l10n/is.php b/apps/files_encryption/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..a2559cf2b76c9ea4103cd1eb457979c11ab10a24 --- /dev/null +++ b/apps/files_encryption/l10n/is.php @@ -0,0 +1,5 @@ + "Dulkóðun", +"Exclude the following file types from encryption" => "Undanskilja eftirfarandi skráartegundir frá dulkóðun", +"None" => "Ekkert" +); diff --git a/apps/files_encryption/l10n/it.php b/apps/files_encryption/l10n/it.php index 5136b061797344fb2f8137357abe88d1f7440f5d..de62f0508f32009a7fa2b6440d44dc44f1307447 100644 --- a/apps/files_encryption/l10n/it.php +++ b/apps/files_encryption/l10n/it.php @@ -1,6 +1,14 @@ "Passa al tuo client ownCloud e cambia la password di cifratura per completare la conversione.", +"switched to client side encryption" => "passato alla cifratura lato client", +"Please check your passwords and try again." => "Controlla la password e prova ancora.", +"Choose encryption mode:" => "Scegli la modalità di cifratura.", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Cifratura lato client (più sicura ma rende impossibile accedere ai propri dati dall'interfaccia web)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Cifratura lato server (ti consente di accedere ai tuoi file dall'interfaccia web e dal client desktop)", +"None (no encryption at all)" => "Nessuna (senza alcuna cifratura)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Importante: una volta selezionata la modalità di cifratura non sarà possibile tornare indietro", +"User specific (let the user decide)" => "Specificato dall'utente (lascia decidere all'utente)", "Encryption" => "Cifratura", "Exclude the following file types from encryption" => "Escludi i seguenti tipi di file dalla cifratura", -"None" => "Nessuna", -"Enable Encryption" => "Abilita cifratura" +"None" => "Nessuna" ); diff --git a/apps/files_encryption/l10n/ja_JP.php b/apps/files_encryption/l10n/ja_JP.php index 2c3e5410de3584eb827de47807dcabe05340f607..4100908e00c11d7b8c35ff7d1462d2ad200f5282 100644 --- a/apps/files_encryption/l10n/ja_JP.php +++ b/apps/files_encryption/l10n/ja_JP.php @@ -1,6 +1,16 @@ "変換を完了するために、ownCloud クライアントに切り替えて、暗号化パスワードを変更してください。", +"switched to client side encryption" => "クライアントサイドの暗号化に切り替えました", +"Change encryption password to login password" => "暗号化パスワードをログインパスワードに変更", +"Please check your passwords and try again." => "パスワードを確認してもう一度行なってください。", +"Could not change your file encryption password to your login password" => "ファイル暗号化パスワードをログインパスワードに変更できませんでした。", +"Choose encryption mode:" => "暗号化モードを選択:", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "クライアントサイドの暗号化(最もセキュアですが、WEBインターフェースからデータにアクセスできなくなります)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "サーバサイド暗号化(WEBインターフェースおよびデスクトップクライアントからファイルにアクセスすることができます)", +"None (no encryption at all)" => "暗号化無し(何も暗号化しません)", +"Important: Once you selected an encryption mode there is no way to change it back" => "重要: 一度暗号化を選択してしまうと、もとに戻す方法はありません", +"User specific (let the user decide)" => "ユーザ指定(ユーザが選べるようにする)", "Encryption" => "暗号化", "Exclude the following file types from encryption" => "暗号化から除外するファイルタイプ", -"None" => "なし", -"Enable Encryption" => "暗号化を有効にする" +"None" => "なし" ); diff --git a/apps/files_encryption/l10n/ko.php b/apps/files_encryption/l10n/ko.php index 4702753435ebdaf32a3547976bc0a67132b7405d..68d60c1ae30b033b7629f49924024bc63947f79e 100644 --- a/apps/files_encryption/l10n/ko.php +++ b/apps/files_encryption/l10n/ko.php @@ -1,6 +1,5 @@ "암호화", "Exclude the following file types from encryption" => "다음 파일 형식은 암호화하지 않음", -"None" => "없음", -"Enable Encryption" => "암호화 사용" +"None" => "없음" ); diff --git a/apps/files_encryption/l10n/ku_IQ.php b/apps/files_encryption/l10n/ku_IQ.php index bd8977ac5156b6a6116a9b4a4dc38ff8a1ee115f..06bb9b932514d6f4be0ff2a9fc152f9104ae667f 100644 --- a/apps/files_encryption/l10n/ku_IQ.php +++ b/apps/files_encryption/l10n/ku_IQ.php @@ -1,6 +1,5 @@ "نهێنیکردن", "Exclude the following file types from encryption" => "به‌ربه‌ست کردنی ئه‌م جۆره‌ په‌ڕگانه له‌ نهێنیکردن", -"None" => "هیچ", -"Enable Encryption" => "چالاکردنی نهێنیکردن" +"None" => "هیچ" ); diff --git a/apps/files_encryption/l10n/lt_LT.php b/apps/files_encryption/l10n/lt_LT.php index b939df164c8576b82cc5c59489905e986b5a171c..22cbe7a4ffa3727bbfb18999a97ec81da568df5d 100644 --- a/apps/files_encryption/l10n/lt_LT.php +++ b/apps/files_encryption/l10n/lt_LT.php @@ -1,6 +1,5 @@ "Šifravimas", "Exclude the following file types from encryption" => "Nešifruoti pasirinkto tipo failų", -"None" => "Nieko", -"Enable Encryption" => "Įjungti šifravimą" +"None" => "Nieko" ); diff --git a/apps/files_encryption/l10n/mk.php b/apps/files_encryption/l10n/mk.php index dfcaed9f37eda45ee0ff3f1402fa682e4005a8e7..7ccf8ac2d5b92a3eb8e3e00a2f10dfbc59879a2c 100644 --- a/apps/files_encryption/l10n/mk.php +++ b/apps/files_encryption/l10n/mk.php @@ -1,6 +1,5 @@ "Енкрипција", "Exclude the following file types from encryption" => "Исклучи ги следните типови на датотеки од енкрипција", -"None" => "Ништо", -"Enable Encryption" => "Овозможи енкрипција" +"None" => "Ништо" ); diff --git a/apps/files_encryption/l10n/nb_NO.php b/apps/files_encryption/l10n/nb_NO.php index e65df7b6ce30ec1cf6ceaef2d9fea62c69efb426..2ec6670e928563e34be13b8f361438d6b209ea25 100644 --- a/apps/files_encryption/l10n/nb_NO.php +++ b/apps/files_encryption/l10n/nb_NO.php @@ -1,6 +1,5 @@ "Kryptering", "Exclude the following file types from encryption" => "Ekskluder følgende filer fra kryptering", -"None" => "Ingen", -"Enable Encryption" => "Slå på kryptering" +"None" => "Ingen" ); diff --git a/apps/files_encryption/l10n/nl.php b/apps/files_encryption/l10n/nl.php index 1ea56006fc3933793dbef249773abc76e1183d76..7c09009cba90091c0933fa7163d5695c65bf381d 100644 --- a/apps/files_encryption/l10n/nl.php +++ b/apps/files_encryption/l10n/nl.php @@ -1,6 +1,5 @@ "Versleuteling", "Exclude the following file types from encryption" => "Versleutel de volgende bestand types niet", -"None" => "Geen", -"Enable Encryption" => "Zet versleuteling aan" +"None" => "Geen" ); diff --git a/apps/files_encryption/l10n/pl.php b/apps/files_encryption/l10n/pl.php index 5cfc707450e17664ec6060650ca11343b1b0c336..896086108ec8e2cc593d0990b5c6e3c8aa0776da 100644 --- a/apps/files_encryption/l10n/pl.php +++ b/apps/files_encryption/l10n/pl.php @@ -1,6 +1,5 @@ "Szyfrowanie", "Exclude the following file types from encryption" => "Wyłącz następujące typy plików z szyfrowania", -"None" => "Brak", -"Enable Encryption" => "Włącz szyfrowanie" +"None" => "Brak" ); diff --git a/apps/files_encryption/l10n/pt_BR.php b/apps/files_encryption/l10n/pt_BR.php index 5c02f52217fdf6a72b381928a45b74d978b74d79..086d073cf5c5fbb499644c2533d57c2297027ac1 100644 --- a/apps/files_encryption/l10n/pt_BR.php +++ b/apps/files_encryption/l10n/pt_BR.php @@ -1,6 +1,5 @@ "Criptografia", "Exclude the following file types from encryption" => "Excluir os seguintes tipos de arquivo da criptografia", -"None" => "Nenhuma", -"Enable Encryption" => "Habilitar Criptografia" +"None" => "Nenhuma" ); diff --git a/apps/files_encryption/l10n/pt_PT.php b/apps/files_encryption/l10n/pt_PT.php index 570462b414f593db9250ca819f07b21cc22b124a..b6eedcdc5095266da98fa1dda5267fa7030472fa 100644 --- a/apps/files_encryption/l10n/pt_PT.php +++ b/apps/files_encryption/l10n/pt_PT.php @@ -1,6 +1,16 @@ "Por favor, use o seu cliente de sincronização do ownCloud e altere a sua password de encriptação para concluír a conversão.", +"switched to client side encryption" => "Alterado para encriptação do lado do cliente", +"Change encryption password to login password" => "Alterar a password de encriptação para a password de login", +"Please check your passwords and try again." => "Por favor verifique as suas paswords e tente de novo.", +"Could not change your file encryption password to your login password" => "Não foi possível alterar a password de encriptação de ficheiros para a sua password de login", +"Choose encryption mode:" => "Escolha o método de encriptação", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Encriptação do lado do cliente (mais seguro mas torna possível o acesso aos dados através do interface web)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Encriptação do lado do servidor (permite o acesso aos seus ficheiros através do interface web e do cliente de sincronização)", +"None (no encryption at all)" => "Nenhuma (sem encriptação)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Importante: Uma vez escolhido o modo de encriptação, não existe maneira de o alterar!", +"User specific (let the user decide)" => "Escolhido pelo utilizador", "Encryption" => "Encriptação", "Exclude the following file types from encryption" => "Excluir da encriptação os seguintes tipo de ficheiros", -"None" => "Nenhum", -"Enable Encryption" => "Activar Encriptação" +"None" => "Nenhum" ); diff --git a/apps/files_encryption/l10n/ro.php b/apps/files_encryption/l10n/ro.php index 97f3f262d76e9a93de01ee3c7932f66665fae905..fc0f24f483ddf4f55e21ef460f86f6b35fc3d40b 100644 --- a/apps/files_encryption/l10n/ro.php +++ b/apps/files_encryption/l10n/ro.php @@ -1,6 +1,5 @@ "Încriptare", "Exclude the following file types from encryption" => "Exclude următoarele tipuri de fișiere de la încriptare", -"None" => "Niciuna", -"Enable Encryption" => "Activare încriptare" +"None" => "Niciuna" ); diff --git a/apps/files_encryption/l10n/ru.php b/apps/files_encryption/l10n/ru.php index 3a7e84b6d01e7b31f1a999452f0a5e22f6b4d770..14115c12683c03f92bebc50ecbddd4f9a74de536 100644 --- a/apps/files_encryption/l10n/ru.php +++ b/apps/files_encryption/l10n/ru.php @@ -1,6 +1,5 @@ "Шифрование", "Exclude the following file types from encryption" => "Исключить шифрование следующих типов файлов", -"None" => "Ничего", -"Enable Encryption" => "Включить шифрование" +"None" => "Ничего" ); diff --git a/apps/files_encryption/l10n/ru_RU.php b/apps/files_encryption/l10n/ru_RU.php index 1328b0d03596d3b4c46bc3d7ee71415169b343cd..4321fb8a8a33988c58dde54a3e16a25012dfe05f 100644 --- a/apps/files_encryption/l10n/ru_RU.php +++ b/apps/files_encryption/l10n/ru_RU.php @@ -1,6 +1,5 @@ "Шифрование", "Exclude the following file types from encryption" => "Исключите следующие типы файлов из шифрования", -"None" => "Ни один", -"Enable Encryption" => "Включить шифрование" +"None" => "Ни один" ); diff --git a/apps/files_encryption/l10n/si_LK.php b/apps/files_encryption/l10n/si_LK.php index a29884afffd89dce95dcb191e266bca50476214c..2d61bec45b825cef384310b83ac777618293d902 100644 --- a/apps/files_encryption/l10n/si_LK.php +++ b/apps/files_encryption/l10n/si_LK.php @@ -1,6 +1,5 @@ "ගුප්ත කේතනය", "Exclude the following file types from encryption" => "මෙම ගොනු වර්ග ගුප්ත කේතනය කිරීමෙන් බැහැරව තබන්න", -"None" => "කිසිවක් නැත", -"Enable Encryption" => "ගුප්ත කේතනය සක්‍රිය කරන්න" +"None" => "කිසිවක් නැත" ); diff --git a/apps/files_encryption/l10n/sk_SK.php b/apps/files_encryption/l10n/sk_SK.php index 598f1294f6ec69633ffe9668bc2f07f52a0fd7f8..5aebb6e35bd1d29558a25577d3d8a07b11b98a0a 100644 --- a/apps/files_encryption/l10n/sk_SK.php +++ b/apps/files_encryption/l10n/sk_SK.php @@ -1,6 +1,5 @@ "Šifrovanie", "Exclude the following file types from encryption" => "Vynechať nasledujúce súbory pri šifrovaní", -"None" => "Žiadne", -"Enable Encryption" => "Zapnúť šifrovanie" +"None" => "Žiadne" ); diff --git a/apps/files_encryption/l10n/sl.php b/apps/files_encryption/l10n/sl.php index f62fe781c6aac5d3345f7f08b4dc3054571369d6..db963ef2f8dc22c21f1ec240206a8c41e8528ef7 100644 --- a/apps/files_encryption/l10n/sl.php +++ b/apps/files_encryption/l10n/sl.php @@ -1,6 +1,5 @@ "Šifriranje", "Exclude the following file types from encryption" => "Navedene vrste datotek naj ne bodo šifrirane", -"None" => "Brez", -"Enable Encryption" => "Omogoči šifriranje" +"None" => "Brez" ); diff --git a/apps/files_encryption/l10n/sr.php b/apps/files_encryption/l10n/sr.php index 4718780ee5232cc1e6a265810e30805c53383140..198bcc94ef96aa1573d441bd185dbc583d8b56d2 100644 --- a/apps/files_encryption/l10n/sr.php +++ b/apps/files_encryption/l10n/sr.php @@ -1,6 +1,5 @@ "Шифровање", "Exclude the following file types from encryption" => "Не шифруј следеће типове датотека", -"None" => "Ништа", -"Enable Encryption" => "Омогући шифровање" +"None" => "Ништа" ); diff --git a/apps/files_encryption/l10n/sv.php b/apps/files_encryption/l10n/sv.php index 0a477f834609cc6c0304b125d9b04c6fbecd6089..9b6ce141782954ad4c9c0af1800a50c9db6b9151 100644 --- a/apps/files_encryption/l10n/sv.php +++ b/apps/files_encryption/l10n/sv.php @@ -1,6 +1,16 @@ "Vänligen växla till ownCloud klienten och ändra ditt krypteringslösenord för att slutföra omvandlingen.", +"switched to client side encryption" => "Bytte till kryptering på klientsidan", +"Change encryption password to login password" => "Ändra krypteringslösenord till loginlösenord", +"Please check your passwords and try again." => "Kontrollera dina lösenord och försök igen.", +"Could not change your file encryption password to your login password" => "Kunde inte ändra ditt filkrypteringslösenord till ditt loginlösenord", +"Choose encryption mode:" => "Välj krypteringsläge:", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "Kryptering på klientsidan (säkraste men gör det omöjligt att komma åt dina filer med en webbläsare)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "Kryptering på serversidan (kan komma åt dina filer från webbläsare och datorklient)", +"None (no encryption at all)" => "Ingen (ingen kryptering alls)", +"Important: Once you selected an encryption mode there is no way to change it back" => "Viktigt: När du har valt ett krypteringsläge finns det inget sätt att ändra tillbaka", +"User specific (let the user decide)" => "Användarspecifik (låter användaren bestämma)", "Encryption" => "Kryptering", "Exclude the following file types from encryption" => "Exkludera följande filtyper från kryptering", -"None" => "Ingen", -"Enable Encryption" => "Aktivera kryptering" +"None" => "Ingen" ); diff --git a/apps/files_encryption/l10n/ta_LK.php b/apps/files_encryption/l10n/ta_LK.php index 1d1ef74007edf2d61dfb1d9e9b66c397a9efa4cc..aab628b55198a4a11eb5228a17ab4062fa681dbb 100644 --- a/apps/files_encryption/l10n/ta_LK.php +++ b/apps/files_encryption/l10n/ta_LK.php @@ -1,6 +1,5 @@ "மறைக்குறியீடு", "Exclude the following file types from encryption" => "மறைக்குறியாக்கலில் பின்வரும் கோப்பு வகைகளை நீக்கவும்", -"None" => "ஒன்றுமில்லை", -"Enable Encryption" => "மறைக்குறியாக்கலை இயலுமைப்படுத்துக" +"None" => "ஒன்றுமில்லை" ); diff --git a/apps/files_encryption/l10n/th_TH.php b/apps/files_encryption/l10n/th_TH.php index c2685de6e3a76a614d7a177abc64e7a7dc8e57ca..f8c19456ab324db40a6fc2ddf15b569b3a49e791 100644 --- a/apps/files_encryption/l10n/th_TH.php +++ b/apps/files_encryption/l10n/th_TH.php @@ -1,6 +1,16 @@ "กรุณาสลับไปที่โปรแกรมไคลเอนต์ ownCloud ของคุณ แล้วเปลี่ยนรหัสผ่านสำหรับการเข้ารหัสเพื่อแปลงข้อมูลให้เสร็จสมบูรณ์", +"switched to client side encryption" => "สลับไปใช้การเข้ารหัสจากโปรแกรมไคลเอนต์", +"Change encryption password to login password" => "เปลี่ยนรหัสผ่านสำหรับเข้ารหัสไปเป็นรหัสผ่านสำหรับการเข้าสู่ระบบ", +"Please check your passwords and try again." => "กรุณาตรวจสอบรหัสผ่านของคุณแล้วลองใหม่อีกครั้ง", +"Could not change your file encryption password to your login password" => "ไม่สามารถเปลี่ยนรหัสผ่านสำหรับการเข้ารหัสไฟล์ของคุณไปเป็นรหัสผ่านสำหรับการเข้าสู่ระบบของคุณได้", +"Choose encryption mode:" => "เลือกรูปแบบการเข้ารหัส:", +"Client side encryption (most secure but makes it impossible to access your data from the web interface)" => "การเข้ารหัสด้วยโปรแกรมไคลเอนต์ (ปลอดภัยที่สุด แต่จะทำให้คุณไม่สามารถเข้าถึงข้อมูลต่างๆจากหน้าจอเว็บไซต์ได้)", +"Server side encryption (allows you to access your files from the web interface and the desktop client)" => "การเข้ารหัสจากทางฝั่งเซิร์ฟเวอร์ (อนุญาตให้คุณเข้าถึงไฟล์ของคุณจากหน้าจอเว็บไซต์ และโปรแกรมไคลเอนต์จากเครื่องเดสก์ท็อปได้)", +"None (no encryption at all)" => "ไม่ต้อง (ไม่มีการเข้ารหัสเลย)", +"Important: Once you selected an encryption mode there is no way to change it back" => "ข้อความสำคัญ: หลังจากที่คุณได้เลือกรูปแบบการเข้ารหัสแล้ว จะไม่สามารถเปลี่ยนกลับมาใหม่ได้อีก", +"User specific (let the user decide)" => "ให้ผู้ใช้งานเลือกเอง (ปล่อยให้ผู้ใช้งานตัดสินใจเอง)", "Encryption" => "การเข้ารหัส", "Exclude the following file types from encryption" => "ไม่ต้องรวมชนิดของไฟล์ดังต่อไปนี้จากการเข้ารหัส", -"None" => "ไม่ต้อง", -"Enable Encryption" => "เปิดใช้งานการเข้ารหัส" +"None" => "ไม่ต้อง" ); diff --git a/apps/files_encryption/l10n/tr.php b/apps/files_encryption/l10n/tr.php new file mode 100644 index 0000000000000000000000000000000000000000..07f78d148c85f0b9c2a61d588bc1546e745a4d68 --- /dev/null +++ b/apps/files_encryption/l10n/tr.php @@ -0,0 +1,5 @@ + "Şifreleme", +"Exclude the following file types from encryption" => "Aşağıdaki dosya tiplerini şifrelemeye dahil etme", +"None" => "Hiçbiri" +); diff --git a/apps/files_encryption/l10n/uk.php b/apps/files_encryption/l10n/uk.php index 3c15bb284368fee51bb97314744083b0e9cc4659..e3589215658e8871bcc693a5e19a8a91b6c18630 100644 --- a/apps/files_encryption/l10n/uk.php +++ b/apps/files_encryption/l10n/uk.php @@ -1,6 +1,5 @@ "Шифрування", "Exclude the following file types from encryption" => "Не шифрувати файли наступних типів", -"None" => "Жоден", -"Enable Encryption" => "Включити шифрування" +"None" => "Жоден" ); diff --git a/apps/files_encryption/l10n/vi.php b/apps/files_encryption/l10n/vi.php index 6365084fdc6642578038be515e72db0d9ac4378b..218285b675a66b1b4d06d1be8516b9b98423cff5 100644 --- a/apps/files_encryption/l10n/vi.php +++ b/apps/files_encryption/l10n/vi.php @@ -1,6 +1,5 @@ "Mã hóa", "Exclude the following file types from encryption" => "Loại trừ các loại tập tin sau đây từ mã hóa", -"None" => "Không có gì hết", -"Enable Encryption" => "BẬT mã hóa" +"None" => "Không có gì hết" ); diff --git a/apps/files_encryption/l10n/zh_CN.GB2312.php b/apps/files_encryption/l10n/zh_CN.GB2312.php index 297444fcf558cc43f74b1ff8269c24691d4bf2a2..31a3d3b49b83c2047fd141cb93057c0dcd268e6b 100644 --- a/apps/files_encryption/l10n/zh_CN.GB2312.php +++ b/apps/files_encryption/l10n/zh_CN.GB2312.php @@ -1,6 +1,5 @@ "加密", "Exclude the following file types from encryption" => "从加密中排除如下文件类型", -"None" => "无", -"Enable Encryption" => "启用加密" +"None" => "无" ); diff --git a/apps/files_encryption/l10n/zh_CN.php b/apps/files_encryption/l10n/zh_CN.php index 1e1247d15ffa4bb03e64a242ad63d671c2ed39d8..aa4817b590c69d257c43326f71e54225ff947060 100644 --- a/apps/files_encryption/l10n/zh_CN.php +++ b/apps/files_encryption/l10n/zh_CN.php @@ -1,6 +1,5 @@ "加密", "Exclude the following file types from encryption" => "从加密中排除列出的文件类型", -"None" => "None", -"Enable Encryption" => "开启加密" +"None" => "None" ); diff --git a/apps/files_encryption/l10n/zh_TW.php b/apps/files_encryption/l10n/zh_TW.php index 4c62130cf4f7b94977d99001a9f9a87eb151ebaf..fecebbe25093eabb78529c22d3ae95a0bdaefdd8 100644 --- a/apps/files_encryption/l10n/zh_TW.php +++ b/apps/files_encryption/l10n/zh_TW.php @@ -1,6 +1,5 @@ "加密", "Exclude the following file types from encryption" => "下列的檔案類型不加密", -"None" => "無", -"Enable Encryption" => "啟用加密" +"None" => "無" ); diff --git a/apps/files_encryption/lib/crypt.php b/apps/files_encryption/lib/crypt.php old mode 100644 new mode 100755 index 666fedb4e1b459cd0aed29380b41c8832240a05f..fddc89dae54b83da0f9f6c5d4b0ee8c5cc250dc0 --- a/apps/files_encryption/lib/crypt.php +++ b/apps/files_encryption/lib/crypt.php @@ -1,220 +1,732 @@ -. - * - */ - - - -// Todo: -// - 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/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 - - -require_once 'Crypt_Blowfish/Blowfish.php'; - -/** - * This class is for crypting and decrypting - */ -class OC_Crypt { - static private $bf = null; - - public static function loginListener($params) { - self::init($params['uid'], $params['password']); - } - - public static function init($login, $password) { - $view=new OC_FilesystemView('/'); - if ( ! $view->file_exists('/'.$login)) { - $view->mkdir('/'.$login); - } - - OC_FileProxy::$enabled=false; - if ( ! $view->file_exists('/'.$login.'/encryption.key')) {// does key exist? - OC_Crypt::createkey($login, $password); - } - $key=$view->file_get_contents('/'.$login.'/encryption.key'); - OC_FileProxy::$enabled=true; - $_SESSION['enckey']=OC_Crypt::decrypt($key, $password); - } - - - /** - * get the blowfish encryption handeler for a key - * @param string $key (optional) - * @return Crypt_Blowfish - * - * if the key is left out, the default handeler will be used - */ - public static function getBlowfish($key='') { - if ($key) { - return new Crypt_Blowfish($key); - } else { - if ( ! isset($_SESSION['enckey'])) { - return false; - } - if ( ! self::$bf) { - self::$bf=new Crypt_Blowfish($_SESSION['enckey']); - } - return self::$bf; - } - } - - public static function createkey($username, $passcode) { - // generate a random key - $key=mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999).mt_rand(10000, 99999); - - // encrypt the key with the passcode of the user - $enckey=OC_Crypt::encrypt($key, $passcode); - - // Write the file - $proxyEnabled=OC_FileProxy::$enabled; - OC_FileProxy::$enabled=false; - $view=new OC_FilesystemView('/'.$username); - $view->file_put_contents('/encryption.key', $enckey); - OC_FileProxy::$enabled=$proxyEnabled; - } - - public static function changekeypasscode($oldPassword, $newPassword) { - if (OCP\User::isLoggedIn()) { - $username=OCP\USER::getUser(); - $view=new OC_FilesystemView('/'.$username); - - // read old key - $key=$view->file_get_contents('/encryption.key'); - - // decrypt key with old passcode - $key=OC_Crypt::decrypt($key, $oldPassword); - - // encrypt again with new passcode - $key=OC_Crypt::encrypt($key, $newPassword); - - // store the new key - $view->file_put_contents('/encryption.key', $key ); - } - } - - /** - * @brief encrypts an content - * @param $content the cleartext message you want to encrypt - * @param $key the encryption key (optional) - * @returns encrypted content - * - * This function encrypts an content - */ - public static function encrypt( $content, $key='') { - $bf = self::getBlowfish($key); - return $bf->encrypt($content); - } - - /** - * @brief decryption of an content - * @param $content the cleartext message you want to decrypt - * @param $key the encryption key (optional) - * @returns cleartext content - * - * This function decrypts an content - */ - public static function decrypt( $content, $key='') { - $bf = self::getBlowfish($key); - $data=$bf->decrypt($content); - return $data; - } - - /** - * @brief encryption of a file - * @param string $source - * @param string $target - * @param string $key the decryption key - * - * This function encrypts a file - */ - public static function encryptFile( $source, $target, $key='') { - $handleread = fopen($source, "rb"); - if ($handleread!=false) { - $handlewrite = fopen($target, "wb"); - while (!feof($handleread)) { - $content = fread($handleread, 8192); - $enccontent=OC_CRYPT::encrypt( $content, $key); - fwrite($handlewrite, $enccontent); - } - fclose($handlewrite); - fclose($handleread); - } - } - - - /** - * @brief decryption of a file - * @param string $source - * @param string $target - * @param string $key the decryption key - * - * This function decrypts a file - */ - public static function decryptFile( $source, $target, $key='') { - $handleread = fopen($source, "rb"); - if ($handleread!=false) { - $handlewrite = fopen($target, "wb"); - while (!feof($handleread)) { - $content = fread($handleread, 8192); - $enccontent=OC_CRYPT::decrypt( $content, $key); - if (feof($handleread)) { - $enccontent=rtrim($enccontent, "\0"); - } - fwrite($handlewrite, $enccontent); - } - fclose($handlewrite); - fclose($handleread); - } - } - - /** - * encrypt data in 8192b sized blocks - */ - public static function blockEncrypt($data, $key='') { - $result=''; - while (strlen($data)) { - $result.=self::encrypt(substr($data, 0, 8192), $key); - $data=substr($data, 8192); - } - return $result; - } - - /** - * decrypt data in 8192b sized blocks - */ - public static function blockDecrypt($data, $key='', $maxLength=0) { - $result=''; - while (strlen($data)) { - $result.=self::decrypt(substr($data, 0, 8192), $key); - $data=substr($data, 8192); - } - if ($maxLength>0) { - return substr($result, 0, $maxLength); - } else { - return rtrim($result, "\0"); - } - } -} +. + * + */ + +namespace OCA\Encryption; + +require_once 'Crypt_Blowfish/Blowfish.php'; + +// Todo: +// - 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/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 + +/** + * Class for common cryptography functionality + */ + +class Crypt { + + /** + * @brief return encryption mode client or server side encryption + * @param string user name (use system wide setting if name=null) + * @return string 'client' or 'server' + */ + public static function mode( $user = null ) { + +// $mode = \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ); +// +// if ( $mode == 'user') { +// if ( !$user ) { +// $user = \OCP\User::getUser(); +// } +// $mode = 'none'; +// if ( $user ) { +// $query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" ); +// $result = $query->execute(array($user)); +// if ($row = $result->fetchRow()){ +// $mode = $row['mode']; +// } +// } +// } +// +// return $mode; + + return 'server'; + + } + + /** + * @brief Create a new encryption keypair + * @return array publicKey, privatekey + */ + public static function createKeypair() { + + $res = openssl_pkey_new(); + + // Get private key + openssl_pkey_export( $res, $privateKey ); + + // Get public key + $publicKey = openssl_pkey_get_details( $res ); + + $publicKey = $publicKey['key']; + + return( array( 'publicKey' => $publicKey, 'privateKey' => $privateKey ) ); + + } + + /** + * @brief Add arbitrary padding to encrypted data + * @param string $data data to be padded + * @return padded data + * @note In order to end up with data exactly 8192 bytes long we must add two letters. It is impossible to achieve exactly 8192 length blocks with encryption alone, hence padding is added to achieve the required length. + */ + public static function addPadding( $data ) { + + $padded = $data . 'xx'; + + return $padded; + + } + + /** + * @brief Remove arbitrary padding to encrypted data + * @param string $padded padded data to remove padding from + * @return unpadded data on success, false on error + */ + public static function removePadding( $padded ) { + + if ( substr( $padded, -2 ) == 'xx' ) { + + $data = substr( $padded, 0, -2 ); + + return $data; + + } else { + + # TODO: log the fact that unpadded data was submitted for removal of padding + return false; + + } + + } + + /** + * @brief Check if a file's contents contains an IV and is symmetrically encrypted + * @return true / false + * @note see also OCA\Encryption\Util->isEncryptedPath() + */ + public static function isEncryptedContent( $content ) { + + if ( !$content ) { + + return false; + + } + + $noPadding = self::removePadding( $content ); + + // Fetch encryption metadata from end of file + $meta = substr( $noPadding, -22 ); + + // Fetch IV from end of file + $iv = substr( $meta, -16 ); + + // Fetch identifier from start of metadata + $identifier = substr( $meta, 0, 6 ); + + if ( $identifier == '00iv00') { + + return true; + + } else { + + return false; + + } + + } + + /** + * Check if a file is encrypted according to database file cache + * @param string $path + * @return bool + */ + public static function isEncryptedMeta( $path ) { + + # TODO: Use DI to get OC_FileCache_Cached out of here + + // Fetch all file metadata from DB + $metadata = \OC_FileCache_Cached::get( $path, '' ); + + // Return encryption status + return isset( $metadata['encrypted'] ) and ( bool )$metadata['encrypted']; + + } + + /** + * @brief Check if a file is encrypted via legacy system + * @return true / false + */ + public static function isLegacyEncryptedContent( $content ) { + + // Fetch all file metadata from DB + $metadata = \OC_FileCache_Cached::get( $content, '' ); + + // 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 ( + $content + and isset( $metadata['encrypted'] ) + and $metadata['encrypted'] === true + and !self::isEncryptedContent( $content ) + ) { + + return true; + + } else { + + return false; + + } + + } + + /** + * @brief Symmetrically encrypt a string + * @returns encrypted file + */ + public static function encrypt( $plainContent, $iv, $passphrase = '' ) { + + if ( $encryptedContent = openssl_encrypt( $plainContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + return $encryptedContent; + + } else { + + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of content failed' , \OC_Log::ERROR ); + + return false; + + } + + } + + /** + * @brief Symmetrically decrypt a string + * @returns decrypted file + */ + public static function decrypt( $encryptedContent, $iv, $passphrase ) { + + if ( $plainContent = openssl_decrypt( $encryptedContent, 'AES-128-CFB', $passphrase, false, $iv ) ) { + + return $plainContent; + + + } else { + + throw new \Exception( 'Encryption library: Decryption (symmetric) of content failed' ); + + return false; + + } + + } + + /** + * @brief Concatenate encrypted data with its IV and padding + * @param string $content content to be concatenated + * @param string $iv IV to be concatenated + * @returns string concatenated content + */ + public static function concatIv ( $content, $iv ) { + + $combined = $content . '00iv00' . $iv; + + return $combined; + + } + + /** + * @brief Split concatenated data and IV into respective parts + * @param string $catFile concatenated data to be split + * @returns array keys: encrypted, iv + */ + public static function splitIv ( $catFile ) { + + // Fetch encryption metadata from end of file + $meta = substr( $catFile, -22 ); + + // Fetch IV from end of file + $iv = substr( $meta, -16 ); + + // Remove IV and IV identifier text to expose encrypted content + $encrypted = substr( $catFile, 0, -22 ); + + $split = array( + 'encrypted' => $encrypted + , 'iv' => $iv + ); + + return $split; + + } + + /** + * @brief Symmetrically encrypts a string and returns keyfile content + * @param $plainContent content to be encrypted in keyfile + * @returns encrypted content combined with IV + * @note IV need not be specified, as it will be stored in the returned keyfile + * and remain accessible therein. + */ + public static function symmetricEncryptFileContent( $plainContent, $passphrase = '' ) { + + if ( !$plainContent ) { + + return false; + + } + + $iv = self::generateIv(); + + if ( $encryptedContent = self::encrypt( $plainContent, $iv, $passphrase ) ) { + + // Combine content to encrypt with IV identifier and actual IV + $catfile = self::concatIv( $encryptedContent, $iv ); + + $padded = self::addPadding( $catfile ); + + return $padded; + + } else { + + \OC_Log::write( 'Encryption library', 'Encryption (symmetric) of keyfile content failed' , \OC_Log::ERROR ); + + return false; + + } + + } + + + /** + * @brief Symmetrically decrypts keyfile content + * @param string $source + * @param string $target + * @param string $key the decryption key + * @returns decrypted content + * + * This function decrypts a file + */ + public static function symmetricDecryptFileContent( $keyfileContent, $passphrase = '' ) { + + if ( !$keyfileContent ) { + + throw new \Exception( 'Encryption library: no data provided for decryption' ); + + } + + // Remove padding + $noPadding = self::removePadding( $keyfileContent ); + + // Split into enc data and catfile + $catfile = self::splitIv( $noPadding ); + + if ( $plainContent = self::decrypt( $catfile['encrypted'], $catfile['iv'], $passphrase ) ) { + + return $plainContent; + + } + + } + + /** + * @brief Creates symmetric keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @returns array keys: key, encrypted + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function symmetricEncryptFileContentKeyfile( $plainContent ) { + + $key = self::generateKey(); + + if( $encryptedContent = self::symmetricEncryptFileContent( $plainContent, $key ) ) { + + return array( + 'key' => $key + , 'encrypted' => $encryptedContent + ); + + } else { + + return false; + + } + + } + + /** + * @brief Create asymmetrically encrypted keyfile content using a generated key + * @param string $plainContent content to be encrypted + * @returns array keys: key, encrypted + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function multiKeyEncrypt( $plainContent, array $publicKeys ) { + + $envKeys = array(); + + if( openssl_seal( $plainContent, $sealed, $envKeys, $publicKeys ) ) { + + return array( + 'keys' => $envKeys + , 'encrypted' => $sealed + ); + + } else { + + return false; + + } + + } + + /** + * @brief Asymmetrically encrypt a file using multiple public keys + * @param string $plainContent content to be encrypted + * @returns string $plainContent decrypted string + * @note symmetricDecryptFileContent() can be used to decrypt files created using this method + * + * This function decrypts a file + */ + public static function multiKeyDecrypt( $encryptedContent, $envKey, $privateKey ) { + + if ( !$encryptedContent ) { + + return false; + + } + + if ( openssl_open( $encryptedContent, $plainContent, $envKey, $privateKey ) ) { + + return $plainContent; + + } else { + + \OC_Log::write( 'Encryption library', 'Decryption (asymmetric) of sealed content failed' , \OC_Log::ERROR ); + + return false; + + } + + } + + /** + * @brief Asymetrically encrypt a string using a public key + * @returns encrypted file + */ + public static function keyEncrypt( $plainContent, $publicKey ) { + + openssl_public_encrypt( $plainContent, $encryptedContent, $publicKey ); + + return $encryptedContent; + + } + + /** + * @brief Asymetrically decrypt a file using a private key + * @returns decrypted file + */ + public static function keyDecrypt( $encryptedContent, $privatekey ) { + + openssl_private_decrypt( $encryptedContent, $plainContent, $privatekey ); + + return $plainContent; + + } + + /** + * @brief Encrypts content symmetrically and generates keyfile asymmetrically + * @returns array containing catfile and new keyfile. + * keys: data, key + * @note this method is a wrapper for combining other crypt class methods + */ + public static function keyEncryptKeyfile( $plainContent, $publicKey ) { + + // Encrypt plain data, generate keyfile & encrypted file + $cryptedData = self::symmetricEncryptFileContentKeyfile( $plainContent ); + + // Encrypt keyfile + $cryptedKey = self::keyEncrypt( $cryptedData['key'], $publicKey ); + + return array( 'data' => $cryptedData['encrypted'], 'key' => $cryptedKey ); + + } + + /** + * @brief Takes catfile, keyfile, and private key, and + * performs decryption + * @returns decrypted content + * @note this method is a wrapper for combining other crypt class methods + */ + public static function keyDecryptKeyfile( $catfile, $keyfile, $privateKey ) { + + // Decrypt the keyfile with the user's private key + $decryptedKeyfile = self::keyDecrypt( $keyfile, $privateKey ); + + // Decrypt the catfile symmetrically using the decrypted keyfile + $decryptedData = self::symmetricDecryptFileContent( $catfile, $decryptedKeyfile ); + + return $decryptedData; + + } + + /** + * @brief Symmetrically encrypt a file by combining encrypted component data blocks + */ + public static function symmetricBlockEncryptFileContent( $plainContent, $key ) { + + $crypted = ''; + + $remaining = $plainContent; + + $testarray = array(); + + while( strlen( $remaining ) ) { + + //echo "\n\n\$block = ".substr( $remaining, 0, 6126 ); + + // Encrypt a chunk of unencrypted data and add it to the rest + $block = self::symmetricEncryptFileContent( substr( $remaining, 0, 6126 ), $key ); + + $padded = self::addPadding( $block ); + + $crypted .= $block; + + $testarray[] = $block; + + // Remove the data already encrypted from remaining unencrypted data + $remaining = substr( $remaining, 6126 ); + + } + + //echo "hags "; + + //echo "\n\n\n\$crypted = $crypted\n\n\n"; + + //print_r($testarray); + + return $crypted; + + } + + + /** + * @brief Symmetrically decrypt a file by combining encrypted component data blocks + */ + public static function symmetricBlockDecryptFileContent( $crypted, $key ) { + + $decrypted = ''; + + $remaining = $crypted; + + $testarray = array(); + + while( strlen( $remaining ) ) { + + $testarray[] = substr( $remaining, 0, 8192 ); + + // Decrypt a chunk of unencrypted data and add it to the rest + $decrypted .= self::symmetricDecryptFileContent( $remaining, $key ); + + // Remove the data already encrypted from remaining unencrypted data + $remaining = substr( $remaining, 8192 ); + + } + + //echo "\n\n\$testarray = "; print_r($testarray); + + return $decrypted; + + } + + /** + * @brief Generates a pseudo random initialisation vector + * @return String $iv generated IV + */ + public static function generateIv() { + + if ( $random = openssl_random_pseudo_bytes( 12, $strong ) ) { + + if ( !$strong ) { + + // If OpenSSL indicates randomness is insecure, log error + \OC_Log::write( 'Encryption library', 'Insecure symmetric key was generated using openssl_random_pseudo_bytes()' , \OC_Log::WARN ); + + } + + // We encode the iv purely for string manipulation + // purposes - it gets decoded before use + $iv = base64_encode( $random ); + + return $iv; + + } else { + + throw new Exception( 'Generating IV failed' ); + + } + + } + + /** + * @brief Generate a pseudo random 1024kb ASCII key + * @returns $key Generated key + */ + public static function generateKey() { + + // Generate key + if ( $key = base64_encode( openssl_random_pseudo_bytes( 183, $strong ) ) ) { + + if ( !$strong ) { + + // If OpenSSL indicates randomness is insecure, log error + throw new Exception ( 'Encryption library, Insecure symmetric key was generated using openssl_random_pseudo_bytes()' ); + + } + + return $key; + + } else { + + return false; + + } + + } + + public static function changekeypasscode($oldPassword, $newPassword) { + + if(\OCP\User::isLoggedIn()){ + $key = Keymanager::getPrivateKey( $user, $view ); + if ( ($key = Crypt::symmetricDecryptFileContent($key,$oldpasswd)) ) { + if ( ($key = Crypt::symmetricEncryptFileContent($key, $newpasswd)) ) { + Keymanager::setPrivateKey($key); + return true; + } + } + } + return false; + } + + /** + * @brief Get the blowfish encryption handeler for a key + * @param $key string (optional) + * @return Crypt_Blowfish blowfish object + * + * if the key is left out, the default handeler will be used + */ + public static function getBlowfish( $key = '' ) { + + if ( $key ) { + + return new \Crypt_Blowfish( $key ); + + } else { + + return false; + + } + + } + + public static function legacyCreateKey( $passphrase ) { + + // Generate a random integer + $key = mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ) . mt_rand( 10000, 99999 ); + + // Encrypt the key with the passphrase + $legacyEncKey = self::legacyEncrypt( $key, $passphrase ); + + return $legacyEncKey; + + } + + /** + * @brief encrypts content using legacy blowfish system + * @param $content the cleartext message you want to encrypt + * @param $key the encryption key (optional) + * @returns encrypted content + * + * This function encrypts an content + */ + public static function legacyEncrypt( $content, $passphrase = '' ) { + + $bf = self::getBlowfish( $passphrase ); + + return $bf->encrypt( $content ); + + } + + /** + * @brief decrypts content using legacy blowfish system + * @param $content the cleartext message you want to decrypt + * @param $key the encryption key (optional) + * @returns cleartext content + * + * This function decrypts an content + */ + public static function legacyDecrypt( $content, $passphrase = '' ) { + + $bf = self::getBlowfish( $passphrase ); + + $decrypted = $bf->decrypt( $content ); + + $trimmed = rtrim( $decrypted, "\0" ); + + return $trimmed; + + } + + public static function legacyKeyRecryptKeyfile( $legacyEncryptedContent, $legacyPassphrase, $publicKey, $newPassphrase ) { + + $decrypted = self::legacyDecrypt( $legacyEncryptedContent, $legacyPassphrase ); + + $recrypted = self::keyEncryptKeyfile( $decrypted, $publicKey ); + + return $recrypted; + + } + + /** + * @brief Re-encryptes a legacy blowfish encrypted file using AES with integrated IV + * @param $legacyContent the legacy encrypted content to re-encrypt + * @returns cleartext content + * + * This function decrypts an content + */ + public static function legacyRecrypt( $legacyContent, $legacyPassphrase, $newPassphrase ) { + + # TODO: write me + + } + +} + +?> \ No newline at end of file diff --git a/apps/files_encryption/lib/cryptstream.php b/apps/files_encryption/lib/cryptstream.php deleted file mode 100644 index d516c0c21b22904d8bca4779787bc7a39c1adfdf..0000000000000000000000000000000000000000 --- a/apps/files_encryption/lib/cryptstream.php +++ /dev/null @@ -1,177 +0,0 @@ -. - * - */ - -/** - * transparently encrypted filestream - * - * you can use it as wrapper around an existing stream by setting - * OC_CryptStream::$sourceStreams['foo']=array('path'=>$path, 'stream'=>$stream) - * and then fopen('crypt://streams/foo'); - */ - -class OC_CryptStream{ - public static $sourceStreams=array(); - private $source; - private $path; - private $meta=array();//header/meta for source stream - private $writeCache; - private $size; - private static $rootView; - - public function stream_open($path, $mode, $options, &$opened_path) { - if ( ! self::$rootView) { - self::$rootView=new OC_FilesystemView(''); - } - $path=str_replace('crypt://', '', $path); - if (dirname($path)=='streams' and isset(self::$sourceStreams[basename($path)])) { - $this->source=self::$sourceStreams[basename($path)]['stream']; - $this->path=self::$sourceStreams[basename($path)]['path']; - $this->size=self::$sourceStreams[basename($path)]['size']; - } else { - $this->path=$path; - if ($mode=='w' or $mode=='w+' or $mode=='wb' or $mode=='wb+') { - $this->size=0; - } else { - $this->size=self::$rootView->filesize($path, $mode); - } - OC_FileProxy::$enabled=false;//disable fileproxies so we can open the source file - $this->source=self::$rootView->fopen($path, $mode); - OC_FileProxy::$enabled=true; - if ( ! is_resource($this->source)) { - OCP\Util::writeLog('files_encryption', 'failed to open '.$path, OCP\Util::ERROR); - } - } - if (is_resource($this->source)) { - $this->meta=stream_get_meta_data($this->source); - } - return is_resource($this->source); - } - - public function stream_seek($offset, $whence=SEEK_SET) { - $this->flush(); - fseek($this->source, $offset, $whence); - } - - public function stream_tell() { - return ftell($this->source); - } - - public function stream_read($count) { - //$count will always be 8192 https://bugs.php.net/bug.php?id=21641 - //This makes this function a lot simpler but will breake everything the moment it's fixed - $this->writeCache=''; - if ($count!=8192) { - OCP\Util::writeLog('files_encryption', - 'php bug 21641 no longer holds, decryption will not work', - OCP\Util::FATAL); - die(); - } - $pos=ftell($this->source); - $data=fread($this->source, 8192); - if (strlen($data)) { - $result=OC_Crypt::decrypt($data); - } else { - $result=''; - } - $length=$this->size-$pos; - if ($length<8192) { - $result=substr($result, 0, $length); - } - return $result; - } - - public function stream_write($data) { - $length=strlen($data); - $currentPos=ftell($this->source); - if ($this->writeCache) { - $data=$this->writeCache.$data; - $this->writeCache=''; - } - if ($currentPos%8192!=0) { - //make sure we always start on a block start - fseek($this->source, -($currentPos%8192), SEEK_CUR); - $encryptedBlock=fread($this->source, 8192); - fseek($this->source, -($currentPos%8192), SEEK_CUR); - $block=OC_Crypt::decrypt($encryptedBlock); - $data=substr($block, 0, $currentPos%8192).$data; - fseek($this->source, -($currentPos%8192), SEEK_CUR); - } - $currentPos=ftell($this->source); - while ($remainingLength=strlen($data)>0) { - if ($remainingLength<8192) { - $this->writeCache=$data; - $data=''; - } else { - $encrypted=OC_Crypt::encrypt(substr($data, 0, 8192)); - fwrite($this->source, $encrypted); - $data=substr($data, 8192); - } - } - $this->size=max($this->size, $currentPos+$length); - return $length; - } - - public function stream_set_option($option, $arg1, $arg2) { - switch($option) { - case STREAM_OPTION_BLOCKING: - stream_set_blocking($this->source, $arg1); - break; - case STREAM_OPTION_READ_TIMEOUT: - stream_set_timeout($this->source, $arg1, $arg2); - break; - case STREAM_OPTION_WRITE_BUFFER: - stream_set_write_buffer($this->source, $arg1, $arg2); - } - } - - public function stream_stat() { - return fstat($this->source); - } - - public function stream_lock($mode) { - flock($this->source, $mode); - } - - public function stream_flush() { - return fflush($this->source); - } - - public function stream_eof() { - return feof($this->source); - } - - private function flush() { - if ($this->writeCache) { - $encrypted=OC_Crypt::encrypt($this->writeCache); - fwrite($this->source, $encrypted); - $this->writeCache=''; - } - } - - public function stream_close() { - $this->flush(); - if ($this->meta['mode']!='r' and $this->meta['mode']!='rb') { - OC_FileCache::put($this->path, array('encrypted'=>true, 'size'=>$this->size), ''); - } - return fclose($this->source); - } -} diff --git a/apps/files_encryption/lib/keymanager.php b/apps/files_encryption/lib/keymanager.php new file mode 100755 index 0000000000000000000000000000000000000000..706e1c2661e6a263cac03875bd948fb93c67a544 --- /dev/null +++ b/apps/files_encryption/lib/keymanager.php @@ -0,0 +1,365 @@ + + * + * 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 . + * + */ + +namespace OCA\Encryption; + +/** + * @brief Class to manage storage and retrieval of encryption keys + * @note Where a method requires a view object, it's root must be '/' + */ +class Keymanager { + + # TODO: make all dependencies (including static classes) explicit, such as ocfsview objects, by adding them as method arguments (dependency injection) + + /** + * @brief retrieve the ENCRYPTED private key from a user + * + * @return string private key or false + * @note the key returned by this method must be decrypted before use + */ + public static function getPrivateKey( \OC_FilesystemView $view, $user ) { + + $path = '/' . $user . '/' . 'files_encryption' . '/' . $user.'.private.key'; + + $key = $view->file_get_contents( $path ); + + return $key; + } + + /** + * @brief retrieve public key for a specified user + * @return string public key or false + */ + public static function getPublicKey( \OC_FilesystemView $view, $userId ) { + + return $view->file_get_contents( '/public-keys/' . '/' . $userId . '.public.key' ); + + } + + /** + * @brief retrieve both keys from a user (private and public) + * @return array keys: privateKey, publicKey + */ + public static function getUserKeys( \OC_FilesystemView $view, $userId ) { + + return array( + 'publicKey' => self::getPublicKey( $view, $userId ) + , 'privateKey' => self::getPrivateKey( $view, $userId ) + ); + + } + + /** + * @brief Retrieve public keys of all users with access to a file + * @param string $path Path to file + * @return array of public keys for the given file + * @note Checks that the sharing app is enabled should be performed + * by client code, that isn't checked here + */ + public static function getPublicKeys( \OC_FilesystemView $view, $userId, $filePath ) { + + $path = ltrim( $path, '/' ); + + $filepath = '/' . $userId . '/files/' . $filePath; + + // Check if sharing is enabled + if ( OC_App::isEnabled( 'files_sharing' ) ) { + +// // Check if file was shared with other users +// $query = \OC_DB::prepare( " +// SELECT +// uid_owner +// , source +// , target +// , uid_shared_with +// FROM +// `*PREFIX*sharing` +// WHERE +// ( target = ? AND uid_shared_with = ? ) +// OR source = ? +// " ); +// +// $result = $query->execute( array ( $filepath, $userId, $filepath ) ); +// +// $users = array(); +// +// if ( $row = $result->fetchRow() ) +// { +// $source = $row['source']; +// $owner = $row['uid_owner']; +// $users[] = $owner; +// // get the uids of all user with access to the file +// $query = \OC_DB::prepare( "SELECT source, uid_shared_with FROM `*PREFIX*sharing` WHERE source = ?" ); +// $result = $query->execute( array ($source)); +// while ( ($row = $result->fetchRow()) ) { +// $users[] = $row['uid_shared_with']; +// +// } +// +// } + + } else { + + // check if it is a file owned by the user and not shared at all + $userview = new \OC_FilesystemView( '/'.$userId.'/files/' ); + + if ( $userview->file_exists( $path ) ) { + + $users[] = $userId; + + } + + } + + $view = new \OC_FilesystemView( '/public-keys/' ); + + $keylist = array(); + + $count = 0; + + foreach ( $users as $user ) { + + $keylist['key'.++$count] = $view->file_get_contents( $user.'.public.key' ); + + } + + return $keylist; + + } + + /** + * @brief retrieve keyfile for an encrypted file + * @param string file name + * @return string file key or false + * @note The keyfile returned is asymmetrically encrypted. Decryption + * of the keyfile must be performed by client code + */ + public static function getFileKey( \OC_FilesystemView $view, $userId, $filePath ) { + + $filePath_f = ltrim( $filePath, '/' ); + +// // update $keypath and $userId if path point to a file shared by someone else +// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); +// +// $result = $query->execute( array ('/'.$userId.'/files/'.$keypath, $userId)); +// +// if ($row = $result->fetchRow()) { +// +// $keypath = $row['source']; +// $keypath_parts = explode( '/', $keypath ); +// $userId = $keypath_parts[1]; +// $keypath = str_replace( '/' . $userId . '/files/', '', $keypath ); +// +// } + + return $view->file_get_contents( '/' . $userId . '/files_encryption/keyfiles/' . $filePath_f . '.key' ); + + } + + /** + * @brief retrieve file encryption key + * + * @param string file name + * @return string file key or false + */ + public static function deleteFileKey( $path, $staticUserClass = 'OCP\User' ) { + + $keypath = ltrim( $path, '/' ); + $user = $staticUserClass::getUser(); + + // update $keypath and $user if path point to a file shared by someone else +// $query = \OC_DB::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); +// +// $result = $query->execute( array ('/'.$user.'/files/'.$keypath, $user)); +// +// if ($row = $result->fetchRow()) { +// +// $keypath = $row['source']; +// $keypath_parts = explode( '/', $keypath ); +// $user = $keypath_parts[1]; +// $keypath = str_replace( '/' . $user . '/files/', '', $keypath ); +// +// } + + $view = new \OC_FilesystemView('/'.$user.'/files_encryption/keyfiles/'); + + return $view->unlink( $keypath . '.key' ); + + } + + /** + * @brief store private key from the user + * @param string key + * @return bool + * @note Encryption of the private key must be performed by client code + * as no encryption takes place here + */ + public static function setPrivateKey( $key ) { + + $user = \OCP\User::getUser(); + + $view = new \OC_FilesystemView( '/' . $user . '/files_encryption' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); + + return $view->file_put_contents( $user . '.private.key', $key ); + + \OC_FileProxy::$enabled = true; + + } + + /** + * @brief store private keys from the user + * + * @param string privatekey + * @param string publickey + * @return bool true/false + */ + public static function setUserKeys($privatekey, $publickey) { + + return (self::setPrivateKey($privatekey) && self::setPublicKey($publickey)); + + } + + /** + * @brief store public key of the user + * + * @param string key + * @return bool true/false + */ + public static function setPublicKey( $key ) { + + $view = new \OC_FilesystemView( '/public-keys' ); + + \OC_FileProxy::$enabled = false; + + if ( !$view->file_exists( '' ) ) $view->mkdir( '' ); + + return $view->file_put_contents( \OCP\User::getUser() . '.public.key', $key ); + + \OC_FileProxy::$enabled = true; + + } + + /** + * @brief store file encryption key + * + * @param string $path relative path of the file, including filename + * @param string $key + * @return bool true/false + * @note The keyfile is not encrypted here. Client code must + * asymmetrically encrypt the keyfile before passing it to this method + */ + public static function setFileKey( $path, $key, $view = Null, $dbClassName = '\OC_DB') { + + $targetPath = ltrim( $path, '/' ); + $user = \OCP\User::getUser(); + +// // update $keytarget and $user if key belongs to a file shared by someone else +// $query = $dbClassName::prepare( "SELECT uid_owner, source, target FROM `*PREFIX*sharing` WHERE target = ? AND uid_shared_with = ?" ); +// +// $result = $query->execute( array ( '/'.$user.'/files/'.$targetPath, $user ) ); +// +// if ( $row = $result->fetchRow( ) ) { +// +// $targetPath = $row['source']; +// +// $targetPath_parts = explode( '/', $targetPath ); +// +// $user = $targetPath_parts[1]; +// +// $rootview = new \OC_FilesystemView( '/' ); +// +// if ( ! $rootview->is_writable( $targetPath ) ) { +// +// \OC_Log::write( 'Encryption library', "File Key not updated because you don't have write access for the corresponding file", \OC_Log::ERROR ); +// +// return false; +// +// } +// +// $targetPath = str_replace( '/'.$user.'/files/', '', $targetPath ); +// +// //TODO: check for write permission on shared file once the new sharing API is in place +// +// } + + $path_parts = pathinfo( $targetPath ); + + if ( !$view ) { + + $view = new \OC_FilesystemView( '/' ); + + } + + $view->chroot( '/' . $user . '/files_encryption/keyfiles' ); + + // If the file resides within a subdirectory, create it + if ( + isset( $path_parts['dirname'] ) + && ! $view->file_exists( $path_parts['dirname'] ) + ) { + + $view->mkdir( $path_parts['dirname'] ); + + } + + // Save the keyfile in parallel directory + return $view->file_put_contents( '/' . $targetPath . '.key', $key ); + + } + + /** + * @brief change password of private encryption key + * + * @param string $oldpasswd old password + * @param string $newpasswd new password + * @return bool true/false + */ + public static function changePasswd($oldpasswd, $newpasswd) { + + if ( \OCP\User::checkPassword(\OCP\User::getUser(), $newpasswd) ) { + return Crypt::changekeypasscode($oldpasswd, $newpasswd); + } + return false; + + } + + /** + * @brief Fetch the legacy encryption key from user files + * @param string $login used to locate the legacy key + * @param string $passphrase used to decrypt the legacy key + * @return true / false + * + * if the key is left out, the default handeler will be used + */ + public function getLegacyKey() { + + $user = \OCP\User::getUser(); + $view = new \OC_FilesystemView( '/' . $user ); + return $view->file_get_contents( 'encryption.key' ); + + } + +} \ No newline at end of file diff --git a/apps/files_encryption/lib/proxy.php b/apps/files_encryption/lib/proxy.php index e8dbd95c29d2a242c9a422194e9500d3c21b8c7c..52f47dba2940faacfa6625c744695434a9282377 100644 --- a/apps/files_encryption/lib/proxy.php +++ b/apps/files_encryption/lib/proxy.php @@ -3,8 +3,9 @@ /** * ownCloud * -* @author Robin Appelman -* @copyright 2011 Robin Appelman icewind1991@gmail.com +* @author Sam Tuke, Robin Appelman +* @copyright 2012 Sam Tuke samtuke@owncloud.com, Robin Appelman +* icewind1991@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 @@ -21,111 +22,267 @@ * */ -/** - * transparent encryption - */ +namespace OCA\Encryption; -class OC_FileProxy_Encryption extends OC_FileProxy{ - private static $blackList=null; //mimetypes blacklisted from encryption - private static $enableEncryption=null; +class Proxy extends \OC_FileProxy { + private static $blackList = null; //mimetypes blacklisted from encryption + + private static $enableEncryption = null; + /** - * check if a file should be encrypted during write + * Check if a file requires encryption * @param string $path * @return bool + * + * Tests if server side encryption is enabled, and file is allowed by blacklists */ - private static function shouldEncrypt($path) { - if (is_null(self::$enableEncryption)) { - self::$enableEncryption=(OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true')=='true'); + private static function shouldEncrypt( $path ) { + + if ( is_null( self::$enableEncryption ) ) { + + if ( + \OCP\Config::getAppValue( 'files_encryption', 'enable_encryption', 'true' ) == 'true' + && Crypt::mode() == 'server' + ) { + + self::$enableEncryption = true; + + } else { + + self::$enableEncryption = false; + + } + } - if ( ! self::$enableEncryption) { + + if ( !self::$enableEncryption ) { + return false; + } - if (is_null(self::$blackList)) { - self::$blackList=explode(',', OCP\Config::getAppValue('files_encryption', - 'type_blacklist', - 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg')); + + if ( is_null(self::$blackList ) ) { + + self::$blackList = explode(',', \OCP\Config::getAppValue( 'files_encryption','type_blacklist','jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); + } - if (self::isEncrypted($path)) { + + if ( Crypt::isEncryptedContent( $path ) ) { + return true; + } - $extension=substr($path, strrpos($path, '.')+1); - if (array_search($extension, self::$blackList)===false) { + + $extension = substr( $path, strrpos( $path,'.' ) +1 ); + + if ( array_search( $extension, self::$blackList ) === false ){ + return true; + } + + return false; } - - /** - * check if a file is encrypted - * @param string $path - * @return bool - */ - private static function isEncrypted($path) { - $metadata=OC_FileCache_Cached::get($path, ''); - return isset($metadata['encrypted']) and (bool)$metadata['encrypted']; - } - - public function preFile_put_contents($path,&$data) { - if (self::shouldEncrypt($path)) { - if ( ! is_resource($data)) {//stream put contents should have been converter to fopen - $size=strlen($data); - $data=OC_Crypt::blockEncrypt($data); - OC_FileCache::put($path, array('encrypted'=>true,'size'=>$size), ''); + + public function preFile_put_contents( $path, &$data ) { + + if ( self::shouldEncrypt( $path ) ) { + + if ( !is_resource( $data ) ) { //stream put contents should have been converted to fopen + + $userId = \OCP\USER::getUser(); + + $rootView = new \OC_FilesystemView( '/' ); + + // Set the filesize for userland, before encrypting + $size = strlen( $data ); + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + // Encrypt plain data and fetch key + $encrypted = Crypt::keyEncryptKeyfile( $data, Keymanager::getPublicKey( $rootView, $userId ) ); + + // Replace plain content with encrypted content by reference + $data = $encrypted['data']; + + $filePath = explode( '/', $path ); + + $filePath = array_slice( $filePath, 3 ); + + $filePath = '/' . implode( '/', $filePath ); + + # TODO: make keyfile dir dynamic from app config + $view = new \OC_FilesystemView( '/' . $userId . '/files_encryption/keyfiles' ); + + // Save keyfile for newly encrypted file in parallel directory tree + Keymanager::setFileKey( $filePath, $encrypted['key'], $view, '\OC_DB' ); + + // Update the file cache with file info + \OC_FileCache::put( $path, array( 'encrypted'=>true, 'size' => $size ), '' ); + + // Re-enable proxy - our work is done + \OC_FileProxy::$enabled = true; + } } + } + + /** + * @param string $path Path of file from which has been read + * @param string $data Data that has been read from file + */ + public function postFile_get_contents( $path, $data ) { + + # TODO: Use dependency injection to add required args for view and user etc. to this method + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + // If data is a catfile + if ( + Crypt::mode() == 'server' + && Crypt::isEncryptedContent( $data ) + ) { + + $split = explode( '/', $path ); + + $filePath = array_slice( $split, 3 ); + + $filePath = '/' . implode( '/', $filePath ); + + //$cached = \OC_FileCache_Cached::get( $path, '' ); + + $view = new \OC_FilesystemView( '' ); + + $userId = \OCP\USER::getUser(); + + $encryptedKeyfile = Keymanager::getFileKey( $view, $userId, $filePath ); - public function postFile_get_contents($path, $data) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); - $data=OC_Crypt::blockDecrypt($data, '', $cached['size']); + $session = new Session(); + + $decrypted = Crypt::keyDecryptKeyfile( $data, $encryptedKeyfile, $session->getPrivateKey( $split[1] ) ); + + } elseif ( + Crypt::mode() == 'server' + && isset( $_SESSION['legacyenckey'] ) + && Crypt::isEncryptedMeta( $path ) + ) { + + $decrypted = Crypt::legacyDecrypt( $data, $_SESSION['legacyenckey'] ); + } - return $data; + + \OC_FileProxy::$enabled = true; + + if ( ! isset( $decrypted ) ) { + + $decrypted = $data; + + } + + return $decrypted; + } - - public function postFopen($path,&$result) { - if ( ! $result) { + + public function postFopen( $path, &$result ){ + + if ( !$result ) { + return $result; + } - $meta=stream_get_meta_data($result); - if (self::isEncrypted($path)) { - fclose($result); - $result=fopen('crypt://'.$path, $meta['mode']); - } elseif (self::shouldEncrypt($path) and $meta['mode']!='r' and $meta['mode']!='rb') { - if (OC_Filesystem::file_exists($path) and OC_Filesystem::filesize($path)>0) { - //first encrypt the target file so we don't end up with a half encrypted file - OCP\Util::writeLog('files_encryption', 'Decrypting '.$path.' before writing', OCP\Util::DEBUG); - $tmp=fopen('php://temp'); - OCP\Files::streamCopy($result, $tmp); - fclose($result); - OC_Filesystem::file_put_contents($path, $tmp); - fclose($tmp); + + // Reformat path for use with OC_FSV + $path_split = explode( '/', $path ); + $path_f = implode( array_slice( $path_split, 3 ) ); + + // Disable encryption proxy to prevent recursive calls + \OC_FileProxy::$enabled = false; + + $meta = stream_get_meta_data( $result ); + + $view = new \OC_FilesystemView( '' ); + + $util = new Util( $view, \OCP\USER::getUser()); + + // If file is already encrypted, decrypt using crypto protocol + if ( + Crypt::mode() == 'server' + && $util->isEncryptedPath( $path ) + ) { + + // Close the original encrypted file + fclose( $result ); + + // Open the file using the crypto stream wrapper + // protocol and let it do the decryption work instead + $result = fopen( 'crypt://' . $path_f, $meta['mode'] ); + + + } elseif ( + self::shouldEncrypt( $path ) + and $meta ['mode'] != 'r' + and $meta['mode'] != 'rb' + ) { + // If the file is not yet encrypted, but should be + // encrypted when it's saved (it's not read only) + + // NOTE: this is the case for new files saved via WebDAV + + if ( + $view->file_exists( $path ) + and $view->filesize( $path ) > 0 + ) { + $x = $view->file_get_contents( $path ); + + $tmp = tmpfile(); + +// // Make a temporary copy of the original file +// \OCP\Files::streamCopy( $result, $tmp ); +// +// // Close the original stream, we'll return another one +// fclose( $result ); +// +// $view->file_put_contents( $path_f, $tmp ); +// +// fclose( $tmp ); + } - $result=fopen('crypt://'.$path, $meta['mode']); + + $result = fopen( 'crypt://'.$path_f, $meta['mode'] ); + } + + // Re-enable the proxy + \OC_FileProxy::$enabled = true; + return $result; + } - public function postGetMimeType($path, $mime) { - if (self::isEncrypted($path)) { - $mime=OCP\Files::getMimeType('crypt://'.$path, 'w'); + public function postGetMimeType($path,$mime){ + if( Crypt::isEncryptedContent($path)){ + $mime = \OCP\Files::getMimeType('crypt://'.$path,'w'); } return $mime; } - public function postStat($path, $data) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); + public function postStat($path,$data){ + if( Crypt::isEncryptedContent($path)){ + $cached= \OC_FileCache_Cached::get($path,''); $data['size']=$cached['size']; } return $data; } - public function postFileSize($path, $size) { - if (self::isEncrypted($path)) { - $cached=OC_FileCache_Cached::get($path, ''); + public function postFileSize($path,$size){ + if( Crypt::isEncryptedContent($path)){ + $cached = \OC_FileCache_Cached::get($path,''); return $cached['size']; - } else { + }else{ return $size; } } diff --git a/apps/files_versions/ajax/expireAll.php b/apps/files_encryption/lib/session.php similarity index 53% rename from apps/files_versions/ajax/expireAll.php rename to apps/files_encryption/lib/session.php index 5c95885ffbdc15281bdb891967cbf0f04b34e32b..85d533fde7a6d7bdff1b047d4e6649af82657229 100644 --- a/apps/files_versions/ajax/expireAll.php +++ b/apps/files_encryption/lib/session.php @@ -1,7 +1,6 @@ expireAll() ) { - - OCP\JSON::success(); - die(); +/** + * Class for handling encryption related session data + */ -} else { +class Session { - OCP\JSON::error(); - die(); + /** + * @brief Sets user id for session and triggers emit + * @return bool + * + */ + public function setPrivateKey( $privateKey, $userId ) { + + $_SESSION['privateKey'] = $privateKey; + + return true; + + } + + /** + * @brief Gets user id for session and triggers emit + * @returns string $privateKey The user's plaintext private key + * + */ + public function getPrivateKey( $userId ) { + + if ( + isset( $_SESSION['privateKey'] ) + && !empty( $_SESSION['privateKey'] ) + ) { + + return $_SESSION['privateKey']; + + } else { + + return false; + + } + + } } \ No newline at end of file diff --git a/apps/files_encryption/lib/stream.php b/apps/files_encryption/lib/stream.php new file mode 100644 index 0000000000000000000000000000000000000000..f482e2d75ac13480f293564291bbc8b548aa4ca6 --- /dev/null +++ b/apps/files_encryption/lib/stream.php @@ -0,0 +1,464 @@ +, 2011 Robin Appelman + * + * + * 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 . + * + */ + +/** + * transparently encrypted filestream + * + * you can use it as wrapper around an existing stream by setting CryptStream::$sourceStreams['foo']=array('path'=>$path,'stream'=>$stream) + * and then fopen('crypt://streams/foo'); + */ + +namespace OCA\Encryption; + +/** + * @brief Provides 'crypt://' stream wrapper protocol. + * @note We use a stream wrapper because it is the most secure way to handle + * decrypted content transfers. There is no safe way to decrypt the entire file + * somewhere on the server, so we have to encrypt and decrypt blocks on the fly. + * @note Paths used with this protocol MUST BE RELATIVE. Use URLs like: + * crypt://filename, or crypt://subdirectory/filename, NOT + * crypt:///home/user/owncloud/data. Otherwise keyfiles will be put in + * [owncloud]/data/user/files_encryption/keyfiles/home/user/owncloud/data and + * will not be accessible to other methods. + * @note Data read and written must always be 8192 bytes long, as this is the + * buffer size used internally by PHP. The encryption process makes the input + * data longer, and input is chunked into smaller pieces in order to result in + * a 8192 encrypted block size. + */ +class Stream { + + public static $sourceStreams = array(); + + # TODO: make all below properties private again once unit testing is configured correctly + public $rawPath; // The raw path received by stream_open + public $path_f; // The raw path formatted to include username and data directory + private $userId; + private $handle; // Resource returned by fopen + private $path; + private $readBuffer; // For streams that dont support seeking + private $meta = array(); // Header / meta for source stream + private $count; + private $writeCache; + public $size; + private $publicKey; + private $keyfile; + private $encKeyfile; + private static $view; // a fsview object set to user dir + private $rootView; // a fsview object set to '/' + + public function stream_open( $path, $mode, $options, &$opened_path ) { + + // Get access to filesystem via filesystemview object + if ( !self::$view ) { + + self::$view = new \OC_FilesystemView( $this->userId . '/' ); + + } + + // Set rootview object if necessary + if ( ! $this->rootView ) { + + $this->rootView = new \OC_FilesystemView( $this->userId . '/' ); + + } + + $this->userId = \OCP\User::getUser(); + + // Get the bare file path + $path = str_replace( 'crypt://', '', $path ); + + $this->rawPath = $path; + + $this->path_f = $this->userId . '/files/' . $path; + + if ( + dirname( $path ) == 'streams' + and isset( self::$sourceStreams[basename( $path )] ) + ) { + + // Is this just for unit testing purposes? + + $this->handle = self::$sourceStreams[basename( $path )]['stream']; + + $this->path = self::$sourceStreams[basename( $path )]['path']; + + $this->size = self::$sourceStreams[basename( $path )]['size']; + + } else { + + if ( + $mode == 'w' + or $mode == 'w+' + or $mode == 'wb' + or $mode == 'wb+' + ) { + + $this->size = 0; + + } else { + + + + $this->size = self::$view->filesize( $this->path_f, $mode ); + + //$this->size = filesize( $path ); + + } + + // Disable fileproxies so we can open the source file without recursive encryption + \OC_FileProxy::$enabled = false; + + //$this->handle = fopen( $path, $mode ); + + $this->handle = self::$view->fopen( $this->path_f, $mode ); + + \OC_FileProxy::$enabled = true; + + if ( !is_resource( $this->handle ) ) { + + \OCP\Util::writeLog( 'files_encryption', 'failed to open '.$path, \OCP\Util::ERROR ); + + } + + } + + if ( is_resource( $this->handle ) ) { + + $this->meta = stream_get_meta_data( $this->handle ); + + } + + return is_resource( $this->handle ); + + } + + public function stream_seek( $offset, $whence = SEEK_SET ) { + + $this->flush(); + + fseek( $this->handle, $offset, $whence ); + + } + + public function stream_tell() { + return ftell($this->handle); + } + + public function stream_read( $count ) { + + $this->writeCache = ''; + + if ( $count != 8192 ) { + + // $count will always be 8192 https://bugs.php.net/bug.php?id=21641 + // This makes this function a lot simpler, but will break this class if the above 'bug' gets 'fixed' + \OCP\Util::writeLog( 'files_encryption', 'PHP "bug" 21641 no longer holds, decryption system requires refactoring', OCP\Util::FATAL ); + + die(); + + } + +// $pos = ftell( $this->handle ); +// + // Get the data from the file handle + $data = fread( $this->handle, 8192 ); + + if ( strlen( $data ) ) { + + $this->getKey(); + + $result = Crypt::symmetricDecryptFileContent( $data, $this->keyfile ); + + } else { + + $result = ''; + + } + +// $length = $this->size - $pos; +// +// if ( $length < 8192 ) { +// +// $result = substr( $result, 0, $length ); +// +// } + + return $result; + + } + + /** + * @brief Encrypt and pad data ready for writting to disk + * @param string $plainData data to be encrypted + * @param string $key key to use for encryption + * @return encrypted data on success, false on failure + */ + public function preWriteEncrypt( $plainData, $key ) { + + // Encrypt data to 'catfile', which includes IV + if ( $encrypted = Crypt::symmetricEncryptFileContent( $plainData, $key ) ) { + + return $encrypted; + + } else { + + return false; + + } + + } + + /** + * @brief Get the keyfile for the current file, generate one if necessary + * @param bool $generate if true, a new key will be generated if none can be found + * @return bool true on key found and set, false on key not found and new key generated and set + */ + public function getKey() { + + // If a keyfile already exists for a file named identically to file to be written + if ( self::$view->file_exists( $this->userId . '/'. 'files_encryption' . '/' . 'keyfiles' . '/' . $this->rawPath . '.key' ) ) { + + # TODO: add error handling for when file exists but no keyfile + + // Fetch existing keyfile + $this->encKeyfile = Keymanager::getFileKey( $this->rootView, $this->userId, $this->rawPath ); + + $this->getUser(); + + $session = new Session(); + + $privateKey = $session->getPrivateKey( $this->userId ); + + $this->keyfile = Crypt::keyDecrypt( $this->encKeyfile, $privateKey ); + + return true; + + } else { + + return false; + + } + + } + + public function getuser() { + + // Only get the user again if it isn't already set + if ( empty( $this->userId ) ) { + + # TODO: Move this user call out of here - it belongs elsewhere + $this->userId = \OCP\User::getUser(); + + } + + # TODO: Add a method for getting the user in case OCP\User:: + # getUser() doesn't work (can that scenario ever occur?) + + } + + /** + * @brief Handle plain data from the stream, and write it in 8192 byte blocks + * @param string $data data to be written to disk + * @note the data will be written to the path stored in the stream handle, set in stream_open() + * @note $data is only ever be a maximum of 8192 bytes long. This is set by PHP internally. stream_write() is called multiple times in a loop on data larger than 8192 bytes + * @note Because the encryption process used increases the length of $data, a writeCache is used to carry over data which would not fit in the required block size + * @note Padding is added to each encrypted block to ensure that the resulting block is exactly 8192 bytes. This is removed during stream_read + * @note PHP automatically updates the file pointer after writing data to reflect it's length. There is generally no need to update the poitner manually using fseek + */ + public function stream_write( $data ) { + + // Disable the file proxies so that encryption is not automatically attempted when the file is written to disk - we are handling that separately here and we don't want to get into an infinite loop + \OC_FileProxy::$enabled = false; + + // Get the length of the unencrypted data that we are handling + $length = strlen( $data ); + + // So far this round, no data has been written + $written = 0; + + // Find out where we are up to in the writing of data to the file + $pointer = ftell( $this->handle ); + + // Make sure the userId is set + $this->getuser(); + + // Get / generate the keyfile for the file we're handling + // If we're writing a new file (not overwriting an existing one), save the newly generated keyfile + if ( ! $this->getKey() ) { + + $this->keyfile = Crypt::generateKey(); + + $this->publicKey = Keymanager::getPublicKey( $this->rootView, $this->userId ); + + $this->encKeyfile = Crypt::keyEncrypt( $this->keyfile, $this->publicKey ); + + // Save the new encrypted file key + Keymanager::setFileKey( $this->rawPath, $this->encKeyfile, new \OC_FilesystemView( '/' ) ); + + # TODO: move this new OCFSV out of here some how, use DI + + } + + // If extra data is left over from the last round, make sure it is integrated into the next 6126 / 8192 block + if ( $this->writeCache ) { + + // Concat writeCache to start of $data + $data = $this->writeCache . $data; + + // Clear the write cache, ready for resuse - it has been flushed and its old contents processed + $this->writeCache = ''; + + } +// +// // Make sure we always start on a block start + if ( 0 != ( $pointer % 8192 ) ) { // if the current positoin of file indicator is not aligned to a 8192 byte block, fix it so that it is + +// fseek( $this->handle, - ( $pointer % 8192 ), SEEK_CUR ); +// +// $pointer = ftell( $this->handle ); +// +// $unencryptedNewBlock = fread( $this->handle, 8192 ); +// +// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); +// +// $block = Crypt::symmetricDecryptFileContent( $unencryptedNewBlock, $this->keyfile ); +// +// $x = substr( $block, 0, $currentPos % 8192 ); +// +// $data = $x . $data; +// +// fseek( $this->handle, - ( $currentPos % 8192 ), SEEK_CUR ); +// + } + +// $currentPos = ftell( $this->handle ); + +// // While there still remains somed data to be processed & written + while( strlen( $data ) > 0 ) { +// +// // Remaining length for this iteration, not of the entire file (may be greater than 8192 bytes) +// $remainingLength = strlen( $data ); +// +// // If data remaining to be written is less than the size of 1 6126 byte block + if ( strlen( $data ) < 6126 ) { + + // Set writeCache to contents of $data + // The writeCache will be carried over to the next write round, and added to the start of $data to ensure that written blocks are always the correct length. If there is still data in writeCache after the writing round has finished, then the data will be written to disk by $this->flush(). + $this->writeCache = $data; + + // Clear $data ready for next round + $data = ''; +// + } else { + + // Read the chunk from the start of $data + $chunk = substr( $data, 0, 6126 ); + + $encrypted = $this->preWriteEncrypt( $chunk, $this->keyfile ); + + // Write the data chunk to disk. This will be addended to the last data chunk if the file being handled totals more than 6126 bytes + fwrite( $this->handle, $encrypted ); + + $writtenLen = strlen( $encrypted ); + //fseek( $this->handle, $writtenLen, SEEK_CUR ); + + // Remove the chunk we just processed from $data, leaving only unprocessed data in $data var, for handling on the next round + $data = substr( $data, 6126 ); + + } + + } + + $this->size = max( $this->size, $pointer + $length ); + + return $length; + + } + + + public function stream_set_option($option,$arg1,$arg2) { + switch($option) { + case STREAM_OPTION_BLOCKING: + stream_set_blocking($this->handle,$arg1); + break; + case STREAM_OPTION_READ_TIMEOUT: + stream_set_timeout($this->handle,$arg1,$arg2); + break; + case STREAM_OPTION_WRITE_BUFFER: + stream_set_write_buffer($this->handle,$arg1,$arg2); + } + } + + public function stream_stat() { + return fstat($this->handle); + } + + public function stream_lock($mode) { + flock($this->handle,$mode); + } + + public function stream_flush() { + + return fflush($this->handle); // Not a typo: http://php.net/manual/en/function.fflush.php + + } + + public function stream_eof() { + return feof($this->handle); + } + + private function flush() { + + if ( $this->writeCache ) { + + // Set keyfile property for file in question + $this->getKey(); + + $encrypted = $this->preWriteEncrypt( $this->writeCache, $this->keyfile ); + + fwrite( $this->handle, $encrypted ); + + $this->writeCache = ''; + + } + + } + + public function stream_close() { + + $this->flush(); + + if ( + $this->meta['mode']!='r' + and $this->meta['mode']!='rb' + ) { + + \OC_FileCache::put( $this->path, array( 'encrypted' => true, 'size' => $this->size ), '' ); + + } + + return fclose( $this->handle ); + + } + +} diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php new file mode 100644 index 0000000000000000000000000000000000000000..cd46d23108af1f884aafb28ea0cc444a267731dc --- /dev/null +++ b/apps/files_encryption/lib/util.php @@ -0,0 +1,330 @@ +. + * + */ + +// Todo: +// - 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/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 + +namespace OCA\Encryption; + +/** + * @brief Class for utilities relating to encrypted file storage system + * @param $view OC_FilesystemView object, expected to have OC '/' as root path + * @param $client flag indicating status of client side encryption. Currently + * unused, likely to become obsolete shortly + */ + +class Util { + + + # Web UI: + + ## DONE: files created via web ui are encrypted + ## DONE: file created & encrypted via web ui are readable in web ui + ## DONE: file created & encrypted via web ui are readable via webdav + + + # WebDAV: + + ## DONE: new data filled files added via webdav get encrypted + ## DONE: new data filled files added via webdav are readable via webdav + ## DONE: reading unencrypted files when encryption is enabled works via webdav + ## DONE: files created & encrypted via web ui are readable via webdav + + + # Legacy support: + + ## DONE: add method to check if file is encrypted using new system + ## DONE: add method to check if file is encrypted using old system + ## DONE: add method to fetch legacy key + ## DONE: add method to decrypt legacy encrypted data + + ## TODO: add method to encrypt all user files using new system + ## TODO: add method to decrypt all user files using new system + ## TODO: add method to encrypt all user files using old system + ## TODO: add method to decrypt all user files using old system + + + # Admin UI: + + ## DONE: changing user password also changes encryption passphrase + + ## TODO: add support for optional recovery in case of lost passphrase / keys + ## TODO: add admin optional required long passphrase for users + ## TODO: add UI buttons for encrypt / decrypt everything + ## TODO: implement flag system to allow user to specify encryption by folder, subfolder, etc. + + + # Sharing: + + ## TODO: add support for encrypting to multiple public keys + ## TODO: add support for decrypting to multiple private keys + + + # Integration testing: + + ## TODO: test new encryption with webdav + ## TODO: test new encryption with versioning + ## TODO: test new encryption with sharing + ## TODO: test new encryption with proxies + + + private $view; // OC_FilesystemView object for filesystem operations + private $pwd; // User Password + private $client; // Client side encryption mode flag + private $publicKeyDir; // Directory containing all public user keys + private $encryptionDir; // Directory containing user's files_encryption + private $keyfilesPath; // Directory containing user's keyfiles + private $publicKeyPath; // Path to user's public key + private $privateKeyPath; // Path to user's private key + + public function __construct( \OC_FilesystemView $view, $userId, $client = false ) { + + $this->view = $view; + $this->userId = $userId; + $this->client = $client; + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + + } + + public function ready() { + + if( + !$this->view->file_exists( $this->keyfilesPath ) + or !$this->view->file_exists( $this->publicKeyPath ) + or !$this->view->file_exists( $this->privateKeyPath ) + ) { + + return false; + + } else { + + return true; + + } + + } + + /** + * @brief Sets up user folders and keys for serverside encryption + * @param $passphrase passphrase to encrypt server-stored private key with + */ + public function setupServerSide( $passphrase = null ) { + + // Create shared public key directory + if( !$this->view->file_exists( $this->publicKeyDir ) ) { + + $this->view->mkdir( $this->publicKeyDir ); + + } + + // Create encryption app directory + if( !$this->view->file_exists( $this->encryptionDir ) ) { + + $this->view->mkdir( $this->encryptionDir ); + + } + + // Create mirrored keyfile directory + if( !$this->view->file_exists( $this->keyfilesPath ) ) { + + $this->view->mkdir( $this->keyfilesPath ); + + } + + // Create user keypair + if ( + !$this->view->file_exists( $this->publicKeyPath ) + or !$this->view->file_exists( $this->privateKeyPath ) + ) { + + // Generate keypair + $keypair = Crypt::createKeypair(); + + \OC_FileProxy::$enabled = false; + + // Save public key + $this->view->file_put_contents( $this->publicKeyPath, $keypair['publicKey'] ); + + // Encrypt private key with user pwd as passphrase + $encryptedPrivateKey = Crypt::symmetricEncryptFileContent( $keypair['privateKey'], $passphrase ); + + // Save private key + $this->view->file_put_contents( $this->privateKeyPath, $encryptedPrivateKey ); + + \OC_FileProxy::$enabled = true; + + } + + return true; + + } + + public function findFiles( $directory, $type = 'plain' ) { + + # TODO: test finding non plain content + + if ( $handle = $this->view->opendir( $directory ) ) { + + while ( false !== ( $file = readdir( $handle ) ) ) { + + if ( + $file != "." + && $file != ".." + ) { + + $filePath = $directory . '/' . $this->view->getRelativePath( '/' . $file ); + + var_dump($filePath); + + if ( $this->view->is_dir( $filePath ) ) { + + $this->findFiles( $filePath ); + + } elseif ( $this->view->is_file( $filePath ) ) { + + if ( $type == 'plain' ) { + + $this->files[] = array( 'name' => $file, 'path' => $filePath ); + + } elseif ( $type == 'encrypted' ) { + + if ( Crypt::isEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { + + $this->files[] = array( 'name' => $file, 'path' => $filePath ); + + } + + } elseif ( $type == 'legacy' ) { + + if ( Crypt::isLegacyEncryptedContent( $this->view->file_get_contents( $filePath ) ) ) { + + $this->files[] = array( 'name' => $file, 'path' => $filePath ); + + } + + } + + } + + } + + } + + if ( !empty( $this->files ) ) { + + return $this->files; + + } else { + + return false; + + } + + } + + return false; + + } + + /** + * @brief Check if a given path identifies an encrypted file + * @return true / false + */ + public function isEncryptedPath( $path ) { + + // Disable encryption proxy so data retreived is in its + // original form + \OC_FileProxy::$enabled = false; + + $data = $this->view->file_get_contents( $path ); + + \OC_FileProxy::$enabled = true; + + return Crypt::isEncryptedContent( $data ); + + } + + public function encryptAll( $directory ) { + + $plainFiles = $this->findFiles( $this->view, 'plain' ); + + if ( $this->encryptFiles( $plainFiles ) ) { + + return true; + + } else { + + return false; + + } + + } + + public function getPath( $pathName ) { + + switch ( $pathName ) { + + case 'publicKeyDir': + + return $this->publicKeyDir; + + break; + + case 'encryptionDir': + + return $this->encryptionDir; + + break; + + case 'keyfilesPath': + + return $this->keyfilesPath; + + break; + + case 'publicKeyPath': + + return $this->publicKeyPath; + + break; + + case 'privateKeyPath': + + return $this->privateKeyPath; + + break; + + } + + } + +} diff --git a/apps/files_encryption/settings-personal.php b/apps/files_encryption/settings-personal.php new file mode 100644 index 0000000000000000000000000000000000000000..014288f2efe7d4dff3f79bf0a9a4775dd4e3ad63 --- /dev/null +++ b/apps/files_encryption/settings-personal.php @@ -0,0 +1,29 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +$sysEncMode = \OC_Appconfig::getValue('files_encryption', 'mode', 'none'); + +if ($sysEncMode == 'user') { + + $tmpl = new OCP\Template( 'files_encryption', 'settings-personal'); + + $query = \OC_DB::prepare( "SELECT mode FROM *PREFIX*encryption WHERE uid = ?" ); + $result = $query->execute(array(\OCP\User::getUser())); + + if ($row = $result->fetchRow()){ + $mode = $row['mode']; + } else { + $mode = 'none'; + } + + OCP\Util::addscript('files_encryption','settings-personal'); + $tmpl->assign('encryption_mode', $mode); + return $tmpl->fetchPage(); +} + +return null; diff --git a/apps/files_encryption/settings.php b/apps/files_encryption/settings.php index 94ff5ab94bab3561774780c16d777891915d79c4..d1260f44e9f6ef98a6702f13a9fc3fd3a2a38073 100644 --- a/apps/files_encryption/settings.php +++ b/apps/files_encryption/settings.php @@ -6,17 +6,16 @@ * See the COPYING-README file. */ -OC_Util::checkAdminUser(); +\OC_Util::checkAdminUser(); -$tmpl = new OCP\Template( 'files_encryption', 'settings'); -$blackList=explode(',', OCP\Config::getAppValue('files_encryption', - 'type_blacklist', - 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg')); -$enabled=(OCP\Config::getAppValue('files_encryption', 'enable_encryption', 'true')=='true'); -$tmpl->assign('blacklist', $blackList); -$tmpl->assign('encryption_enabled', $enabled); +$tmpl = new OCP\Template( 'files_encryption', 'settings' ); -OCP\Util::addscript('files_encryption', 'settings'); -OCP\Util::addscript('core', 'multiselect'); +$blackList = explode( ',', \OCP\Config::getAppValue( 'files_encryption', 'type_blacklist', 'jpg,png,jpeg,avi,mpg,mpeg,mkv,mp3,oga,ogv,ogg' ) ); + +$tmpl->assign( 'blacklist', $blackList ); +$tmpl->assign( 'encryption_mode', \OC_Appconfig::getValue( 'files_encryption', 'mode', 'none' ) ); + +\OCP\Util::addscript( 'files_encryption', 'settings' ); +\OCP\Util::addscript( 'core', 'multiselect' ); return $tmpl->fetchPage(); diff --git a/apps/files_encryption/templates/settings-personal.php b/apps/files_encryption/templates/settings-personal.php new file mode 100644 index 0000000000000000000000000000000000000000..1274bd3bb5c34b26a35cacde2acaf4f4460acd2c --- /dev/null +++ b/apps/files_encryption/templates/settings-personal.php @@ -0,0 +1,45 @@ +
+
+ t('Choose encryption mode:'); ?> +

+ + + + /> + t('Client side encryption (most secure but makes it impossible to access your data from the web interface)'); ?> +
+ + + /> + t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?> +
+ + + /> + t('None (no encryption at all)'); ?> +
+

+
+
diff --git a/apps/files_encryption/templates/settings.php b/apps/files_encryption/templates/settings.php index 268b1a80ccd10e26df27eeceda2e961a7eb4e6c5..544ec793f375890e1781342b4bfac9d6d3e0263b 100644 --- a/apps/files_encryption/templates/settings.php +++ b/apps/files_encryption/templates/settings.php @@ -1,14 +1,79 @@ -
+
- t('Encryption');?> - checked="checked" - id='enable_encryption' > -
- + /> + + t("Client side encryption (most secure but makes it impossible to access your data from the web interface)"); ?> +
+ + + /> + + t('Server side encryption (allows you to access your files from the web interface and the desktop client)'); ?> +
+ + + /> + + t('User specific (let the user decide)'); ?> +
+ + + /> + + t('None (no encryption at all)'); ?> +
+ +

+

+ t('Encryption'); ?> + + t("Exclude the following file types from encryption"); ?> + +
- t('Exclude the following file types from encryption'); ?> + +

diff --git a/apps/files_encryption/tests/binary b/apps/files_encryption/test/binary similarity index 100% rename from apps/files_encryption/tests/binary rename to apps/files_encryption/test/binary diff --git a/apps/files_encryption/test/crypt.php b/apps/files_encryption/test/crypt.php new file mode 100755 index 0000000000000000000000000000000000000000..19c10ab0ab5b358a363358004d223e2e7a965d58 --- /dev/null +++ b/apps/files_encryption/test/crypt.php @@ -0,0 +1,667 @@ +, and + * Robin Appelman + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +//require_once "PHPUnit/Framework/TestCase.php"; +require_once realpath( dirname(__FILE__).'/../../../3rdparty/Crypt_Blowfish/Blowfish.php' ); +require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); +require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); +require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); +require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); +require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); +require_once realpath( dirname(__FILE__).'/../lib/util.php' ); +require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); + +use OCA\Encryption; + +// This has to go here because otherwise session errors arise, and the private +// encryption key needs to be saved in the session +\OC_User::login( 'admin', 'admin' ); + +/** + * @note It would be better to use Mockery here for mocking out the session + * handling process, and isolate calls to session class and data from the unit + * tests relating to them (stream etc.). However getting mockery to work and + * overload classes whilst also using the OC autoloader is difficult due to + * load order Pear errors. + */ + +class Test_Crypt extends \PHPUnit_Framework_TestCase { + + function setUp() { + + // set content for encrypting / decrypting in tests + $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + $this->dataShort = 'hats'; + $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); + $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); + $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->randomKey = Encryption\Crypt::generateKey(); + + $keypair = Encryption\Crypt::createKeypair(); + $this->genPublicKey = $keypair['publicKey']; + $this->genPrivateKey = $keypair['privateKey']; + + $this->view = new \OC_FilesystemView( '/' ); + + \OC_User::setUserId( 'admin' ); + $this->userId = 'admin'; + $this->pass = 'admin'; + + \OC_Filesystem::init( '/' ); + \OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' ); + + } + + function tearDown() { + + } + + function testGenerateKey() { + + # TODO: use more accurate (larger) string length for test confirmation + + $key = Encryption\Crypt::generateKey(); + + $this->assertTrue( strlen( $key ) > 16 ); + + } + + function testGenerateIv() { + + $iv = Encryption\Crypt::generateIv(); + + $this->assertEquals( 16, strlen( $iv ) ); + + return $iv; + + } + + /** + * @depends testGenerateIv + */ + function testConcatIv( $iv ) { + + $catFile = Encryption\Crypt::concatIv( $this->dataLong, $iv ); + + // Fetch encryption metadata from end of file + $meta = substr( $catFile, -22 ); + + $identifier = substr( $meta, 0, 6); + + // Fetch IV from end of file + $foundIv = substr( $meta, 6 ); + + $this->assertEquals( '00iv00', $identifier ); + + $this->assertEquals( $iv, $foundIv ); + + // Remove IV and IV identifier text to expose encrypted content + $data = substr( $catFile, 0, -22 ); + + $this->assertEquals( $this->dataLong, $data ); + + return array( + 'iv' => $iv + , 'catfile' => $catFile + ); + + } + + /** + * @depends testConcatIv + */ + function testSplitIv( $testConcatIv ) { + + // Split catfile into components + $splitCatfile = Encryption\Crypt::splitIv( $testConcatIv['catfile'] ); + + // Check that original IV and split IV match + $this->assertEquals( $testConcatIv['iv'], $splitCatfile['iv'] ); + + // Check that original data and split data match + $this->assertEquals( $this->dataLong, $splitCatfile['encrypted'] ); + + } + + function testAddPadding() { + + $padded = Encryption\Crypt::addPadding( $this->dataLong ); + + $padding = substr( $padded, -2 ); + + $this->assertEquals( 'xx' , $padding ); + + return $padded; + + } + + /** + * @depends testAddPadding + */ + function testRemovePadding( $padded ) { + + $noPadding = Encryption\Crypt::RemovePadding( $padded ); + + $this->assertEquals( $this->dataLong, $noPadding ); + + } + + function testEncrypt() { + + $random = openssl_random_pseudo_bytes( 13 ); + + $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); + + $this->assertNotEquals( $this->dataUrl, $crypted ); + + } + + function testDecrypt() { + + $random = openssl_random_pseudo_bytes( 13 ); + + $iv = substr( base64_encode( $random ), 0, -4 ); // i.e. E5IG033j+mRNKrht + + $crypted = Encryption\Crypt::encrypt( $this->dataUrl, $iv, 'hat' ); + + $decrypt = Encryption\Crypt::decrypt( $crypted, $iv, 'hat' ); + + $this->assertEquals( $this->dataUrl, $decrypt ); + + } + + function testSymmetricEncryptFileContent() { + + # TODO: search in keyfile for actual content as IV will ensure this test always passes + + $crypted = Encryption\Crypt::symmetricEncryptFileContent( $this->dataShort, 'hat' ); + + $this->assertNotEquals( $this->dataShort, $crypted ); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted, 'hat' ); + + $this->assertEquals( $this->dataShort, $decrypt ); + + } + + // These aren't used for now +// function testSymmetricBlockEncryptShortFileContent() { +// +// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataShort, $this->randomKey ); +// +// $this->assertNotEquals( $this->dataShort, $crypted ); +// +// +// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey ); +// +// $this->assertEquals( $this->dataShort, $decrypt ); +// +// } +// +// function testSymmetricBlockEncryptLongFileContent() { +// +// $crypted = Encryption\Crypt::symmetricBlockEncryptFileContent( $this->dataLong, $this->randomKey ); +// +// $this->assertNotEquals( $this->dataLong, $crypted ); +// +// +// $decrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $crypted, $this->randomKey ); +// +// $this->assertEquals( $this->dataLong, $decrypt ); +// +// } + + function testSymmetricStreamEncryptShortFileContent() { + + $filename = 'tmp-'.time(); + + $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); + + // Test that data was successfully written + $this->assertTrue( is_int( $cryptedFile ) ); + + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename ); + + // Check that the file was encrypted before being written to disk + $this->assertNotEquals( $this->dataShort, $retreivedCryptedFile ); + + // Get private key + $encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); + + $decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass ); + + + // Get keyfile + $encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + + $decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey ); + + + // Manually decrypt + $manualDecrypt = Encryption\Crypt::symmetricBlockDecryptFileContent( $retreivedCryptedFile, $decryptedKeyfile ); + + // Check that decrypted data matches + $this->assertEquals( $this->dataShort, $manualDecrypt ); + + } + + /** + * @brief Test that data that is written by the crypto stream wrapper + * @note Encrypted data is manually prepared and decrypted here to avoid dependency on success of stream_read + * @note If this test fails with truncate content, check that enough array slices are being rejoined to form $e, as the crypt.php file may have gotten longer and broken the manual + * reassembly of its data + */ + function testSymmetricStreamEncryptLongFileContent() { + + // Generate a a random filename + $filename = 'tmp-'.time(); + + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong.$this->dataLong ); + + // Test that data was successfully written + $this->assertTrue( is_int( $cryptedFile ) ); + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename ); + +// echo "\n\n\$retreivedCryptedFile = $retreivedCryptedFile\n\n"; + + // Check that the file was encrypted before being written to disk + $this->assertNotEquals( $this->dataLong.$this->dataLong, $retreivedCryptedFile ); + + // Manuallly split saved file into separate IVs and encrypted chunks + $r = preg_split('/(00iv00.{16,18})/', $retreivedCryptedFile, NULL, PREG_SPLIT_DELIM_CAPTURE); + + //print_r($r); + + // Join IVs and their respective data chunks + $e = array( $r[0].$r[1], $r[2].$r[3], $r[4].$r[5], $r[6].$r[7], $r[8].$r[9], $r[10].$r[11], $r[12].$r[13] );//.$r[11], $r[12].$r[13], $r[14] ); + + //print_r($e); + + + // Get private key + $encryptedPrivateKey = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); + + $decryptedPrivateKey = Encryption\Crypt::symmetricDecryptFileContent( $encryptedPrivateKey, $this->pass ); + + + // Get keyfile + $encryptedKeyfile = Encryption\Keymanager::getFileKey( $this->view, $this->userId, $filename ); + + $decryptedKeyfile = Encryption\Crypt::keyDecrypt( $encryptedKeyfile, $decryptedPrivateKey ); + + + // Set var for reassembling decrypted content + $decrypt = ''; + + // Manually decrypt chunk + foreach ($e as $e) { + +// echo "\n\$e = $e"; + + $chunkDecrypt = Encryption\Crypt::symmetricDecryptFileContent( $e, $decryptedKeyfile ); + + // Assemble decrypted chunks + $decrypt .= $chunkDecrypt; + +// echo "\n\$chunkDecrypt = $chunkDecrypt"; + + } + +// echo "\n\$decrypt = $decrypt"; + + $this->assertEquals( $this->dataLong.$this->dataLong, $decrypt ); + + // Teardown + + $this->view->unlink( $filename ); + + Encryption\Keymanager::deleteFileKey( $filename ); + + } + + /** + * @brief Test that data that is read by the crypto stream wrapper + */ + function testSymmetricStreamDecryptShortFileContent() { + + $filename = 'tmp-'.time(); + + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataShort ); + + // Test that data was successfully written + $this->assertTrue( is_int( $cryptedFile ) ); + + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename ); + + $decrypt = file_get_contents( 'crypt://' . $filename ); + + $this->assertEquals( $this->dataShort, $decrypt ); + + } + + function testSymmetricStreamDecryptLongFileContent() { + + $filename = 'tmp-'.time(); + + // Save long data as encrypted file using stream wrapper + $cryptedFile = file_put_contents( 'crypt://' . $filename, $this->dataLong ); + + // Test that data was successfully written + $this->assertTrue( is_int( $cryptedFile ) ); + + + // Get file contents without using any wrapper to get it's actual contents on disk + $retreivedCryptedFile = $this->view->file_get_contents( $this->userId . '/files/' . $filename ); + + $decrypt = file_get_contents( 'crypt://' . $filename ); + + $this->assertEquals( $this->dataLong, $decrypt ); + + } + + // Is this test still necessary? +// function testSymmetricBlockStreamDecryptFileContent() { +// +// \OC_User::setUserId( 'admin' ); +// +// // Disable encryption proxy to prevent unwanted en/decryption +// \OC_FileProxy::$enabled = false; +// +// $cryptedFile = file_put_contents( 'crypt://' . '/blockEncrypt', $this->dataUrl ); +// +// // Disable encryption proxy to prevent unwanted en/decryption +// \OC_FileProxy::$enabled = false; +// +// echo "\n\n\$cryptedFile = " . $this->view->file_get_contents( '/blockEncrypt' ); +// +// $retreivedCryptedFile = file_get_contents( 'crypt://' . '/blockEncrypt' ); +// +// $this->assertEquals( $this->dataUrl, $retreivedCryptedFile ); +// +// \OC_FileProxy::$enabled = false; +// +// } + + function testSymmetricEncryptFileContentKeyfile() { + + # TODO: search in keyfile for actual content as IV will ensure this test always passes + + $crypted = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl ); + + $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] ); + + + $decrypt = Encryption\Crypt::symmetricDecryptFileContent( $crypted['encrypted'], $crypted['key'] ); + + $this->assertEquals( $this->dataUrl, $decrypt ); + + } + + function testIsEncryptedContent() { + + $this->assertFalse( Encryption\Crypt::isEncryptedContent( $this->dataUrl ) ); + + $this->assertFalse( Encryption\Crypt::isEncryptedContent( $this->legacyEncryptedData ) ); + + $keyfileContent = Encryption\Crypt::symmetricEncryptFileContent( $this->dataUrl, 'hat' ); + + $this->assertTrue( Encryption\Crypt::isEncryptedContent( $keyfileContent ) ); + + } + + function testMultiKeyEncrypt() { + + # TODO: search in keyfile for actual content as IV will ensure this test always passes + + $pair1 = Encryption\Crypt::createKeypair(); + + $this->assertEquals( 2, count( $pair1 ) ); + + $this->assertTrue( strlen( $pair1['publicKey'] ) > 1 ); + + $this->assertTrue( strlen( $pair1['privateKey'] ) > 1 ); + + + $crypted = Encryption\Crypt::multiKeyEncrypt( $this->dataUrl, array( $pair1['publicKey'] ) ); + + $this->assertNotEquals( $this->dataUrl, $crypted['encrypted'] ); + + + $decrypt = Encryption\Crypt::multiKeyDecrypt( $crypted['encrypted'], $crypted['keys'][0], $pair1['privateKey'] ); + + $this->assertEquals( $this->dataUrl, $decrypt ); + + } + + function testKeyEncrypt() { + + // Generate keypair + $pair1 = Encryption\Crypt::createKeypair(); + + // Encrypt data + $crypted = Encryption\Crypt::keyEncrypt( $this->dataUrl, $pair1['publicKey'] ); + + $this->assertNotEquals( $this->dataUrl, $crypted ); + + // Decrypt data + $decrypt = Encryption\Crypt::keyDecrypt( $crypted, $pair1['privateKey'] ); + + $this->assertEquals( $this->dataUrl, $decrypt ); + + } + + // What is the point of this test? It doesn't use keyEncryptKeyfile() + function testKeyEncryptKeyfile() { + + # TODO: Don't repeat encryption from previous tests, use PHPUnit test interdependency instead + + // Generate keypair + $pair1 = Encryption\Crypt::createKeypair(); + + // Encrypt plain data, generate keyfile & encrypted file + $cryptedData = Encryption\Crypt::symmetricEncryptFileContentKeyfile( $this->dataUrl ); + + // Encrypt keyfile + $cryptedKey = Encryption\Crypt::keyEncrypt( $cryptedData['key'], $pair1['publicKey'] ); + + // Decrypt keyfile + $decryptKey = Encryption\Crypt::keyDecrypt( $cryptedKey, $pair1['privateKey'] ); + + // Decrypt encrypted file + $decryptData = Encryption\Crypt::symmetricDecryptFileContent( $cryptedData['encrypted'], $decryptKey ); + + $this->assertEquals( $this->dataUrl, $decryptData ); + + } + + /** + * @brief test functionality of keyEncryptKeyfile() and + * keyDecryptKeyfile() + */ + function testKeyDecryptKeyfile() { + + $encrypted = Encryption\Crypt::keyEncryptKeyfile( $this->dataShort, $this->genPublicKey ); + + $this->assertNotEquals( $encrypted['data'], $this->dataShort ); + + $decrypted = Encryption\Crypt::keyDecryptKeyfile( $encrypted['data'], $encrypted['key'], $this->genPrivateKey ); + + $this->assertEquals( $decrypted, $this->dataShort ); + + } + + + /** + * @brief test encryption using legacy blowfish method + */ + function testLegacyEncryptShort() { + + $crypted = Encryption\Crypt::legacyEncrypt( $this->dataShort, $this->pass ); + + $this->assertNotEquals( $this->dataShort, $crypted ); + + # TODO: search inencrypted text for actual content to ensure it + # genuine transformation + + return $crypted; + + } + + /** + * @brief test decryption using legacy blowfish method + * @depends testLegacyEncryptShort + */ + function testLegacyDecryptShort( $crypted ) { + + $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); + + $this->assertEquals( $this->dataShort, $decrypted ); + + } + + /** + * @brief test encryption using legacy blowfish method + */ + function testLegacyEncryptLong() { + + $crypted = Encryption\Crypt::legacyEncrypt( $this->dataLong, $this->pass ); + + $this->assertNotEquals( $this->dataLong, $crypted ); + + # TODO: search inencrypted text for actual content to ensure it + # genuine transformation + + return $crypted; + + } + + /** + * @brief test decryption using legacy blowfish method + * @depends testLegacyEncryptLong + */ + function testLegacyDecryptLong( $crypted ) { + + $decrypted = Encryption\Crypt::legacyDecrypt( $crypted, $this->pass ); + + $this->assertEquals( $this->dataLong, $decrypted ); + + } + + /** + * @brief test generation of legacy encryption key + * @depends testLegacyDecryptShort + */ + function testLegacyCreateKey() { + + // Create encrypted key + $encKey = Encryption\Crypt::legacyCreateKey( $this->pass ); + + // Decrypt key + $key = Encryption\Crypt::legacyDecrypt( $encKey, $this->pass ); + + $this->assertTrue( is_numeric( $key ) ); + + // Check that key is correct length + $this->assertEquals( 20, strlen( $key ) ); + + } + + /** + * @brief test decryption using legacy blowfish method + * @depends testLegacyEncryptLong + */ + function testLegacyKeyRecryptKeyfileEncrypt( $crypted ) { + + $recrypted = Encryption\Crypt::LegacyKeyRecryptKeyfile( $crypted, $this->pass, $this->genPublicKey, $this->pass ); + + $this->assertNotEquals( $this->dataLong, $recrypted['data'] ); + + return $recrypted; + + # TODO: search inencrypted text for actual content to ensure it + # genuine transformation + + } + +// function testEncryption(){ +// +// $key=uniqid(); +// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; +// $source=file_get_contents($file); //nice large text file +// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); +// $decrypted=rtrim($decrypted, "\0"); +// $this->assertNotEquals($encrypted,$source); +// $this->assertEquals($decrypted,$source); +// +// $chunk=substr($source,0,8192); +// $encrypted=OC_Encryption\Crypt::encrypt($chunk,$key); +// $this->assertEquals(strlen($chunk),strlen($encrypted)); +// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); +// $decrypted=rtrim($decrypted, "\0"); +// $this->assertEquals($decrypted,$chunk); +// +// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); +// $this->assertNotEquals($encrypted,$source); +// $this->assertEquals($decrypted,$source); +// +// $tmpFileEncrypted=OCP\Files::tmpFile(); +// OC_Encryption\Crypt::encryptfile($file,$tmpFileEncrypted,$key); +// $encrypted=file_get_contents($tmpFileEncrypted); +// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); +// $this->assertNotEquals($encrypted,$source); +// $this->assertEquals($decrypted,$source); +// +// $tmpFileDecrypted=OCP\Files::tmpFile(); +// OC_Encryption\Crypt::decryptfile($tmpFileEncrypted,$tmpFileDecrypted,$key); +// $decrypted=file_get_contents($tmpFileDecrypted); +// $this->assertEquals($decrypted,$source); +// +// $file=OC::$SERVERROOT.'/core/img/weather-clear.png'; +// $source=file_get_contents($file); //binary file +// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); +// $decrypted=rtrim($decrypted, "\0"); +// $this->assertEquals($decrypted,$source); +// +// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key); +// $this->assertEquals($decrypted,$source); +// +// } +// +// function testBinary(){ +// $key=uniqid(); +// +// $file=__DIR__.'/binary'; +// $source=file_get_contents($file); //binary file +// $encrypted=OC_Encryption\Crypt::encrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::decrypt($encrypted,$key); +// +// $decrypted=rtrim($decrypted, "\0"); +// $this->assertEquals($decrypted,$source); +// +// $encrypted=OC_Encryption\Crypt::blockEncrypt($source,$key); +// $decrypted=OC_Encryption\Crypt::blockDecrypt($encrypted,$key,strlen($source)); +// $this->assertEquals($decrypted,$source); +// } + +} diff --git a/apps/files_encryption/test/keymanager.php b/apps/files_encryption/test/keymanager.php new file mode 100644 index 0000000000000000000000000000000000000000..f02d6eb5f7a873428bae80b3b011b10d24072ed9 --- /dev/null +++ b/apps/files_encryption/test/keymanager.php @@ -0,0 +1,132 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +//require_once "PHPUnit/Framework/TestCase.php"; +require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); +require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); +require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); +require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); +require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); +require_once realpath( dirname(__FILE__).'/../lib/util.php' ); +require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); + +use OCA\Encryption; + +// This has to go here because otherwise session errors arise, and the private +// encryption key needs to be saved in the session +\OC_User::login( 'admin', 'admin' ); + +class Test_Keymanager extends \PHPUnit_Framework_TestCase { + + function setUp() { + + \OC_FileProxy::$enabled = false; + + // set content for encrypting / decrypting in tests + $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + $this->dataShort = 'hats'; + $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); + $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); + $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + $this->randomKey = Encryption\Crypt::generateKey(); + + $keypair = Encryption\Crypt::createKeypair(); + $this->genPublicKey = $keypair['publicKey']; + $this->genPrivateKey = $keypair['privateKey']; + + $this->view = new \OC_FilesystemView( '/' ); + + \OC_User::setUserId( 'admin' ); + $this->userId = 'admin'; + $this->pass = 'admin'; + + \OC_Filesystem::init( '/' ); + \OC_Filesystem::mount( 'OC_Filestorage_Local', array('datadir' => \OC_User::getHome($this->userId)), '/' ); + + } + + function tearDown(){ + + \OC_FileProxy::$enabled = true; + + } + + function testGetPrivateKey() { + + $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); + + // Will this length vary? Perhaps we should use a range instead + $this->assertEquals( 2296, strlen( $key ) ); + + } + + function testGetPublicKey() { + + $key = Encryption\Keymanager::getPublicKey( $this->view, $this->userId ); + + $this->assertEquals( 451, strlen( $key ) ); + + $this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $key, 0, 26 ) ); + } + + function testSetFileKey() { + + # NOTE: This cannot be tested until we are able to break out + # of the FileSystemView data directory root + +// $key = Crypt::symmetricEncryptFileContentKeyfile( $this->data, 'hat' ); +// +// $tmpPath = sys_get_temp_dir(). '/' . 'testSetFileKey'; +// +// $view = new \OC_FilesystemView( '/tmp/' ); +// +// //$view = new \OC_FilesystemView( '/' . $this->userId . '/files_encryption/keyfiles' ); +// +// Encryption\Keymanager::setFileKey( $tmpPath, $key['key'], $view ); + + } + +// /** +// * @depends testGetPrivateKey +// */ +// function testGetPrivateKey_decrypt() { +// +// $key = Encryption\Keymanager::getPrivateKey( $this->view, $this->userId ); +// +// # TODO: replace call to Crypt with a mock object? +// $decrypted = Encryption\Crypt::symmetricDecryptFileContent( $key, $this->passphrase ); +// +// $this->assertEquals( 1704, strlen( $decrypted ) ); +// +// $this->assertEquals( '-----BEGIN PRIVATE KEY-----', substr( $decrypted, 0, 27 ) ); +// +// } + + function testGetUserKeys() { + + $keys = Encryption\Keymanager::getUserKeys( $this->view, $this->userId ); + + $this->assertEquals( 451, strlen( $keys['publicKey'] ) ); + $this->assertEquals( '-----BEGIN PUBLIC KEY-----', substr( $keys['publicKey'], 0, 26 ) ); + $this->assertEquals( 2296, strlen( $keys['privateKey'] ) ); + + } + + function testGetPublicKeys() { + + # TODO: write me + + } + + function testGetFileKey() { + +// Encryption\Keymanager::getFileKey( $this->view, $this->userId, $this->filePath ); + + } + +} diff --git a/apps/files_encryption/test/legacy-encrypted-text.txt b/apps/files_encryption/test/legacy-encrypted-text.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb5bf50550d91842c8a0bd214edf9569daeadc48 Binary files /dev/null and b/apps/files_encryption/test/legacy-encrypted-text.txt differ diff --git a/apps/files_encryption/test/proxy.php b/apps/files_encryption/test/proxy.php new file mode 100644 index 0000000000000000000000000000000000000000..709730f7609ca2464a1faa2c410569b50fa80c19 --- /dev/null +++ b/apps/files_encryption/test/proxy.php @@ -0,0 +1,220 @@ +, + * and Robin Appelman + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// require_once "PHPUnit/Framework/TestCase.php"; +// require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Generator.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/MockInterface.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Mock.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Container.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Configuration.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CompositeExpectation.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/ExpectationDirector.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Expectation.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/Exception.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/CountValidatorAbstract.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/Exception.php' ); +// require_once realpath( dirname(__FILE__).'/../../../3rdparty/mockery/Mockery/CountValidator/Exact.php' ); +// +// use \Mockery as m; +// use OCA\Encryption; + +// class Test_Util extends \PHPUnit_Framework_TestCase { +// +// public function setUp() { +// +// $this->proxy = new Encryption\Proxy(); +// +// $this->tmpFileName = "tmpFile-".time(); +// +// $this->privateKey = file_get_contents( realpath( dirname(__FILE__).'/data/admin.public.key' ) ); +// $this->publicKey = file_get_contents( realpath( dirname(__FILE__).'/data/admin.private.key' ) ); +// $this->encDataShort = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester-enc' ) ); +// $this->encDataShortKey = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester.key' ) ); +// +// $this->dataShort = file_get_contents( realpath( dirname(__FILE__).'/data/yoga-manchester' ) ); +// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); +// $this->longDataPath = realpath( dirname(__FILE__).'/../lib/crypt.php' ); +// +// $this->data1 = file_get_contents( realpath( dirname(__FILE__).'/../../../data/admin/files/enc-test.txt' ) ); +// +// \OC_FileProxy::$enabled = false; +// $this->Encdata1 = file_get_contents( realpath( dirname(__FILE__).'/../../../data/admin/files/enc-test.txt' ) ); +// \OC_FileProxy::$enabled = true; +// +// $this->userId = 'admin'; +// $this->pass = 'admin'; +// +// $this->session = new Encryption\Session(); +// +// $this->session->setPrivateKey( +// '-----BEGIN PRIVATE KEY----- +// MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDiH3EA4EpFA7Fx +// s2dyyfL5jwXeYXrTqQJ6DqKgGn8VsbT3eu8R9KzM2XitVwZe8c8L52DvJ06o5vg0 +// GqPYxilFdOFJe/ggac5Tq8UmJiZS4EqYEMwxBIfIyWTxeGV06/0HOwnVAkqHMcBz +// 64qldtgi5O8kZMEM2/gKBgU0kMLJzM+8oEWhL1+gsUWQhxd8cKLXypS6iWgqFJrz +// f/X0hJsJR+gyYxNpahtnjzd/LxLAETrOMsl2tue+BAxmjbAM0aG0NEM0div+b59s +// 2uz/iWbxImp5pOdYVKcVW89D4XBMyGegR40trV2VwiuX1blKCfdjMsJhiaL9pymp +// ug1wzyQFAgMBAAECggEAK6c+PZkPPXuVCgpEcliiW6NM0r2m5K3AGKgypQ34csu3 +// z/8foCvIIFPrhCtEw5eTDQ1CHWlNOjY8vHJYJ0U6Onpx86nHIRrMBkMm8FJ1G5LJ +// U8oKYXwqaozWu/cuPwA//OFc6I5krOzh5n8WaRMkbrgbor8AtebRX74By0AXGrXe +// cswJI7zR96oFn4Dm7Pgvpg5Zhk1vFJ+w6QtH+4DDJ6PBvlZsRkGxYBLGVd/3qhAI +// sBAyjFlSzuP4eCRhHOhHC/e4gmAH9evFVXB88jFyRZm3K+jQ5W5CwrVRBCV2lph6 +// 2B6P7CBJN+IjGKMhy+75y13UvvKPv9IwH8Fzl2x1gQKBgQD8qQOr7a6KhSj16wQE +// jim2xqt9gQ2jH5No405NrKs/PFQQZnzD4YseQsiK//NUjOJiUhaT+L5jhIpzINHt +// RJpt3bGkEZmLyjdjgTpB3GwZdXa28DNK9VdXZ19qIl/ZH0qAjKmJCRahUDASMnVi +// M4Pkk9yx9ZIKkri4TcuMWqc0DQKBgQDlHKBTITZq/arYPD6Nl3NsoOdqVRqJrGay +// 0TjXAVbBXe46+z5lnMsqwXb79nx14hdmSEsZULrw/3f+MnQbdjMTYLFP24visZg9 +// MN8vAiALiiiR1a+Crz+DTA1Q8sGOMVCMqMDmD7QBys3ZuWxuapm0txAiIYUtsjJZ +// XN76T4nZ2QKBgQCHaT3igzwsWTmesxowJtEMeGWomeXpKx8h89EfqA8PkRGsyIDN +// qq+YxEoe1RZgljEuaLhZDdNcGsjo8woPk9kAUPTH7fbRCMuutK+4ZJ469s1tNkcH +// QX5SBcEJbOrZvv967ehe3VQXmJZq6kgnHVzuwKBjcC2ZJRGDFY6l5l/+cQKBgCqh +// +Adf/8NK7paMJ0urqfPFwSodKfICXZ3apswDWMRkmSbqh4La+Uc8dsqN5Dz/VEFZ +// JHhSeGbN8uMfOlG93eU2MehdPxtw1pZUWMNjjtj23XO9ooob2CKzbSrp8TBnZsi1 +// widNNr66oTFpeo7VUUK6acsgF6sYJJxSVr+XO1yJAoGAEhvitq8shNKcEY0xCipS +// k1kbgyS7KKB7opVxI5+ChEqyUDijS3Y9FZixrRIWE6i2uGu86UG+v2lbKvSbM4Qm +// xvbOcX9OVMnlRb7n8woOP10UMY+ZE2x+YEUXQTLtPYq7F66e1OfxltstMxLQA+3d +// Y1d5piFV8PXK3Fg2F+Cj5qg= +// -----END PRIVATE KEY----- +// ' +// , $this->userId +// ); +// +// \OC_User::setUserId( $this->userId ); +// +// } +// +// public function testpreFile_get_contents() { +// +// // This won't work for now because mocking of the static keymanager class isn't working :( +// +// // $mock = m::mock( 'alias:OCA\Encryption\Keymanager' ); +// // +// // $mock->shouldReceive( 'getFileKey' )->times(2)->andReturn( $this->encDataShort ); +// // +// // $encrypted = $this->proxy->postFile_get_contents( 'data/'.$this->tmpFileName, $this->encDataShortKey ); +// // +// // $this->assertNotEquals( $this->dataShort, $encrypted ); +// +// $decrypted = $this->proxy->postFile_get_contents( 'data/admin/files/enc-test.txt', $this->data1 ); +// +// } +// +// } + +// class Test_CryptProxy extends PHPUnit_Framework_TestCase { +// private $oldConfig; +// private $oldKey; +// +// public function setUp(){ +// $user=OC_User::getUser(); +// +// $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption','true'); +// OCP\Config::setAppValue('files_encryption','enable_encryption','true'); +// $this->oldKey=isset($_SESSION['privateKey'])?$_SESSION['privateKey']:null; +// +// +// //set testing key +// $_SESSION['privateKey']=md5(time()); +// +// //clear all proxies and hooks so we can do clean testing +// OC_FileProxy::clearProxies(); +// OC_Hook::clear('OC_Filesystem'); +// +// //enable only the encryption hook +// OC_FileProxy::register(new OC_FileProxy_Encryption()); +// +// //set up temporary storage +// OC_Filesystem::clearMounts(); +// OC_Filesystem::mount('OC_Filestorage_Temporary',array(),'/'); +// +// OC_Filesystem::init('/'.$user.'/files'); +// +// //set up the users home folder in the temp storage +// $rootView=new OC_FilesystemView(''); +// $rootView->mkdir('/'.$user); +// $rootView->mkdir('/'.$user.'/files'); +// } +// +// public function tearDown(){ +// OCP\Config::setAppValue('files_encryption','enable_encryption',$this->oldConfig); +// if(!is_null($this->oldKey)){ +// $_SESSION['privateKey']=$this->oldKey; +// } +// } +// +// public function testSimple(){ +// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; +// $original=file_get_contents($file); +// +// OC_Filesystem::file_put_contents('/file',$original); +// +// OC_FileProxy::$enabled=false; +// $stored=OC_Filesystem::file_get_contents('/file'); +// OC_FileProxy::$enabled=true; +// +// $fromFile=OC_Filesystem::file_get_contents('/file'); +// $this->assertNotEquals($original,$stored); +// $this->assertEquals(strlen($original),strlen($fromFile)); +// $this->assertEquals($original,$fromFile); +// +// } +// +// public function testView(){ +// $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; +// $original=file_get_contents($file); +// +// $rootView=new OC_FilesystemView(''); +// $view=new OC_FilesystemView('/'.OC_User::getUser()); +// $userDir='/'.OC_User::getUser().'/files'; +// +// $rootView->file_put_contents($userDir.'/file',$original); +// +// OC_FileProxy::$enabled=false; +// $stored=$rootView->file_get_contents($userDir.'/file'); +// OC_FileProxy::$enabled=true; +// +// $this->assertNotEquals($original,$stored); +// $fromFile=$rootView->file_get_contents($userDir.'/file'); +// $this->assertEquals($original,$fromFile); +// +// $fromFile=$view->file_get_contents('files/file'); +// $this->assertEquals($original,$fromFile); +// } +// +// public function testBinary(){ +// $file=__DIR__.'/binary'; +// $original=file_get_contents($file); +// +// OC_Filesystem::file_put_contents('/file',$original); +// +// OC_FileProxy::$enabled=false; +// $stored=OC_Filesystem::file_get_contents('/file'); +// OC_FileProxy::$enabled=true; +// +// $fromFile=OC_Filesystem::file_get_contents('/file'); +// $this->assertNotEquals($original,$stored); +// $this->assertEquals(strlen($original),strlen($fromFile)); +// $this->assertEquals($original,$fromFile); +// +// $file=__DIR__.'/zeros'; +// $original=file_get_contents($file); +// +// OC_Filesystem::file_put_contents('/file',$original); +// +// OC_FileProxy::$enabled=false; +// $stored=OC_Filesystem::file_get_contents('/file'); +// OC_FileProxy::$enabled=true; +// +// $fromFile=OC_Filesystem::file_get_contents('/file'); +// $this->assertNotEquals($original,$stored); +// $this->assertEquals(strlen($original),strlen($fromFile)); +// } +// } diff --git a/apps/files_encryption/test/stream.php b/apps/files_encryption/test/stream.php new file mode 100644 index 0000000000000000000000000000000000000000..ba82ac80eabb17dc16d01dce0d61d0f042c8a1b0 --- /dev/null +++ b/apps/files_encryption/test/stream.php @@ -0,0 +1,226 @@ +// +// * This file is licensed under the Affero General Public License version 3 or +// * later. +// * See the COPYING-README file. +// */ +// +// namespace OCA\Encryption; +// +// class Test_Stream extends \PHPUnit_Framework_TestCase { +// +// function setUp() { +// +// \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' ); +// +// $this->empty = ''; +// +// $this->stream = new Stream(); +// +// $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); +// $this->dataShort = 'hats'; +// +// $this->emptyTmpFilePath = \OCP\Files::tmpFile(); +// +// $this->dataTmpFilePath = \OCP\Files::tmpFile(); +// +// file_put_contents( $this->dataTmpFilePath, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor. Pellentesque auctor nisi id magna consequat sagittis. Curabitur dapibus enim sit amet elit pharetra tincidunt feugiat nisl imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros. Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est." ); +// +// } +// +// function testStreamOpen() { +// +// $stream1 = new Stream(); +// +// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'wb', array(), $this->empty ); +// +// // Test that resource was returned successfully +// $this->assertTrue( $handle1 ); +// +// // Test that file has correct size +// $this->assertEquals( 0, $stream1->size ); +// +// // Test that path is correct +// $this->assertEquals( $this->emptyTmpFilePath, $stream1->rawPath ); +// +// $stream2 = new Stream(); +// +// $handle2 = $stream2->stream_open( 'crypt://' . $this->emptyTmpFilePath, 'wb', array(), $this->empty ); +// +// // Test that protocol identifier is removed from path +// $this->assertEquals( $this->emptyTmpFilePath, $stream2->rawPath ); +// +// // "Stat failed error" prevents this test from executing +// // $stream3 = new Stream(); +// // +// // $handle3 = $stream3->stream_open( $this->dataTmpFilePath, 'r', array(), $this->empty ); +// // +// // $this->assertEquals( 0, $stream3->size ); +// +// } +// +// function testStreamWrite() { +// +// $stream1 = new Stream(); +// +// $handle1 = $stream1->stream_open( $this->emptyTmpFilePath, 'r+b', array(), $this->empty ); +// +// # what about the keymanager? there is no key for the newly created temporary file! +// +// $stream1->stream_write( $this->dataShort ); +// +// } +// +// // function getStream( $id, $mode, $size ) { +// // +// // if ( $id === '' ) { +// // +// // $id = uniqid(); +// // } +// // +// // +// // if ( !isset( $this->tmpFiles[$id] ) ) { +// // +// // // If tempfile with given name does not already exist, create it +// // +// // $file = OCP\Files::tmpFile(); +// // +// // $this->tmpFiles[$id] = $file; +// // +// // } else { +// // +// // $file = $this->tmpFiles[$id]; +// // +// // } +// // +// // $stream = fopen( $file, $mode ); +// // +// // Stream::$sourceStreams[$id] = array( 'path' => 'dummy' . $id, 'stream' => $stream, 'size' => $size ); +// // +// // return fopen( 'crypt://streams/'.$id, $mode ); +// // +// // } +// // +// // function testStream( ){ +// // +// // $stream = $this->getStream( 'test1', 'w', strlen( 'foobar' ) ); +// // +// // fwrite( $stream, 'foobar' ); +// // +// // fclose( $stream ); +// // +// // +// // $stream = $this->getStream( 'test1', 'r', strlen( 'foobar' ) ); +// // +// // $data = fread( $stream, 6 ); +// // +// // fclose( $stream ); +// // +// // $this->assertEquals( 'foobar', $data ); +// // +// // +// // $file = OC::$SERVERROOT.'/3rdparty/MDB2.php'; +// // +// // $source = fopen( $file, 'r' ); +// // +// // $target = $this->getStream( 'test2', 'w', 0 ); +// // +// // OCP\Files::streamCopy( $source, $target ); +// // +// // fclose( $target ); +// // +// // fclose( $source ); +// // +// // +// // $stream = $this->getStream( 'test2', 'r', filesize( $file ) ); +// // +// // $data = stream_get_contents( $stream ); +// // +// // $original = file_get_contents( $file ); +// // +// // $this->assertEquals( strlen( $original ), strlen( $data ) ); +// // +// // $this->assertEquals( $original, $data ); +// // +// // } +// +// } +// +// // class Test_CryptStream extends PHPUnit_Framework_TestCase { +// // private $tmpFiles=array(); +// // +// // function testStream(){ +// // $stream=$this->getStream('test1','w',strlen('foobar')); +// // fwrite($stream,'foobar'); +// // fclose($stream); +// // +// // $stream=$this->getStream('test1','r',strlen('foobar')); +// // $data=fread($stream,6); +// // fclose($stream); +// // $this->assertEquals('foobar',$data); +// // +// // $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; +// // $source=fopen($file,'r'); +// // $target=$this->getStream('test2','w',0); +// // OCP\Files::streamCopy($source,$target); +// // fclose($target); +// // fclose($source); +// // +// // $stream=$this->getStream('test2','r',filesize($file)); +// // $data=stream_get_contents($stream); +// // $original=file_get_contents($file); +// // $this->assertEquals(strlen($original),strlen($data)); +// // $this->assertEquals($original,$data); +// // } +// // +// // /** +// // * get a cryptstream to a temporary file +// // * @param string $id +// // * @param string $mode +// // * @param int size +// // * @return resource +// // */ +// // function getStream($id,$mode,$size){ +// // if($id===''){ +// // $id=uniqid(); +// // } +// // if(!isset($this->tmpFiles[$id])){ +// // $file=OCP\Files::tmpFile(); +// // $this->tmpFiles[$id]=$file; +// // }else{ +// // $file=$this->tmpFiles[$id]; +// // } +// // $stream=fopen($file,$mode); +// // OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id,'stream'=>$stream,'size'=>$size); +// // return fopen('crypt://streams/'.$id,$mode); +// // } +// // +// // function testBinary(){ +// // $file=__DIR__.'/binary'; +// // $source=file_get_contents($file); +// // +// // $stream=$this->getStream('test','w',strlen($source)); +// // fwrite($stream,$source); +// // fclose($stream); +// // +// // $stream=$this->getStream('test','r',strlen($source)); +// // $data=stream_get_contents($stream); +// // fclose($stream); +// // $this->assertEquals(strlen($data),strlen($source)); +// // $this->assertEquals($source,$data); +// // +// // $file=__DIR__.'/zeros'; +// // $source=file_get_contents($file); +// // +// // $stream=$this->getStream('test2','w',strlen($source)); +// // fwrite($stream,$source); +// // fclose($stream); +// // +// // $stream=$this->getStream('test2','r',strlen($source)); +// // $data=stream_get_contents($stream); +// // fclose($stream); +// // $this->assertEquals(strlen($data),strlen($source)); +// // $this->assertEquals($source,$data); +// // } +// // } diff --git a/apps/files_encryption/test/util.php b/apps/files_encryption/test/util.php new file mode 100755 index 0000000000000000000000000000000000000000..a299ec67f598644cb739300ba9f2308164b01d21 --- /dev/null +++ b/apps/files_encryption/test/util.php @@ -0,0 +1,210 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +//require_once "PHPUnit/Framework/TestCase.php"; +require_once realpath( dirname(__FILE__).'/../../../lib/base.php' ); +require_once realpath( dirname(__FILE__).'/../lib/crypt.php' ); +require_once realpath( dirname(__FILE__).'/../lib/keymanager.php' ); +require_once realpath( dirname(__FILE__).'/../lib/proxy.php' ); +require_once realpath( dirname(__FILE__).'/../lib/stream.php' ); +require_once realpath( dirname(__FILE__).'/../lib/util.php' ); +require_once realpath( dirname(__FILE__).'/../appinfo/app.php' ); + +// Load mockery files +require_once 'Mockery/Loader.php'; +require_once 'Hamcrest/Hamcrest.php'; +$loader = new \Mockery\Loader; +$loader->register(); + +use \Mockery as m; +use OCA\Encryption; + +class Test_Enc_Util extends \PHPUnit_Framework_TestCase { + + function setUp() { + + \OC_Filesystem::mount( 'OC_Filestorage_Local', array(), '/' ); + + // set content for encrypting / decrypting in tests + $this->dataUrl = realpath( dirname(__FILE__).'/../lib/crypt.php' ); + $this->dataShort = 'hats'; + $this->dataLong = file_get_contents( realpath( dirname(__FILE__).'/../lib/crypt.php' ) ); + $this->legacyData = realpath( dirname(__FILE__).'/legacy-text.txt' ); + $this->legacyEncryptedData = realpath( dirname(__FILE__).'/legacy-encrypted-text.txt' ); + + $this->userId = 'admin'; + $this->pass = 'admin'; + + $keypair = Encryption\Crypt::createKeypair(); + + $this->genPublicKey = $keypair['publicKey']; + $this->genPrivateKey = $keypair['privateKey']; + + $this->publicKeyDir = '/' . 'public-keys'; + $this->encryptionDir = '/' . $this->userId . '/' . 'files_encryption'; + $this->keyfilesPath = $this->encryptionDir . '/' . 'keyfiles'; + $this->publicKeyPath = $this->publicKeyDir . '/' . $this->userId . '.public.key'; // e.g. data/public-keys/admin.public.key + $this->privateKeyPath = $this->encryptionDir . '/' . $this->userId . '.private.key'; // e.g. data/admin/admin.private.key + + $this->view = new OC_FilesystemView( '/admin' ); + + $this->mockView = m::mock('OC_FilesystemView'); + $this->util = new Encryption\Util( $this->mockView, $this->userId ); + + } + + function tearDown(){ + + m::close(); + + } + + /** + * @brief test that paths set during User construction are correct + */ + function testKeyPaths() { + + $mockView = m::mock('OC_FilesystemView'); + + $util = new Encryption\Util( $mockView, $this->userId ); + + $this->assertEquals( $this->publicKeyDir, $util->getPath( 'publicKeyDir' ) ); + $this->assertEquals( $this->encryptionDir, $util->getPath( 'encryptionDir' ) ); + $this->assertEquals( $this->keyfilesPath, $util->getPath( 'keyfilesPath' ) ); + $this->assertEquals( $this->publicKeyPath, $util->getPath( 'publicKeyPath' ) ); + $this->assertEquals( $this->privateKeyPath, $util->getPath( 'privateKeyPath' ) ); + + } + + /** + * @brief test setup of encryption directories when they don't yet exist + */ + function testSetupServerSideNotSetup() { + + $mockView = m::mock('OC_FilesystemView'); + + $mockView->shouldReceive( 'file_exists' )->times(4)->andReturn( false ); + $mockView->shouldReceive( 'mkdir' )->times(3)->andReturn( true ); + $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs(); + + $util = new Encryption\Util( $mockView, $this->userId ); + + $this->assertEquals( true, $util->setupServerSide( $this->pass ) ); + + } + + /** + * @brief test setup of encryption directories when they already exist + */ + function testSetupServerSideIsSetup() { + + $mockView = m::mock('OC_FilesystemView'); + + $mockView->shouldReceive( 'file_exists' )->times(5)->andReturn( true ); + $mockView->shouldReceive( 'file_put_contents' )->withAnyArgs(); + + $util = new Encryption\Util( $mockView, $this->userId ); + + $this->assertEquals( true, $util->setupServerSide( $this->pass ) ); + + } + + /** + * @brief test checking whether account is ready for encryption, when it isn't ready + */ + function testReadyNotReady() { + + $mockView = m::mock('OC_FilesystemView'); + + $mockView->shouldReceive( 'file_exists' )->times(1)->andReturn( false ); + + $util = new Encryption\Util( $mockView, $this->userId ); + + $this->assertEquals( false, $util->ready() ); + + # TODO: Add more tests here to check that if any of the dirs are + # then false will be returned. Use strict ordering? + + } + + /** + * @brief test checking whether account is ready for encryption, when it is ready + */ + function testReadyIsReady() { + + $mockView = m::mock('OC_FilesystemView'); + + $mockView->shouldReceive( 'file_exists' )->times(3)->andReturn( true ); + + $util = new Encryption\Util( $mockView, $this->userId ); + + $this->assertEquals( true, $util->ready() ); + + # TODO: Add more tests here to check that if any of the dirs are + # then false will be returned. Use strict ordering? + + } + +// /** +// * @brief test decryption using legacy blowfish method +// * @depends testLegacyEncryptLong +// */ +// function testLegacyKeyRecryptKeyfileDecrypt( $recrypted ) { +// +// $decrypted = Encryption\Crypt::keyDecryptKeyfile( $recrypted['data'], $recrypted['key'], $this->genPrivateKey ); +// +// $this->assertEquals( $this->dataLong, $decrypted ); +// +// } + +// // Cannot use this test for now due to hidden dependencies in OC_FileCache +// function testIsLegacyEncryptedContent() { +// +// $keyfileContent = OCA\Encryption\Crypt::symmetricEncryptFileContent( $this->legacyEncryptedData, 'hat' ); +// +// $this->assertFalse( OCA\Encryption\Crypt::isLegacyEncryptedContent( $keyfileContent, '/files/admin/test.txt' ) ); +// +// OC_FileCache::put( '/admin/files/legacy-encrypted-test.txt', $this->legacyEncryptedData ); +// +// $this->assertTrue( OCA\Encryption\Crypt::isLegacyEncryptedContent( $this->legacyEncryptedData, '/files/admin/test.txt' ) ); +// +// } + +// // Cannot use this test for now due to need for different root in OC_Filesystem_view class +// function testGetLegacyKey() { +// +// $c = new \OCA\Encryption\Util( $view, false ); +// +// $bool = $c->getLegacyKey( 'admin' ); +// +// $this->assertTrue( $bool ); +// +// $this->assertTrue( $c->legacyKey ); +// +// $this->assertTrue( is_int( $c->legacyKey ) ); +// +// $this->assertTrue( strlen( $c->legacyKey ) == 20 ); +// +// } + +// // Cannot use this test for now due to need for different root in OC_Filesystem_view class +// function testLegacyDecrypt() { +// +// $c = new OCA\Encryption\Util( $this->view, false ); +// +// $bool = $c->getLegacyKey( 'admin' ); +// +// $encrypted = $c->legacyEncrypt( $this->data, $c->legacyKey ); +// +// $decrypted = $c->legacyDecrypt( $encrypted, $c->legacyKey ); +// +// $this->assertEquals( $decrypted, $this->data ); +// +// } + +} \ No newline at end of file diff --git a/apps/files_encryption/tests/zeros b/apps/files_encryption/test/zeros similarity index 100% rename from apps/files_encryption/tests/zeros rename to apps/files_encryption/test/zeros diff --git a/apps/files_encryption/tests/encryption.php b/apps/files_encryption/tests/encryption.php deleted file mode 100644 index 0e119f55bea1b6c4cd2b88cd3829eb046259b330..0000000000000000000000000000000000000000 --- a/apps/files_encryption/tests/encryption.php +++ /dev/null @@ -1,72 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class Test_Encryption extends UnitTestCase { - function testEncryption() { - $key=uniqid(); - $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; - $source=file_get_contents($file); //nice large text file - $encrypted=OC_Crypt::encrypt($source, $key); - $decrypted=OC_Crypt::decrypt($encrypted, $key); - $decrypted=rtrim($decrypted, "\0"); - $this->assertNotEqual($encrypted, $source); - $this->assertEqual($decrypted, $source); - - $chunk=substr($source, 0, 8192); - $encrypted=OC_Crypt::encrypt($chunk, $key); - $this->assertEqual(strlen($chunk), strlen($encrypted)); - $decrypted=OC_Crypt::decrypt($encrypted, $key); - $decrypted=rtrim($decrypted, "\0"); - $this->assertEqual($decrypted, $chunk); - - $encrypted=OC_Crypt::blockEncrypt($source, $key); - $decrypted=OC_Crypt::blockDecrypt($encrypted, $key); - $this->assertNotEqual($encrypted, $source); - $this->assertEqual($decrypted, $source); - - $tmpFileEncrypted=OCP\Files::tmpFile(); - OC_Crypt::encryptfile($file, $tmpFileEncrypted, $key); - $encrypted=file_get_contents($tmpFileEncrypted); - $decrypted=OC_Crypt::blockDecrypt($encrypted, $key); - $this->assertNotEqual($encrypted, $source); - $this->assertEqual($decrypted, $source); - - $tmpFileDecrypted=OCP\Files::tmpFile(); - OC_Crypt::decryptfile($tmpFileEncrypted, $tmpFileDecrypted, $key); - $decrypted=file_get_contents($tmpFileDecrypted); - $this->assertEqual($decrypted, $source); - - $file=OC::$SERVERROOT.'/core/img/weather-clear.png'; - $source=file_get_contents($file); //binary file - $encrypted=OC_Crypt::encrypt($source, $key); - $decrypted=OC_Crypt::decrypt($encrypted, $key); - $decrypted=rtrim($decrypted, "\0"); - $this->assertEqual($decrypted, $source); - - $encrypted=OC_Crypt::blockEncrypt($source, $key); - $decrypted=OC_Crypt::blockDecrypt($encrypted, $key); - $this->assertEqual($decrypted, $source); - - } - - function testBinary() { - $key=uniqid(); - - $file=__DIR__.'/binary'; - $source=file_get_contents($file); //binary file - $encrypted=OC_Crypt::encrypt($source, $key); - $decrypted=OC_Crypt::decrypt($encrypted, $key); - - $decrypted=rtrim($decrypted, "\0"); - $this->assertEqual($decrypted, $source); - - $encrypted=OC_Crypt::blockEncrypt($source, $key); - $decrypted=OC_Crypt::blockDecrypt($encrypted, $key, strlen($source)); - $this->assertEqual($decrypted, $source); - } -} diff --git a/apps/files_encryption/tests/proxy.php b/apps/files_encryption/tests/proxy.php deleted file mode 100644 index 5aa617e7472b00d5da4651e93ca61d75ded6463b..0000000000000000000000000000000000000000 --- a/apps/files_encryption/tests/proxy.php +++ /dev/null @@ -1,117 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class Test_CryptProxy extends UnitTestCase { - private $oldConfig; - private $oldKey; - - public function setUp() { - $user=OC_User::getUser(); - - $this->oldConfig=OCP\Config::getAppValue('files_encryption','enable_encryption', 'true'); - OCP\Config::setAppValue('files_encryption', 'enable_encryption', 'true'); - $this->oldKey=isset($_SESSION['enckey'])?$_SESSION['enckey']:null; - - - //set testing key - $_SESSION['enckey']=md5(time()); - - //clear all proxies and hooks so we can do clean testing - OC_FileProxy::clearProxies(); - OC_Hook::clear('OC_Filesystem'); - - //enable only the encryption hook - OC_FileProxy::register(new OC_FileProxy_Encryption()); - - //set up temporary storage - OC_Filesystem::clearMounts(); - OC_Filesystem::mount('OC_Filestorage_Temporary', array(), '/'); - - OC_Filesystem::init('/'.$user.'/files'); - - //set up the users home folder in the temp storage - $rootView=new OC_FilesystemView(''); - $rootView->mkdir('/'.$user); - $rootView->mkdir('/'.$user.'/files'); - } - - public function tearDown() { - OCP\Config::setAppValue('files_encryption', 'enable_encryption', $this->oldConfig); - if ( ! is_null($this->oldKey)) { - $_SESSION['enckey']=$this->oldKey; - } - } - - public function testSimple() { - $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; - $original=file_get_contents($file); - - OC_Filesystem::file_put_contents('/file', $original); - - OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); - OC_FileProxy::$enabled=true; - - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); - $this->assertEqual(strlen($original), strlen($fromFile)); - $this->assertEqual($original, $fromFile); - - } - - public function testView() { - $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; - $original=file_get_contents($file); - - $rootView=new OC_FilesystemView(''); - $view=new OC_FilesystemView('/'.OC_User::getUser()); - $userDir='/'.OC_User::getUser().'/files'; - - $rootView->file_put_contents($userDir.'/file', $original); - - OC_FileProxy::$enabled=false; - $stored=$rootView->file_get_contents($userDir.'/file'); - OC_FileProxy::$enabled=true; - - $this->assertNotEqual($original, $stored); - $fromFile=$rootView->file_get_contents($userDir.'/file'); - $this->assertEqual($original, $fromFile); - - $fromFile=$view->file_get_contents('files/file'); - $this->assertEqual($original, $fromFile); - } - - public function testBinary() { - $file=__DIR__.'/binary'; - $original=file_get_contents($file); - - OC_Filesystem::file_put_contents('/file', $original); - - OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); - OC_FileProxy::$enabled=true; - - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); - $this->assertEqual(strlen($original), strlen($fromFile)); - $this->assertEqual($original, $fromFile); - - $file=__DIR__.'/zeros'; - $original=file_get_contents($file); - - OC_Filesystem::file_put_contents('/file', $original); - - OC_FileProxy::$enabled=false; - $stored=OC_Filesystem::file_get_contents('/file'); - OC_FileProxy::$enabled=true; - - $fromFile=OC_Filesystem::file_get_contents('/file'); - $this->assertNotEqual($original, $stored); - $this->assertEqual(strlen($original), strlen($fromFile)); - } -} diff --git a/apps/files_encryption/tests/stream.php b/apps/files_encryption/tests/stream.php deleted file mode 100644 index e4af17d47b5b404cc0ab169c255921d76b210170..0000000000000000000000000000000000000000 --- a/apps/files_encryption/tests/stream.php +++ /dev/null @@ -1,85 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -class Test_CryptStream extends UnitTestCase { - private $tmpFiles=array(); - - function testStream() { - $stream=$this->getStream('test1', 'w', strlen('foobar')); - fwrite($stream, 'foobar'); - fclose($stream); - - $stream=$this->getStream('test1', 'r', strlen('foobar')); - $data=fread($stream, 6); - fclose($stream); - $this->assertEqual('foobar', $data); - - $file=OC::$SERVERROOT.'/3rdparty/MDB2.php'; - $source=fopen($file, 'r'); - $target=$this->getStream('test2', 'w', 0); - OCP\Files::streamCopy($source, $target); - fclose($target); - fclose($source); - - $stream=$this->getStream('test2', 'r', filesize($file)); - $data=stream_get_contents($stream); - $original=file_get_contents($file); - $this->assertEqual(strlen($original), strlen($data)); - $this->assertEqual($original, $data); - } - - /** - * get a cryptstream to a temporary file - * @param string $id - * @param string $mode - * @param int size - * @return resource - */ - function getStream($id, $mode, $size) { - if ($id==='') { - $id=uniqid(); - } - if ( ! isset($this->tmpFiles[$id])) { - $file=OCP\Files::tmpFile(); - $this->tmpFiles[$id]=$file; - } else { - $file=$this->tmpFiles[$id]; - } - $stream=fopen($file, $mode); - OC_CryptStream::$sourceStreams[$id]=array('path'=>'dummy'.$id, 'stream'=>$stream, 'size'=>$size); - return fopen('crypt://streams/'.$id, $mode); - } - - function testBinary() { - $file=__DIR__.'/binary'; - $source=file_get_contents($file); - - $stream=$this->getStream('test', 'w', strlen($source)); - fwrite($stream, $source); - fclose($stream); - - $stream=$this->getStream('test', 'r', strlen($source)); - $data=stream_get_contents($stream); - fclose($stream); - $this->assertEqual(strlen($data), strlen($source)); - $this->assertEqual($source, $data); - - $file=__DIR__.'/zeros'; - $source=file_get_contents($file); - - $stream=$this->getStream('test2', 'w', strlen($source)); - fwrite($stream, $source); - fclose($stream); - - $stream=$this->getStream('test2', 'r', strlen($source)); - $data=stream_get_contents($stream); - fclose($stream); - $this->assertEqual(strlen($data), strlen($source)); - $this->assertEqual($source, $data); - } -} diff --git a/apps/files_external/l10n/bg_BG.php b/apps/files_external/l10n/bg_BG.php index 48779581846167902e73f50151eee2c1433728e7..1f2c29d54c5596ccbd7bf6d5f6b839b3c7c0fff7 100644 --- a/apps/files_external/l10n/bg_BG.php +++ b/apps/files_external/l10n/bg_BG.php @@ -1,4 +1,18 @@ "Достъпът е даден", +"Grant access" => "Даване на достъп", +"Fill out all required fields" => "Попълнете всички задължителни полета", +"External Storage" => "Външно хранилище", +"Backend" => "Администрация", +"Configuration" => "Конфигурация", +"Options" => "Опции", +"None set" => "Няма избрано", +"All Users" => "Всички потребители", "Groups" => "Групи", -"Delete" => "Изтриване" +"Users" => "Потребители", +"Delete" => "Изтриване", +"Enable User External Storage" => "Вкл. на поддръжка за външно потр. хранилище", +"Allow users to mount their own external storage" => "Позволено е на потребителите да ползват тяхно лично външно хранилище", +"SSL root certificates" => "SSL основни сертификати", +"Import Root Certificate" => "Импортиране на основен сертификат" ); diff --git a/apps/files_external/l10n/bn_BD.php b/apps/files_external/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..a4a2b23030b9aefe8b0ac1c0069ba97b738cf2da --- /dev/null +++ b/apps/files_external/l10n/bn_BD.php @@ -0,0 +1,24 @@ + "অধিগমনের অনুমতি প্রদান করা হলো", +"Error configuring Dropbox storage" => "Dropbox সংরক্ষণাগার নির্ধারণ করতে সমস্যা ", +"Grant access" => "অধিগমনের অনুমতি প্রদান কর", +"Fill out all required fields" => "আবশ্যিক সমস্ত ক্ষেত্র পূরণ করুন", +"Please provide a valid Dropbox app key and secret." => "দয়া করে সঠিক এবং বৈধ Dropbox app key and secret প্রদান করুন।", +"Error configuring Google Drive storage" => "Google Drive সংরক্ষণাগার নির্ধারণ করতে সমস্যা ", +"External Storage" => "বাহ্যিক সংরক্ষণাগার", +"Mount point" => "মাউন্ট পয়েন্ট", +"Backend" => "পশ্চাদপট", +"Configuration" => "কনফিগারেসন", +"Options" => "বিকল্পসমূহ", +"Applicable" => "প্রযোজ্য", +"Add mount point" => "মাউন্ট পয়েন্ট যোগ কর", +"None set" => "কোনটিই নির্ধারণ করা হয় নি", +"All Users" => "সমস্ত ব্যবহারকারী", +"Groups" => "গোষ্ঠীসমূহ", +"Users" => "ব্যবহারকারী", +"Delete" => "মুছে ফেল", +"Enable User External Storage" => "ব্যবহারকারীর বাহ্যিক সংরক্ষণাগার সক্রিয় কর", +"Allow users to mount their own external storage" => "ব্যবহারকারীদেরকে তাদের নিজস্ব বাহ্যিক সংরক্ষনাগার সাউন্ট করতে অনুমোদন দাও", +"SSL root certificates" => "SSL রুট সনদপত্র", +"Import Root Certificate" => "রুট সনদপত্রটি আমদানি করুন" +); diff --git a/apps/files_external/l10n/eu.php b/apps/files_external/l10n/eu.php index dccd377b119bc13c7cecbe2545485015ba064b4f..597204c894d4e14c21a83c8beaee91dc96e28088 100644 --- a/apps/files_external/l10n/eu.php +++ b/apps/files_external/l10n/eu.php @@ -5,6 +5,8 @@ "Fill out all required fields" => "Bete eskatutako eremu guztiak", "Please provide a valid Dropbox app key and secret." => "Mesedez eman baliozkoa den Dropbox app giltza eta sekretua", "Error configuring Google Drive storage" => "Errore bat egon da Google Drive biltegiratzea konfiguratzean", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Abisua: \"smbclient\" ez dago instalatuta. CIFS/SMB partekatutako karpetak montatzea ez da posible. Mesedez eskatu zure sistema kudeatzaileari instalatzea.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Abisua: PHPren FTP modulua ez dago instalatuta edo gaitua. FTP partekatutako karpetak montatzea ez da posible. Mesedez eskatu zure sistema kudeatzaileari instalatzea.", "External Storage" => "Kanpoko Biltegiratzea", "Mount point" => "Montatze puntua", "Backend" => "Motorra", diff --git a/apps/files_external/l10n/fr.php b/apps/files_external/l10n/fr.php index 90007aafaaf02b8ccb6647ebbbbf0437ad46a4a0..0825a961b1c26ee555389a9a4e41f372fc826575 100644 --- a/apps/files_external/l10n/fr.php +++ b/apps/files_external/l10n/fr.php @@ -5,6 +5,8 @@ "Fill out all required fields" => "Veuillez remplir tous les champs requis", "Please provide a valid Dropbox app key and secret." => "Veuillez fournir une clé d'application (app key) ainsi qu'un mot de passe valides.", "Error configuring Google Drive storage" => "Erreur lors de la configuration du support de stockage Google Drive", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Attention : \"smbclient\" n'est pas installé. Le montage des partages CIFS/SMB n'est pas disponible. Contactez votre administrateur système pour l'installer.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Attention : Le support FTP de PHP n'est pas activé ou installé. Le montage des partages FTP n'est pas disponible. Contactez votre administrateur système pour l'installer.", "External Storage" => "Stockage externe", "Mount point" => "Point de montage", "Backend" => "Infrastructure", diff --git a/apps/files_external/l10n/gl.php b/apps/files_external/l10n/gl.php index 5024dac4d8c937d5c096eaf6f7aaa7a09a29f245..f8100e14620a97972c0d0e1ba5956505328e7c8e 100644 --- a/apps/files_external/l10n/gl.php +++ b/apps/files_external/l10n/gl.php @@ -3,8 +3,10 @@ "Error configuring Dropbox storage" => "Produciuse un erro ao configurar o almacenamento en Dropbox", "Grant access" => "Permitir o acceso", "Fill out all required fields" => "Cubrir todos os campos obrigatorios", -"Please provide a valid Dropbox app key and secret." => "Dá o segredo e a chave correcta do aplicativo de Dropbox.", +"Please provide a valid Dropbox app key and secret." => "Forneza unha chave correcta e segreda do Dropbox.", "Error configuring Google Drive storage" => "Produciuse un erro ao configurar o almacenamento en Google Drive", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Aviso: «smbclient» non está instalado. Non é posibel a montaxe de comparticións CIFS/SMB. Consulte co administrador do sistema para instalalo.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aviso: A compatibilidade de FTP en PHP non está activada ou instalada. Non é posibel a montaxe de comparticións FTP. Consulte co administrador do sistema para instalalo.", "External Storage" => "Almacenamento externo", "Mount point" => "Punto de montaxe", "Backend" => "Infraestrutura", diff --git a/apps/files_external/l10n/hu_HU.php b/apps/files_external/l10n/hu_HU.php index e915c34b9501ec6931639d9c33d9f36e6ce34287..b8973c9641111ee2a505385899b83191b3d0b94e 100644 --- a/apps/files_external/l10n/hu_HU.php +++ b/apps/files_external/l10n/hu_HU.php @@ -1,5 +1,26 @@ "Érvényes hozzáférés", +"Error configuring Dropbox storage" => "A Dropbox tárolót nem sikerült beállítani", +"Grant access" => "Megadom a hozzáférést", +"Fill out all required fields" => "Töltse ki az összes szükséges mezőt", +"Please provide a valid Dropbox app key and secret." => "Adjon meg egy érvényes Dropbox app key-t és secretet!", +"Error configuring Google Drive storage" => "A Google Drive tárolót nem sikerült beállítani", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Figyelem: az \"smbclient\" nincs telepítve a kiszolgálón. Emiatt nem lehet CIFS/SMB megosztásokat fölcsatolni. Kérje meg a rendszergazdát, hogy telepítse a szükséges programot.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Figyelem: a PHP FTP támogatása vagy nincs telepítve, vagy nincs engedélyezve a kiszolgálón. Emiatt nem lehetséges FTP-tárolókat fölcsatolni. Kérje meg a rendszergazdát, hogy telepítse a szükséges programot.", +"External Storage" => "Külső tárolási szolgáltatások becsatolása", +"Mount point" => "Hova csatoljuk", +"Backend" => "Külső tárolórendszer", +"Configuration" => "Beállítások", +"Options" => "Opciók", +"Applicable" => "Érvényességi kör", +"Add mount point" => "Új csatolás létrehozása", +"None set" => "Nincs beállítva", +"All Users" => "Az összes felhasználó", "Groups" => "Csoportok", "Users" => "Felhasználók", -"Delete" => "Törlés" +"Delete" => "Törlés", +"Enable User External Storage" => "Külső tárolók engedélyezése a felhasználók részére", +"Allow users to mount their own external storage" => "Lehetővé teszi, hogy a felhasználók külső tárolási szolgáltatásokat csatoljanak be a saját területükre", +"SSL root certificates" => "SSL tanúsítványok", +"Import Root Certificate" => "SSL tanúsítványok importálása" ); diff --git a/apps/files_external/l10n/is.php b/apps/files_external/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..5110bf5ad2704d3c86b9aef8c99db2df8a2f1f39 --- /dev/null +++ b/apps/files_external/l10n/is.php @@ -0,0 +1,26 @@ + "Aðgengi veitt", +"Error configuring Dropbox storage" => "Villa við að setja upp Dropbox gagnasvæði", +"Grant access" => "Veita aðgengi", +"Fill out all required fields" => "Fylltu út alla skilyrta reiti", +"Please provide a valid Dropbox app key and secret." => "Gefðu upp virkan Dropbox lykil og leynikóða", +"Error configuring Google Drive storage" => "Villa kom upp við að setja upp Google Drive gagnasvæði", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Aðvörun: \"smbclient\" er ekki uppsettur. Uppsetning á CIFS/SMB gagnasvæðum er ekki möguleg. Hafðu samband við kerfisstjóra til að fá hann uppsettan.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Aðvörun: FTP stuðningur í PHP er ekki virkur. Uppsetning á FTP gagnasvæðum er ekki möguleg. Hafðu samband við kerfisstjóra til að fá hann uppsettan.", +"External Storage" => "Ytri gagnageymsla", +"Mount point" => "Mount svæði", +"Backend" => "Stjórnun", +"Configuration" => "Uppsetning", +"Options" => "Stillingar", +"Applicable" => "Gilt", +"Add mount point" => "Bæta við mount svæði", +"None set" => "Ekkert sett", +"All Users" => "Allir notendur", +"Groups" => "Hópar", +"Users" => "Notendur", +"Delete" => "Eyða", +"Enable User External Storage" => "Virkja ytra gagnasvæði notenda", +"Allow users to mount their own external storage" => "Leyfa notendum að bæta við sínum eigin ytri gagnasvæðum", +"SSL root certificates" => "SSL rótar skilríki", +"Import Root Certificate" => "Flytja inn rótar skilríki" +); diff --git a/apps/files_external/l10n/ko.php b/apps/files_external/l10n/ko.php index 74a400303b2cc33588ccddec19531ed58476fc94..cb691cf5e3d1f57c97fdef17ba9b2d0709f23e07 100644 --- a/apps/files_external/l10n/ko.php +++ b/apps/files_external/l10n/ko.php @@ -5,6 +5,8 @@ "Fill out all required fields" => "모든 필수 항목을 입력하십시오", "Please provide a valid Dropbox app key and secret." => "올바른 Dropbox 앱 키와 암호를 입력하십시오.", "Error configuring Google Drive storage" => "Google 드라이브 저장소 설정 오류", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "경고\"smbclient\"가 설치되지 않았습니다. CIFS/SMB 공유애 연결이 불가능 합니다.. 시스템 관리자에게 요청하여 설치하시기 바랍니다.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "경고PHP용 FTP 지원이 사용 불가능 하거나 설치되지 않았습니다. FTP 공유에 연결이 불가능 합니다. 시스템 관리자에게 요청하여 설치하시기 바랍니다. ", "External Storage" => "외부 저장소", "Mount point" => "마운트 지점", "Backend" => "백엔드", diff --git a/apps/files_external/l10n/mk.php b/apps/files_external/l10n/mk.php index 597623323b0c5baa37df8d3dda2fae67c5e665a3..e3c1e4652b3ff53d9537af9b23da7cc318b240ad 100644 --- a/apps/files_external/l10n/mk.php +++ b/apps/files_external/l10n/mk.php @@ -1,6 +1,26 @@ "Пристапот е дозволен", +"Error configuring Dropbox storage" => "Грешка при конфигурација на Dropbox", +"Grant access" => "Дозволи пристап", +"Fill out all required fields" => "Пополни ги сите задолжителни полиња", +"Please provide a valid Dropbox app key and secret." => "Ве молам доставите валиден Dropbox клуч и тајна лозинка.", +"Error configuring Google Drive storage" => "Грешка при конфигурација на Google Drive", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "Внимание: \"smbclient\" не е инсталиран. Не е можно монтирање на CIFS/SMB дискови. Замолете го Вашиот систем администратор да го инсталира.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "Внимание: Не е овозможена или инсталирани FTP подршка во PHP. Не е можно монтирање на FTP дискови. Замолете го Вашиот систем администратор да го инсталира.", +"External Storage" => "Надворешно складиште", +"Mount point" => "Точка на монтирање", "Backend" => "Админ", +"Configuration" => "Конфигурација", +"Options" => "Опции", +"Applicable" => "Применливо", +"Add mount point" => "Додади точка на монтирање", +"None set" => "Ништо поставено", +"All Users" => "Сите корисници", "Groups" => "Групи", "Users" => "Корисници", -"Delete" => "Избриши" +"Delete" => "Избриши", +"Enable User External Storage" => "Овозможи надворешни за корисници", +"Allow users to mount their own external storage" => "Дозволи им на корисниците да монтираат свои надворешни дискови", +"SSL root certificates" => "SSL root сертификати", +"Import Root Certificate" => "Увези" ); diff --git a/apps/files_external/l10n/th_TH.php b/apps/files_external/l10n/th_TH.php index 70ab8d3348566df40a632bebbaf8ed809db220ee..870995c8e7a111b29725c696f7b8a7e62531c4c2 100644 --- a/apps/files_external/l10n/th_TH.php +++ b/apps/files_external/l10n/th_TH.php @@ -5,6 +5,8 @@ "Fill out all required fields" => "กรอกข้อมูลในช่องข้อมูลที่จำเป็นต้องกรอกทั้งหมด", "Please provide a valid Dropbox app key and secret." => "กรุณากรอกรหัส app key ของ Dropbox และรหัสลับ", "Error configuring Google Drive storage" => "เกิดข้อผิดพลาดในการกำหนดค่าการจัดเก็บข้อมูลในพื้นที่ของ Google Drive", +"Warning: \"smbclient\" is not installed. Mounting of CIFS/SMB shares is not possible. Please ask your system administrator to install it." => "คำเตือน: \"smbclient\" ยังไม่ได้ถูกติดตั้ง. การชี้ CIFS/SMB เพื่อแชร์ข้อมูลไม่สามารถกระทำได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง.", +"Warning: The FTP support in PHP is not enabled or installed. Mounting of FTP shares is not possible. Please ask your system administrator to install it." => "คำเตือน: การสนับสนุนการใช้งาน FTP ในภาษา PHP ยังไม่ได้ถูกเปิดใช้งานหรือถูกติดตั้ง. การชี้ FTP เพื่อแชร์ข้อมูลไม่สามารถดำเนินการได้ กรุณาสอบถามข้อมูลเพิ่มเติมจากผู้ดูแลระบบเพื่อติดตั้ง", "External Storage" => "พื้นทีจัดเก็บข้อมูลจากภายนอก", "Mount point" => "จุดชี้ตำแหน่ง", "Backend" => "ด้านหลังระบบ", diff --git a/apps/files_external/l10n/tr.php b/apps/files_external/l10n/tr.php index c5e9f8f892f6a64ce3b03d3fa4ea2c6975b74a65..e9a045aab572b6749197bd27e2093387ad403181 100644 --- a/apps/files_external/l10n/tr.php +++ b/apps/files_external/l10n/tr.php @@ -1,5 +1,16 @@ "Harici Depolama", +"Mount point" => "Bağlama Noktası", +"Backend" => "Yönetici", +"Configuration" => "Yapılandırma", +"Options" => "Seçenekler", +"Applicable" => "Uygulanabilir", +"Add mount point" => "Bağlama noktası ekle", +"None set" => "Hiçbiri", +"All Users" => "Tüm Kullanıcılar", "Groups" => "Gruplar", "Users" => "Kullanıcılar", -"Delete" => "Sil" +"Delete" => "Sil", +"SSL root certificates" => "SSL kök sertifikaları", +"Import Root Certificate" => "Kök Sertifikalarını İçe Aktar" ); diff --git a/apps/files_external/lib/amazons3.php b/apps/files_external/lib/amazons3.php index 235ade06db6271044456ecbbc89acc3015a42bbe..e5ef4eb097c10e3e5258cc4a563bd2867d59ddcc 100644 --- a/apps/files_external/lib/amazons3.php +++ b/apps/files_external/lib/amazons3.php @@ -108,7 +108,7 @@ class OC_Filestorage_AmazonS3 extends OC_Filestorage_Common { $stat['atime'] = time(); $stat['mtime'] = $stat['atime']; $stat['ctime'] = $stat['atime']; - } else { + } else { $object = $this->getObject($path); if ($object) { $stat['size'] = $object['Size']; diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 880e6d97e647bd5ac76797ebe41b9760deaaa3c3..2038939153c1c8086176289c67de6f95a2e2f483 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -38,7 +38,7 @@ class OC_Mount_Config { * @return array */ public static function getBackends() { - + $backends['OC_Filestorage_Local']=array( 'backend' => 'Local', 'configuration' => array( @@ -77,7 +77,7 @@ class OC_Mount_Config { 'token' => '#token', 'token_secret' => '#token secret'), 'custom' => 'google'); - + $backends['OC_Filestorage_SWIFT']=array( 'backend' => 'OpenStack Swift', 'configuration' => array( @@ -86,7 +86,7 @@ class OC_Mount_Config { 'token' => '*Token', 'root' => '&Root', 'secure' => '!Secure ftps://')); - + if(OC_Mount_Config::checksmbclient()) $backends['OC_Filestorage_SMB']=array( 'backend' => 'SMB / CIFS', 'configuration' => array( @@ -95,7 +95,7 @@ class OC_Mount_Config { 'password' => '*Password', 'share' => 'Share', 'root' => '&Root')); - + $backends['OC_Filestorage_DAV']=array( 'backend' => 'ownCloud / WebDAV', 'configuration' => array( @@ -411,7 +411,7 @@ class OC_Mount_Config { } /** - * check if smbclient is installed + * check if smbclient is installed */ public static function checksmbclient() { if(function_exists('shell_exec')) { diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 68aca228bc578c4874553dea75e226a6c5c89f68..920aefc12dee703e0f9cd4d9f4dc4510df5d1200 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -50,7 +50,7 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ 'password' => $this->password, ); - $this->client = new OC_Connector_Sabre_Client($settings); + $this->client = new Sabre_DAV_Client($settings); $caview = \OCP\Files::getStorage('files_external'); if ($caview) { @@ -234,12 +234,11 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $path1=$this->cleanPath($path1); $path2=$this->root.$this->cleanPath($path2); try { - $response=$this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); + $this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); return true; } catch(Exception $e) { echo $e; echo 'fail'; - var_dump($response); return false; } } @@ -248,12 +247,11 @@ class OC_FileStorage_DAV extends OC_Filestorage_Common{ $path1=$this->cleanPath($path1); $path2=$this->root.$this->cleanPath($path2); try { - $response=$this->client->request('COPY', $path1, null, array('Destination'=>$path2)); + $this->client->request('COPY', $path1, null, array('Destination'=>$path2)); return true; } catch(Exception $e) { echo $e; echo 'fail'; - var_dump($response); return false; } } diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php index dd537d779a66731ee898f1d408a41e94076bbc34..78ca1c87feefa3f1b22648bc4484fbfbb7ad2c6b 100644 --- a/apps/files_external/templates/settings.php +++ b/apps/files_external/templates/settings.php @@ -1,7 +1,7 @@
t('External Storage'); ?> - '')) echo ''.$_['dependencies'].''; ?> + '')) echo ''.$_['dependencies'].''; ?> '> @@ -47,7 +47,7 @@ diff --git a/apps/files_external/tests/ftp.php b/apps/files_external/tests/ftp.php index d0404b5f34cdbf11e7618a62c1bfeaf9ea03f8b3..91e4589ed184d10daa41cf1e2af6a5a1b8245bb6 100644 --- a/apps/files_external/tests/ftp.php +++ b/apps/files_external/tests/ftp.php @@ -32,18 +32,18 @@ class Test_Filestorage_FTP extends Test_FileStorage { 'root' => '/', 'secure' => false ); $instance = new OC_Filestorage_FTP($config); - $this->assertEqual('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); + $this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = true; $instance = new OC_Filestorage_FTP($config); - $this->assertEqual('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); + $this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = 'false'; $instance = new OC_Filestorage_FTP($config); - $this->assertEqual('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); + $this->assertEquals('ftp://ftp:ftp@localhost/', $instance->constructUrl('')); $config['secure'] = 'true'; $instance = new OC_Filestorage_FTP($config); - $this->assertEqual('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); + $this->assertEquals('ftps://ftp:ftp@localhost/', $instance->constructUrl('')); } } diff --git a/apps/files_sharing/appinfo/app.php b/apps/files_sharing/appinfo/app.php index 109f86b2e8752b78c9fd53270d383b61d45f4ecf..0104d0d017f98bcc92590ae131400b1ccecba7ec 100644 --- a/apps/files_sharing/appinfo/app.php +++ b/apps/files_sharing/appinfo/app.php @@ -6,4 +6,4 @@ OC::$CLASSPATH['OC_Filestorage_Shared'] = "apps/files_sharing/lib/sharedstorage. OCP\Util::connectHook('OC_Filesystem', 'setup', 'OC_Filestorage_Shared', 'setup'); OCP\Share::registerBackend('file', 'OC_Share_Backend_File'); OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file'); -OCP\Util::addScript('files_sharing', 'share'); +OCP\Util::addScript('files_sharing', 'share'); \ No newline at end of file diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 8a546d62163d8ffa520d92eda8f8a6b86108844e..780b9c1bf6d9eb925680ee1552a8066066dcf7c0 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -1,7 +1,7 @@ $(document).ready(function() { - if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined' && !publicListView) { - + if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined' && !disableSharing) { + FileActions.register('all', 'Share', OC.PERMISSION_READ, OC.imagePath('core', 'actions/share'), function(filename) { if ($('#dir').val() == '/') { var item = $('#dir').val() + filename; diff --git a/apps/files_sharing/l10n/bg_BG.php b/apps/files_sharing/l10n/bg_BG.php new file mode 100644 index 0000000000000000000000000000000000000000..ac94358c4f9690de89281d20a58ece3202fe2500 --- /dev/null +++ b/apps/files_sharing/l10n/bg_BG.php @@ -0,0 +1,9 @@ + "Парола", +"Submit" => "Потвърждение", +"%s shared the folder %s with you" => "%s сподели папката %s с Вас", +"%s shared the file %s with you" => "%s сподели файла %s с Вас", +"Download" => "Изтегляне", +"No preview available for" => "Няма наличен преглед за", +"web services under your control" => "уеб услуги под Ваш контрол" +); diff --git a/apps/files_sharing/l10n/bn_BD.php b/apps/files_sharing/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..c3af434ee2934d590c2467400afb792661c9cbc0 --- /dev/null +++ b/apps/files_sharing/l10n/bn_BD.php @@ -0,0 +1,9 @@ + "কূটশব্দ", +"Submit" => "জমা দাও", +"%s shared the folder %s with you" => "%s আপনার সাথে %s ফোল্ডারটি ভাগাভাগি করেছেন", +"%s shared the file %s with you" => "%s আপনার সাথে %s ফাইলটি ভাগাভাগি করেছেন", +"Download" => "ডাউনলোড", +"No preview available for" => "এর জন্য কোন প্রাকবীক্ষণ সুলভ নয়", +"web services under your control" => "ওয়েব সার্ভিস আপনার হাতের মুঠোয়" +); diff --git a/apps/files_sharing/l10n/hu_HU.php b/apps/files_sharing/l10n/hu_HU.php index 881b5afd817eca8246c281405cd1769ed51f1df7..f8ca541260d10676aaf4c2733d4e59aae2e7f8ba 100644 --- a/apps/files_sharing/l10n/hu_HU.php +++ b/apps/files_sharing/l10n/hu_HU.php @@ -1,6 +1,9 @@ "Méret", -"Modified" => "Módosítva", -"Delete all" => "Összes törlése", -"Delete" => "Törlés" +"Password" => "Jelszó", +"Submit" => "Elküld", +"%s shared the folder %s with you" => "%s megosztotta Önnel ezt a mappát: %s", +"%s shared the file %s with you" => "%s megosztotta Önnel ezt az állományt: %s", +"Download" => "Letöltés", +"No preview available for" => "Nem áll rendelkezésre előnézet ehhez: ", +"web services under your control" => "webszolgáltatások saját kézben" ); diff --git a/apps/files_sharing/l10n/is.php b/apps/files_sharing/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..bf1975c54ae271bb86a7b6b3b7ee0d4d08fd05a2 --- /dev/null +++ b/apps/files_sharing/l10n/is.php @@ -0,0 +1,9 @@ + "Lykilorð", +"Submit" => "Senda", +"%s shared the folder %s with you" => "%s deildi möppunni %s með þér", +"%s shared the file %s with you" => "%s deildi skránni %s með þér", +"Download" => "Niðurhal", +"No preview available for" => "Yfirlit ekki í boði fyrir", +"web services under your control" => "vefþjónusta undir þinni stjórn" +); diff --git a/apps/files_sharing/l10n/sr.php b/apps/files_sharing/l10n/sr.php new file mode 100644 index 0000000000000000000000000000000000000000..7a922b890028cf5c2f03e89f89aa52522e915901 --- /dev/null +++ b/apps/files_sharing/l10n/sr.php @@ -0,0 +1,3 @@ + "Пошаљи" +); diff --git a/apps/files_sharing/l10n/zh_TW.php b/apps/files_sharing/l10n/zh_TW.php index fa4f8075c6e4fb146454efe5ab987df7aaf5e53d..f1d28731a7fc78f11f3f48033e64cbd4423d63ba 100644 --- a/apps/files_sharing/l10n/zh_TW.php +++ b/apps/files_sharing/l10n/zh_TW.php @@ -4,5 +4,6 @@ "%s shared the folder %s with you" => "%s 分享了資料夾 %s 給您", "%s shared the file %s with you" => "%s 分享了檔案 %s 給您", "Download" => "下載", -"No preview available for" => "無法預覽" +"No preview available for" => "無法預覽", +"web services under your control" => "在您掌控之下的網路服務" ); diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php index fef0ed8a8c291f92a488a06410ef01dadee2c96c..acd5353faff3d5e16d6199435583cdca4081f0fd 100644 --- a/apps/files_sharing/public.php +++ b/apps/files_sharing/public.php @@ -7,7 +7,7 @@ OC_App::loadApps(); // support will be removed in OC 5.0,a if (isset($_GET['token'])) { unset($_GET['file']); - $qry = \OC_DB::prepare('SELECT `source` FROM `*PREFIX*sharing` WHERE `target` = ? LIMIT 1'); + $qry = \OC_DB::prepare('SELECT `source` FROM `*PREFIX*sharing` WHERE `target` = ?', 1); $filepath = $qry->execute(array($_GET['token']))->fetchOne(); if(isset($filepath)) { $info = OC_FileCache_Cached::get($filepath, ''); @@ -16,7 +16,9 @@ if (isset($_GET['token'])) { } else { $_GET['file'] = $filepath; } - \OCP\Util::writeLog('files_sharing', 'You have files that are shared by link originating from ownCloud 4.0. Redistribute the new links, because backwards compatibility will be removed in ownCloud 5.', \OCP\Util::WARN); + \OCP\Util::writeLog('files_sharing', 'You have files that are shared by link originating from ownCloud 4.0.' + .' Redistribute the new links, because backwards compatibility will be removed in ownCloud 5.', + \OCP\Util::WARN); } } @@ -27,7 +29,10 @@ function getID($path) { $path_parts = explode('/', $path, 5); $user = $path_parts[1]; $intPath = '/'.$path_parts[4]; - $query = \OC_DB::prepare('SELECT `item_source` FROM `*PREFIX*share` WHERE `uid_owner` = ? AND `file_target` = ? '); + $query = \OC_DB::prepare('SELECT `item_source`' + .' FROM `*PREFIX*share`' + .' WHERE `uid_owner` = ?' + .' AND `file_target` = ? '); $result = $query->execute(array($user, $intPath)); $row = $result->fetchRow(); $fileSource = $row['item_source']; @@ -61,21 +66,22 @@ if (isset($_GET['t'])) { $type = $linkItem['item_type']; $fileSource = $linkItem['file_source']; $shareOwner = $linkItem['uid_owner']; - + if (OCP\User::userExists($shareOwner) && $fileSource != -1 ) { - + $pathAndUser = getPathAndUser($linkItem['file_source']); $fileOwner = $pathAndUser['user']; - + //if this is a reshare check the file owner also exists if ($shareOwner != $fileOwner && ! OCP\User::userExists($fileOwner)) { - OCP\Util::writeLog('share', 'original file owner '.$fileOwner.' does not exist for share '.$linkItem['id'], \OCP\Util::ERROR); + OCP\Util::writeLog('share', 'original file owner '.$fileOwner + .' does not exist for share '.$linkItem['id'], \OCP\Util::ERROR); header('HTTP/1.0 404 Not Found'); $tmpl = new OCP\Template('', '404', 'guest'); $tmpl->printPage(); exit(); } - + //mount filesystem of file owner OC_Util::setupFS($fileOwner); } @@ -98,7 +104,7 @@ if (isset($_GET['t'])) { } } $shareOwner = substr($path, 1, strpos($path, '/', 1) - 1); - + if (OCP\User::userExists($shareOwner)) { OC_Util::setupFS($shareOwner); $fileSource = getId($path); @@ -134,7 +140,8 @@ if ($linkItem) { // Check Password $forcePortable = (CRYPT_BLOWFISH != 1); $hasher = new PasswordHash(8, $forcePortable); - if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), $linkItem['share_with']))) { + if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''), + $linkItem['share_with']))) { $tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest'); $tmpl->assign('URL', $url); $tmpl->assign('error', true); @@ -145,19 +152,25 @@ if ($linkItem) { $_SESSION['public_link_authenticated'] = $linkItem['id']; } } else { - OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type'].' for share id '.$linkItem['id'], \OCP\Util::ERROR); + OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type'] + .' for share id '.$linkItem['id'], \OCP\Util::ERROR); header('HTTP/1.0 404 Not Found'); $tmpl = new OCP\Template('', '404', 'guest'); $tmpl->printPage(); exit(); } - // Check if item id is set in session - } else if (!isset($_SESSION['public_link_authenticated']) || $_SESSION['public_link_authenticated'] !== $linkItem['id']) { - // Prompt for password - $tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest'); - $tmpl->assign('URL', $url); - $tmpl->printPage(); - exit(); + + } else { + // Check if item id is set in session + if (!isset($_SESSION['public_link_authenticated']) + || $_SESSION['public_link_authenticated'] !== $linkItem['id'] + ) { + // Prompt for password + $tmpl = new OCP\Template('files_sharing', 'authenticate', 'guest'); + $tmpl->assign('URL', $url); + $tmpl->printPage(); + exit(); + } } } $basePath = substr($pathAndUser['path'], strlen('/'.$fileOwner.'/files')); @@ -203,7 +216,9 @@ if ($linkItem) { $getPath = ''; } // - $urlLinkIdentifiers= (isset($token)?'&t='.$token:'').(isset($_GET['dir'])?'&dir='.$_GET['dir']:'').(isset($_GET['file'])?'&file='.$_GET['file']:''); + $urlLinkIdentifiers= (isset($token)?'&t='.$token:'') + .(isset($_GET['dir'])?'&dir='.$_GET['dir']:'') + .(isset($_GET['file'])?'&file='.$_GET['file']:''); // Show file list if (OC_Filesystem::is_dir($path)) { OCP\Util::addStyle('files', 'files'); @@ -242,7 +257,7 @@ if ($linkItem) { $list = new OCP\Template('files', 'part.list', ''); $list->assign('files', $files, false); - $list->assign('publicListView', true); + $list->assign('disableSharing', true); $list->assign('baseURL', OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&path=', false); $list->assign('downloadURL', OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path=', false); $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '' ); @@ -260,13 +275,16 @@ if ($linkItem) { $folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); $tmpl->assign('folder', $folder->fetchPage(), false); $tmpl->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true))); - $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') + .$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); } else { // Show file preview if viewer is available if ($type == 'file') { - $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download'); + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') + .$urlLinkIdentifiers.'&download'); } else { - $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files').$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); + $tmpl->assign('downloadURL', OCP\Util::linkToPublic('files') + .$urlLinkIdentifiers.'&download&path='.urlencode($getPath)); } } $tmpl->printPage(); diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index 647e1e08a31e4e511f21daa15d915bd34b793b51..275360ac2a869e86d705696a379ef62a845b6dfa 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -1,11 +1,5 @@ - + + diff --git a/apps/files_versions/ajax/getVersions.php b/apps/files_versions/ajax/getVersions.php index 8476e5e8a51c54312954e5e357d8ca7906defcb0..600e69cf798054bca6f9fe63a140c0e2c0cb0eca 100644 --- a/apps/files_versions/ajax/getVersions.php +++ b/apps/files_versions/ajax/getVersions.php @@ -4,10 +4,9 @@ OCP\JSON::checkAppEnabled('files_versions'); $userDirectory = "/".OCP\USER::getUser()."/files"; $source = $_GET['source']; -if( OCA_Versions\Storage::isversioned( $source ) ) { +$count = 5; //show the newest revisions +if( ($versions = OCA_Versions\Storage::getVersions( $source, $count)) ) { - $count=5; //show the newest revisions - $versions = OCA_Versions\Storage::getVersions( $source, $count); $versionsFormatted = array(); foreach ( $versions AS $version ) { diff --git a/apps/files_versions/ajax/rollbackVersion.php b/apps/files_versions/ajax/rollbackVersion.php index f1b02eb4b928647fbc567fa543890a9a521f5901..f2c211d9c1ec944247c0469c5d1ca654e8331f13 100644 --- a/apps/files_versions/ajax/rollbackVersion.php +++ b/apps/files_versions/ajax/rollbackVersion.php @@ -8,10 +8,9 @@ $userDirectory = "/".OCP\USER::getUser()."/files"; $file = $_GET['file']; $revision=(int)$_GET['revision']; -if( OCA_Versions\Storage::isversioned( $file ) ) { - if(OCA_Versions\Storage::rollback( $file, $revision )) { - OCP\JSON::success(array("data" => array( "revision" => $revision, "file" => $file ))); - }else{ - OCP\JSON::error(array("data" => array( "message" => "Could not revert:" . $file ))); - } +if(OCA_Versions\Storage::rollback( $file, $revision )) { + OCP\JSON::success(array("data" => array( "revision" => $revision, "file" => $file ))); +}else{ + OCP\JSON::error(array("data" => array( "message" => "Could not revert:" . $file ))); } + diff --git a/apps/files_versions/history.php b/apps/files_versions/history.php index d4c278ebd85f0692b362c362bd820c0d484c76ab..6071240e58320c9572742a6185efc1f224885d52 100644 --- a/apps/files_versions/history.php +++ b/apps/files_versions/history.php @@ -28,7 +28,6 @@ $tmpl = new OCP\Template( 'files_versions', 'history', 'user' ); if ( isset( $_GET['path'] ) ) { $path = $_GET['path']; - $path = $path; $tmpl->assign( 'path', $path ); $versions = new OCA_Versions\Storage(); @@ -52,10 +51,8 @@ if ( isset( $_GET['path'] ) ) { } // show the history only if there is something to show - if( OCA_Versions\Storage::isversioned( $path ) ) { - - $count = 999; //show the newest revisions - $versions = OCA_Versions\Storage::getVersions( $path, $count); + $count = 999; //show the newest revisions + if( ($versions = OCA_Versions\Storage::getVersions( $path, $count)) ) { $tmpl->assign( 'versions', array_reverse( $versions ) ); diff --git a/apps/files_versions/js/settings-personal.js b/apps/files_versions/js/settings-personal.js deleted file mode 100644 index 1e6b036fdab8136a0425ab6bceb2abd799c5d4ad..0000000000000000000000000000000000000000 --- a/apps/files_versions/js/settings-personal.js +++ /dev/null @@ -1,39 +0,0 @@ -// TODO: allow the button to be clicked only once - -$( document ).ready(function(){ - // - $( '#expireAllBtn' ).click( - - function( event ) { - - // Prevent page from reloading - event.preventDefault(); - - // Show loading gif - $('.expireAllLoading').show(); - - $.getJSON( - OC.filePath('files_versions','ajax','expireAll.php'), - function(result){ - if (result.status == 'success') { - $('.expireAllLoading').hide(); - $('#expireAllBtn').html('Expiration successful'); - } else { - - // Cancel loading - $('#expireAllBtn').html('Expiration failed'); - - // Show Dialog - OC.dialogs.alert( - 'Something went wrong, your files may not have been expired', - 'An error has occurred', - function(){ - $('#expireAllBtn').html(t('files_versions', 'Expire all versions')+''); - } - ); - } - } - ); - } - ); -}); \ No newline at end of file diff --git a/apps/files_versions/l10n/ar.php b/apps/files_versions/l10n/ar.php index fea7f1c7562a4ac5b923ea66877e872f401e9d2d..1f1f3100405941888a419eb9dcf8fff0c7496af4 100644 --- a/apps/files_versions/l10n/ar.php +++ b/apps/files_versions/l10n/ar.php @@ -1,8 +1,5 @@ "إنهاء تاريخ الإنتهاء لجميع الإصدارات", "History" => "السجل الزمني", -"Versions" => "الإصدارات", -"This will delete all existing backup versions of your files" => "هذه العملية ستقوم بإلغاء جميع إصدارات النسخ الاحتياطي للملفات", "Files Versioning" => "أصدرة الملفات", "Enable" => "تفعيل" ); diff --git a/apps/files_versions/l10n/bg_BG.php b/apps/files_versions/l10n/bg_BG.php new file mode 100644 index 0000000000000000000000000000000000000000..6ecf12d0b00c50686c7a413e339db78a6e3c764b --- /dev/null +++ b/apps/files_versions/l10n/bg_BG.php @@ -0,0 +1,4 @@ + "История", +"Enable" => "Включено" +); diff --git a/apps/files_versions/l10n/bn_BD.php b/apps/files_versions/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..dffa4d79a06f72c21afa13fd361bb5041512aa1e --- /dev/null +++ b/apps/files_versions/l10n/bn_BD.php @@ -0,0 +1,5 @@ + "ইতিহাস", +"Files Versioning" => "ফাইল ভার্সন করা", +"Enable" => "সক্রিয় " +); diff --git a/apps/files_versions/l10n/ca.php b/apps/files_versions/l10n/ca.php index 0076d02992f910fb9a1c7f28856592aa82df94da..01e0a116873ae558685316cf0dd2e9522ee15e60 100644 --- a/apps/files_versions/l10n/ca.php +++ b/apps/files_versions/l10n/ca.php @@ -1,8 +1,5 @@ "Expira totes les versions", "History" => "Historial", -"Versions" => "Versions", -"This will delete all existing backup versions of your files" => "Això eliminarà totes les versions de còpia de seguretat dels vostres fitxers", "Files Versioning" => "Fitxers de Versions", "Enable" => "Habilita" ); diff --git a/apps/files_versions/l10n/cs_CZ.php b/apps/files_versions/l10n/cs_CZ.php index 3995334d9ee230b4012c5bdc42b9baa4cb3f2c7a..d219c3e68daea5c2f6b14ffa182c1d5ed580af1f 100644 --- a/apps/files_versions/l10n/cs_CZ.php +++ b/apps/files_versions/l10n/cs_CZ.php @@ -1,8 +1,5 @@ "Vypršet všechny verze", "History" => "Historie", -"Versions" => "Verze", -"This will delete all existing backup versions of your files" => "Odstraní všechny existující zálohované verze Vašich souborů", "Files Versioning" => "Verzování souborů", "Enable" => "Povolit" ); diff --git a/apps/files_versions/l10n/da.php b/apps/files_versions/l10n/da.php index bc02b47f2ad4fda3207bd590948280b9c806abd7..985797476439ed9074b3a24d57d4ed8aaddcd32b 100644 --- a/apps/files_versions/l10n/da.php +++ b/apps/files_versions/l10n/da.php @@ -1,8 +1,5 @@ "Lad alle versioner udløbe", "History" => "Historik", -"Versions" => "Versioner", -"This will delete all existing backup versions of your files" => "Dette vil slette alle eksisterende backupversioner af dine filer", "Files Versioning" => "Versionering af filer", "Enable" => "Aktiver" ); diff --git a/apps/files_versions/l10n/de.php b/apps/files_versions/l10n/de.php index 092bbfbff70eeccf83fb66f5a160c35aa47fff24..2fcb996de7bae035700e178be957b88e65c44bc7 100644 --- a/apps/files_versions/l10n/de.php +++ b/apps/files_versions/l10n/de.php @@ -1,8 +1,5 @@ "Alle Versionen löschen", "History" => "Historie", -"Versions" => "Versionen", -"This will delete all existing backup versions of your files" => "Dies löscht alle vorhandenen Sicherungsversionen Deiner Dateien.", "Files Versioning" => "Dateiversionierung", "Enable" => "Aktivieren" ); diff --git a/apps/files_versions/l10n/de_DE.php b/apps/files_versions/l10n/de_DE.php index a568112d02db19d2f1cc1561ce743b0fc22dd3e9..2fcb996de7bae035700e178be957b88e65c44bc7 100644 --- a/apps/files_versions/l10n/de_DE.php +++ b/apps/files_versions/l10n/de_DE.php @@ -1,8 +1,5 @@ "Alle Versionen löschen", "History" => "Historie", -"Versions" => "Versionen", -"This will delete all existing backup versions of your files" => "Dies löscht alle vorhandenen Sicherungsversionen Ihrer Dateien.", "Files Versioning" => "Dateiversionierung", "Enable" => "Aktivieren" ); diff --git a/apps/files_versions/l10n/el.php b/apps/files_versions/l10n/el.php index f6b9a5b2998de835eaa04cb79c72eb8d427e575b..6b189c2cdd398168d89a99c53f1b90cccfa73253 100644 --- a/apps/files_versions/l10n/el.php +++ b/apps/files_versions/l10n/el.php @@ -1,8 +1,5 @@ "Λήξη όλων των εκδόσεων", "History" => "Ιστορικό", -"Versions" => "Εκδόσεις", -"This will delete all existing backup versions of your files" => "Αυτό θα διαγράψει όλες τις υπάρχουσες εκδόσεις των αντιγράφων ασφαλείας των αρχείων σας", "Files Versioning" => "Εκδόσεις Αρχείων", "Enable" => "Ενεργοποίηση" ); diff --git a/apps/files_versions/l10n/eo.php b/apps/files_versions/l10n/eo.php index 0c3835373ef19f659619a00cd5a015d2283b74c7..87b314655c0d48f8f5cc7143c96ebd6737b402e5 100644 --- a/apps/files_versions/l10n/eo.php +++ b/apps/files_versions/l10n/eo.php @@ -1,8 +1,5 @@ "Eksvalidigi ĉiujn eldonojn", "History" => "Historio", -"Versions" => "Eldonoj", -"This will delete all existing backup versions of your files" => "Ĉi tio forigos ĉiujn estantajn sekurkopiajn eldonojn de viaj dosieroj", "Files Versioning" => "Dosiereldonigo", "Enable" => "Kapabligi" ); diff --git a/apps/files_versions/l10n/es.php b/apps/files_versions/l10n/es.php index f6b63df7c2b5484d72733cd0bf968f19106a7208..4a8c34e518081a2891fff577419c1d2af91266e6 100644 --- a/apps/files_versions/l10n/es.php +++ b/apps/files_versions/l10n/es.php @@ -1,8 +1,5 @@ "Expirar todas las versiones", "History" => "Historial", -"Versions" => "Versiones", -"This will delete all existing backup versions of your files" => "Esto eliminará todas las versiones guardadas como copia de seguridad de tus archivos", "Files Versioning" => "Versionado de archivos", "Enable" => "Habilitar" ); diff --git a/apps/files_versions/l10n/es_AR.php b/apps/files_versions/l10n/es_AR.php index a78264de03fdb55bb6b082dc2d63ba42cbbc58f4..74d8907fc3539a3f4c73dd3b549d6de13e667e4b 100644 --- a/apps/files_versions/l10n/es_AR.php +++ b/apps/files_versions/l10n/es_AR.php @@ -1,8 +1,5 @@ "Expirar todas las versiones", "History" => "Historia", -"Versions" => "Versiones", -"This will delete all existing backup versions of your files" => "Hacer estom borrará todas las versiones guardadas como copia de seguridad de tus archivos", "Files Versioning" => "Versionado de archivos", "Enable" => "Activar" ); diff --git a/apps/files_versions/l10n/et_EE.php b/apps/files_versions/l10n/et_EE.php index f1296f23fcd3a3cea22cf63504c2b6b3c4bc08fa..ff119d5374efa7fc9ab4deccbd6c1b391e4aa47c 100644 --- a/apps/files_versions/l10n/et_EE.php +++ b/apps/files_versions/l10n/et_EE.php @@ -1,8 +1,5 @@ "Kõikide versioonide aegumine", "History" => "Ajalugu", -"Versions" => "Versioonid", -"This will delete all existing backup versions of your files" => "See kustutab kõik sinu failidest tehtud varuversiooni", "Files Versioning" => "Failide versioonihaldus", "Enable" => "Luba" ); diff --git a/apps/files_versions/l10n/eu.php b/apps/files_versions/l10n/eu.php index d84d901170766e0e0f439f77c02bbb80e810e3ca..c6b4cd7692dada9b554fc4a56d00edfca3cc9d8a 100644 --- a/apps/files_versions/l10n/eu.php +++ b/apps/files_versions/l10n/eu.php @@ -1,8 +1,5 @@ "Iraungi bertsio guztiak", "History" => "Historia", -"Versions" => "Bertsioak", -"This will delete all existing backup versions of your files" => "Honek zure fitxategien bertsio guztiak ezabatuko ditu", "Files Versioning" => "Fitxategien Bertsioak", "Enable" => "Gaitu" ); diff --git a/apps/files_versions/l10n/fi_FI.php b/apps/files_versions/l10n/fi_FI.php index 3cec4c04bfe095a9ec28de6eae6b9cc8d1e81c92..bdce8e9fe5209dc563dac6532bd64f17acda02d0 100644 --- a/apps/files_versions/l10n/fi_FI.php +++ b/apps/files_versions/l10n/fi_FI.php @@ -1,8 +1,5 @@ "Vanhenna kaikki versiot", "History" => "Historia", -"Versions" => "Versiot", -"This will delete all existing backup versions of your files" => "Tämä poistaa kaikki tiedostojesi olemassa olevat varmuuskopioversiot", "Files Versioning" => "Tiedostojen versiointi", "Enable" => "Käytä" ); diff --git a/apps/files_versions/l10n/fr.php b/apps/files_versions/l10n/fr.php index e6dbc274456ae1dbf295a41f04fe3a9ab0a723c3..2d26b98860ac147ac64d03e4c8fea11f1c4ace58 100644 --- a/apps/files_versions/l10n/fr.php +++ b/apps/files_versions/l10n/fr.php @@ -1,8 +1,5 @@ "Supprimer les versions intermédiaires", "History" => "Historique", -"Versions" => "Versions", -"This will delete all existing backup versions of your files" => "Cette opération va effacer toutes les versions intermédiaires de vos fichiers (et ne garder que la dernière version en date).", "Files Versioning" => "Versionnage des fichiers", "Enable" => "Activer" ); diff --git a/apps/files_versions/l10n/gl.php b/apps/files_versions/l10n/gl.php index f10c1e162639438a4026d11eb4c96048640ec348..7e44b8898bfa68e9f0d073922a5d824749f43ac4 100644 --- a/apps/files_versions/l10n/gl.php +++ b/apps/files_versions/l10n/gl.php @@ -1,8 +1,5 @@ "Caducan todas as versións", "History" => "Historial", -"Versions" => "Versións", -"This will delete all existing backup versions of your files" => "Isto eliminará todas as copias de seguranza que haxa dos seus ficheiros", "Files Versioning" => "Sistema de versión de ficheiros", "Enable" => "Activar" ); diff --git a/apps/files_versions/l10n/he.php b/apps/files_versions/l10n/he.php index 061e88b0dbf54116f2f3e84136e594cbfaeeb21e..9eb4df64857fbd7675bc0814d65a286c39b96871 100644 --- a/apps/files_versions/l10n/he.php +++ b/apps/files_versions/l10n/he.php @@ -1,8 +1,5 @@ "הפגת תוקף כל הגרסאות", "History" => "היסטוריה", -"Versions" => "גרסאות", -"This will delete all existing backup versions of your files" => "פעולה זו תמחק את כל גיבויי הגרסאות הקיימים של הקבצים שלך", "Files Versioning" => "שמירת הבדלי גרסאות של קבצים", "Enable" => "הפעלה" ); diff --git a/apps/files_versions/l10n/hu_HU.php b/apps/files_versions/l10n/hu_HU.php new file mode 100644 index 0000000000000000000000000000000000000000..95d37ad06ed686b7b692b81802c5479785e91a5c --- /dev/null +++ b/apps/files_versions/l10n/hu_HU.php @@ -0,0 +1,5 @@ + "Korábbi változatok", +"Files Versioning" => "Az állományok verzionálása", +"Enable" => "engedélyezve" +); diff --git a/apps/files_versions/l10n/id.php b/apps/files_versions/l10n/id.php index d8ac66c9763d9a69591d68b86bb7e229ad76cfc6..6c553327c42aca3414bdffb9850465b8737d405a 100644 --- a/apps/files_versions/l10n/id.php +++ b/apps/files_versions/l10n/id.php @@ -1,8 +1,5 @@ "kadaluarsakan semua versi", "History" => "riwayat", -"Versions" => "versi", -"This will delete all existing backup versions of your files" => "ini akan menghapus semua versi backup yang ada dari file anda", "Files Versioning" => "pembuatan versi file", "Enable" => "aktifkan" ); diff --git a/apps/files_versions/l10n/is.php b/apps/files_versions/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..ccb8287b71e9be068471d5db9332e2b5fd34ea66 --- /dev/null +++ b/apps/files_versions/l10n/is.php @@ -0,0 +1,5 @@ + "Saga", +"Files Versioning" => "Útgáfur af skrám", +"Enable" => "Virkja" +); diff --git a/apps/files_versions/l10n/it.php b/apps/files_versions/l10n/it.php index 0b1e70823d5839db1425f878c3519097fa2787e6..c57b09301110bb6c825b9118ea1587f35cc95728 100644 --- a/apps/files_versions/l10n/it.php +++ b/apps/files_versions/l10n/it.php @@ -1,8 +1,5 @@ "Scadenza di tutte le versioni", "History" => "Cronologia", -"Versions" => "Versioni", -"This will delete all existing backup versions of your files" => "Ciò eliminerà tutte le versioni esistenti dei tuoi file", "Files Versioning" => "Controllo di versione dei file", "Enable" => "Abilita" ); diff --git a/apps/files_versions/l10n/ja_JP.php b/apps/files_versions/l10n/ja_JP.php index 367152c0743abadf07c04e27006e634499de161f..c97ba3d00ee81849ce81d15f60d062a44211d59a 100644 --- a/apps/files_versions/l10n/ja_JP.php +++ b/apps/files_versions/l10n/ja_JP.php @@ -1,8 +1,5 @@ "すべてのバージョンを削除する", "History" => "履歴", -"Versions" => "バージョン", -"This will delete all existing backup versions of your files" => "これは、あなたのファイルのすべてのバックアップバージョンを削除します", "Files Versioning" => "ファイルのバージョン管理", "Enable" => "有効化" ); diff --git a/apps/files_versions/l10n/ko.php b/apps/files_versions/l10n/ko.php index 688babb11219b334c88df4f7d5c969800baa99a5..f40925e1be2dc2d0a2b6d08dca26e0d40a144cb9 100644 --- a/apps/files_versions/l10n/ko.php +++ b/apps/files_versions/l10n/ko.php @@ -1,8 +1,5 @@ "모든 버전 삭제", "History" => "역사", -"Versions" => "버전", -"This will delete all existing backup versions of your files" => "이 파일의 모든 백업 버전을 삭제합니다", "Files Versioning" => "파일 버전 관리", "Enable" => "사용함" ); diff --git a/apps/files_versions/l10n/ku_IQ.php b/apps/files_versions/l10n/ku_IQ.php index 5fa3b9080d7e91ec399eef0e70e59d2cc5672d8a..db5dbad49fcae65da0279cb0693592900767bca7 100644 --- a/apps/files_versions/l10n/ku_IQ.php +++ b/apps/files_versions/l10n/ku_IQ.php @@ -1,8 +1,5 @@ "وه‌شانه‌کان گشتیان به‌سه‌رده‌چن", "History" => "مێژوو", -"Versions" => "وه‌شان", -"This will delete all existing backup versions of your files" => "ئه‌مه‌ سه‌رجه‌م پاڵپشتی وه‌شانه‌ هه‌بووه‌کانی په‌ڕگه‌کانت ده‌سڕینته‌وه", "Files Versioning" => "وه‌شانی په‌ڕگه", "Enable" => "چالاککردن" ); diff --git a/apps/files_versions/l10n/lt_LT.php b/apps/files_versions/l10n/lt_LT.php index 3250ddc7c3c51ca11cd11cb4bee29d851e694a58..adf4893020e583c923c1893373b8907f6487ac08 100644 --- a/apps/files_versions/l10n/lt_LT.php +++ b/apps/files_versions/l10n/lt_LT.php @@ -1,8 +1,5 @@ "Panaikinti visų versijų galiojimą", "History" => "Istorija", -"Versions" => "Versijos", -"This will delete all existing backup versions of your files" => "Tai ištrins visas esamas failo versijas", "Files Versioning" => "Failų versijos", "Enable" => "Įjungti" ); diff --git a/apps/files_versions/l10n/mk.php b/apps/files_versions/l10n/mk.php index 60a06ad3384fe4dbb11da73eec6a51a29c57b622..d3ec233fe4130e90f7a181a397a3ceac7e720951 100644 --- a/apps/files_versions/l10n/mk.php +++ b/apps/files_versions/l10n/mk.php @@ -1,8 +1,5 @@ "Истечи ги сите верзии", "History" => "Историја", -"Versions" => "Версии", -"This will delete all existing backup versions of your files" => "Ова ќе ги избрише сите постоечки резервни копии од вашите датотеки", "Files Versioning" => "Верзии на датотеки", "Enable" => "Овозможи" ); diff --git a/apps/files_versions/l10n/nb_NO.php b/apps/files_versions/l10n/nb_NO.php index b441008db017f50cc106cdd0c997152a7a4fe1c2..18c725061027a0a0d216ca3850a5aaf50e71c1ff 100644 --- a/apps/files_versions/l10n/nb_NO.php +++ b/apps/files_versions/l10n/nb_NO.php @@ -1,7 +1,5 @@ "Historie", -"Versions" => "Versjoner", -"This will delete all existing backup versions of your files" => "Dette vil slette alle tidligere versjoner av alle filene dine", "Files Versioning" => "Fil versjonering", "Enable" => "Aktiver" ); diff --git a/apps/files_versions/l10n/nl.php b/apps/files_versions/l10n/nl.php index f9b5507621d1bd4ee44a0dba21af78e6117d6af5..cd147ca693f0af302b7a479a9d643bb1c51ebf35 100644 --- a/apps/files_versions/l10n/nl.php +++ b/apps/files_versions/l10n/nl.php @@ -1,8 +1,5 @@ "Alle versies laten verlopen", "History" => "Geschiedenis", -"Versions" => "Versies", -"This will delete all existing backup versions of your files" => "Dit zal alle bestaande backup versies van uw bestanden verwijderen", "Files Versioning" => "Bestand versies", "Enable" => "Activeer" ); diff --git a/apps/files_versions/l10n/pl.php b/apps/files_versions/l10n/pl.php index 46c28d4590ab910ef720e388bbfc8411d8e75f1e..a0247b8abc62d5caa6a8279c347915901031ce8a 100644 --- a/apps/files_versions/l10n/pl.php +++ b/apps/files_versions/l10n/pl.php @@ -1,8 +1,5 @@ "Wygasają wszystkie wersje", "History" => "Historia", -"Versions" => "Wersje", -"This will delete all existing backup versions of your files" => "Spowoduje to usunięcie wszystkich istniejących wersji kopii zapasowych plików", "Files Versioning" => "Wersjonowanie plików", "Enable" => "Włącz" ); diff --git a/apps/files_versions/l10n/pt_BR.php b/apps/files_versions/l10n/pt_BR.php index 3d39a533d65f0a90bdce9606bdebc5e03a3a195f..854a30e6beeab87a003cddd422d0a5209a91a533 100644 --- a/apps/files_versions/l10n/pt_BR.php +++ b/apps/files_versions/l10n/pt_BR.php @@ -1,8 +1,5 @@ "Expirar todas as versões", "History" => "Histórico", -"Versions" => "Versões", -"This will delete all existing backup versions of your files" => "Isso removerá todas as versões de backup existentes dos seus arquivos", "Files Versioning" => "Versionamento de Arquivos", "Enable" => "Habilitar" ); diff --git a/apps/files_versions/l10n/pt_PT.php b/apps/files_versions/l10n/pt_PT.php index 2ddf70cc6c56e0f29165250792f0de988c799de2..dc1bde08cad0853c72c4eef5e9ec028dca68247f 100644 --- a/apps/files_versions/l10n/pt_PT.php +++ b/apps/files_versions/l10n/pt_PT.php @@ -1,8 +1,5 @@ "Expirar todas as versões", "History" => "Histórico", -"Versions" => "Versões", -"This will delete all existing backup versions of your files" => "Isto irá apagar todas as versões de backup do seus ficheiros", "Files Versioning" => "Versionamento de Ficheiros", "Enable" => "Activar" ); diff --git a/apps/files_versions/l10n/ro.php b/apps/files_versions/l10n/ro.php index e23e771e3927867a17d988c4c670bb1c5c9a5a65..7dfaee3672b1c391f0968599560062f54ccc4cb0 100644 --- a/apps/files_versions/l10n/ro.php +++ b/apps/files_versions/l10n/ro.php @@ -1,8 +1,5 @@ "Expiră toate versiunile", "History" => "Istoric", -"Versions" => "Versiuni", -"This will delete all existing backup versions of your files" => "Această acțiune va șterge toate versiunile salvate ale fișierelor tale", "Files Versioning" => "Versionare fișiere", "Enable" => "Activare" ); diff --git a/apps/files_versions/l10n/ru.php b/apps/files_versions/l10n/ru.php index d698e90b8b86747138eef47239ed26e1517d8ff5..4c7fb5010912d39808cbc267d4a926f7efba29b3 100644 --- a/apps/files_versions/l10n/ru.php +++ b/apps/files_versions/l10n/ru.php @@ -1,8 +1,5 @@ "Просрочить все версии", "History" => "История", -"Versions" => "Версии", -"This will delete all existing backup versions of your files" => "Очистить список версий ваших файлов", "Files Versioning" => "Версии файлов", "Enable" => "Включить" ); diff --git a/apps/files_versions/l10n/ru_RU.php b/apps/files_versions/l10n/ru_RU.php index 557c2f8e6d19bae1e6662ff176bd0189df9dfafd..8656e346eb6e51d36f165fc00afd310b2fb93e8d 100644 --- a/apps/files_versions/l10n/ru_RU.php +++ b/apps/files_versions/l10n/ru_RU.php @@ -1,8 +1,5 @@ "Срок действия всех версий истекает", "History" => "История", -"Versions" => "Версии", -"This will delete all existing backup versions of your files" => "Это приведет к удалению всех существующих версий резервной копии Ваших файлов", "Files Versioning" => "Файлы управления версиями", "Enable" => "Включить" ); diff --git a/apps/files_versions/l10n/si_LK.php b/apps/files_versions/l10n/si_LK.php index dbddf6dc2e9db674d26697a05d24b04e9859cf1e..37debf869bc55f054c322f5993256f8f8e9c7ebf 100644 --- a/apps/files_versions/l10n/si_LK.php +++ b/apps/files_versions/l10n/si_LK.php @@ -1,8 +1,5 @@ "සියලු අනුවාද අවලංගු කරන්න", "History" => "ඉතිහාසය", -"Versions" => "අනුවාද", -"This will delete all existing backup versions of your files" => "මෙයින් ඔබගේ ගොනුවේ රක්ශිත කරනු ලැබු අනුවාද සියල්ල මකා දමනු ලැබේ", "Files Versioning" => "ගොනු අනුවාදයන්", "Enable" => "සක්‍රිය කරන්න" ); diff --git a/apps/files_versions/l10n/sk_SK.php b/apps/files_versions/l10n/sk_SK.php index 132c6c09682b006252aed57d37a5ef2d4018df58..a3a3567cb4f99465180f82a8b5f4c2e47914b3e1 100644 --- a/apps/files_versions/l10n/sk_SK.php +++ b/apps/files_versions/l10n/sk_SK.php @@ -1,8 +1,5 @@ "Expirovať všetky verzie", "History" => "História", -"Versions" => "Verzie", -"This will delete all existing backup versions of your files" => "Budú zmazané všetky zálohované verzie vašich súborov", "Files Versioning" => "Vytváranie verzií súborov", "Enable" => "Zapnúť" ); diff --git a/apps/files_versions/l10n/sl.php b/apps/files_versions/l10n/sl.php index 22b890a042dfdda891711e0c104da3088032e5b6..7f386c9edaa2d8a6d49755c776f34f414e73185f 100644 --- a/apps/files_versions/l10n/sl.php +++ b/apps/files_versions/l10n/sl.php @@ -1,8 +1,5 @@ "Zastaraj vse različice", "History" => "Zgodovina", -"Versions" => "Različice", -"This will delete all existing backup versions of your files" => "S tem bodo izbrisane vse obstoječe različice varnostnih kopij vaših datotek", "Files Versioning" => "Sledenje različicam", "Enable" => "Omogoči" ); diff --git a/apps/files_versions/l10n/sv.php b/apps/files_versions/l10n/sv.php index e36164e30ab060cd557b03e2e4b40f848f87865c..6788d1fb0f969a942cb01fd191de89f91924843b 100644 --- a/apps/files_versions/l10n/sv.php +++ b/apps/files_versions/l10n/sv.php @@ -1,8 +1,5 @@ "Upphör alla versioner", "History" => "Historik", -"Versions" => "Versioner", -"This will delete all existing backup versions of your files" => "Detta kommer att radera alla befintliga säkerhetskopior av dina filer", "Files Versioning" => "Versionshantering av filer", "Enable" => "Aktivera" ); diff --git a/apps/files_versions/l10n/ta_LK.php b/apps/files_versions/l10n/ta_LK.php index f1215b3ecc1097ee8b9c4396127f7eaa51bc501d..aca76dcc2621697e3f515abcbbc9229da15a6511 100644 --- a/apps/files_versions/l10n/ta_LK.php +++ b/apps/files_versions/l10n/ta_LK.php @@ -1,8 +1,5 @@ "எல்லா பதிப்புகளும் காலாவதியாகிவிட்டது", "History" => "வரலாறு", -"Versions" => "பதிப்புகள்", -"This will delete all existing backup versions of your files" => "உங்களுடைய கோப்புக்களில் ஏற்கனவே உள்ள ஆதாரநகல்களின் பதிப்புக்களை இவை அழித்துவிடும்", "Files Versioning" => "கோப்பு பதிப்புகள்", "Enable" => "இயலுமைப்படுத்துக" ); diff --git a/apps/files_versions/l10n/th_TH.php b/apps/files_versions/l10n/th_TH.php index 89b9f6269112692ff01ac7d1f9e54077b5f8d06b..e1e996903aea02efcef879b9c7c8525ae842928c 100644 --- a/apps/files_versions/l10n/th_TH.php +++ b/apps/files_versions/l10n/th_TH.php @@ -1,8 +1,5 @@ "หมดอายุทุกรุ่น", "History" => "ประวัติ", -"Versions" => "รุ่น", -"This will delete all existing backup versions of your files" => "นี่จะเป็นลบทิ้งไฟล์รุ่นที่ทำการสำรองข้อมูลทั้งหมดที่มีอยู่ของคุณทิ้งไป", "Files Versioning" => "การกำหนดเวอร์ชั่นของไฟล์", "Enable" => "เปิดใช้งาน" ); diff --git a/apps/files_versions/l10n/tr.php b/apps/files_versions/l10n/tr.php new file mode 100644 index 0000000000000000000000000000000000000000..e9a4c4702e13b2d635ef060cf5469d57b0d958c4 --- /dev/null +++ b/apps/files_versions/l10n/tr.php @@ -0,0 +1,5 @@ + "Geçmiş", +"Files Versioning" => "Dosya Sürümleri", +"Enable" => "Etkinleştir" +); diff --git a/apps/files_versions/l10n/uk.php b/apps/files_versions/l10n/uk.php index 7532f755c881699e84ff11f275965e69df458d10..49acda810792942ad0243edac376e8e921195ea2 100644 --- a/apps/files_versions/l10n/uk.php +++ b/apps/files_versions/l10n/uk.php @@ -1,8 +1,5 @@ "Термін дії всіх версій", "History" => "Історія", -"Versions" => "Версії", -"This will delete all existing backup versions of your files" => "Це призведе до знищення всіх існуючих збережених версій Ваших файлів", "Files Versioning" => "Версії файлів", "Enable" => "Включити" ); diff --git a/apps/files_versions/l10n/vi.php b/apps/files_versions/l10n/vi.php index 260c3b6b39c7575432a83f97ad4c51c9561fc8bc..bb7163f6b1875bcafeb1f6f6f6b28502ee9adb52 100644 --- a/apps/files_versions/l10n/vi.php +++ b/apps/files_versions/l10n/vi.php @@ -1,8 +1,5 @@ "Hết hạn tất cả các phiên bản", "History" => "Lịch sử", -"Versions" => "Phiên bản", -"This will delete all existing backup versions of your files" => "Khi bạn thực hiện thao tác này sẽ xóa tất cả các phiên bản sao lưu hiện có ", "Files Versioning" => "Phiên bản tập tin", "Enable" => "Bật " ); diff --git a/apps/files_versions/l10n/zh_CN.GB2312.php b/apps/files_versions/l10n/zh_CN.GB2312.php index 107805221b85beaa53027f1e0fd2da322c66321d..d9e788033aaab1f995650b04f86b8db67de4f29b 100644 --- a/apps/files_versions/l10n/zh_CN.GB2312.php +++ b/apps/files_versions/l10n/zh_CN.GB2312.php @@ -1,8 +1,5 @@ "作废所有版本", "History" => "历史", -"Versions" => "版本", -"This will delete all existing backup versions of your files" => "这将删除所有您现有文件的备份版本", "Files Versioning" => "文件版本", "Enable" => "启用" ); diff --git a/apps/files_versions/l10n/zh_CN.php b/apps/files_versions/l10n/zh_CN.php index 48e7157c98ffdb57425e929686292456592c4004..14301ff0c04a39f35edfe677115e8394fac33c49 100644 --- a/apps/files_versions/l10n/zh_CN.php +++ b/apps/files_versions/l10n/zh_CN.php @@ -1,8 +1,5 @@ "过期所有版本", "History" => "历史", -"Versions" => "版本", -"This will delete all existing backup versions of your files" => "将会删除您的文件的所有备份版本", "Files Versioning" => "文件版本", "Enable" => "开启" ); diff --git a/apps/files_versions/l10n/zh_TW.php b/apps/files_versions/l10n/zh_TW.php index a21fdc85f8d969ae80c40dc923a2d44a7228e4f6..a7b496b37dbcdf613fe379e41cac880a060cc602 100644 --- a/apps/files_versions/l10n/zh_TW.php +++ b/apps/files_versions/l10n/zh_TW.php @@ -1,7 +1,5 @@ "所有逾期的版本", "History" => "歷史", -"Versions" => "版本", "Files Versioning" => "檔案版本化中...", "Enable" => "啟用" ); diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php index e897a81f7af4588de258115ca8f17003b46bdef5..5fb9dc3c3c550631fd669d7d9557782cde012394 100644 --- a/apps/files_versions/lib/hooks.php +++ b/apps/files_versions/lib/hooks.php @@ -39,15 +39,15 @@ class Hooks { * cleanup the versions directory if the actual file gets deleted */ public static function remove_hook($params) { - $versions_fileview = \OCP\Files::getStorage('files_versions'); - $rel_path = $params['path']; - $abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$rel_path.'.v'; - if(Storage::isversioned($rel_path)) { - $versions = Storage::getVersions($rel_path); - foreach ($versions as $v) { - unlink($abs_path . $v['version']); - } - } + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + $versions = new Storage( new \OC_FilesystemView('') ); + + $path = $params[\OC_Filesystem::signal_param_path]; + + if($path<>'') $versions->delete( $path ); + + } } /** @@ -58,18 +58,16 @@ class Hooks { * of the stored versions along the actual file */ public static function rename_hook($params) { - $versions_fileview = \OCP\Files::getStorage('files_versions'); - $rel_oldpath = $params['oldpath']; - $abs_oldpath = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$rel_oldpath.'.v'; - $abs_newpath = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$params['newpath'].'.v'; - if(Storage::isversioned($rel_oldpath)) { - $info=pathinfo($abs_newpath); - if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true); - $versions = Storage::getVersions($rel_oldpath); - foreach ($versions as $v) { - rename($abs_oldpath.$v['version'], $abs_newpath.$v['version']); - } + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + + $versions = new Storage( new \OC_FilesystemView('') ); + + $oldpath = $params['oldpath']; + $newpath = $params['newpath']; + + if($oldpath<>'' && $newpath<>'') $versions->rename( $oldpath, $newpath ); + } } - + } diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php index 0ccaaf1095dd1079f8c991e089f94d14638bc601..48be5e223ac0eef2b3c6b0973b97274a4bd31245 100644 --- a/apps/files_versions/lib/versions.php +++ b/apps/files_versions/lib/versions.php @@ -1,6 +1,7 @@ + * 2013 Bjoern Schiessle * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -16,24 +17,23 @@ namespace OCA_Versions; class Storage { - - // config.php configuration: - // - files_versions - // - files_versionsfolder - // - files_versionsblacklist - // - files_versionsmaxfilesize - // - files_versionsinterval - // - files_versionmaxversions - // - // todo: - // - finish porting to OC_FilesystemView to enable network transparency - // - add transparent compression. first test if it´s worth it. - const DEFAULTENABLED=true; - const DEFAULTBLACKLIST='avi mp3 mpg mp4 ctmp'; - const DEFAULTMAXFILESIZE=1048576; // 10MB - const DEFAULTMININTERVAL=60; // 1 min - const DEFAULTMAXVERSIONS=50; + const DEFAULTMAXSIZE=50; // unit: percentage; 50% of available disk space/quota + + private static $max_versions_per_interval = array( + 1 => array('intervalEndsAfter' => 10, //first 10sec, one version every 2sec + 'step' => 2), + 2 => array('intervalEndsAfter' => 60, //next minute, one version every 10sec + 'step' => 10), + 3 => array('intervalEndsAfter' => 3600, //next hour, one version every minute + 'step' => 60), + 4 => array('intervalEndsAfter' => 86400, //next 24h, one version every hour + 'step' => 3600), + 5 => array('intervalEndsAfter' => 2592000, //next 30days, one version per day + 'step' => 86400), + 6 => array('intervalEndsAfter' => -1, //until the end one version per week + 'step' => 604800), + ); private static function getUidAndFilename($filename) { @@ -72,55 +72,77 @@ class Storage { return false; } - // check filetype blacklist - $blacklist=explode(' ', \OCP\Config::getSystemValue('files_versionsblacklist', Storage::DEFAULTBLACKLIST)); - foreach($blacklist as $bl) { - $parts=explode('.', $filename); - $ext=end($parts); - if(strtolower($ext)==$bl) { - return false; - } - } // we should have a source file to work with if (!$files_view->file_exists($filename)) { return false; } - // check filesize - if($files_view->filesize($filename)>\OCP\Config::getSystemValue('files_versionsmaxfilesize', Storage::DEFAULTMAXFILESIZE)) { - return false; - } - - - // check mininterval if the file is being modified by the owner (all shared files should be versioned despite mininterval) - if ($uid == \OCP\User::getUser()) { - $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); - $versionsName=\OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath($filename); - $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath(''); - $matches=glob($versionsName.'.v*'); - sort($matches); - $parts=explode('.v', end($matches)); - if((end($parts)+Storage::DEFAULTMININTERVAL)>time()) { - return false; - } - } - - // create all parent folders $info=pathinfo($filename); + $versionsFolderName=\OCP\Config::getSystemValue('datadirectory').$users_view->getAbsolutePath('files_versions/'); if(!file_exists($versionsFolderName.'/'.$info['dirname'])) { mkdir($versionsFolderName.'/'.$info['dirname'], 0750, true); } // store a new version of a file - $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.time()); - + $result = $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename)); + if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) { + $versionsSize = self::calculateSize($uid); + } + $versionsSize += $users_view->filesize('files'.$filename); + // expire old revisions if necessary - Storage::expire($filename); + $newSize = self::expire($filename, $versionsSize); + + if ( $newSize != $versionsSize ) { + \OCP\Config::setAppValue('files_versions', 'size', $versionsSize); + } } } + /** + * Delete versions of a file + */ + public static function delete($filename) { + list($uid, $filename) = self::getUidAndFilename($filename); + $versions_fileview = new \OC_FilesystemView('/'.$uid .'/files_versions'); + + $abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$filename.'.v'; + if( ($versions = self::getVersions($filename)) ) { + if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) { + $versionsSize = self::calculateSize($uid); + } + foreach ($versions as $v) { + unlink($abs_path . $v['version']); + $versionsSize -= $v['size']; + } + \OCP\Config::setAppValue('files_versions', 'size', $versionsSize); + } + } + + /** + * rename versions of a file + */ + public static function rename($oldpath, $newpath) { + list($uid, $oldpath) = self::getUidAndFilename($oldpath); + list($uidn, $newpath) = self::getUidAndFilename($newpath); + $versions_view = new \OC_FilesystemView('/'.$uid .'/files_versions'); + $files_view = new \OC_FilesystemView('/'.$uid .'/files'); + $abs_newpath = \OCP\Config::getSystemValue('datadirectory').$versions_view->getAbsolutePath('').$newpath; + + if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) { + $versions_view->rename($oldpath, $newpath); + } else if ( ($versions = Storage::getVersions($oldpath)) ) { + $info=pathinfo($abs_newpath); + if(!file_exists($info['dirname'])) mkdir($info['dirname'], 0750, true); + $versions = Storage::getVersions($oldpath); + foreach ($versions as $v) { + $versions_view->rename($oldpath.'.v'.$v['version'], $newpath.'.v'.$v['version']); + } + } + } + /** * rollback to an old version of a file. */ @@ -129,45 +151,29 @@ class Storage { if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { list($uid, $filename) = self::getUidAndFilename($filename); $users_view = new \OC_FilesystemView('/'.$uid); - + $versionCreated = false; + + //first create a new version + $version = 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename); + if ( !$users_view->file_exists($version)) { + $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename)); + $versionCreated = true; + } + // rollback if( @$users_view->copy('files_versions'.$filename.'.v'.$revision, 'files'.$filename) ) { - + $users_view->touch('files'.$filename, $revision); + Storage::expire($filename); return true; - }else{ - - return false; - + }else if ( $versionCreated ) { + $users_view->unlink($version); } - } + return false; } - /** - * check if old versions of a file exist. - */ - public static function isversioned($filename) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - list($uid, $filename) = self::getUidAndFilename($filename); - $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); - - $versionsName=\OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath($filename); - - // check for old versions - $matches=glob($versionsName.'.v*'); - if(count($matches)>0) { - return true; - }else{ - return false; - } - }else{ - return(false); - } - } - - /** * @brief get a list of all available versions of a file in descending chronological order @@ -187,92 +193,232 @@ class Storage { sort( $matches ); - $i = 0; - - $files_view = new \OC_FilesystemView('/'.\OCP\User::getUser().'/files'); + $files_view = new \OC_FilesystemView('/'.$uid.'/files'); $local_file = $files_view->getLocalFile($filename); - foreach( $matches as $ma ) { - $i++; - $versions[$i]['cur'] = 0; + foreach( $matches as $ma ) { $parts = explode( '.v', $ma ); - $versions[$i]['version'] = ( end( $parts ) ); + $version = ( end( $parts ) ); + $key = $version.'#'.$filename; + $versions[$key]['cur'] = 0; + $versions[$key]['version'] = $version; + $versions[$key]['path'] = $filename; + $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 ) == \md5_file( $local_file ) ? $versions[$i]['fileMatch'] = 1 : $versions[$i]['fileMatch'] = 0 ); + ( \md5_file( $ma ) == \md5_file( $local_file ) ? $versions[$key]['fileMatch'] = 1 : $versions[$key]['fileMatch'] = 0 ); } $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; - } - } $versions = array_reverse( $versions ); // only show the newest commits if( $count != 0 and ( count( $versions )>$count ) ) { - $versions = array_slice( $versions, count( $versions ) - $count ); - } return( $versions ); - } else { - // if versioning isn't enabled then return an empty array return( array() ); - } } + /** + * @brief get the size of all stored versions from a given user + * @param $uid id from the user + * @return size of vesions + */ + private static function calculateSize($uid) { + if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { + $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); + $versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath(''); + + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST); + + $size = 0; + + foreach ($iterator as $path) { + if ( preg_match('/^.+\.v(\d+)$/', $path, $match) ) { + $relpath = substr($path, strlen($versionsRoot)-1); + $size += $versions_fileview->filesize($relpath); + } + } + + return $size; + } + } + /** - * @brief Erase a file's versions which exceed the set quota + * @brief returns all stored file versions from a given user + * @param $uid id to the user + * @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename */ - public static function expire($filename) { - if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { - list($uid, $filename) = self::getUidAndFilename($filename); + private static function getAllVersions($uid) { + if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) { $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); - - $versionsName=\OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath($filename); - - // check for old versions - $matches = glob( $versionsName.'.v*' ); - - if( count( $matches ) > \OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ) ) { - - $numberToDelete = count($matches) - \OCP\Config::getSystemValue( 'files_versionmaxversions', Storage::DEFAULTMAXVERSIONS ); - - // delete old versions of a file - $deleteItems = array_slice( $matches, 0, $numberToDelete ); - - foreach( $deleteItems as $de ) { - - unlink( $versionsName.'.v'.$de ); - + $versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath(''); + + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST); + + $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]); } + } + + 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); + + $result['all'][$key]['version'] = $value['timestamp']; + $result['all'][$key]['path'] = $filename; + $result['all'][$key]['size'] = $size; + + $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; + } + + return $result; } } /** - * @brief Erase all old versions of all user files - * @return true/false + * @brief Erase a file's versions which exceed the set quota */ - public function expireAll() { - $view = \OCP\Files::getStorage('files_versions'); - return $view->deleteAll('', true); + private static function expire($filename, $versionsSize = null) { + if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') { + list($uid, $filename) = self::getUidAndFilename($filename); + $versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions'); + + // get available disk space for user + $quota = \OCP\Util::computerFileSize(\OC_Preferences::getValue($uid, 'files', 'quota')); + if ( $quota == null ) { + $quota = \OCP\Util::computerFileSize(\OC_Appconfig::getValue('files', 'default_quota')); + } + if ( $quota == null ) { + $quota = \OC_Filesystem::free_space('/'); + } + + // make sure that we have the current size of the version history + if ( $versionsSize === null ) { + if ( ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) { + $versionsSize = self::calculateSize($uid); + } + } + + // calculate available space for version history + $rootInfo = \OC_FileCache::get('', '/'. $uid . '/files'); + $free = $quota-$rootInfo['size']; // remaining free space for user + if ( $free > 0 ) { + $availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions + } else { + $availableSpace = $free-$versionsSize; + } + + // after every 1000s run reduce the number of all versions not only for the current file + $random = rand(0, 1000); + if ($random == 0) { + $result = Storage::getAllVersions($uid); + $versions_by_file = $result['by_file']; + $all_versions = $result['all']; + } else { + $all_versions = Storage::getVersions($filename); + $versions_by_file[$filename] = $all_versions; + } + + $time = time(); + + // it is possible to expire versions from more than one file + // iterate through all given files + foreach ($versions_by_file as $filename => $versions) { + $versions = array_reverse($versions); // newest version first + + $interval = 1; + $step = Storage::$max_versions_per_interval[$interval]['step']; + if (Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1) { + $nextInterval = -1; + } else { + $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter']; + } + + $firstVersion = reset($versions); + $firstKey = key($versions); + $prevTimestamp = $firstVersion['version']; + $nextVersion = $firstVersion['version'] - $step; + $remaining_versions[$firstKey] = $firstVersion; + unset($versions[$firstKey]); + + foreach ($versions as $key => $version) { + $newInterval = true; + while ( $newInterval ) { + if ( $nextInterval == -1 || $version['version'] >= $nextInterval ) { + if ( $version['version'] > $nextVersion ) { + //distance between two version too small, delete version + $versions_fileview->unlink($version['path'].'.v'.$version['version']); + $availableSpace += $version['size']; + $versionsSize -= $version['size']; + unset($all_versions[$key]); // update array with all versions + } else { + $nextVersion = $version['version'] - $step; + } + $newInterval = false; // version checked so we can move to the next one + } else { // time to move on to the next interval + $interval++; + $step = Storage::$max_versions_per_interval[$interval]['step']; + $nextVersion = $prevTimestamp - $step; + if ( Storage::$max_versions_per_interval[$interval]['intervalEndsAfter'] == -1 ) { + $nextInterval = -1; + } else { + $nextInterval = $time - Storage::$max_versions_per_interval[$interval]['intervalEndsAfter']; + } + $newInterval = true; // we changed the interval -> check same version with new interval + } + } + $prevTimestamp = $version['version']; + } + } + + // check if enough space is available after versions are rearranged. + // if not we delete the oldest versions until we meet the size limit for versions + $numOfVersions = count($all_versions); + $i = 0; + while ($availableSpace < 0) { + if ($i = $numOfVersions-2) break; // keep at least the last version + $versions_fileview->unlink($all_versions[$i]['path'].'.v'.$all_versions[$i]['version']); + $versionsSize -= $all_versions[$i]['size']; + $availableSpace += $all_versions[$i]['size']; + $i++; + } + + return $versionsSize; // finally return the new size of the version history + } + + return false; } } diff --git a/apps/files_versions/settings-personal.php b/apps/files_versions/settings-personal.php deleted file mode 100644 index 6555bc99c3e193250255c47ab38d34688e89b399..0000000000000000000000000000000000000000 --- a/apps/files_versions/settings-personal.php +++ /dev/null @@ -1,7 +0,0 @@ -fetchPage(); diff --git a/apps/files_versions/templates/settings-personal.php b/apps/files_versions/templates/settings-personal.php deleted file mode 100644 index 2b313a07c8827d835f76d83ae14e559ba752ebfb..0000000000000000000000000000000000000000 --- a/apps/files_versions/templates/settings-personal.php +++ /dev/null @@ -1,12 +0,0 @@ - -
- - t('Versions'); ?> - - -
t('This will delete all existing backup versions of your files'); ?> -
- diff --git a/apps/files_versions/templates/settings.php b/apps/files_versions/templates/settings.php index 88063cb075ba246f7e2e5d99de22fb23ba3e2c11..bfca8366f5da50d78ce670fdcf9d088f35ca306f 100644 --- a/apps/files_versions/templates/settings.php +++ b/apps/files_versions/templates/settings.php @@ -1,6 +1,6 @@
-
- t('Files Versioning');?> - />
-
+
+ t('Files Versioning');?> + />
+
diff --git a/apps/user_ldap/css/settings.css b/apps/user_ldap/css/settings.css index f3f41fb2d8bea101c1b5b29acf8464938ad90f36..84ada0832ab52f5ac263a65aaf93dde25e22fa71 100644 --- a/apps/user_ldap/css/settings.css +++ b/apps/user_ldap/css/settings.css @@ -2,9 +2,11 @@ width: 20%; max-width: 200px; display: inline-block; + vertical-align: top; + padding-top: 9px; } -#ldap fieldset input { +#ldap fieldset input, #ldap fieldset textarea { width: 70%; display: inline-block; } diff --git a/apps/user_ldap/l10n/ar.php b/apps/user_ldap/l10n/ar.php index ced0b4293b71f145c1b02d1d3bf3f171d77b31fd..da1710a0a3c6a33a090abc241c35bf4c1d7ef2b2 100644 --- a/apps/user_ldap/l10n/ar.php +++ b/apps/user_ldap/l10n/ar.php @@ -1,3 +1,4 @@ "كلمة المرور" +"Password" => "كلمة المرور", +"Help" => "المساعدة" ); diff --git a/apps/user_ldap/l10n/bg_BG.php b/apps/user_ldap/l10n/bg_BG.php new file mode 100644 index 0000000000000000000000000000000000000000..c064534a6b8a16924045f7478c423f53d0d50ece --- /dev/null +++ b/apps/user_ldap/l10n/bg_BG.php @@ -0,0 +1,4 @@ + "Парола", +"Help" => "Помощ" +); diff --git a/apps/user_ldap/l10n/bn_BD.php b/apps/user_ldap/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..094b20cad2d99d3ed9f4d925aae5a94fe5be1202 --- /dev/null +++ b/apps/user_ldap/l10n/bn_BD.php @@ -0,0 +1,37 @@ + "হোস্ট", +"You can omit the protocol, except you require SSL. Then start with ldaps://" => "SSL আবশ্যক না হলে আপনি এই প্রটোকলটি মুছে ফেলতে পারেন । এরপর শুরু করুন এটা দিয়ে ldaps://", +"Base DN" => "ভিত্তি DN", +"You can specify Base DN for users and groups in the Advanced tab" => "সুচারু ট্যঅবে গিয়ে আপনি ব্যবহারকারি এবং গোষ্ঠীসমূহের জন্য ভিত্তি DN নির্ধারণ করতে পারেন।", +"User DN" => "ব্যবহারকারি DN", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. পরিচয় গোপন রেখে অধিগমনের জন্য DN এবং কূটশব্দটি ফাঁকা রাখুন।", +"Password" => "কূটশব্দ", +"For anonymous access, leave DN and Password empty." => "অজ্ঞাতকুলশীল অধিগমনের জন্য DN এবং কূটশব্দটি ফাঁকা রাখুন।", +"User Login Filter" => "ব্যবহারকারির প্রবেশ ছাঁকনী", +"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action." => "প্রবেশের চেষ্টা করার সময় প্রযোজ্য ছাঁকনীটি নির্ধারণ করবে। প্রবেশের সময় ব্যবহারকারী নামটি %%uid দিয়ে প্রতিস্থাপিত হবে।", +"use %%uid placeholder, e.g. \"uid=%%uid\"" => "%%uid স্থানধারক ব্যবহার করুন, উদাহরণঃ \"uid=%%uid\"", +"User List Filter" => "ব্যবহারকারী তালিকা ছাঁকনী", +"Defines the filter to apply, when retrieving users." => "ব্যবহারকারী উদ্ধার করার সময় প্রয়োগের জন্য ছাঁকনী নির্ধারণ করবে।", +"without any placeholder, e.g. \"objectClass=person\"." => "কোন স্থানধারক ব্যতীত, যেমনঃ \"objectClass=person\"।", +"Group Filter" => "গোষ্ঠী ছাঁকনী", +"Defines the filter to apply, when retrieving groups." => "গোষ্ঠীসমূহ উদ্ধার করার সময় প্রয়োগের জন্য ছাঁকনী নির্ধারণ করবে।", +"without any placeholder, e.g. \"objectClass=posixGroup\"." => "কোন স্থান ধারক ব্যতীত, উদাহরণঃ\"objectClass=posixGroup\"।", +"Port" => "পোর্ট", +"Base User Tree" => "ভিত্তি ব্যবহারকারি বৃক্ষাকারে", +"Base Group Tree" => "ভিত্তি গোষ্ঠী বৃক্ষাকারে", +"Group-Member association" => "গোষ্ঠী-সদস্য সংস্থাপন", +"Use TLS" => "TLS ব্যবহার কর", +"Do not use it for SSL connections, it will fail." => "SSL সংযোগের জন্য এটি ব্যবহার করবেন না, তাহলে ব্যর্থ হবেনই।", +"Case insensitve LDAP server (Windows)" => "বর্ণ অসংবেদী LDAP সার্ভার (উইন্ডোজ)", +"Turn off SSL certificate validation." => "SSL সনদপত্র যাচাইকরণ বন্ধ রাক।", +"If connection only works with this option, import the LDAP server's SSL certificate in your ownCloud server." => "শুধুমাত্র যদি এই বিকল্পটি ব্যবহার করেই সংযোগ কার্যকরী হয় তবে আপনার ownCloud সার্ভারে LDAP সার্ভারের SSL সনদপত্রটি আমদানি করুন।", +"Not recommended, use for testing only." => "অনুমোদিত নয়, শুধুমাত্র পরীক্ষামূলক ব্যবহারের জন্য।", +"User Display Name Field" => "ব্যবহারকারীর প্রদর্শিতব্য নামের ক্ষেত্র", +"The LDAP attribute to use to generate the user`s ownCloud name." => "ব্যবহারকারীর ownCloud নাম তৈরি করার জন্য ব্যভহৃত LDAP বৈশিষ্ট্য।", +"Group Display Name Field" => "গোষ্ঠীর প্রদর্শিতব্য নামের ক্ষেত্র", +"The LDAP attribute to use to generate the groups`s ownCloud name." => "গোষ্ঠীর ownCloud নাম তৈরি করার জন্য ব্যভহৃত LDAP বৈশিষ্ট্য।", +"in bytes" => "বাইটে", +"in seconds. A change empties the cache." => "সেকেন্ডে। কোন পরিবর্তন ক্যাসে খালি করবে।", +"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "ব্যবহারকারী নামের জন্য ফাঁকা রাখুন (পূর্বনির্ধারিত)। অন্যথায়, LDAP/AD বৈশিষ্ট্য নির্ধারণ করুন।", +"Help" => "সহায়িকা" +); diff --git a/apps/user_ldap/l10n/ca.php b/apps/user_ldap/l10n/ca.php index d801ddff63196363c32a9481a885ad2f8111f761..06255c1249a511f7fd442e647565377d894e6a06 100644 --- a/apps/user_ldap/l10n/ca.php +++ b/apps/user_ldap/l10n/ca.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Avís: Les aplicacions user_ldap i user_webdavauth són incompatibles. Podeu experimentar comportaments no desitjats. Demaneu a l'administrador del sistema que en desactivi una.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Avís: El mòdul PHP LDAP necessari no està instal·lat, el dorsal no funcionarà. Demaneu a l'administrador del sistema que l'instal·li.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Avís: El mòdul PHP LDAP no està instal·lat, el dorsal no funcionarà. Demaneu a l'administrador del sistema que l'instal·li.", "Host" => "Màquina", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Podeu ometre el protocol, excepte si requeriu SSL. Llavors comenceu amb ldaps://", "Base DN" => "DN Base", +"One Base DN per line" => "Una DN Base per línia", "You can specify Base DN for users and groups in the Advanced tab" => "Podeu especificar DN Base per usuaris i grups a la pestanya Avançat", "User DN" => "DN Usuari", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "La DN de l'usuari client amb la que s'haurà de fer, per exemple uid=agent,dc=exemple,dc=com. Per un accés anònim, deixeu la DN i la contrasenya en blanc.", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "sense cap paràmetre de substitució, per exemple \"objectClass=grupPosix\".", "Port" => "Port", "Base User Tree" => "Arbre base d'usuaris", +"One User Base DN per line" => "Una DN Base d'Usuari per línia", "Base Group Tree" => "Arbre base de grups", +"One Group Base DN per line" => "Una DN Base de Grup per línia", "Group-Member association" => "Associació membres-grup", "Use TLS" => "Usa TLS", "Do not use it for SSL connections, it will fail." => "No ho useu en connexions SSL, fallarà.", diff --git a/apps/user_ldap/l10n/cs_CZ.php b/apps/user_ldap/l10n/cs_CZ.php index 0c14ebb9d1ee660eefa51b89392cf61af89ae3d2..80e27f1e62a5673012ec7f6364498f334991e362 100644 --- a/apps/user_ldap/l10n/cs_CZ.php +++ b/apps/user_ldap/l10n/cs_CZ.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Varování: Aplikace user_ldap a user_webdavauth nejsou kompatibilní. Může nastávat neočekávané chování. Požádejte, prosím, správce systému aby jednu z nich zakázal.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Varování: není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte, prosím, správce systému aby jej nainstaloval.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Varování: není nainstalován LDAP modul pro PHP, podpůrná vrstva nebude fungovat. Požádejte, prosím, správce systému aby jej nainstaloval.", "Host" => "Počítač", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Můžete vynechat protokol, vyjma pokud požadujete SSL. Tehdy začněte s ldaps://", "Base DN" => "Základní DN", +"One Base DN per line" => "Jedna základní DN na řádku", "You can specify Base DN for users and groups in the Advanced tab" => "V rozšířeném nastavení můžete určit základní DN pro uživatele a skupiny", "User DN" => "Uživatelské DN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN klentského uživatele ke kterému tvoříte vazbu, např. uid=agent,dc=example,dc=com. Pro anonymní přístup ponechte údaje DN and Heslo prázdné.", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "bez zástupných znaků, např. \"objectClass=posixGroup\".", "Port" => "Port", "Base User Tree" => "Základní uživatelský strom", +"One User Base DN per line" => "Jedna uživatelská základní DN na řádku", "Base Group Tree" => "Základní skupinový strom", +"One Group Base DN per line" => "Jedna skupinová základní DN na řádku", "Group-Member association" => "Asociace člena skupiny", "Use TLS" => "Použít TLS", "Do not use it for SSL connections, it will fail." => "Nepoužívejte pro připojení pomocí SSL, připojení selže.", diff --git a/apps/user_ldap/l10n/de.php b/apps/user_ldap/l10n/de.php index 87579cb243108f7543a286d69079e19dfd73c4d6..89bda8af97fb6a37707d75077dd70af3853fbd87 100644 --- a/apps/user_ldap/l10n/de.php +++ b/apps/user_ldap/l10n/de.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Warnung: Die Anwendungen user_ldap und user_webdavauth sind inkompatibel. Es kann demzufolge zu unerwarteten Verhalten kommen. Bitte Deinen Systemadministator eine der beiden Anwendungen zu deaktivieren.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Warnung: Das PHP-Modul, das LDAP benöntigt, ist nicht installiert. Das Backend wird nicht funktionieren. Bitte deinen Systemadministrator das Modul zu installieren.", "Host" => "Host", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Du kannst das Protokoll auslassen, außer wenn Du SSL benötigst. Beginne dann mit ldaps://", "Base DN" => "Basis-DN", diff --git a/apps/user_ldap/l10n/de_DE.php b/apps/user_ldap/l10n/de_DE.php index f986ae83e8732d27f52f6a28a9a3538198856fc7..1e816018386629cf159ae5ead0917a1d303fd1ec 100644 --- a/apps/user_ldap/l10n/de_DE.php +++ b/apps/user_ldap/l10n/de_DE.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Warnung: Die Anwendungen user_ldap und user_webdavauth sind inkompatibel. Es kann demzufolge zu unerwarteten Verhalten kommen. Bitten Sie Ihren Systemadministator eine der beiden Anwendungen zu deaktivieren.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Warnung: Das PHP-Modul, das LDAP benöntigt, ist nicht installiert. Das Backend wird nicht funktionieren. Bitten Sie Ihren Systemadministrator das Modul zu installieren.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Warnung: Da das PHP-Modul für LDAP nicht installiert ist, wird das Backend nicht funktionieren. Bitten Sie Ihren Systemadministrator das Modul zu installieren.", "Host" => "Host", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Sie können das Protokoll auslassen, außer wenn Sie SSL benötigen. Beginnen Sie dann mit ldaps://", "Base DN" => "Basis-DN", +"One Base DN per line" => "Ein Base DN pro Zeile", "You can specify Base DN for users and groups in the Advanced tab" => "Sie können Basis-DN für Benutzer und Gruppen in dem \"Erweitert\"-Reiter konfigurieren", "User DN" => "Benutzer-DN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Der DN des Benutzers für LDAP-Bind, z.B.: uid=agent,dc=example,dc=com. Für anonymen Zugriff lassen Sie DN und Passwort leer.", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "ohne Platzhalter, z.B.: \"objectClass=posixGroup\"", "Port" => "Port", "Base User Tree" => "Basis-Benutzerbaum", +"One User Base DN per line" => "Ein Benutzer Base DN pro Zeile", "Base Group Tree" => "Basis-Gruppenbaum", +"One Group Base DN per line" => "Ein Gruppen Base DN pro Zeile", "Group-Member association" => "Assoziation zwischen Gruppe und Benutzer", "Use TLS" => "Nutze TLS", "Do not use it for SSL connections, it will fail." => "Verwenden Sie dies nicht für SSL-Verbindungen, es wird fehlschlagen.", diff --git a/apps/user_ldap/l10n/el.php b/apps/user_ldap/l10n/el.php index e973eaac0a99a86f534b4c34496b7e9083e3cf3c..1f75a687a5d60691a11bc0f9f731cb81f97d3974 100644 --- a/apps/user_ldap/l10n/el.php +++ b/apps/user_ldap/l10n/el.php @@ -1,18 +1,38 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Προσοχή: Οι εφαρμογές user_ldap και user_webdavauth είναι ασύμβατες. Μπορεί να αντιμετωπίσετε απρόβλεπτη συμπεριφορά. Παρακαλώ ζητήστε από τον διαχειριστή συστήματος να απενεργοποιήσει μία από αυτές.", +"Host" => "Διακομιστής", +"You can omit the protocol, except you require SSL. Then start with ldaps://" => "Μπορείτε να παραλείψετε το πρωτόκολλο, εκτός αν απαιτείται SSL. Σε αυτή την περίπτωση ξεκινήστε με ldaps://", "Base DN" => "Base DN", +"You can specify Base DN for users and groups in the Advanced tab" => "Μπορείτε να καθορίσετε το Base DN για χρήστες και ομάδες από την καρτέλα Προηγμένες ρυθμίσεις", "User DN" => "User DN", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Το DN του χρήστη πελάτη με το οποίο θα πρέπει να γίνει η σύνδεση, π.χ. uid=agent,dc=example,dc=com. Για χρήση χωρίς πιστοποίηση, αφήστε το DN και τον Κωδικό κενά.", "Password" => "Συνθηματικό", +"For anonymous access, leave DN and Password empty." => "Για ανώνυμη πρόσβαση, αφήστε κενά τα πεδία DN και Pasword.", "User Login Filter" => "User Login Filter", +"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action." => "Καθορίζει το φίλτρο που θα ισχύει κατά την προσπάθεια σύνδεσης χρήστη. %%uid αντικαθιστά το όνομα χρήστη κατά τη σύνδεση. ", +"use %%uid placeholder, e.g. \"uid=%%uid\"" => "χρησιμοποιήστε τη μεταβλητή %%uid, π.χ. \"uid=%%uid\"", "User List Filter" => "User List Filter", +"Defines the filter to apply, when retrieving users." => "Καθορίζει το φίλτρο που θα ισχύει κατά την ανάκτηση επαφών.", +"without any placeholder, e.g. \"objectClass=person\"." => "χωρίς κάποια μεταβλητή, π.χ. \"objectClass=άτομο\".", "Group Filter" => "Group Filter", +"Defines the filter to apply, when retrieving groups." => "Καθορίζει το φίλτρο που θα ισχύει κατά την ανάκτηση ομάδων.", +"without any placeholder, e.g. \"objectClass=posixGroup\"." => "χωρίς κάποια μεταβλητή, π.χ. \"objectClass=ΟμάδαPosix\".", "Port" => "Θύρα", "Base User Tree" => "Base User Tree", "Base Group Tree" => "Base Group Tree", "Group-Member association" => "Group-Member association", "Use TLS" => "Χρήση TLS", +"Do not use it for SSL connections, it will fail." => "Μην χρησιμοποιείτε για συνδέσεις SSL, θα αποτύχει.", +"Case insensitve LDAP server (Windows)" => "LDAP server (Windows) με διάκριση πεζών-ΚΕΦΑΛΑΙΩΝ", +"Turn off SSL certificate validation." => "Απενεργοποίηση επικύρωσης πιστοποιητικού SSL.", +"If connection only works with this option, import the LDAP server's SSL certificate in your ownCloud server." => "Εάν η σύνδεση δουλεύει μόνο με αυτή την επιλογή, εισάγετε το LDAP SSL πιστοποιητικό του διακομιστή στον ownCloud server σας.", "Not recommended, use for testing only." => "Δεν προτείνεται, χρήση μόνο για δοκιμές.", "User Display Name Field" => "Πεδίο Ονόματος Χρήστη", +"The LDAP attribute to use to generate the user`s ownCloud name." => "Η ιδιότητα LDAP που θα χρησιμοποιείται για τη δημιουργία του ονόματος χρήστη του ownCloud.", "Group Display Name Field" => "Group Display Name Field", +"The LDAP attribute to use to generate the groups`s ownCloud name." => "Η ιδιότητα LDAP που θα χρησιμοποιείται για τη δημιουργία του ονόματος ομάδας του ownCloud.", "in bytes" => "σε bytes", +"in seconds. A change empties the cache." => "σε δευτερόλεπτα. Μια αλλαγή αδειάζει την μνήμη cache.", +"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Αφήστε το κενό για το όνομα χρήστη (προεπιλογή). Διαφορετικά, συμπληρώστε μία ιδιότητα LDAP/AD.", "Help" => "Βοήθεια" ); diff --git a/apps/user_ldap/l10n/eo.php b/apps/user_ldap/l10n/eo.php index ef8aff8a39092171a12e83ab913b37e339ca2438..35f436a0b0aef01b7761e5a1aa25d6b9376391cc 100644 --- a/apps/user_ldap/l10n/eo.php +++ b/apps/user_ldap/l10n/eo.php @@ -1,7 +1,7 @@ "Gastigo", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Vi povas neglekti la protokolon, escepte se vi bezonas SSL-on. Tiuokaze, komencu per ldaps://", -"Base DN" => "Baz-DN", +"Base DN" => "Bazo-DN", "User DN" => "Uzanto-DN", "Password" => "Pasvorto", "For anonymous access, leave DN and Password empty." => "Por sennoman aliron, lasu DN-on kaj Pasvorton malplenaj.", diff --git a/apps/user_ldap/l10n/es.php b/apps/user_ldap/l10n/es.php index 4931af79eaf360ced70aeab20fd2e2c3fd9780d8..48e7b24734ecce5560a5b3b0e43fd5db36d82c6f 100644 --- a/apps/user_ldap/l10n/es.php +++ b/apps/user_ldap/l10n/es.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Advertencia: Los Apps user_ldap y user_webdavauth son incompatibles. Puede que experimente un comportamiento inesperado. Pregunte al administrador del sistema para desactivar uno de ellos.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Advertencia: El módulo PHP LDAP necesario no está instalado, el sistema no funcionará. Pregunte al administrador del sistema para instalarlo.", "Host" => "Servidor", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Puede omitir el protocolo, excepto si requiere SSL. En ese caso, empiece con ldaps://", "Base DN" => "DN base", diff --git a/apps/user_ldap/l10n/es_AR.php b/apps/user_ldap/l10n/es_AR.php index 6bd452e9d90b8e47e7a2800f96967ba3f57268ee..331bf8699f48d1aedb32e4e3bf596bd03bc4c7e1 100644 --- a/apps/user_ldap/l10n/es_AR.php +++ b/apps/user_ldap/l10n/es_AR.php @@ -1,4 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Advertencia: Los Apps user_ldap y user_webdavauth son incompatibles. Puede que experimente un comportamiento inesperado. Pregunte al administrador del sistema para desactivar uno de ellos.", "Host" => "Servidor", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Podés omitir el protocolo, excepto si SSL es requerido. En ese caso, empezá con ldaps://", "Base DN" => "DN base", diff --git a/apps/user_ldap/l10n/eu.php b/apps/user_ldap/l10n/eu.php index 35dacef3f2f5a449781825d6412f4c20bb35ea61..e2b50f28ee9d6464c3106f1f1db34ded0f14dfe9 100644 --- a/apps/user_ldap/l10n/eu.php +++ b/apps/user_ldap/l10n/eu.php @@ -1,7 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Abisua: user_ldap eta user_webdavauth aplikazioak bateraezinak dira. Portaera berezia izan dezakezu. Mesedez eskatu zure sistema kudeatzaileari bietako bat desgaitzeko.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Abisua: PHPk behar duen LDAP modulua ez dago instalaturik, motorrak ez du funtzionatuko. Mesedez eskatu zure sistema kudeatzaileari instala dezan.", "Host" => "Hostalaria", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Protokoloa ez da beharrezkoa, SSL behar baldin ez baduzu. Honela bada hasi ldaps://", "Base DN" => "Oinarrizko DN", +"One Base DN per line" => "DN Oinarri bat lerroko", "You can specify Base DN for users and groups in the Advanced tab" => "Erabiltzaile eta taldeentzako Oinarrizko DN zehaztu dezakezu Aurreratu fitxan", "User DN" => "Erabiltzaile DN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Lotura egingo den bezero erabiltzailearen DNa, adb. uid=agent,dc=example,dc=com. Sarrera anonimoak gaitzeko utzi DN eta Pasahitza hutsik.", @@ -18,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "txantiloirik gabe, adb. \"objectClass=posixGroup\".", "Port" => "Portua", "Base User Tree" => "Oinarrizko Erabiltzaile Zuhaitza", +"One User Base DN per line" => "Erabiltzaile DN Oinarri bat lerroko", "Base Group Tree" => "Oinarrizko Talde Zuhaitza", +"One Group Base DN per line" => "Talde DN Oinarri bat lerroko", "Group-Member association" => "Talde-Kide elkarketak", "Use TLS" => "Erabili TLS", "Do not use it for SSL connections, it will fail." => "Ez erabili SSL konexioetan, huts egingo du.", diff --git a/apps/user_ldap/l10n/fr.php b/apps/user_ldap/l10n/fr.php index 9750d1352a8ea6698a2cb8ca1267bd5c9be2d707..28ee6346ef4a405372924b58dde8eaf12328c7c3 100644 --- a/apps/user_ldap/l10n/fr.php +++ b/apps/user_ldap/l10n/fr.php @@ -1,12 +1,13 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Avertissement: Les applications user_ldap et user_webdavauth sont incompatibles. Des disfonctionnements peuvent survenir. Contactez votre administrateur système pour qu'il désactive l'une d'elles.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Avertissement: Le module PHP LDAP requis n'est pas installé, l'application ne marchera pas. Contactez votre administrateur système pour qu'il l'installe.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Attention : Le module php LDAP n'est pas installé, par conséquent cette extension ne pourra fonctionner. Veuillez contacter votre administrateur système afin qu'il l'installe.", "Host" => "Hôte", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Vous pouvez omettre le protocole, sauf si vous avez besoin de SSL. Dans ce cas préfixez avec ldaps://", "Base DN" => "DN Racine", -"You can specify Base DN for users and groups in the Advanced tab" => "Vous pouvez détailler les DN Racines de vos utilisateurs et groupes dans l'onglet Avancé", +"One Base DN per line" => "Un DN racine par ligne", +"You can specify Base DN for users and groups in the Advanced tab" => "Vous pouvez spécifier les DN Racines de vos utilisateurs et groupes via l'onglet Avancé", "User DN" => "DN Utilisateur (Autorisé à consulter l'annuaire)", -"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Le DN de l'utilisateur client avec lequel la liaison doit se faire, par exemple uid=agent,dc=example,dc=com. Pour l'accès anonyme, laisser le DN et le mot de passe vides.", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN de l'utilisateur client pour lequel la liaison doit se faire, par exemple uid=agent,dc=example,dc=com. Pour un accès anonyme, laisser le DN et le mot de passe vides.", "Password" => "Mot de passe", "For anonymous access, leave DN and Password empty." => "Pour un accès anonyme, laisser le DN Utilisateur et le mot de passe vides.", "User Login Filter" => "Modèle d'authentification utilisateurs", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "sans élément de substitution, par exemple \"objectClass=posixGroup\".", "Port" => "Port", "Base User Tree" => "DN racine de l'arbre utilisateurs", +"One User Base DN per line" => "Un DN racine utilisateur par ligne", "Base Group Tree" => "DN racine de l'arbre groupes", +"One Group Base DN per line" => "Un DN racine groupe par ligne", "Group-Member association" => "Association groupe-membre", "Use TLS" => "Utiliser TLS", "Do not use it for SSL connections, it will fail." => "Ne pas utiliser pour les connexions SSL, car cela échouera.", diff --git a/apps/user_ldap/l10n/gl.php b/apps/user_ldap/l10n/gl.php index 41431293cbaf63a6c3e6ee728505369793aa14c5..d60521c4a02ee77367189836bb1c005fcbc3eea4 100644 --- a/apps/user_ldap/l10n/gl.php +++ b/apps/user_ldap/l10n/gl.php @@ -1,10 +1,11 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Aviso: Os aplicativos user_ldap e user_webdavauth son incompatíbeis. Pode acontecer un comportamento estraño. Consulte co administrador do sistema para desactivar un deles.", "Host" => "Servidor", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Pode omitir o protocolo agás que precise de SSL. Nese caso comece con ldaps://", "Base DN" => "DN base", "You can specify Base DN for users and groups in the Advanced tab" => "Pode especificar a DN base para usuarios e grupos na lapela de «Avanzado»", "User DN" => "DN do usuario", -"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "O DN do cliente do usuario co que hai que estabelecer unha conexión, p.ex uid=axente, dc=exemplo, dc=com. Para o acceso en anónimo de o DN e o contrasinal baleiros.", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "O DN do cliente do usuario co que hai que estabelecer unha conexión, p.ex uid=axente, dc=exemplo, dc=com. Para o acceso anónimo deixe o DN e o contrasinal baleiros.", "Password" => "Contrasinal", "For anonymous access, leave DN and Password empty." => "Para o acceso anónimo deixe o DN e o contrasinal baleiros.", "User Login Filter" => "Filtro de acceso de usuarios", @@ -21,7 +22,7 @@ "Base Group Tree" => "Base da árbore de grupo", "Group-Member association" => "Asociación de grupos e membros", "Use TLS" => "Usar TLS", -"Do not use it for SSL connections, it will fail." => "Non empregualo para conexións SSL: fallará.", +"Do not use it for SSL connections, it will fail." => "Non empregalo para conexións SSL: fallará.", "Case insensitve LDAP server (Windows)" => "Servidor LDAP que non distingue entre maiúsculas e minúsculas (Windows)", "Turn off SSL certificate validation." => "Desactiva a validación do certificado SSL.", "If connection only works with this option, import the LDAP server's SSL certificate in your ownCloud server." => "Se a conexión só funciona con esta opción importa o certificado SSL do servidor LDAP no seu servidor ownCloud.", diff --git a/apps/user_ldap/l10n/he.php b/apps/user_ldap/l10n/he.php new file mode 100644 index 0000000000000000000000000000000000000000..d33ecaadf050f84e55bac6a633826de0ce1625b3 --- /dev/null +++ b/apps/user_ldap/l10n/he.php @@ -0,0 +1,12 @@ + "מארח", +"User DN" => "DN משתמש", +"Password" => "סיסמא", +"For anonymous access, leave DN and Password empty." => "לגישה אנונימית, השאר את הDM והסיסמא ריקים.", +"User Login Filter" => "סנן כניסת משתמש", +"User List Filter" => "סנן רשימת משתמשים", +"Group Filter" => "סנן קבוצה", +"in bytes" => "בבתים", +"in seconds. A change empties the cache." => "בשניות. שינוי מרוקן את המטמון.", +"Help" => "עזרה" +); diff --git a/apps/user_ldap/l10n/hr.php b/apps/user_ldap/l10n/hr.php new file mode 100644 index 0000000000000000000000000000000000000000..91503315066c42bb31391ed0f1ea03a8c3fb95b3 --- /dev/null +++ b/apps/user_ldap/l10n/hr.php @@ -0,0 +1,3 @@ + "Pomoć" +); diff --git a/apps/user_ldap/l10n/hu_HU.php b/apps/user_ldap/l10n/hu_HU.php new file mode 100644 index 0000000000000000000000000000000000000000..25ee47786efb103bb3bad79556088fb6915c5ac6 --- /dev/null +++ b/apps/user_ldap/l10n/hu_HU.php @@ -0,0 +1,42 @@ +Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Figyelem: a user_ldap és user_webdavauth alkalmazások nem kompatibilisek. Együttes használatuk váratlan eredményekhez vezethet. Kérje meg a rendszergazdát, hogy a kettő közül kapcsolja ki az egyiket.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Figyelmeztetés: Az LDAP PHP modul nincs telepítve, ezért ez az alrendszer nem fog működni. Kérje meg a rendszergazdát, hogy telepítse!", +"Host" => "Kiszolgáló", +"You can omit the protocol, except you require SSL. Then start with ldaps://" => "A protokoll előtag elhagyható, kivéve, ha SSL-t kíván használni. Ebben az esetben kezdje így: ldaps://", +"Base DN" => "DN-gyökér", +"One Base DN per line" => "Soronként egy DN-gyökér", +"You can specify Base DN for users and groups in the Advanced tab" => "A Haladó fülre kattintva külön DN-gyökér állítható be a felhasználók és a csoportok számára", +"User DN" => "A kapcsolódó felhasználó DN-je", +"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Annak a felhasználónak a DN-je, akinek a nevében bejelentkezve kapcsolódunk a kiszolgálóhoz, pl. uid=agent,dc=example,dc=com. Bejelentkezés nélküli eléréshez ne töltse ki a DN és Jelszó mezőket!", +"Password" => "Jelszó", +"For anonymous access, leave DN and Password empty." => "Bejelentkezés nélküli eléréshez ne töltse ki a DN és Jelszó mezőket!", +"User Login Filter" => "Szűrő a bejelentkezéshez", +"Defines the filter to apply, when login is attempted. %%uid replaces the username in the login action." => "Ez a szűrő érvényes a bejelentkezés megkísérlésekor. Ekkor az %%uid változó helyére a bejelentkezési név kerül.", +"use %%uid placeholder, e.g. \"uid=%%uid\"" => "használja az %%uid változót, pl. \"uid=%%uid\"", +"User List Filter" => "A felhasználók szűrője", +"Defines the filter to apply, when retrieving users." => "Ez a szűrő érvényes a felhasználók listázásakor.", +"without any placeholder, e.g. \"objectClass=person\"." => "itt ne használjon változót, pl. \"objectClass=person\".", +"Group Filter" => "A csoportok szűrője", +"Defines the filter to apply, when retrieving groups." => "Ez a szűrő érvényes a csoportok listázásakor.", +"without any placeholder, e.g. \"objectClass=posixGroup\"." => "itt ne használjunk változót, pl. \"objectClass=posixGroup\".", +"Port" => "Port", +"Base User Tree" => "A felhasználói fa gyökere", +"One User Base DN per line" => "Soronként egy felhasználói fa gyökerét adhatjuk meg", +"Base Group Tree" => "A csoportfa gyökere", +"One Group Base DN per line" => "Soronként egy csoportfa gyökerét adhatjuk meg", +"Group-Member association" => "A csoporttagság attribútuma", +"Use TLS" => "Használjunk TLS-t", +"Do not use it for SSL connections, it will fail." => "Ne használjuk SSL-kapcsolat esetén, mert nem fog működni!", +"Case insensitve LDAP server (Windows)" => "Az LDAP-kiszolgáló nem tesz különbséget a kis- és nagybetűk között (Windows)", +"Turn off SSL certificate validation." => "Ne ellenőrizzük az SSL-tanúsítvány érvényességét", +"If connection only works with this option, import the LDAP server's SSL certificate in your ownCloud server." => "Ha a kapcsolat csak ezzel a beállítással működik, akkor importálja az LDAP-kiszolgáló SSL tanúsítványát az ownCloud kiszolgálóra!", +"Not recommended, use for testing only." => "Nem javasolt, csak tesztelésre érdemes használni.", +"User Display Name Field" => "A felhasználónév mezője", +"The LDAP attribute to use to generate the user`s ownCloud name." => "Ebből az LDAP attribútumból képződik a felhasználó elnevezése, ami megjelenik az ownCloudban.", +"Group Display Name Field" => "A csoport nevének mezője", +"The LDAP attribute to use to generate the groups`s ownCloud name." => "Ebből az LDAP attribútumból képződik a csoport elnevezése, ami megjelenik az ownCloudban.", +"in bytes" => "bájtban", +"in seconds. A change empties the cache." => "másodpercben. A változtatás törli a cache tartalmát.", +"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Hagyja üresen, ha a felhasználónevet kívánja használni. Ellenkező esetben adjon meg egy LDAP/AD attribútumot!", +"Help" => "Súgó" +); diff --git a/apps/user_ldap/l10n/ia.php b/apps/user_ldap/l10n/ia.php new file mode 100644 index 0000000000000000000000000000000000000000..3586bf5a2e74cb7ea0cec1f9979b5ca872777621 --- /dev/null +++ b/apps/user_ldap/l10n/ia.php @@ -0,0 +1,3 @@ + "Adjuta" +); diff --git a/apps/user_ldap/l10n/is.php b/apps/user_ldap/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..29bc769279588e25bbe41e52870b0dd4c362851f --- /dev/null +++ b/apps/user_ldap/l10n/is.php @@ -0,0 +1,5 @@ + "Netþjónn", +"Password" => "Lykilorð", +"Help" => "Hjálp" +); diff --git a/apps/user_ldap/l10n/it.php b/apps/user_ldap/l10n/it.php index 915ce3af5b8894228ec3e5e0a6178150c4229639..bee30cfe6ec50f4a5cffcca25d35736eccfb5243 100644 --- a/apps/user_ldap/l10n/it.php +++ b/apps/user_ldap/l10n/it.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Avviso: le applicazioni user_ldap e user_webdavauth sono incompatibili. Potresti riscontrare un comportamento inatteso. Chiedi al tuo amministratore di sistema di disabilitarne uno.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Avviso: il modulo PHP LDAP richiesto non è installato, il motore non funzionerà. Chiedi al tuo amministratore di sistema di installarlo.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Avviso: il modulo PHP LDAP non è installato, il motore non funzionerà. Chiedi al tuo amministratore di sistema di installarlo.", "Host" => "Host", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "È possibile omettere il protocollo, ad eccezione se è necessario SSL. Quindi inizia con ldaps://", "Base DN" => "DN base", +"One Base DN per line" => "Un DN base per riga", "You can specify Base DN for users and groups in the Advanced tab" => "Puoi specificare una DN base per gli utenti ed i gruppi nella scheda Avanzate", "User DN" => "DN utente", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "Il DN per il client dell'utente con cui deve essere associato, ad esempio uid=agent,dc=example,dc=com. Per l'accesso anonimo, lasciare vuoti i campi DN e Password", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "senza nessun segnaposto, per esempio \"objectClass=posixGroup\".", "Port" => "Porta", "Base User Tree" => "Struttura base dell'utente", +"One User Base DN per line" => "Un DN base utente per riga", "Base Group Tree" => "Struttura base del gruppo", +"One Group Base DN per line" => "Un DN base gruppo per riga", "Group-Member association" => "Associazione gruppo-utente ", "Use TLS" => "Usa TLS", "Do not use it for SSL connections, it will fail." => "Non utilizzare per le connessioni SSL, fallirà.", diff --git a/apps/user_ldap/l10n/ja_JP.php b/apps/user_ldap/l10n/ja_JP.php index c7b2a0f91b8ed5886b9a804be61ce33177001571..1c93db7ba09539a9a1d07cb410de0adb2cf74604 100644 --- a/apps/user_ldap/l10n/ja_JP.php +++ b/apps/user_ldap/l10n/ja_JP.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "警告: user_ldap と user_webdavauth のアプリには互換性がありません。予期せぬ動作をする可能姓があります。システム管理者にどちらかを無効にするよう問い合わせてください。", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "警告: PHP LDAP モジュールがインストールされていません。バックエンドが正しくどうさしません。システム管理者にインストールするよう問い合わせてください。", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "警告: PHP LDAP モジュールがインストールされていません。バックエンドが正しく動作しません。システム管理者にインストールするよう問い合わせてください。", "Host" => "ホスト", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "SSL通信しない場合には、プロトコル名を省略することができます。そうでない場合には、ldaps:// から始めてください。", "Base DN" => "ベースDN", +"One Base DN per line" => "1行に1つのベースDN", "You can specify Base DN for users and groups in the Advanced tab" => "拡張タブでユーザとグループのベースDNを指定することができます。", "User DN" => "ユーザDN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "クライアントユーザーのDNは、特定のものに結びつけることはしません。 例えば uid=agent,dc=example,dc=com. だと匿名アクセスの場合、DNとパスワードは空のままです。", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "プレースホルダーを利用しないでください。例 \"objectClass=posixGroup\"", "Port" => "ポート", "Base User Tree" => "ベースユーザツリー", +"One User Base DN per line" => "1行に1つのユーザベースDN", "Base Group Tree" => "ベースグループツリー", +"One Group Base DN per line" => "1行に1つのグループベースDN", "Group-Member association" => "グループとメンバーの関連付け", "Use TLS" => "TLSを利用", "Do not use it for SSL connections, it will fail." => "SSL接続に利用しないでください、失敗します。", diff --git a/apps/user_ldap/l10n/ka_GE.php b/apps/user_ldap/l10n/ka_GE.php new file mode 100644 index 0000000000000000000000000000000000000000..630d92b73ad0c4fbe2b7c2e058fefda3d14253da --- /dev/null +++ b/apps/user_ldap/l10n/ka_GE.php @@ -0,0 +1,3 @@ + "დახმარება" +); diff --git a/apps/user_ldap/l10n/ko.php b/apps/user_ldap/l10n/ko.php index aa775e42b16c0a47bfd57da567c68f683434a644..c0d09b5c3c1fbdc04be923738125faf9780a144e 100644 --- a/apps/user_ldap/l10n/ko.php +++ b/apps/user_ldap/l10n/ko.php @@ -1,4 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "경고user_ldap 앱과 user_webdavauth 앱은 호환되지 않습니다. 오동작을 일으킬 수 있으므로, 시스템 관리자에게 요청하여, 둘 중 하나를 비활성화 하시기 바랍니다.", "Host" => "호스트", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "SSL을 사용하는 경우가 아니라면 프로토콜을 입력하지 않아도 됩니다. SSL을 사용하려면 ldaps://를 입력하십시오.", "Base DN" => "기본 DN", diff --git a/apps/user_ldap/l10n/ku_IQ.php b/apps/user_ldap/l10n/ku_IQ.php new file mode 100644 index 0000000000000000000000000000000000000000..1ae808ddd91007e3b322192016aed9d0c25781ea --- /dev/null +++ b/apps/user_ldap/l10n/ku_IQ.php @@ -0,0 +1,3 @@ + "یارمەتی" +); diff --git a/apps/user_ldap/l10n/lb.php b/apps/user_ldap/l10n/lb.php new file mode 100644 index 0000000000000000000000000000000000000000..2926538b5b0bfc1ba2c9afce0005caf31c98d6ba --- /dev/null +++ b/apps/user_ldap/l10n/lb.php @@ -0,0 +1,3 @@ + "Hëllef" +); diff --git a/apps/user_ldap/l10n/lv.php b/apps/user_ldap/l10n/lv.php new file mode 100644 index 0000000000000000000000000000000000000000..52353472e4d5bb0ce5a85663fe227181361e8d73 --- /dev/null +++ b/apps/user_ldap/l10n/lv.php @@ -0,0 +1,3 @@ + "Palīdzība" +); diff --git a/apps/user_ldap/l10n/mk.php b/apps/user_ldap/l10n/mk.php index f0a348b74215ec363bccaedc684cb1211b28d9cd..4c231b516d47910b5c826f75bc48c58773640959 100644 --- a/apps/user_ldap/l10n/mk.php +++ b/apps/user_ldap/l10n/mk.php @@ -1,3 +1,6 @@ "Лозинка" +"Host" => "Домаќин", +"You can omit the protocol, except you require SSL. Then start with ldaps://" => "Може да го скокнете протколот освен ако не ви треба SSL. Тогаш ставете ldaps://", +"Password" => "Лозинка", +"Help" => "Помош" ); diff --git a/apps/user_ldap/l10n/ms_MY.php b/apps/user_ldap/l10n/ms_MY.php new file mode 100644 index 0000000000000000000000000000000000000000..077a5390cf8b4f06bcedb471a2b99b2203c8e82c --- /dev/null +++ b/apps/user_ldap/l10n/ms_MY.php @@ -0,0 +1,3 @@ + "Bantuan" +); diff --git a/apps/user_ldap/l10n/nl.php b/apps/user_ldap/l10n/nl.php index 23e9a15c0104a758d2149a637ac23b8d4b2d8753..27c4407360ec000d453e30e6a3b7b0cb05353617 100644 --- a/apps/user_ldap/l10n/nl.php +++ b/apps/user_ldap/l10n/nl.php @@ -1,11 +1,12 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Waarschuwing: De Apps user_ldap en user_webdavauth zijn incompatible. U kunt onverwacht gedrag ervaren. Vraag uw beheerder om een van beide apps de deactiveren.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Waarschuwing: De PHP LDAP module is niet geïnstalleerd, de backend zal dus niet werken. Vraag uw beheerder de module te installeren.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Waarschuwing: De PHP LDAP module is niet geïnstalleerd, het backend zal niet werken. Vraag uw systeembeheerder om de module te installeren.", "Host" => "Host", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Je kunt het protocol weglaten, tenzij je SSL vereist. Start in dat geval met ldaps://", -"Base DN" => "Basis DN", -"You can specify Base DN for users and groups in the Advanced tab" => "Je kunt het standaard DN voor gebruikers en groepen specificeren in het tab Geavanceerd.", -"User DN" => "Gebruikers DN", +"Base DN" => "Base DN", +"One Base DN per line" => "Een Base DN per regel", +"You can specify Base DN for users and groups in the Advanced tab" => "Je kunt het Base DN voor gebruikers en groepen specificeren in het tab Geavanceerd.", +"User DN" => "User DN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "De DN van de client gebruiker waarmee de verbinding zal worden gemaakt, bijv. uid=agent,dc=example,dc=com. Voor anonieme toegang laat je het DN en het wachtwoord leeg.", "Password" => "Wachtwoord", "For anonymous access, leave DN and Password empty." => "Voor anonieme toegang, laat de DN en het wachtwoord leeg.", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "zonder een placeholder, bijv. \"objectClass=posixGroup\"", "Port" => "Poort", "Base User Tree" => "Basis Gebruikers Structuur", +"One User Base DN per line" => "Een User Base DN per regel", "Base Group Tree" => "Basis Groupen Structuur", +"One Group Base DN per line" => "Een Group Base DN per regel", "Group-Member association" => "Groepslid associatie", "Use TLS" => "Gebruik TLS", "Do not use it for SSL connections, it will fail." => "Gebruik niet voor SSL connecties, deze mislukken.", diff --git a/apps/user_ldap/l10n/nn_NO.php b/apps/user_ldap/l10n/nn_NO.php new file mode 100644 index 0000000000000000000000000000000000000000..54d1f158f65f05cca5fb71c7d96c5ee838a9f6fe --- /dev/null +++ b/apps/user_ldap/l10n/nn_NO.php @@ -0,0 +1,3 @@ + "Hjelp" +); diff --git a/apps/user_ldap/l10n/oc.php b/apps/user_ldap/l10n/oc.php new file mode 100644 index 0000000000000000000000000000000000000000..0bf27d74f2febc053e5599fc828e2683ff4dbf3b --- /dev/null +++ b/apps/user_ldap/l10n/oc.php @@ -0,0 +1,3 @@ + "Ajuda" +); diff --git a/apps/user_ldap/l10n/pl.php b/apps/user_ldap/l10n/pl.php index 0a3dea14c94a6a593147da8dbd2508b27aada212..55110b8a8308313c216076cb517ea120a1191ed3 100644 --- a/apps/user_ldap/l10n/pl.php +++ b/apps/user_ldap/l10n/pl.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Ostrzeżenie: Aplikacje user_ldap i user_webdavauth nie są kompatybilne. Mogą powodować nieoczekiwane zachowanie. Poproś administratora o wyłączenie jednej z nich.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Ostrzeżenie: Moduł PHP LDAP nie jest zainstalowany i nie będzie działał. Poproś administratora o włączenie go.", "Host" => "Host", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Można pominąć protokół, z wyjątkiem wymaganego protokołu SSL. Następnie uruchom z ldaps://", "Base DN" => "Baza DN", diff --git a/apps/user_ldap/l10n/pt_PT.php b/apps/user_ldap/l10n/pt_PT.php index 1b21b899a2e12a34459fc0478ffee18ffce30095..9059f17876968a022e4236fdf3affec6922f4238 100644 --- a/apps/user_ldap/l10n/pt_PT.php +++ b/apps/user_ldap/l10n/pt_PT.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Aviso: A aplicação user_ldap e user_webdavauth são incompativeis. A aplicação pode tornar-se instável. Por favor, peça ao seu administrador para desactivar uma das aplicações.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Aviso: O módulo PHP LDAP necessário não está instalado, o backend não irá funcionar. Peça ao seu administrador para o instalar.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Aviso: O módulo PHP LDAP não está instalado, logo não irá funcionar. Por favor peça ao administrador para o instalar.", "Host" => "Anfitrião", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Pode omitir o protocolo, excepto se necessitar de SSL. Neste caso, comece com ldaps://", "Base DN" => "DN base", +"One Base DN per line" => "Uma base DN por linho", "You can specify Base DN for users and groups in the Advanced tab" => "Pode especificar o ND Base para utilizadores e grupos no separador Avançado", "User DN" => "DN do utilizador", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "O DN to cliente ", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "Sem nenhuma variável. Exemplo: \"objectClass=posixGroup\".", "Port" => "Porto", "Base User Tree" => "Base da árvore de utilizadores.", +"One User Base DN per line" => "Uma base de utilizador DN por linha", "Base Group Tree" => "Base da árvore de grupos.", +"One Group Base DN per line" => "Uma base de grupo DN por linha", "Group-Member association" => "Associar utilizador ao grupo.", "Use TLS" => "Usar TLS", "Do not use it for SSL connections, it will fail." => "Não use para ligações SSL, irá falhar.", diff --git a/apps/user_ldap/l10n/ro.php b/apps/user_ldap/l10n/ro.php index beeed857455c30306271313e705e97ec2ae457cd..d83c890b747ab20cd460515985d48b42fb80e8c6 100644 --- a/apps/user_ldap/l10n/ro.php +++ b/apps/user_ldap/l10n/ro.php @@ -1,7 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Atentie: Apps user_ldap si user_webdavauth sunt incompatibile. Este posibil sa experimentati un comportament neasteptat. Vă rugăm să întrebați administratorul de sistem pentru a dezactiva una dintre ele.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Atenție Modulul PHP LDAP nu este instalat, infrastructura nu va funcționa. Contactează administratorul sistemului pentru al instala.", "Host" => "Gazdă", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Puteți omite protocolul, decât dacă folosiți SSL. Atunci se începe cu ldaps://", "Base DN" => "DN de bază", +"One Base DN per line" => "Un Base DN pe linie", "You can specify Base DN for users and groups in the Advanced tab" => "Puteți să specificați DN de bază pentru utilizatori și grupuri în fila Avansat", "User DN" => "DN al utilizatorului", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN-ul clientului utilizator cu care se va efectua conectarea, d.e. uid=agent,dc=example,dc=com. Pentru acces anonim, lăsăți DN și Parolă libere.", @@ -18,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "fără substituenți, d.e. \"objectClass=posixGroup\"", "Port" => "Portul", "Base User Tree" => "Arborele de bază al Utilizatorilor", +"One User Base DN per line" => "Un User Base DN pe linie", "Base Group Tree" => "Arborele de bază al Grupurilor", +"One Group Base DN per line" => "Un Group Base DN pe linie", "Group-Member association" => "Asocierea Grup-Membru", "Use TLS" => "Utilizează TLS", "Do not use it for SSL connections, it will fail." => "A nu se utiliza pentru conexiuni SSL, va eșua.", diff --git a/apps/user_ldap/l10n/ru.php b/apps/user_ldap/l10n/ru.php index f41a0b058387414ca48f4cdbfda67faa62ceee51..42fba32f43fcf0adf94a6be1c6200564383a6e46 100644 --- a/apps/user_ldap/l10n/ru.php +++ b/apps/user_ldap/l10n/ru.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Внимание:Приложения user_ldap и user_webdavauth несовместимы. Вы можете столкнуться с неожиданным поведением. Пожалуйста, обратитесь к системному администратору, чтобы отключить одно из них.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Внимание: Необходимый PHP LDAP модуль не установлен, внутренний интерфейс не будет работать. Пожалуйста, обратитесь к системному администратору, чтобы установить его.", "Host" => "Сервер", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Можно опустить протокол, за исключением того, когда вам требуется SSL. Тогда начните с ldaps :/ /", "Base DN" => "Базовый DN", diff --git a/apps/user_ldap/l10n/ru_RU.php b/apps/user_ldap/l10n/ru_RU.php index 09d7899249a29b48c3519d626a85606dbf764e4b..64ba1176f6e8942ad36c0980ce30e4710587ba8d 100644 --- a/apps/user_ldap/l10n/ru_RU.php +++ b/apps/user_ldap/l10n/ru_RU.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Предупреждение: Приложения user_ldap и user_webdavauth несовместимы. Вы можете столкнуться с неожиданным поведением системы. Пожалуйста, обратитесь к системному администратору для отключения одного из них.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Предупреждение: Необходимый PHP LDAP-модуль не установлен, backend не будет работать. Пожалуйста, обратитесь к системному администратору, чтобы установить его.", "Host" => "Хост", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Вы можете пропустить протокол, если Вам не требуется SSL. Затем начните с ldaps://", "Base DN" => "База DN", diff --git a/apps/user_ldap/l10n/sl.php b/apps/user_ldap/l10n/sl.php index 1d1fc33a83bc05d35d0204a1c682be3361e59610..247f2bfdcbd73550e7a7456b23c70a48ff9b5e29 100644 --- a/apps/user_ldap/l10n/sl.php +++ b/apps/user_ldap/l10n/sl.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Opozorilo: Aplikaciji user_ldap in user_webdavauth nista združljivi. Morda boste opazili nepričakovano obnašanje sistema. Prosimo, prosite vašega skrbnika, da eno od aplikacij onemogoči.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Opozorilo: PHP LDAP modul mora biti nameščen, sicer ta vmesnik ne bo deloval. Prosimo, prosite vašega skrbnika, če ga namesti.", "Host" => "Gostitelj", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Protokol je lahko izpuščen, če ni posebej zahtevan SSL. V tem primeru se mora naslov začeti z ldaps://", "Base DN" => "Osnovni DN", diff --git a/apps/user_ldap/l10n/sr.php b/apps/user_ldap/l10n/sr.php new file mode 100644 index 0000000000000000000000000000000000000000..fff39aadc2403a97e089fb11e9a2840f0456764e --- /dev/null +++ b/apps/user_ldap/l10n/sr.php @@ -0,0 +1,3 @@ + "Помоћ" +); diff --git a/apps/user_ldap/l10n/sr@latin.php b/apps/user_ldap/l10n/sr@latin.php new file mode 100644 index 0000000000000000000000000000000000000000..91503315066c42bb31391ed0f1ea03a8c3fb95b3 --- /dev/null +++ b/apps/user_ldap/l10n/sr@latin.php @@ -0,0 +1,3 @@ + "Pomoć" +); diff --git a/apps/user_ldap/l10n/sv.php b/apps/user_ldap/l10n/sv.php index e8e14af7aca799c720f738b0306e596c9df2934d..25abfdd7ddb092469d2540b7ffe3ee41611dbec5 100644 --- a/apps/user_ldap/l10n/sv.php +++ b/apps/user_ldap/l10n/sv.php @@ -1,9 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Varning: Apps user_ldap och user_webdavauth är inkompatibla. Oväntade problem kan uppstå. Be din systemadministratör att inaktivera en av dom.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Varning: PHP LDAP-modulen måste vara installerad, serversidan kommer inte att fungera. Be din systemadministratör att installera den.", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "Varning: PHP LDAP - modulen är inte installerad, serversidan kommer inte att fungera. Kontakta din systemadministratör för installation.", "Host" => "Server", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Du behöver inte ange protokoll förutom om du använder SSL. Starta då med ldaps://", "Base DN" => "Start DN", +"One Base DN per line" => "Ett Start DN per rad", "You can specify Base DN for users and groups in the Advanced tab" => "Du kan ange start DN för användare och grupper under fliken Avancerat", "User DN" => "Användare DN", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN för användaren som skall användas, t.ex. uid=agent, dc=example, dc=com. För anonym åtkomst, lämna DN och lösenord tomt.", @@ -20,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "utan platshållare, t.ex. \"objectClass=posixGroup\".", "Port" => "Port", "Base User Tree" => "Bas för användare i katalogtjänst", +"One User Base DN per line" => "En Användare start DN per rad", "Base Group Tree" => "Bas för grupper i katalogtjänst", +"One Group Base DN per line" => "En Grupp start DN per rad", "Group-Member association" => "Attribut för gruppmedlemmar", "Use TLS" => "Använd TLS", "Do not use it for SSL connections, it will fail." => "Använd inte för SSL-anslutningar, det kommer inte att fungera.", diff --git a/apps/user_ldap/l10n/th_TH.php b/apps/user_ldap/l10n/th_TH.php index acc7a4936bcca688c8a72dbe2f89686fdb1fa640..e3a941c424484593194a272b78437409c62d2c23 100644 --- a/apps/user_ldap/l10n/th_TH.php +++ b/apps/user_ldap/l10n/th_TH.php @@ -1,7 +1,10 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "คำเตือน: แอปฯ user_ldap และ user_webdavauth ไม่สามารถใช้งานร่วมกันได้. คุณอาจประสพปัญหาที่ไม่คาดคิดจากเหตุการณ์ดังกล่าว กรุณาติดต่อผู้ดูแลระบบของคุณเพื่อระงับการใช้งานแอปฯ ตัวใดตัวหนึ่งข้างต้น", +"Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it." => "คำเตือน: โมดูล PHP LDAP ยังไม่ได้ถูกติดตั้ง, ระบบด้านหลังจะไม่สามารถทำงานได้ กรุณาติดต่อผู้ดูแลระบบของคุณเพื่อทำการติดตั้งโมดูลดังกล่าว", "Host" => "โฮสต์", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "คุณสามารถปล่อยช่องโปรโตคอลเว้นไว้ได้, ยกเว้นกรณีที่คุณต้องการใช้ SSL จากนั้นเริ่มต้นด้วย ldaps://", "Base DN" => "DN ฐาน", +"One Base DN per line" => "หนึ่ง Base DN ต่อบรรทัด", "You can specify Base DN for users and groups in the Advanced tab" => "คุณสามารถระบุ DN หลักสำหรับผู้ใช้งานและกลุ่มต่างๆในแท็บขั้นสูงได้", "User DN" => "DN ของผู้ใช้งาน", "The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." => "DN ของผู้ใช้งานที่เป็นลูกค้าอะไรก็ตามที่ผูกอยู่ด้วย เช่น uid=agent, dc=example, dc=com, สำหรับการเข้าถึงโดยบุคคลนิรนาม, ให้เว้นว่าง DN และ รหัสผ่านเอาไว้", @@ -18,7 +21,9 @@ "without any placeholder, e.g. \"objectClass=posixGroup\"." => "โดยไม่ต้องมีตัวยึดใดๆ, เช่น \"objectClass=posixGroup\",", "Port" => "พอร์ต", "Base User Tree" => "รายการผู้ใช้งานหลักแบบ Tree", +"One User Base DN per line" => "หนึ่ง User Base DN ต่อบรรทัด", "Base Group Tree" => "รายการกลุ่มหลักแบบ Tree", +"One Group Base DN per line" => "หนึ่ง Group Base DN ต่อบรรทัด", "Group-Member association" => "ความสัมพันธ์ของสมาชิกในกลุ่ม", "Use TLS" => "ใช้ TLS", "Do not use it for SSL connections, it will fail." => "กรุณาอย่าใช้การเชื่อมต่อแบบ SSL การเชื่อมต่อจะเกิดการล้มเหลว", diff --git a/apps/user_ldap/l10n/tr.php b/apps/user_ldap/l10n/tr.php new file mode 100644 index 0000000000000000000000000000000000000000..6da65d9832b5d0570252fc7e2857eadb71d7d51a --- /dev/null +++ b/apps/user_ldap/l10n/tr.php @@ -0,0 +1,24 @@ + "Konak", +"Base DN" => "Base DN", +"User DN" => "User DN", +"Password" => "Parola", +"For anonymous access, leave DN and Password empty." => "Anonim erişim için DN ve Parola alanlarını boş bırakın.", +"User Login Filter" => "Kullanıcı Oturum Açma Süzgeci", +"use %%uid placeholder, e.g. \"uid=%%uid\"" => "%%uid yer tutucusunu kullanın, örneğin \"uid=%%uid\"", +"User List Filter" => "Kullanıcı Liste Süzgeci", +"without any placeholder, e.g. \"objectClass=person\"." => "bir yer tutucusu olmadan, örneğin \"objectClass=person\"", +"Group Filter" => "Grup Süzgeci", +"Port" => "Port", +"Base User Tree" => "Temel Kullanıcı Ağacı", +"Base Group Tree" => "Temel Grup Ağacı", +"Group-Member association" => "Grup-Üye işbirliği", +"Use TLS" => "TLS kullan", +"Do not use it for SSL connections, it will fail." => "SSL bağlantıları ile kullanmayın, başarısız olacaktır.", +"Turn off SSL certificate validation." => "SSL sertifika doğrulamasını kapat.", +"Not recommended, use for testing only." => "Önerilmez, sadece test için kullanın.", +"in bytes" => "byte cinsinden", +"in seconds. A change empties the cache." => "saniye cinsinden. Bir değişiklik önbelleği temizleyecektir.", +"Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "Kullanıcı adı bölümünü boş bırakın (varsayılan). ", +"Help" => "Yardım" +); diff --git a/apps/user_ldap/l10n/uk.php b/apps/user_ldap/l10n/uk.php index f82e9f2a42039bff0473dda31c8dbc5f1565f12c..d617d939265ff24f922d8ea58acc7a787f2aae05 100644 --- a/apps/user_ldap/l10n/uk.php +++ b/apps/user_ldap/l10n/uk.php @@ -1,6 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "Увага: Застосунки user_ldap та user_webdavauth не сумісні. Ви можете зіткнутися з несподіваною поведінкою. Будь ласка, зверніться до системного адміністратора, щоб відключити одну з них.", -"Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it." => "Увага: Потрібний модуль PHP LDAP не встановлено, базова програма працювати не буде. Будь ласка, зверніться до системного адміністратора, щоб встановити його.", "Host" => "Хост", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "Можна не вказувати протокол, якщо вам не потрібен SSL. Тоді почніть з ldaps://", "Base DN" => "Базовий DN", diff --git a/apps/user_ldap/l10n/zh_CN.php b/apps/user_ldap/l10n/zh_CN.php index bb961d534b739a5e41494757f6bf48206c835a1b..ed5041eff06ccc86686bcabc9a9fae066fc115e7 100644 --- a/apps/user_ldap/l10n/zh_CN.php +++ b/apps/user_ldap/l10n/zh_CN.php @@ -1,4 +1,5 @@ Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them." => "警告:应用 user_ldap 和 user_webdavauth 不兼容。您可能遭遇未预料的行为。请垂询您的系统管理员禁用其中一个。", "Host" => "主机", "You can omit the protocol, except you require SSL. Then start with ldaps://" => "可以忽略协议,但如要使用SSL,则需以ldaps://开头", "Base DN" => "Base DN", @@ -31,6 +32,7 @@ "Group Display Name Field" => "组显示名称字段", "The LDAP attribute to use to generate the groups`s ownCloud name." => "用来生成组的ownCloud名称的LDAP属性", "in bytes" => "字节数", +"in seconds. A change empties the cache." => "以秒计。修改将清空缓存。", "Leave empty for user name (default). Otherwise, specify an LDAP/AD attribute." => "将用户名称留空(默认)。否则指定一个LDAP/AD属性", "Help" => "帮助" ); diff --git a/apps/user_ldap/l10n/zh_TW.php b/apps/user_ldap/l10n/zh_TW.php index abc1b03d49dbca9e825c2d44d41e33fa274fc7c2..506ae0f0fbd711803ecbfc04301d38ac353d9a4b 100644 --- a/apps/user_ldap/l10n/zh_TW.php +++ b/apps/user_ldap/l10n/zh_TW.php @@ -1,5 +1,7 @@ "主機", "Password" => "密碼", +"Port" => "連接阜", "Use TLS" => "使用TLS", "Turn off SSL certificate validation." => "關閉 SSL 憑證驗證", "Help" => "說明" diff --git a/apps/user_ldap/lib/access.php b/apps/user_ldap/lib/access.php index f888577aedb59adced4e8dbd56f08f56431797db..422e43fc003469c98a2569e93c9eaf835e2e18a5 100644 --- a/apps/user_ldap/lib/access.php +++ b/apps/user_ldap/lib/access.php @@ -114,6 +114,15 @@ abstract class Access { * @return the sanitized DN */ private function sanitizeDN($dn) { + //treating multiple base DNs + if(is_array($dn)) { + $result = array(); + foreach($dn as $singleDN) { + $result[] = $this->sanitizeDN($singleDN); + } + return $result; + } + //OID sometimes gives back DNs with whitespace after the comma a la "uid=foo, cn=bar, dn=..." We need to tackle this! $dn = preg_replace('/([^\\\]),(\s+)/u', '\1,', $dn); @@ -212,9 +221,13 @@ abstract class Access { * returns the internal ownCloud name for the given LDAP DN of the group, false on DN outside of search DN or failure */ public function dn2groupname($dn, $ldapname = null) { - if(mb_strripos($dn, $this->sanitizeDN($this->connection->ldapBaseGroups), 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen($this->sanitizeDN($this->connection->ldapBaseGroups), 'UTF-8'))) { + //To avoid bypassing the base DN settings under certain circumstances + //with the group support, check whether the provided DN matches one of + //the given Bases + if(!$this->isDNPartOfBase($dn, $this->connection->ldapBaseGroups)) { return false; } + return $this->dn2ocname($dn, $ldapname, false); } @@ -227,9 +240,13 @@ abstract class Access { * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN or failure */ public function dn2username($dn, $ldapname = null) { - if(mb_strripos($dn, $this->sanitizeDN($this->connection->ldapBaseUsers), 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen($this->sanitizeDN($this->connection->ldapBaseUsers), 'UTF-8'))) { + //To avoid bypassing the base DN settings under certain circumstances + //with the group support, check whether the provided DN matches one of + //the given Bases + if(!$this->isDNPartOfBase($dn, $this->connection->ldapBaseUsers)) { return false; } + return $this->dn2ocname($dn, $ldapname, true); } @@ -521,7 +538,7 @@ abstract class Access { /** * @brief executes an LDAP search * @param $filter the LDAP filter for the search - * @param $base the LDAP subtree that shall be searched + * @param $base an array containing the LDAP subtree(s) that shall be searched * @param $attr optional, when a certain attribute shall be filtered out * @returns array with the search result * @@ -544,18 +561,28 @@ abstract class Access { //check wether paged search should be attempted $pagedSearchOK = $this->initPagedSearch($filter, $base, $attr, $limit, $offset); - $sr = ldap_search($link_resource, $base, $filter, $attr); - if(!$sr) { + $linkResources = array_pad(array(), count($base), $link_resource); + $sr = ldap_search($linkResources, $base, $filter, $attr); + $error = ldap_errno($link_resource); + if(!is_array($sr) || $error > 0) { \OCP\Util::writeLog('user_ldap', 'Error when searching: '.ldap_error($link_resource).' code '.ldap_errno($link_resource), \OCP\Util::ERROR); \OCP\Util::writeLog('user_ldap', 'Attempt for Paging? '.print_r($pagedSearchOK, true), \OCP\Util::ERROR); return array(); } - $findings = ldap_get_entries($link_resource, $sr ); + $findings = array(); + foreach($sr as $key => $res) { + $findings = array_merge($findings, ldap_get_entries($link_resource, $res )); + } if($pagedSearchOK) { \OCP\Util::writeLog('user_ldap', 'Paged search successful', \OCP\Util::INFO); - ldap_control_paged_result_response($link_resource, $sr, $cookie); - \OCP\Util::writeLog('user_ldap', 'Set paged search cookie '.$cookie, \OCP\Util::INFO); - $this->setPagedResultCookie($filter, $limit, $offset, $cookie); + foreach($sr as $key => $res) { + $cookie = null; + if(ldap_control_paged_result_response($link_resource, $res, $cookie)) { + \OCP\Util::writeLog('user_ldap', 'Set paged search cookie', \OCP\Util::INFO); + $this->setPagedResultCookie($base[$key], $filter, $limit, $offset, $cookie); + } + } + //browsing through prior pages to get the cookie for the new one if($skipHandling) { return; @@ -565,7 +592,9 @@ abstract class Access { $this->pagedSearchedSuccessful = true; } } else { - \OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO); + if(!is_null($limit)) { + \OCP\Util::writeLog('user_ldap', 'Paged search failed :(', \OCP\Util::INFO); + } } // if we're here, probably no connection resource is returned. @@ -791,20 +820,41 @@ abstract class Access { return str_replace('\\5c', '\\', $dn); } + /** + * @brief checks if the given DN is part of the given base DN(s) + * @param $dn the DN + * @param $bases array containing the allowed base DN or DNs + * @returns Boolean + */ + private function isDNPartOfBase($dn, $bases) { + $bases = $this->sanitizeDN($bases); + foreach($bases as $base) { + $belongsToBase = true; + if(mb_strripos($dn, $base, 0, 'UTF-8') !== (mb_strlen($dn, 'UTF-8')-mb_strlen($base))) { + $belongsToBase = false; + } + if($belongsToBase) { + break; + } + } + return $belongsToBase; + } + /** * @brief get a cookie for the next LDAP paged search + * @param $base a string with the base DN for the search * @param $filter the search filter to identify the correct search * @param $limit the limit (or 'pageSize'), to identify the correct search well * @param $offset the offset for the new search to identify the correct search really good * @returns string containing the key or empty if none is cached */ - private function getPagedResultCookie($filter, $limit, $offset) { + private function getPagedResultCookie($base, $filter, $limit, $offset) { if($offset == 0) { return ''; } $offset -= $limit; //we work with cache here - $cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset; + $cachekey = 'lc' . crc32($base) . '-' . crc32($filter) . '-' . $limit . '-' . $offset; $cookie = $this->connection->getFromCache($cachekey); if(is_null($cookie)) { $cookie = ''; @@ -814,15 +864,16 @@ abstract class Access { /** * @brief set a cookie for LDAP paged search run + * @param $base a string with the base DN for the search * @param $filter the search filter to identify the correct search * @param $limit the limit (or 'pageSize'), to identify the correct search well * @param $offset the offset for the run search to identify the correct search really good * @param $cookie string containing the cookie returned by ldap_control_paged_result_response * @return void */ - private function setPagedResultCookie($filter, $limit, $offset) { + private function setPagedResultCookie($base, $filter, $limit, $offset, $cookie) { if(!empty($cookie)) { - $cachekey = 'lc' . dechex(crc32($filter)) . '-' . $limit . '-' . $offset; + $cachekey = 'lc' . dechex(crc32($base)) . '-' . dechex(crc32($filter)) . '-' .$limit . '-' . $offset; $cookie = $this->connection->writeToCache($cachekey, $cookie); } } @@ -841,40 +892,47 @@ abstract class Access { /** * @brief prepares a paged search, if possible * @param $filter the LDAP filter for the search - * @param $base the LDAP subtree that shall be searched + * @param $bases an array containing the LDAP subtree(s) that shall be searched * @param $attr optional, when a certain attribute shall be filtered outside * @param $limit * @param $offset * */ - private function initPagedSearch($filter, $base, $attr, $limit, $offset) { + private function initPagedSearch($filter, $bases, $attr, $limit, $offset) { $pagedSearchOK = false; if($this->connection->hasPagedResultSupport && !is_null($limit)) { $offset = intval($offset); //can be null - \OCP\Util::writeLog('user_ldap', 'initializing paged search for Filter'.$filter.' base '.$base.' attr '.print_r($attr, true). ' limit ' .$limit.' offset '.$offset, \OCP\Util::DEBUG); + \OCP\Util::writeLog('user_ldap', 'initializing paged search for Filter'.$filter.' base '.print_r($bases, true).' attr '.print_r($attr, true). ' limit ' .$limit.' offset '.$offset, \OCP\Util::INFO); //get the cookie from the search for the previous search, required by LDAP - $cookie = $this->getPagedResultCookie($filter, $limit, $offset); - if(empty($cookie) && ($offset > 0)) { - //no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?) - $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; - //a bit recursive, $offset of 0 is the exit - \OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO); - $this->search($filter, $base, $attr, $limit, $reOffset, true); - $cookie = $this->getPagedResultCookie($filter, $limit, $offset); - //still no cookie? obviously, the server does not like us. Let's skip paging efforts. - //TODO: remember this, probably does not change in the next request... - if(empty($cookie)) { - $cookie = null; + foreach($bases as $base) { + + $cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset); + if(empty($cookie) && ($offset > 0)) { + //no cookie known, although the offset is not 0. Maybe cache run out. We need to start all over *sigh* (btw, Dear Reader, did you need LDAP paged searching was designed by MSFT?) + $reOffset = ($offset - $limit) < 0 ? 0 : $offset - $limit; + //a bit recursive, $offset of 0 is the exit + \OCP\Util::writeLog('user_ldap', 'Looking for cookie L/O '.$limit.'/'.$reOffset, \OCP\Util::INFO); + $this->search($filter, $base, $attr, $limit, $reOffset, true); + $cookie = $this->getPagedResultCookie($base, $filter, $limit, $offset); + //still no cookie? obviously, the server does not like us. Let's skip paging efforts. + //TODO: remember this, probably does not change in the next request... + if(empty($cookie)) { + $cookie = null; + } } - } - if(!is_null($cookie)) { - if($offset > 0) { - \OCP\Util::writeLog('user_ldap', 'Cookie '.$cookie, \OCP\Util::INFO); + if(!is_null($cookie)) { + if($offset > 0) { + \OCP\Util::writeLog('user_ldap', 'Cookie '.$cookie, \OCP\Util::INFO); + } + $pagedSearchOK = ldap_control_paged_result($this->connection->getConnectionResource(), $limit, false, $cookie); + if(!$pagedSearchOK) { + return false; + } + \OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::INFO); + } else { + \OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::INFO); } - $pagedSearchOK = ldap_control_paged_result($this->connection->getConnectionResource(), $limit, false, $cookie); - \OCP\Util::writeLog('user_ldap', 'Ready for a paged search', \OCP\Util::INFO); - } else { - \OCP\Util::writeLog('user_ldap', 'No paged search for us, Cpt., Limit '.$limit.' Offset '.$offset, \OCP\Util::INFO); + } } diff --git a/apps/user_ldap/lib/connection.php b/apps/user_ldap/lib/connection.php index b14cdafff89809cf3b0780d3cac7d2cdcad475e0..7046cbbfc78d9776e267d1686424d341e8c217f7 100644 --- a/apps/user_ldap/lib/connection.php +++ b/apps/user_ldap/lib/connection.php @@ -187,9 +187,9 @@ class Connection { $this->config['ldapPort'] = \OCP\Config::getAppValue($this->configID, 'ldap_port', 389); $this->config['ldapAgentName'] = \OCP\Config::getAppValue($this->configID, 'ldap_dn', ''); $this->config['ldapAgentPassword'] = base64_decode(\OCP\Config::getAppValue($this->configID, 'ldap_agent_password', '')); - $this->config['ldapBase'] = \OCP\Config::getAppValue($this->configID, 'ldap_base', ''); - $this->config['ldapBaseUsers'] = \OCP\Config::getAppValue($this->configID, 'ldap_base_users', $this->config['ldapBase']); - $this->config['ldapBaseGroups'] = \OCP\Config::getAppValue($this->configID, 'ldap_base_groups', $this->config['ldapBase']); + $this->config['ldapBase'] = preg_split('/\r\n|\r|\n/', \OCP\Config::getAppValue($this->configID, 'ldap_base', '')); + $this->config['ldapBaseUsers'] = preg_split('/\r\n|\r|\n/', \OCP\Config::getAppValue($this->configID, 'ldap_base_users', $this->config['ldapBase'])); + $this->config['ldapBaseGroups'] = preg_split('/\r\n|\r|\n/', \OCP\Config::getAppValue($this->configID, 'ldap_base_groups', $this->config['ldapBase'])); $this->config['ldapTLS'] = \OCP\Config::getAppValue($this->configID, 'ldap_tls', 0); $this->config['ldapNoCase'] = \OCP\Config::getAppValue($this->configID, 'ldap_nocase', 0); $this->config['turnOffCertCheck'] = \OCP\Config::getAppValue($this->configID, 'ldap_turn_off_cert_check', 0); diff --git a/apps/user_ldap/templates/settings.php b/apps/user_ldap/templates/settings.php index 8522d2f835cac26d7a63249efd2e0386856fcaf8..b24c6e2f0256a092861b816dbfadffcdbb86f2db 100644 --- a/apps/user_ldap/templates/settings.php +++ b/apps/user_ldap/templates/settings.php @@ -8,12 +8,12 @@ echo '

'.$l->t('Warning: Apps user_ldap and user_webdavauth are incompatible. You may experience unexpected behaviour. Please ask your system administrator to disable one of them.').'

'; } if(!function_exists('ldap_connect')) { - echo '

'.$l->t('Warning: The PHP LDAP module needs is not installed, the backend will not work. Please ask your system administrator to install it.').'

'; + echo '

'.$l->t('Warning: The PHP LDAP module is not installed, the backend will not work. Please ask your system administrator to install it.').'

'; } ?>

-

+


t('use %%uid placeholder, e.g. "uid=%%uid"');?>

@@ -22,8 +22,8 @@

-

-

+

+

title="t('Do not use it for SSL connections, it will fail.');?>" />

>

diff --git a/apps/user_ldap/tests/group_ldap.php b/apps/user_ldap/tests/group_ldap.php index f99902d32f5cb028b4d922507c2e8af7f0f73e00..ae635597b71fcd15de2fa6b707e58fead4f3fc00 100644 --- a/apps/user_ldap/tests/group_ldap.php +++ b/apps/user_ldap/tests/group_ldap.php @@ -20,7 +20,7 @@ * */ -class Test_Group_Ldap extends UnitTestCase { +class Test_Group_Ldap extends PHPUnit_Framework_TestCase { function setUp() { OC_Group::clearBackends(); } diff --git a/apps/user_webdavauth/l10n/bn_BD.php b/apps/user_webdavauth/l10n/bn_BD.php new file mode 100644 index 0000000000000000000000000000000000000000..5366552efae004346a719cbb5d66ba2d839058b6 --- /dev/null +++ b/apps/user_webdavauth/l10n/bn_BD.php @@ -0,0 +1,3 @@ + "URL:http://" +); diff --git a/apps/user_webdavauth/l10n/ca.php b/apps/user_webdavauth/l10n/ca.php index 84a6c599e78df8e85be55c45703a54134940639e..7ac540f21303d7a122d9358f843f46ed651f8b98 100644 --- a/apps/user_webdavauth/l10n/ca.php +++ b/apps/user_webdavauth/l10n/ca.php @@ -1,4 +1,5 @@ "Autenticació WebDAV", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud enviarà les credencials d'usuari a aquesta URL. S'interpretarà http 401 i http 403 com a credencials incorrectes i tots els altres codis com a credencials correctes." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud enviarà les credencials d'usuari a aquesta URL. Aquest endollable en comprova la resposta i interpretarà els codis d'estat 401 i 403 com a credencials no vàlides, i qualsevol altra resposta com a credencials vàlides." ); diff --git a/apps/user_webdavauth/l10n/cs_CZ.php b/apps/user_webdavauth/l10n/cs_CZ.php index 5cb9b4c370448b7023e6675d4a3be1aecc095ad2..9bd4c96a2bb4fd1bc9d4d2c104e639e4de8d9b8d 100644 --- a/apps/user_webdavauth/l10n/cs_CZ.php +++ b/apps/user_webdavauth/l10n/cs_CZ.php @@ -1,4 +1,5 @@ "Ověření WebDAV", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud odešle přihlašovací údaje uživatele na URL a z návratové hodnoty určí stav přihlášení. Http 401 a 403 vyhodnotí jako neplatné údaje a všechny ostatní jako úspěšné přihlášení." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud odešle uživatelské údaje na zadanou URL. Plugin zkontroluje odpověď a považuje návratovou hodnotu HTTP 401 a 403 za neplatné údaje a všechny ostatní hodnoty jako platné přihlašovací údaje." ); diff --git a/apps/user_webdavauth/l10n/da.php b/apps/user_webdavauth/l10n/da.php index 7d9ee1d5b293905e92153a1029decf926b16b1b8..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/da.php +++ b/apps/user_webdavauth/l10n/da.php @@ -1,4 +1,3 @@ "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud vil sende brugeroplysningerne til denne webadresse er fortolker http 401 og http 403 som brugeroplysninger forkerte og alle andre koder som brugeroplysninger korrekte." +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/de.php b/apps/user_webdavauth/l10n/de.php index 8589dc0c4fd748bda8c874d7523389a79e8a85a5..f893bddc71ce599a7d16c97609c703427e57a150 100644 --- a/apps/user_webdavauth/l10n/de.php +++ b/apps/user_webdavauth/l10n/de.php @@ -1,4 +1,5 @@ "WebDAV Authentifikation", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud wird die Logindaten zu dieser URL senden. http 401 und http 403 werden als falsche Logindaten interpretiert und alle anderen Codes als korrekte Logindaten." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud wird die Benutzer-Anmeldedaten an diese URL schicken. Dieses Plugin prüft die Anmeldedaten auf ihre Gültigkeit und interpretiert die HTTP Statusfehler 401 und 403 als ungültige, sowie alle Anderen als gültige Anmeldedaten." ); diff --git a/apps/user_webdavauth/l10n/de_DE.php b/apps/user_webdavauth/l10n/de_DE.php index 3d73dccfe8ec2a30e0d5f71e974a2e78e252ba56..8f67575fc0fd6ae8665f1f4800823fff606a5b3f 100644 --- a/apps/user_webdavauth/l10n/de_DE.php +++ b/apps/user_webdavauth/l10n/de_DE.php @@ -1,4 +1,5 @@ "WebDAV Authentifizierung", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud " +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud sendet die Benutzerdaten an diese URL. Dieses Plugin prüft die Antwort und wird die Statuscodes 401 und 403 als ungültige Daten interpretieren und alle anderen Antworten als gültige Daten." ); diff --git a/apps/user_webdavauth/l10n/el.php b/apps/user_webdavauth/l10n/el.php index 245a5101341d2a51e59b2cc0575b907f85eb3945..951709c4d6490dad92fd4d7e39c2ab3471722129 100644 --- a/apps/user_webdavauth/l10n/el.php +++ b/apps/user_webdavauth/l10n/el.php @@ -1,3 +1,5 @@ "URL: http://" +"WebDAV Authentication" => "Αυθεντικοποίηση μέσω WebDAV ", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "Το ownCloud θα στείλει τα διαπιστευτήρια χρήστη σε αυτό το URL. Αυτό το plugin ελέγχει την απάντηση και την μετατρέπει σε HTTP κωδικό κατάστασης 401 και 403 για μη έγκυρα, όλες οι υπόλοιπες απαντήσεις είναι έγκυρες." ); diff --git a/apps/user_webdavauth/l10n/eo.php b/apps/user_webdavauth/l10n/eo.php index b4a2652d33e32b204230fde802c2097c3072851a..d945f181e6bf65916c5c02254c89beb858a63020 100644 --- a/apps/user_webdavauth/l10n/eo.php +++ b/apps/user_webdavauth/l10n/eo.php @@ -1,3 +1,4 @@ "WebDAV-a URL: http://" +"WebDAV Authentication" => "WebDAV-aŭtentigo", +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/es.php b/apps/user_webdavauth/l10n/es.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..103c3738e2d81d476fded156cf818c12ed97b23b 100644 --- a/apps/user_webdavauth/l10n/es.php +++ b/apps/user_webdavauth/l10n/es.php @@ -1,3 +1,5 @@ "WebDAV URL: http://" +"WebDAV Authentication" => "Autenticación de WevDAV", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "onwCloud enviará las credenciales de usuario a esta URL. Este complemento verifica la respuesta e interpretará los códigos de respuesta HTTP 401 y 403 como credenciales inválidas y todas las otras respuestas como credenciales válidas." ); diff --git a/apps/user_webdavauth/l10n/es_AR.php b/apps/user_webdavauth/l10n/es_AR.php index 81f2ea1e578b8809ecb9d4ceb2c14c22545a15d3..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/es_AR.php +++ b/apps/user_webdavauth/l10n/es_AR.php @@ -1,3 +1,3 @@ "URL de WebDAV: http://" +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/eu.php b/apps/user_webdavauth/l10n/eu.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..d792c1588bbe44d7710f894c79361d610b530e24 100644 --- a/apps/user_webdavauth/l10n/eu.php +++ b/apps/user_webdavauth/l10n/eu.php @@ -1,3 +1,5 @@ "WebDAV URL: http://" +"WebDAV Authentication" => "WebDAV Autentikazioa", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloudek erabiltzailearen kredentzialak URL honetara bidaliko ditu. Plugin honek erantzuna aztertzen du eta HTTP 401 eta 403 egoera kodeak baliogabezko kredentzialtzat hartuko ditu, beste erantzunak kredentzial egokitzat hartuko dituelarik." ); diff --git a/apps/user_webdavauth/l10n/fr.php b/apps/user_webdavauth/l10n/fr.php index 759d45b230e5aa007196cdb4c2f69ec4ecea2f00..9d528a3a9d216efbc2a776cf018a4b2af7d4cc86 100644 --- a/apps/user_webdavauth/l10n/fr.php +++ b/apps/user_webdavauth/l10n/fr.php @@ -1,3 +1,5 @@ "URL WebDAV : http://" +"WebDAV Authentication" => "Authentification WebDAV", +"URL: http://" => "URL : http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud enverra les informations de connexion à cette adresse. Ce module complémentaire analyse le code réponse HTTP et considère tout code différent des codes 401 et 403 comme associé à une authentification correcte." ); diff --git a/apps/user_webdavauth/l10n/gl.php b/apps/user_webdavauth/l10n/gl.php index a5b7e56771f9cdc32f229040b0956062121b3d01..a6b8355c07433c653ed89d68217bcc9133750b81 100644 --- a/apps/user_webdavauth/l10n/gl.php +++ b/apps/user_webdavauth/l10n/gl.php @@ -1,3 +1,5 @@ "URL WebDAV: http://" +"WebDAV Authentication" => "Autenticación WebDAV", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud enviará as credenciais do usuario a esta URL. Este conector comproba a resposta e interpretará os códigos de estado 401 e 403 como credenciais non válidas, e todas as outras respostas como credenciais válidas." ); diff --git a/apps/user_webdavauth/l10n/hu_HU.php b/apps/user_webdavauth/l10n/hu_HU.php new file mode 100644 index 0000000000000000000000000000000000000000..245a5101341d2a51e59b2cc0575b907f85eb3945 --- /dev/null +++ b/apps/user_webdavauth/l10n/hu_HU.php @@ -0,0 +1,3 @@ + "URL: http://" +); diff --git a/apps/user_webdavauth/l10n/is.php b/apps/user_webdavauth/l10n/is.php new file mode 100644 index 0000000000000000000000000000000000000000..8fe0d974b321e9342567b22b0788d794bccbbb5c --- /dev/null +++ b/apps/user_webdavauth/l10n/is.php @@ -0,0 +1,3 @@ + "Vefslóð: http://" +); diff --git a/apps/user_webdavauth/l10n/it.php b/apps/user_webdavauth/l10n/it.php index b0abf2f20822d085ed0368447ca30be94da93d55..a7cd6e8e4b4237d82768491444c7c7de59364008 100644 --- a/apps/user_webdavauth/l10n/it.php +++ b/apps/user_webdavauth/l10n/it.php @@ -1,4 +1,5 @@ "Autenticazione WebDAV", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud invierà le credenziali dell'utente a questo URL. Interpreta i codici http 401 e http 403 come credenziali errate e tutti gli altri codici come credenziali corrette." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud invierà le credenziali dell'utente a questo URL. Questa estensione controlla la risposta e interpreta i codici di stato 401 e 403 come credenziali non valide, e tutte le altre risposte come credenziali valide." ); diff --git a/apps/user_webdavauth/l10n/ja_JP.php b/apps/user_webdavauth/l10n/ja_JP.php index 8643805ffccc79b14edd2f97d38dcb49b6f2c6d4..1cd14a03c727fe6292163c2f6e7b8ace978c596e 100644 --- a/apps/user_webdavauth/l10n/ja_JP.php +++ b/apps/user_webdavauth/l10n/ja_JP.php @@ -1,4 +1,5 @@ "WebDAV 認証", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloudのこのURLへのユーザ資格情報の送信は、資格情報が間違っている場合はHTTP401もしくは403を返し、正しい場合は全てのコードを返します。" +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloudはこのURLにユーザ資格情報を送信します。このプラグインは応答をチェックし、HTTP状態コードが 401 と 403 の場合は無効な資格情報とし、他の応答はすべて有効な資格情報として処理します。" ); diff --git a/apps/user_webdavauth/l10n/ko.php b/apps/user_webdavauth/l10n/ko.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/ko.php +++ b/apps/user_webdavauth/l10n/ko.php @@ -1,3 +1,3 @@ "WebDAV URL: http://" +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/mk.php b/apps/user_webdavauth/l10n/mk.php new file mode 100644 index 0000000000000000000000000000000000000000..245a5101341d2a51e59b2cc0575b907f85eb3945 --- /dev/null +++ b/apps/user_webdavauth/l10n/mk.php @@ -0,0 +1,3 @@ + "URL: http://" +); diff --git a/apps/user_webdavauth/l10n/nb_NO.php b/apps/user_webdavauth/l10n/nb_NO.php new file mode 100644 index 0000000000000000000000000000000000000000..245a5101341d2a51e59b2cc0575b907f85eb3945 --- /dev/null +++ b/apps/user_webdavauth/l10n/nb_NO.php @@ -0,0 +1,3 @@ + "URL: http://" +); diff --git a/apps/user_webdavauth/l10n/nl.php b/apps/user_webdavauth/l10n/nl.php index 687442fb66575e6e67120d1b411abb99d8cbe460..7d1bb33923eefb3dc44730d1871022804202c2a4 100644 --- a/apps/user_webdavauth/l10n/nl.php +++ b/apps/user_webdavauth/l10n/nl.php @@ -1,4 +1,5 @@ "WebDAV authenticatie", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud zal de inloggegevens naar deze URL als geïnterpreteerde http 401 en http 403 als de inloggegevens onjuist zijn. Andere codes als de inloggegevens correct zijn." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud stuurt de inloggegevens naar deze URL. Deze plugin controleert het antwoord en interpreteert de HTTP statuscodes 401 als 403 als ongeldige inloggegevens, maar alle andere antwoorden als geldige inloggegevens." ); diff --git a/apps/user_webdavauth/l10n/pl.php b/apps/user_webdavauth/l10n/pl.php index 245a5101341d2a51e59b2cc0575b907f85eb3945..4887e935316cb15a916da4883004ba9cf62eaa50 100644 --- a/apps/user_webdavauth/l10n/pl.php +++ b/apps/user_webdavauth/l10n/pl.php @@ -1,3 +1,5 @@ "URL: http://" +"WebDAV Authentication" => "Uwierzytelnienie WebDAV", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud wyśle dane uwierzytelniające do tego URL. Ten plugin sprawdza odpowiedź i zinterpretuje kody HTTP 401 oraz 403 jako nieprawidłowe dane uwierzytelniające, a każdy inny kod odpowiedzi jako poprawne dane." ); diff --git a/apps/user_webdavauth/l10n/pt_PT.php b/apps/user_webdavauth/l10n/pt_PT.php index e8bfcfda81ec297a94221c6e240c9baec8f7fd60..d7e87b5c8d19c326eacbbe40394b9a253955fcc5 100644 --- a/apps/user_webdavauth/l10n/pt_PT.php +++ b/apps/user_webdavauth/l10n/pt_PT.php @@ -1,4 +1,5 @@ "Autenticação WebDAV", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "O ownCloud vai enviar as credenciais para este URL. Todos os códigos http 401 e 403 serão interpretados como credenciais inválidas, todos os restantes códigos http serão interpretados como credenciais correctas." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "O ownCloud vai enviar as credenciais do utilizador através deste URL. Este plugin verifica a resposta e vai interpretar os códigos de estado HTTP 401 e 403 como credenciais inválidas, e todas as outras como válidas." ); diff --git a/apps/user_webdavauth/l10n/ro.php b/apps/user_webdavauth/l10n/ro.php new file mode 100644 index 0000000000000000000000000000000000000000..245a5101341d2a51e59b2cc0575b907f85eb3945 --- /dev/null +++ b/apps/user_webdavauth/l10n/ro.php @@ -0,0 +1,3 @@ + "URL: http://" +); diff --git a/apps/user_webdavauth/l10n/ru.php b/apps/user_webdavauth/l10n/ru.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/ru.php +++ b/apps/user_webdavauth/l10n/ru.php @@ -1,3 +1,3 @@ "WebDAV URL: http://" +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/sk_SK.php b/apps/user_webdavauth/l10n/sk_SK.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..6e34b818ed77fbcd56c7f67ad76e259c8ec8531e 100644 --- a/apps/user_webdavauth/l10n/sk_SK.php +++ b/apps/user_webdavauth/l10n/sk_SK.php @@ -1,3 +1,4 @@ "WebDAV URL: http://" +"WebDAV Authentication" => "WebDAV overenie", +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/sl.php b/apps/user_webdavauth/l10n/sl.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/sl.php +++ b/apps/user_webdavauth/l10n/sl.php @@ -1,3 +1,3 @@ "WebDAV URL: http://" +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/sv.php b/apps/user_webdavauth/l10n/sv.php index b7a7e4ea2d9df2a462fef449dbac55d4e0286426..c79b35c27cdb434f7ac8a4712d00f08724e652fa 100644 --- a/apps/user_webdavauth/l10n/sv.php +++ b/apps/user_webdavauth/l10n/sv.php @@ -1,4 +1,5 @@ "WebDAV Autentisering", "URL: http://" => "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud kommer att skicka inloggningsuppgifterna till denna URL och tolkar http 401 och http 403 som fel och alla andra koder som korrekt." +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud kommer skicka användaruppgifterna till denna URL. Denna plugin kontrollerar svaret och tolkar HTTP-statuskoderna 401 och 403 som felaktiga uppgifter, och alla andra svar som giltiga uppgifter." ); diff --git a/apps/user_webdavauth/l10n/th_TH.php b/apps/user_webdavauth/l10n/th_TH.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..2bd1f685e656ec448ccf68f15104ce547b4d0869 100644 --- a/apps/user_webdavauth/l10n/th_TH.php +++ b/apps/user_webdavauth/l10n/th_TH.php @@ -1,3 +1,5 @@ "WebDAV URL: http://" +"WebDAV Authentication" => "WebDAV Authentication", +"URL: http://" => "URL: http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud จะส่งข้อมูลการเข้าใช้งานของผู้ใช้งานไปยังที่อยู่ URL ดังกล่าวนี้ ปลั๊กอินดังกล่าวจะทำการตรวจสอบข้อมูลที่โต้ตอบกลับมาและจะทำการแปลรหัส HTTP statuscodes 401 และ 403 ให้เป็นข้อมูลการเข้าใช้งานที่ไม่สามารถใช้งานได้ ส่วนข้อมูลอื่นๆที่เหลือทั้งหมดจะเป็นข้อมูลการเข้าใช้งานที่สามารถใช้งานได้" ); diff --git a/apps/user_webdavauth/l10n/tr.php b/apps/user_webdavauth/l10n/tr.php index 9bd32954b058d9ad5c43d6604e9ba18e4bd559f3..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/tr.php +++ b/apps/user_webdavauth/l10n/tr.php @@ -1,3 +1,3 @@ "WebDAV URL: http://" +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/uk.php b/apps/user_webdavauth/l10n/uk.php index 57aa90684ae33158dcd115f762ae3b5ad1f5b6a9..245a5101341d2a51e59b2cc0575b907f85eb3945 100644 --- a/apps/user_webdavauth/l10n/uk.php +++ b/apps/user_webdavauth/l10n/uk.php @@ -1,4 +1,3 @@ "URL: http://", -"ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct." => "ownCloud відправить облікові дані на цей URL та буде інтерпретувати http 401 і http 403, як невірні облікові дані, а всі інші коди, як вірні." +"URL: http://" => "URL: http://" ); diff --git a/apps/user_webdavauth/l10n/zh_CN.php b/apps/user_webdavauth/l10n/zh_CN.php index 5b06409b42e0d0c6983f2140160e2e0a08550984..72d2a0c11dff21a2b782198213f5deabbef34a66 100644 --- a/apps/user_webdavauth/l10n/zh_CN.php +++ b/apps/user_webdavauth/l10n/zh_CN.php @@ -1,3 +1,5 @@ "URL:http://" +"WebDAV Authentication" => "WebDAV 认证", +"URL: http://" => "URL:http://", +"ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials." => "ownCloud 将会发送用户的身份到此 URL。这个插件检查返回值并且将 HTTP 状态编码 401 和 403 解释为非法身份,其他所有返回值为合法身份。" ); diff --git a/apps/user_webdavauth/templates/settings.php b/apps/user_webdavauth/templates/settings.php index 62ed45fd278fa489a8b9acb95b2e5adb0d198a0f..880b77ac959182369b4afbd2cd51c5b57a28ece8 100755 --- a/apps/user_webdavauth/templates/settings.php +++ b/apps/user_webdavauth/templates/settings.php @@ -1,8 +1,8 @@
- WebDAV Authentication + t('WebDAV Authentication');?>

-
t('ownCloud will send the user credentials to this URL is interpret http 401 and http 403 as credentials wrong and all other codes as credentials correct.'); ?> +
t('ownCloud will send the user credentials to this URL. This plugin checks the response and will interpret the HTTP statuscodes 401 and 403 as invalid credentials, and all other responses as valid credentials.'); ?>

diff --git a/apps/user_webdavauth/user_webdavauth.php b/apps/user_webdavauth/user_webdavauth.php index 839196c114c9e7f948ce301fd1e24592462cbb36..1459781a3b4034d7229cc4ac1f414c48d2b66ecd 100755 --- a/apps/user_webdavauth/user_webdavauth.php +++ b/apps/user_webdavauth/user_webdavauth.php @@ -65,7 +65,7 @@ class OC_USER_WEBDAVAUTH extends OC_User_Backend { } /* - * we don´t know if a user exists without the password. so we have to return false all the time + * we don´t know if a user exists without the password. so we have to return true all the time */ public function userExists( $uid ){ return true; diff --git a/build/phpcs.xml b/build/phpcs.xml index 1e10be1a11171f33252b3b01dabf5d7d723d5c11..d2909955ed2712adf8e133162f68d4f516846dbe 100644 --- a/build/phpcs.xml +++ b/build/phpcs.xml @@ -10,7 +10,7 @@ */files_pdfviewer/js/pdfjs/* */files_odfviewer/src/* */files_svgedit/svg-edit/* - *jquery-ui-1.8.16.custom.css + *jquery-ui-*.css php diff --git a/config/config.sample.php b/config/config.sample.php index 78dfe17ea790333c722987ac8b8e7980195c52ec..51373327f449cce52da754b894c4d592d99cd069 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1,5 +1,7 @@ "", -/* Enhanced auth forces users to enter their password again when performing potential sensitive actions like creating or deleting users */ -"enhancedauth" => true, - -/* Time in seconds how long an user is authenticated without entering his password again before performing sensitive actions like creating or deleting users etc...*/ -"enhancedauthtime" => 15 * 60, - /* A proxy to use to connect to the internet. For example "myproxy.org:88" */ "proxy" => "", @@ -72,12 +68,25 @@ $CONFIG = array( /* URL of the appstore to use, server should understand OCS */ "appstoreurl" => "http://api.apps.owncloud.com/v1", +/* Enable SMTP class debugging */ +"mail_smtpdebug" => false, + /* Mode to use for sending mail, can be sendmail, smtp, qmail or php, see PHPMailer docs */ "mail_smtpmode" => "sendmail", /* Host to use for sending mail, depends on mail_smtpmode if this is used */ "mail_smtphost" => "127.0.0.1", +/* Port to use for sending mail, depends on mail_smtpmode if this is used */ +"mail_smtpport" => 25, + +/* SMTP server timeout in seconds for sending mail, depends on mail_smtpmode if this is used */ +"mail_smtptimeout" => 10, + +/* SMTP connection prefix or sending mail, depends on mail_smtpmode if this is used. + Can be '', ssl or tls */ +"mail_smtpsecure" => "", + /* authentication needed to send mail, depends on mail_smtpmode if this is used * (false = disable authentication) */ @@ -107,11 +116,17 @@ $CONFIG = array( /* Lifetime of the remember login cookie, default is 15 days */ "remember_login_cookie_lifetime" => 60*60*24*15, +/* Custom CSP policy, changing this will overwrite the standard policy */ +"custom_csp_policy" => "default-src \'self\'; script-src \'self\' \'unsafe-eval\'; style-src \'self\' \'unsafe-inline\'; frame-src *; img-src *", + /* The directory where the user data is stored, default to data in the owncloud * directory. The sqlite database is also stored here, when sqlite is used. */ // "datadirectory" => "", +/* Enable maintenance mode to disable ownCloud */ +"maintenance" => false, + "apps_paths" => array( /* Set an array of path for your apps directories @@ -123,12 +138,12 @@ $CONFIG = array( 'path'=> '/var/www/owncloud/apps', 'url' => '/apps', 'writable' => true, - ), - ), - 'user_backends'=>array( - array( - 'class'=>'OC_User_IMAP', - 'arguments'=>array('{imap.gmail.com:993/imap/ssl}INBOX') - ) - ) + ), +), +'user_backends'=>array( + array( + 'class'=>'OC_User_IMAP', + 'arguments'=>array('{imap.gmail.com:993/imap/ssl}INBOX') + ) +) ); diff --git a/core/ajax/share.php b/core/ajax/share.php index 72ffc52e99749fc0c5720af8a27216e95648be78..077baa8ba569a644acfa1b2b4ac1a266a9f8c187 100644 --- a/core/ajax/share.php +++ b/core/ajax/share.php @@ -98,7 +98,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo OCP\Util::sendMail($to_address, $to_address, $subject, $text, $from_address, $user); OCP\JSON::success(); } catch (Exception $exception) { - OCP\JSON::error(array('data' => array('message' => $exception->getMessage()))); + OCP\JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($exception->getMessage())))); } break; } diff --git a/core/ajax/update.php b/core/ajax/update.php new file mode 100644 index 0000000000000000000000000000000000000000..20ab045c89243b09f433dac2900caba7acb57b17 --- /dev/null +++ b/core/ajax/update.php @@ -0,0 +1,67 @@ +success('Turned on maintenance mode'); + try { + $result = OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/db_structure.xml'); + $watcher->success('Updated database'); + } catch (Exception $exception) { + $watcher->failure($exception->getMessage()); + } + $minimizerCSS = new OC_Minimizer_CSS(); + $minimizerCSS->clearCache(); + $minimizerJS = new OC_Minimizer_JS(); + $minimizerJS->clearCache(); + OC_Config::setValue('version', implode('.', OC_Util::getVersion())); + OC_App::checkAppsRequirements(); + // load all apps to also upgrade enabled apps + OC_App::loadApps(); + OC_Config::setValue('maintenance', false); + $watcher->success('Turned off maintenance mode'); + $watcher->done(); +} + +class UpdateWatcher { + /** + * @var \OC_EventSource $eventSource; + */ + private $eventSource; + + public function __construct($eventSource) { + $this->eventSource = $eventSource; + } + + public function success($message) { + OC_Util::obEnd(); + $this->eventSource->send('success', $message); + ob_start(); + } + + public function error($message) { + OC_Util::obEnd(); + $this->eventSource->send('error', $message); + ob_start(); + } + + public function failure($message) { + OC_Util::obEnd(); + $this->eventSource->send('failure', $message); + $this->eventSource->close(); + die(); + } + + public function done() { + OC_Util::obEnd(); + $this->eventSource->send('done', ''); + $this->eventSource->close(); + } + +} \ No newline at end of file diff --git a/core/css/images/animated-overlay.gif b/core/css/images/animated-overlay.gif new file mode 100644 index 0000000000000000000000000000000000000000..d441f75ebfbdf26a265dfccd670120d25c0a341c Binary files /dev/null and b/core/css/images/animated-overlay.gif differ diff --git a/core/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/core/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..954e22dbd99e8c6dd7091335599abf2d10bf8003 Binary files /dev/null and b/core/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/core/css/images/ui-bg_diagonals-thick_20_666666_40x40.png b/core/css/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..64ece5707d91a6edf9fad4bfcce0c4dbcafcf58d Binary files /dev/null and b/core/css/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/core/css/images/ui-bg_flat_100_ffffff_40x100.png b/core/css/images/ui-bg_flat_100_ffffff_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8b229af950c29356abf64a6c4aa894575445f0 Binary files /dev/null and b/core/css/images/ui-bg_flat_100_ffffff_40x100.png differ diff --git a/core/css/images/ui-bg_flat_10_000000_40x100.png b/core/css/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..abdc01082bf3534eafecc5819d28c9574d44ea89 Binary files /dev/null and b/core/css/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/core/css/images/ui-bg_flat_35_1d2d44_40x100.png b/core/css/images/ui-bg_flat_35_1d2d44_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..904ef14c37d9cff5afe71ef9733141328f22ac3c Binary files /dev/null and b/core/css/images/ui-bg_flat_35_1d2d44_40x100.png differ diff --git a/core/css/images/ui-bg_glass_100_f8f8f8_1x400.png b/core/css/images/ui-bg_glass_100_f8f8f8_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..cd79e9f1966df03e2956237b5a878a7c7cc32872 Binary files /dev/null and b/core/css/images/ui-bg_glass_100_f8f8f8_1x400.png differ diff --git a/core/css/images/ui-bg_highlight-hard_100_f8f8f8_1x100.png b/core/css/images/ui-bg_highlight-hard_100_f8f8f8_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..268e650935da6ff0f4d975a3515c95b12ed4035e Binary files /dev/null and b/core/css/images/ui-bg_highlight-hard_100_f8f8f8_1x100.png differ diff --git a/core/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/core/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f1273672d253263b7564e9e21d69d7d9d0b337d9 Binary files /dev/null and b/core/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/core/css/images/ui-icons_1d2d44_256x240.png b/core/css/images/ui-icons_1d2d44_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..2a857e4da570dbcfedaecc67f4d1092ba321c0a2 Binary files /dev/null and b/core/css/images/ui-icons_1d2d44_256x240.png differ diff --git a/core/css/images/ui-icons_222222_256x240.png b/core/css/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..b273ff111d219c9b9a8b96d57683d0075fb7871a Binary files /dev/null and b/core/css/images/ui-icons_222222_256x240.png differ diff --git a/core/css/images/ui-icons_ffd27a_256x240.png b/core/css/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..e117effa3dca24e7978cfc5f8b967f661e81044f Binary files /dev/null and b/core/css/images/ui-icons_ffd27a_256x240.png differ diff --git a/core/css/images/ui-icons_ffffff_256x240.png b/core/css/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..42f8f992c727ddaa617da224a522e463df690387 Binary files /dev/null and b/core/css/images/ui-icons_ffffff_256x240.png differ diff --git a/core/css/jquery-ui-1.10.0.custom.css b/core/css/jquery-ui-1.10.0.custom.css new file mode 100644 index 0000000000000000000000000000000000000000..a1e9895c7766ddabe568c2b9236df66156c8572b --- /dev/null +++ b/core/css/jquery-ui-1.10.0.custom.css @@ -0,0 +1,1174 @@ +/*! jQuery UI - v1.10.0 - 2013-01-22 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=%22Lucida%20Grande%22%2C%20Arial%2C%20Verdana%2C%20sans-serif&fwDefault=bold&fsDefault=1em&cornerRadius=4px&bgColorHeader=1d2d44&bgTextureHeader=01_flat.png&bgImgOpacityHeader=35&borderColorHeader=1d2d44&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f8f8f8&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=ddd&fcDefault=555&iconColorDefault=1d2d44&bgColorHover=ffffff&bgTextureHover=01_flat.png&bgImgOpacityHover=100&borderColorHover=ddd&fcHover=333&iconColorHover=1d2d44&bgColorActive=f8f8f8&bgTextureActive=02_glass.png&bgImgOpacityActive=100&borderColorActive=1d2d44&fcActive=1d2d44&iconColorActive=1d2d44&bgColorHighlight=f8f8f8&bgTextureHighlight=04_highlight_hard.png&bgImgOpacityHighlight=100&borderColorHighlight=ddd&fcHighlight=555&iconColorHighlight=ffffff&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px +* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin-top: 2px; + padding: .5em .5em .5em .7em; + min-height: 0; /* support: IE7 */ +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-noicons { + padding-left: .7em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: .5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: .1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: .4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: .4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 1em .4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: .4em 2.1em .4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: .4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: .5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: .5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: .2em .2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: .2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month-year { + width: 100%; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: .9em; + border-collapse: collapse; + margin: 0 0 .4em; +} +.ui-datepicker th { + padding: .7em .3em; + text-align: center; + font-weight: bold; + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: .2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: .7em 0 0 0; + padding: 0 .2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: .5em .2em .4em; + cursor: pointer; + padding: .2em .6em .3em .6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto .4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: .2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: .4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: .1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: .3em; + top: 50%; + width: 21px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: .5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: .5em; + padding: .3em 1em .5em .4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: .5em .4em .5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 2px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + margin-top: -3px; + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + padding: 0; + width: 100%; +} +.ui-menu .ui-menu-divider { + margin: 5px -2px 5px -2px; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px .4em; + line-height: 1.5; + min-height: 0; /* support: IE7 */ + font-weight: normal; +} +.ui-menu .ui-menu-item a.ui-state-focus, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} + +.ui-menu .ui-state-disabled { + font-weight: normal; + margin: .4em 0 .2em; + line-height: 1.5; +} +.ui-menu .ui-state-disabled a { + cursor: default; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item a { + position: relative; + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: .2em; + left: .2em; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + position: static; + float: right; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + background: url("images/animated-overlay.gif"); + height: 100%; + filter: alpha(opacity=25); + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: .2em 0; + vertical-align: middle; + margin-left: .4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: .5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to overide default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertical centre icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} + +/* TR overrides */ +.ui-spinner .ui-icon-triangle-1-s { + /* need to fix icons sprite */ + background-position: -65px -16px; +} +.ui-tabs { + position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: .2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: .2em .2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px .2em 0 0; + border-bottom: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav li a { + float: left; + padding: .5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, +.ui-tabs .ui-tabs-nav li.ui-state-disabled a, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { + cursor: text; +} +.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: "Lucida Grande", Arial, Verdana, sans-serif; + font-size: 1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: "Lucida Grande", Arial, Verdana, sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; + color: #333333; +} +.ui-widget-content a { + color: #333333; +} +.ui-widget-header { + border: 1px solid #1d2d44; + background: #1d2d44 url(images/ui-bg_flat_35_1d2d44_40x100.png) 50% 50% repeat-x; + color: #ffffff; + font-weight: bold; +} +.ui-widget-header a { + color: #ffffff; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #ddd; + background: #f8f8f8 url(images/ui-bg_glass_100_f8f8f8_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #555; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #555; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #ddd; + background: #ffffff url(images/ui-bg_flat_100_ffffff_40x100.png) 50% 50% repeat-x; + font-weight: bold; + color: #333; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #333; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #1d2d44; + background: #f8f8f8 url(images/ui-bg_glass_100_f8f8f8_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #1d2d44; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #1d2d44; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #ddd; + background: #f8f8f8 url(images/ui-bg_highlight-hard_100_f8f8f8_1x100.png) 50% top repeat-x; + color: #555; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #555; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; + color: #ffffff; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #ffffff; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #ffffff; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; + background-position: 16px 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(images/ui-icons_222222_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(images/ui-icons_1d2d44_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(images/ui-icons_1d2d44_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(images/ui-icons_1d2d44_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(images/ui-icons_ffffff_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(images/ui-icons_ffd27a_256x240.png); +} + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); +} +.ui-widget-shadow { + margin: -5px 0 0 -5px; + padding: 5px; + background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; + opacity: .2; + filter: Alpha(Opacity=20); + border-radius: 5px; +} diff --git a/core/css/jquery-ui-1.8.16.custom.css b/core/css/jquery-ui-1.8.16.custom.css deleted file mode 100644 index add1c6af08c2395028d51cb99bfa8180c7f09c34..0000000000000000000000000000000000000000 --- a/core/css/jquery-ui-1.8.16.custom.css +++ /dev/null @@ -1,362 +0,0 @@ -/* - * jQuery UI CSS Framework 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } -.ui-helper-clearfix { display: inline-block; } -/* required comment for clearfix to work in Opera \*/ -* html .ui-helper-clearfix { height:1%; } -.ui-helper-clearfix { display:block; } -/* end clearfix */ -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - - -/* - * jQuery UI CSS Framework 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault="Lucida%20Grande",%20Arial,%20Verdana,%20sans-serif&fwDefault=bold&fsDefault=1em&cornerRadius=4px&bgColorHeader=1d2d44&bgTextureHeader=01_flat.png&bgImgOpacityHeader=35&borderColorHeader=1d2d44&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f8f8f8&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=ddd&fcDefault=555&iconColorDefault=1d2d44&bgColorHover=ffffff&bgTextureHover=01_flat.png&bgImgOpacityHover=100&borderColorHover=ddd&fcHover=333&iconColorHover=1d2d44&bgColorActive=f8f8f8&bgTextureActive=02_glass.png&bgImgOpacityActive=100&borderColorActive=1d2d44&fcActive=1d2d44&iconColorActive=1d2d44&bgColorHighlight=f8f8f8&bgTextureHighlight=04_highlight_hard.png&bgImgOpacityHighlight=100&borderColorHighlight=ddd&fcHighlight=555&iconColorHighlight=ffffff&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px - */ - - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: \\\"Lucida Grande\\\", Arial, Verdana, sans-serif; font-size: 1em; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: \\\"Lucida Grande\\\", Arial, Verdana, sans-serif; font-size: 1em; } -.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee; color: #333333; } -.ui-widget-content a { color: #333333; } -.ui-widget-header { border: 1px solid #1d2d44; background: #1d2d44; color: #ffffff; font-weight: bold; } -.ui-widget-header a { color: #ffffff; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #ddd; background: #f8f8f8; font-weight: bold; color: #555; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #ddd; background: #ffffff; font-weight: bold; color: #333; } -.ui-state-hover a, .ui-state-hover a:hover { color: #333; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #1d2d44; background: #f8f8f8; font-weight: bold; color: #1d2d44; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #1d2d44; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - -/* states and images */ -.ui-icon { width: 16px; height: 16px; } -.ui-icon-closethick { background-image: url(../img/actions/delete.png); } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } - -/* Overlays */ -.ui-widget-overlay { background: #666666; opacity: .50;filter:Alpha(Opacity=50); } -.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* - * jQuery UI Resizable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizable#theming - */ -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* - * jQuery UI Selectable 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectable#theming - */ -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } -/* - * jQuery UI Autocomplete 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete#theming - */ -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.16 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} -/* - * jQuery UI Button 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button#theming - */ -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ -/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog#theming - */ -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; background-color: #EEE;} -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } -/* - * jQuery UI Slider 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider#theming - */ -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; }/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } -/* - * jQuery UI Datepicker 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - display: none; /*sorry for IE5*/ - display/**/: block; /*sorry for IE5*/ - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -}/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar#theming - */ -.ui-progressbar { height:2em; text-align: left; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/core/css/multiselect.css b/core/css/multiselect.css index 99f0e039334120ab495afc903c5aa94ba3537d77..31c8ef88eb9f763ed96211b3067db09038c47b25 100644 --- a/core/css/multiselect.css +++ b/core/css/multiselect.css @@ -5,15 +5,25 @@ ul.multiselectoptions { background-color:#fff; border:1px solid #ddd; - border-bottom-left-radius:.5em; - border-bottom-right-radius:.5em; border-top:none; box-shadow:0 1px 1px #ddd; padding-top:.5em; position:absolute; + max-height: 20em; + overflow-y: auto; z-index:49; } + ul.multiselectoptions.down { + border-bottom-left-radius:.5em; + border-bottom-right-radius:.5em; + } + + ul.multiselectoptions.up { + border-top-left-radius:.5em; + border-top-right-radius:.5em; + } + ul.multiselectoptions>li { overflow:hidden; white-space:nowrap; @@ -30,11 +40,20 @@ div.multiselect.active { background-color:#fff; + position:relative; + z-index:50; + } + + div.multiselect.up { + border-top:0 none; + border-top-left-radius:0; + border-top-right-radius:0; + } + + div.multiselect.down { border-bottom:none; border-bottom-left-radius:0; border-bottom-right-radius:0; - position:relative; - z-index:50; } div.multiselect>span:first-child { diff --git a/core/css/styles.css b/core/css/styles.css index d635916b5ae6a5ab554e54de271f0093c5963fb7..022acab4d8adf3d8679292d2681726efb6beb31b 100644 --- a/core/css/styles.css +++ b/core/css/styles.css @@ -34,7 +34,7 @@ filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endC /* INPUTS */ input[type="text"], input[type="password"] { cursor:text; } -input:not([type="checkbox"]), textarea, select, button, .button, #quota, div.jp-progress, .pager li a { +input, textarea, select, button, .button, #quota, div.jp-progress, .pager li a { width:10em; margin:.3em; padding:.6em .5em .4em; font-size:1em; font-family:Arial, Verdana, sans-serif; background:#fff; color:#333; border:1px solid #ddd; outline:none; @@ -56,7 +56,7 @@ input[type="checkbox"]:hover+label, input[type="checkbox"]:focus+label { color:# /* BUTTONS */ input[type="submit"], input[type="button"], button, .button, #quota, div.jp-progress, select, .pager li a { width:auto; padding:.4em; - background-color:rgba(230,230,230,.5); font-weight:bold; color:#555; text-shadow:#fff 0 1px 0; border:1px solid rgba(180,180,180,.5); cursor:pointer; + background-color:rgba(230,230,230,.5); font-weight:bold; color:#555; text-shadow:#fff 0 1px 0; border:1px solid #bbb; border:1px solid rgba(180,180,180,.5); cursor:pointer; -moz-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; box-shadow:0 1px 1px #fff, 0 1px 1px #fff inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; } @@ -94,8 +94,9 @@ input[type="submit"].enabled { background:#66f866; border:1px solid #5e5; -moz-b /* CONTENT ------------------------------------------------------------------ */ #controls { padding:0 0.5em; width:100%; top:3.5em; height:2.8em; margin:0; background:#f7f7f7; border-bottom:1px solid #eee; position:fixed; z-index:50; -moz-box-shadow:0 -3px 7px #000; -webkit-box-shadow:0 -3px 7px #000; box-shadow:0 -3px 7px #000; } #controls .button { display:inline-block; } -#content { top:3.5em; left:12.5em; position:absolute; } -#leftcontent, .leftcontent { position:fixed; overflow:auto; top:6.4em; width:20em; background:#f8f8f8; border-right:1px solid #ddd; } +#content { height: 100%; width: 100%; position: relative; } +#content-wrapper { height: 100%; width: 100%; padding-top: 3.5em; padding-left: 12.5em; box-sizing: border-box; -moz-box-sizing: border-box; position: absolute;} +#leftcontent, .leftcontent { position:fixed; top: 0; overflow:auto; width:20em; background:#f8f8f8; border-right:1px solid #ddd; box-sizing: border-box; -moz-box-sizing: border-box; height: 100%; padding-top: 6.4em } #leftcontent li, .leftcontent li { background:#f8f8f8; padding:.5em .8em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; -webkit-transition:background-color 200ms; -moz-transition:background-color 200ms; -o-transition:background-color 200ms; transition:background-color 200ms; } #leftcontent li:hover, #leftcontent li:active, #leftcontent li.active, .leftcontent li:hover, .leftcontent li:active, .leftcontent li.active { background:#eee; } #leftcontent li.active, .leftcontent li.active { font-weight:bold; } @@ -190,7 +191,8 @@ fieldset.warning legend { color:#b94a48 !important; } .bold { font-weight:bold; } .center { text-align:center; } -#notification { z-index:101; background-color:#fc4; border:0; padding:0 .7em .3em; display:none; position:fixed; left:50%; top:0; -moz-border-radius-bottomleft:1em; -webkit-border-bottom-left-radius:1em; border-bottom-left-radius:1em; -moz-border-radius-bottomright:1em; -webkit-border-bottom-right-radius:1em; border-bottom-right-radius:1em; } +#notification-container { position: fixed; top: 0px; width: 100%; text-align: center; z-index: 101; line-height: 1.2;} +#notification { z-index:101; background-color:#fc4; border:0; padding:0 .7em .3em; display:none; position: relative; top:0; -moz-border-radius-bottomleft:1em; -webkit-border-bottom-left-radius:1em; border-bottom-left-radius:1em; -moz-border-radius-bottomright:1em; -webkit-border-bottom-right-radius:1em; border-bottom-right-radius:1em; } #notification span { cursor:pointer; font-weight:bold; margin-left:1em; } tr .action, .selectedActions a { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0; } @@ -214,7 +216,8 @@ div.jp-play-bar, div.jp-seek-bar { padding:0; } .pager { list-style:none; float:right; display:inline; margin:.7em 13em 0 0; } .pager li { display:inline-block; } -li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ffe .8em .8em no-repeat; color:#FF3B3B; border:1px solid #ccc; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; } +li.update, li.error { width:640px; margin:4em auto; padding:1em 1em 1em 4em; background:#ffe .8em .8em no-repeat; border:1px solid #ccc; -moz-border-radius:10px; -webkit-border-radius:10px; border-radius:10px; cursor:default; } +.error { color:#FF3B3B; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { overflow:hidden; text-overflow:ellipsis; } .hint { background-image:url('../img/actions/info.png'); background-repeat:no-repeat; color:#777777; padding-left:25px; background-position:0 0.3em;} .separator { display:inline; border-left:1px solid #d3d3d3; border-right:1px solid #fff; height:10px; width:0px; margin:4px; } diff --git a/core/js/config.js b/core/js/config.js index f7a29276f7dc1e6eb3f8061ef32ece33121affbe..563df4e66326c163b45788225be2a026cc61aceb 100644 --- a/core/js/config.js +++ b/core/js/config.js @@ -50,6 +50,6 @@ OC.AppConfig={ }, deleteApp:function(app){ OC.AppConfig.postCall('deleteApp',{app:app}); - }, + } }; //TODO OC.Preferences diff --git a/core/js/config.php b/core/js/config.php new file mode 100644 index 0000000000000000000000000000000000000000..e838fb1cd04fd6e9c6129b125c603a586712b308 --- /dev/null +++ b/core/js/config.php @@ -0,0 +1,37 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +// Set the content type to Javascript +header("Content-type: text/javascript"); + +// Disallow caching +header("Cache-Control: no-cache, must-revalidate"); +header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); + +// Enable l10n support +$l = OC_L10N::get('core'); + +// Get the config +$debug = (defined('DEBUG') && DEBUG) ? 'true' : 'false'; +$array = array( + "oc_debug" => $debug, + "oc_webroot" => "\"".OC::$WEBROOT."\"", + "oc_appswebroots" => "\"".$_['apps_paths']. "\"", + "oc_current_user" => "\"".OC_User::getUser(). "\"", + "oc_requesttoken" => "\"".OC_Util::callRegister(). "\"", + "datepickerFormatDate" => json_encode($l->l('jsdate', 'jsdate')), + "dayNames" => json_encode(array((string)$l->t('Sunday'), (string)$l->t('Monday'), (string)$l->t('Tuesday'), (string)$l->t('Wednesday'), (string)$l->t('Thursday'), (string)$l->t('Friday'), (string)$l->t('Saturday'))), + "monthNames" => json_encode(array((string)$l->t('January'), (string)$l->t('February'), (string)$l->t('March'), (string)$l->t('April'), (string)$l->t('May'), (string)$l->t('June'), (string)$l->t('July'), (string)$l->t('August'), (string)$l->t('September'), (string)$l->t('October'), (string)$l->t('November'), (string)$l->t('December'))), + "firstDay" => json_encode($l->l('firstday', 'firstday')) , + ); + +// Echo it +foreach ($array as $setting => $value) { + echo("var ". $setting ."=".$value.";\n"); +} +?> \ No newline at end of file diff --git a/core/js/jquery-ui-1.10.0.custom.js b/core/js/jquery-ui-1.10.0.custom.js new file mode 100644 index 0000000000000000000000000000000000000000..ca57f47ede4632d8ec740832750eed744e87b44a --- /dev/null +++ b/core/js/jquery-ui-1.10.0.custom.js @@ -0,0 +1,14850 @@ +/*! jQuery UI - v1.10.0 - 2013-01-22 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js +* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */ + +(function( $, undefined ) { + +var uuid = 0, + runiqueId = /^ui-id-\d+$/; + +// prevent duplicate loading +// this is only a problem because we proxy existing functions +// and we don't want to double proxy them +$.ui = $.ui || {}; +if ( $.ui.version ) { + return; +} + +$.extend( $.ui, { + version: "1.10.0", + + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 + } +}); + +// plugins +$.fn.extend({ + _focus: $.fn.focus, + focus: function( delay, fn ) { + return typeof delay === "number" ? + this.each(function() { + var elem = this; + setTimeout(function() { + $( elem ).focus(); + if ( fn ) { + fn.call( elem ); + } + }, delay ); + }) : + this._focus.apply( this, arguments ); + }, + + scrollParent: function() { + var scrollParent; + if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { + scrollParent = this.parents().filter(function() { + return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } else { + scrollParent = this.parents().filter(function() { + return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); + }).eq(0); + } + + return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; + }, + + zIndex: function( zIndex ) { + if ( zIndex !== undefined ) { + return this.css( "zIndex", zIndex ); + } + + if ( this.length ) { + var elem = $( this[ 0 ] ), position, value; + while ( elem.length && elem[ 0 ] !== document ) { + // Ignore z-index if position is set to a value where z-index is ignored by the browser + // This makes behavior of this function consistent across browsers + // WebKit always returns auto if the element is positioned + position = elem.css( "position" ); + if ( position === "absolute" || position === "relative" || position === "fixed" ) { + // IE returns 0 when zIndex is not specified + // other browsers return a string + // we ignore the case of nested elements with an explicit value of 0 + //
+ value = parseInt( elem.css( "zIndex" ), 10 ); + if ( !isNaN( value ) && value !== 0 ) { + return value; + } + } + elem = elem.parent(); + } + } + + return 0; + }, + + uniqueId: function() { + return this.each(function() { + if ( !this.id ) { + this.id = "ui-id-" + (++uuid); + } + }); + }, + + removeUniqueId: function() { + return this.each(function() { + if ( runiqueId.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + }); + } +}); + +// selectors +function focusable( element, isTabIndexNotNaN ) { + var map, mapName, img, + nodeName = element.nodeName.toLowerCase(); + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap=#" + mapName + "]" )[0]; + return !!img && visible( img ); + } + return ( /input|select|textarea|button|object/.test( nodeName ) ? + !element.disabled : + "a" === nodeName ? + element.href || isTabIndexNotNaN : + isTabIndexNotNaN) && + // the element and all of its ancestors must be visible + visible( element ); +} + +function visible( element ) { + return $.expr.filters.visible( element ) && + !$( element ).parents().addBack().filter(function() { + return $.css( this, "visibility" ) === "hidden"; + }).length; +} + +$.extend( $.expr[ ":" ], { + data: $.expr.createPseudo ? + $.expr.createPseudo(function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + }) : + // support: jQuery <1.8 + function( elem, i, match ) { + return !!$.data( elem, match[ 3 ] ); + }, + + focusable: function( element ) { + return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); + }, + + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + isTabIndexNaN = isNaN( tabIndex ); + return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); + } +}); + +// support: jQuery <1.8 +if ( !$( "" ).outerWidth( 1 ).jquery ) { + $.each( [ "Width", "Height" ], function( i, name ) { + var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], + type = name.toLowerCase(), + orig = { + innerWidth: $.fn.innerWidth, + innerHeight: $.fn.innerHeight, + outerWidth: $.fn.outerWidth, + outerHeight: $.fn.outerHeight + }; + + function reduce( elem, size, border, margin ) { + $.each( side, function() { + size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; + if ( border ) { + size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; + } + if ( margin ) { + size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; + } + }); + return size; + } + + $.fn[ "inner" + name ] = function( size ) { + if ( size === undefined ) { + return orig[ "inner" + name ].call( this ); + } + + return this.each(function() { + $( this ).css( type, reduce( this, size ) + "px" ); + }); + }; + + $.fn[ "outer" + name] = function( size, margin ) { + if ( typeof size !== "number" ) { + return orig[ "outer" + name ].call( this, size ); + } + + return this.each(function() { + $( this).css( type, reduce( this, size, true, margin ) + "px" ); + }); + }; + }); +} + +// support: jQuery <1.8 +if ( !$.fn.addBack ) { + $.fn.addBack = function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + }; +} + +// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) +if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { + $.fn.removeData = (function( removeData ) { + return function( key ) { + if ( arguments.length ) { + return removeData.call( this, $.camelCase( key ) ); + } else { + return removeData.call( this ); + } + }; + })( $.fn.removeData ); +} + + + + + +// deprecated +$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); + +$.support.selectstart = "onselectstart" in document.createElement( "div" ); +$.fn.extend({ + disableSelection: function() { + return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + + ".ui-disableSelection", function( event ) { + event.preventDefault(); + }); + }, + + enableSelection: function() { + return this.unbind( ".ui-disableSelection" ); + } +}); + +$.extend( $.ui, { + // $.ui.plugin is deprecated. Use the proxy pattern instead. + plugin: { + add: function( module, option, set ) { + var i, + proto = $.ui[ module ].prototype; + for ( i in set ) { + proto.plugins[ i ] = proto.plugins[ i ] || []; + proto.plugins[ i ].push( [ option, set[ i ] ] ); + } + }, + call: function( instance, name, args ) { + var i, + set = instance.plugins[ name ]; + if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { + return; + } + + for ( i = 0; i < set.length; i++ ) { + if ( instance.options[ set[ i ][ 0 ] ] ) { + set[ i ][ 1 ].apply( instance.element, args ); + } + } + } + }, + + // only used by resizable + hasScroll: function( el, a ) { + + //If overflow is hidden, the element might have extra content, but the user wants to hide it + if ( $( el ).css( "overflow" ) === "hidden") { + return false; + } + + var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", + has = false; + + if ( el[ scroll ] > 0 ) { + return true; + } + + // TODO: determine which cases actually cause this to happen + // if the element doesn't have the scroll set, see if it's possible to + // set the scroll + el[ scroll ] = 1; + has = ( el[ scroll ] > 0 ); + el[ scroll ] = 0; + return has; + } +}); + +})( jQuery ); +(function( $, undefined ) { + +var uuid = 0, + slice = Array.prototype.slice, + _cleanData = $.cleanData; +$.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); +}; + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +})( jQuery ); +(function( $, undefined ) { + +var mouseHandled = false; +$( document ).mouseup( function() { + mouseHandled = false; +}); + +$.widget("ui.mouse", { + version: "1.10.0", + options: { + cancel: "input,textarea,button,select,option", + distance: 1, + delay: 0 + }, + _mouseInit: function() { + var that = this; + + this.element + .bind("mousedown."+this.widgetName, function(event) { + return that._mouseDown(event); + }) + .bind("click."+this.widgetName, function(event) { + if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { + $.removeData(event.target, that.widgetName + ".preventClickEvent"); + event.stopImmediatePropagation(); + return false; + } + }); + + this.started = false; + }, + + // TODO: make sure destroying one instance of mouse doesn't mess with + // other instances of mouse + _mouseDestroy: function() { + this.element.unbind("."+this.widgetName); + if ( this._mouseMoveDelegate ) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + } + }, + + _mouseDown: function(event) { + // don't let more than one widget handle mouseStart + if( mouseHandled ) { return; } + + // we may have missed mouseup (out of window) + (this._mouseStarted && this._mouseUp(event)); + + this._mouseDownEvent = event; + + var that = this, + btnIsLeft = (event.which === 1), + // event.target.nodeName works around a bug in IE 8 with + // disabled inputs (#7620) + elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); + if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { + return true; + } + + this.mouseDelayMet = !this.options.delay; + if (!this.mouseDelayMet) { + this._mouseDelayTimer = setTimeout(function() { + that.mouseDelayMet = true; + }, this.options.delay); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = (this._mouseStart(event) !== false); + if (!this._mouseStarted) { + event.preventDefault(); + return true; + } + } + + // Click event may never have fired (Gecko & Opera) + if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { + $.removeData(event.target, this.widgetName + ".preventClickEvent"); + } + + // these delegates are required to keep context + this._mouseMoveDelegate = function(event) { + return that._mouseMove(event); + }; + this._mouseUpDelegate = function(event) { + return that._mouseUp(event); + }; + $(document) + .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .bind("mouseup."+this.widgetName, this._mouseUpDelegate); + + event.preventDefault(); + + mouseHandled = true; + return true; + }, + + _mouseMove: function(event) { + // IE mouseup check - mouseup happened when mouse was out of window + if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { + return this._mouseUp(event); + } + + if (this._mouseStarted) { + this._mouseDrag(event); + return event.preventDefault(); + } + + if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { + this._mouseStarted = + (this._mouseStart(this._mouseDownEvent, event) !== false); + (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); + } + + return !this._mouseStarted; + }, + + _mouseUp: function(event) { + $(document) + .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) + .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); + + if (this._mouseStarted) { + this._mouseStarted = false; + + if (event.target === this._mouseDownEvent.target) { + $.data(event.target, this.widgetName + ".preventClickEvent", true); + } + + this._mouseStop(event); + } + + return false; + }, + + _mouseDistanceMet: function(event) { + return (Math.max( + Math.abs(this._mouseDownEvent.pageX - event.pageX), + Math.abs(this._mouseDownEvent.pageY - event.pageY) + ) >= this.options.distance + ); + }, + + _mouseDelayMet: function(/* event */) { + return this.mouseDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _mouseStart: function(/* event */) {}, + _mouseDrag: function(/* event */) {}, + _mouseStop: function(/* event */) {}, + _mouseCapture: function(/* event */) { return true; } +}); + +})(jQuery); +(function( $, undefined ) { + +$.ui = $.ui || {}; + +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + round = Math.round, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function getDimensions( elem ) { + var raw = elem[0]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( $.isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
" ), + innerDiv = div.children()[0]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[0].clientWidth; + } + + div.remove(); + + return (cachedScrollbarWidth = w1 - w2); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ), + overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + return { + width: hasOverflowX ? $.position.scrollbarWidth() : 0, + height: hasOverflowY ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isWindow = $.isWindow( withinElement[0] ); + return { + element: withinElement, + isWindow: isWindow, + offset: withinElement.offset() || { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: isWindow ? withinElement.width() : withinElement.outerWidth(), + height: isWindow ? withinElement.height() : withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + target = $( options.of ), + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[0].preventDefault ) { + // force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + // clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + }); + + // normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each(function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + // if the browser doesn't support fractions, then round for consistent results + if ( !$.support.offsetFractions ) { + position.left = round( position.left ); + position.top = round( position.top ); + } + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem : elem + }); + } + }); + + if ( options.using ) { + // adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + }); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // element is wider than within + if ( data.collisionWidth > outerWidth ) { + // element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + position.left += overLeft - newOverRight; + // element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + // element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + // too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + // too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + // adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // element is taller than within + if ( data.collisionHeight > outerHeight ) { + // element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + position.top += overTop - newOverBottom; + // element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + // element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + // too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + // too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + // adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } + else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { + position.top += myOffset + atOffset + offset; + } + } + else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +// fraction support test +(function () { + var testElement, testElementParent, testElementStyle, offsetLeft, i, + body = document.getElementsByTagName( "body" )[ 0 ], + div = document.createElement( "div" ); + + //Create a "fake body" for testing based on method used in jQuery.support + testElement = document.createElement( body ? "div" : "body" ); + testElementStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0, + background: "none" + }; + if ( body ) { + $.extend( testElementStyle, { + position: "absolute", + left: "-1000px", + top: "-1000px" + }); + } + for ( i in testElementStyle ) { + testElement.style[ i ] = testElementStyle[ i ]; + } + testElement.appendChild( div ); + testElementParent = body || document.documentElement; + testElementParent.insertBefore( testElement, testElementParent.firstChild ); + + div.style.cssText = "position: absolute; left: 10.7432222px;"; + + offsetLeft = $( div ).offset().left; + $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; + + testElement.innerHTML = ""; + testElementParent.removeChild( testElement ); +})(); + +}( jQuery ) ); +(function( $, undefined ) { + +$.widget("ui.draggable", $.ui.mouse, { + version: "1.10.0", + widgetEventPrefix: "drag", + options: { + addClasses: true, + appendTo: "parent", + axis: false, + connectToSortable: false, + containment: false, + cursor: "auto", + cursorAt: false, + grid: false, + handle: false, + helper: "original", + iframeFix: false, + opacity: false, + refreshPositions: false, + revert: false, + revertDuration: 500, + scope: "default", + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: false, + snapMode: "both", + snapTolerance: 20, + stack: false, + zIndex: false, + + // callbacks + drag: null, + start: null, + stop: null + }, + _create: function() { + + if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { + this.element[0].style.position = "relative"; + } + if (this.options.addClasses){ + this.element.addClass("ui-draggable"); + } + if (this.options.disabled){ + this.element.addClass("ui-draggable-disabled"); + } + + this._mouseInit(); + + }, + + _destroy: function() { + this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); + this._mouseDestroy(); + }, + + _mouseCapture: function(event) { + + var o = this.options; + + // among others, prevent a drag on a resizable-handle + if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { + return false; + } + + //Quit if we're not on a valid handle + this.handle = this._getHandle(event); + if (!this.handle) { + return false; + } + + $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { + $("
") + .css({ + width: this.offsetWidth+"px", height: this.offsetHeight+"px", + position: "absolute", opacity: "0.001", zIndex: 1000 + }) + .css($(this).offset()) + .appendTo("body"); + }); + + return true; + + }, + + _mouseStart: function(event) { + + var o = this.options; + + //Create and append the visible helper + this.helper = this._createHelper(event); + + this.helper.addClass("ui-draggable-dragging"); + + //Cache the helper size + this._cacheHelperProportions(); + + //If ddmanager is used for droppables, set the global draggable + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Store the helper's css position + this.cssPosition = this.helper.css("position"); + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.positionAbs = this.element.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + //Generate the original position + this.originalPosition = this.position = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + //Trigger event + callbacks + if(this._trigger("start", event) === false) { + this._clear(); + return false; + } + + //Recache the helper size + this._cacheHelperProportions(); + + //Prepare the droppable offsets + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + + this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position + + //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) + if ( $.ui.ddmanager ) { + $.ui.ddmanager.dragStart(this, event); + } + + return true; + }, + + _mouseDrag: function(event, noPropagation) { + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + //Call plugins and callbacks and use the resulting position if something is returned + if (!noPropagation) { + var ui = this._uiHash(); + if(this._trigger("drag", event, ui) === false) { + this._mouseUp({}); + return false; + } + this.position = ui.position; + } + + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + return false; + }, + + _mouseStop: function(event) { + + //If we are using droppables, inform the manager about the drop + var element, + that = this, + elementInDom = false, + dropped = false; + if ($.ui.ddmanager && !this.options.dropBehaviour) { + dropped = $.ui.ddmanager.drop(this, event); + } + + //if a drop comes from outside (a sortable) + if(this.dropped) { + dropped = this.dropped; + this.dropped = false; + } + + //if the original element is no longer in the DOM don't bother to continue (see #8269) + element = this.element[0]; + while ( element && (element = element.parentNode) ) { + if (element === document ) { + elementInDom = true; + } + } + if ( !elementInDom && this.options.helper === "original" ) { + return false; + } + + if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { + $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { + if(that._trigger("stop", event) !== false) { + that._clear(); + } + }); + } else { + if(this._trigger("stop", event) !== false) { + this._clear(); + } + } + + return false; + }, + + _mouseUp: function(event) { + //Remove frame helpers + $("div.ui-draggable-iframeFix").each(function() { + this.parentNode.removeChild(this); + }); + + //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) + if( $.ui.ddmanager ) { + $.ui.ddmanager.dragStop(this, event); + } + + return $.ui.mouse.prototype._mouseUp.call(this, event); + }, + + cancel: function() { + + if(this.helper.is(".ui-draggable-dragging")) { + this._mouseUp({}); + } else { + this._clear(); + } + + return this; + + }, + + _getHandle: function(event) { + + var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false; + $(this.options.handle, this.element) + .find("*") + .addBack() + .each(function() { + if(this === event.target) { + handle = true; + } + }); + + return handle; + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); + + if(!helper.parents("body").length) { + helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); + } + + if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { + helper.css("position", "absolute"); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + //This needs to be actually done for all browsers, since pageX/pageY includes this information + //Ugly IE fix + if((this.offsetParent[0] === document.body) || + (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.element.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.element.css("marginLeft"),10) || 0), + top: (parseInt(this.element.css("marginTop"),10) || 0), + right: (parseInt(this.element.css("marginRight"),10) || 0), + bottom: (parseInt(this.element.css("marginBottom"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var over, c, ce, + o = this.options; + + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, + o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, + (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) { + c = $(o.containment); + ce = c[0]; + + if(!ce) { + return; + } + + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), + (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, + (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom + ]; + this.relative_container = c; + + } else if(o.containment.constructor === Array) { + this.containment = o.containment; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var containment, co, top, left, + o = this.options, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName), + pageX = event.pageX, + pageY = event.pageY; + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + if(this.containment) { + if (this.relative_container){ + co = this.relative_container.offset(); + containment = [ this.containment[0] + co.left, + this.containment[1] + co.top, + this.containment[2] + co.left, + this.containment[3] + co.top ]; + } + else { + containment = this.containment; + } + + if(event.pageX - this.offset.click.left < containment[0]) { + pageX = containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < containment[1]) { + pageY = containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > containment[2]) { + pageX = containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > containment[3]) { + pageY = containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) + top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; + pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; + pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _clear: function() { + this.helper.removeClass("ui-draggable-dragging"); + if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { + this.helper.remove(); + } + this.helper = null; + this.cancelHelperRemoval = false; + }, + + // From now on bulk stuff - mainly helpers + + _trigger: function(type, event, ui) { + ui = ui || this._uiHash(); + $.ui.plugin.call(this, type, [event, ui]); + //The absolute position has to be recalculated after plugins + if(type === "drag") { + this.positionAbs = this._convertPositionTo("absolute"); + } + return $.Widget.prototype._trigger.call(this, type, event, ui); + }, + + plugins: {}, + + _uiHash: function() { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs + }; + } + +}); + +$.ui.plugin.add("draggable", "connectToSortable", { + start: function(event, ui) { + + var inst = $(this).data("ui-draggable"), o = inst.options, + uiSortable = $.extend({}, ui, { item: inst.element }); + inst.sortables = []; + $(o.connectToSortable).each(function() { + var sortable = $.data(this, "ui-sortable"); + if (sortable && !sortable.options.disabled) { + inst.sortables.push({ + instance: sortable, + shouldRevert: sortable.options.revert + }); + sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). + sortable._trigger("activate", event, uiSortable); + } + }); + + }, + stop: function(event, ui) { + + //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper + var inst = $(this).data("ui-draggable"), + uiSortable = $.extend({}, ui, { item: inst.element }); + + $.each(inst.sortables, function() { + if(this.instance.isOver) { + + this.instance.isOver = 0; + + inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance + this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) + + //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" + if(this.shouldRevert) { + this.instance.options.revert = true; + } + + //Trigger the stop of the sortable + this.instance._mouseStop(event); + + this.instance.options.helper = this.instance.options._helper; + + //If the helper has been the original item, restore properties in the sortable + if(inst.options.helper === "original") { + this.instance.currentItem.css({ top: "auto", left: "auto" }); + } + + } else { + this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance + this.instance._trigger("deactivate", event, uiSortable); + } + + }); + + }, + drag: function(event, ui) { + + var inst = $(this).data("ui-draggable"), that = this; + + $.each(inst.sortables, function() { + + var innermostIntersecting = false, + thisSortable = this; + + //Copy over some variables to allow calling the sortable's native _intersectsWith + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + + if(this.instance._intersectsWith(this.instance.containerCache)) { + innermostIntersecting = true; + $.each(inst.sortables, function () { + this.instance.positionAbs = inst.positionAbs; + this.instance.helperProportions = inst.helperProportions; + this.instance.offset.click = inst.offset.click; + if (this !== thisSortable && + this.instance._intersectsWith(this.instance.containerCache) && + $.ui.contains(thisSortable.instance.element[0], this.instance.element[0]) + ) { + innermostIntersecting = false; + } + return innermostIntersecting; + }); + } + + + if(innermostIntersecting) { + //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once + if(!this.instance.isOver) { + + this.instance.isOver = 1; + //Now we fake the start of dragging for the sortable instance, + //by cloning the list group item, appending it to the sortable and using it as inst.currentItem + //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) + this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); + this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it + this.instance.options.helper = function() { return ui.helper[0]; }; + + event.target = this.instance.currentItem[0]; + this.instance._mouseCapture(event, true); + this.instance._mouseStart(event, true, true); + + //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes + this.instance.offset.click.top = inst.offset.click.top; + this.instance.offset.click.left = inst.offset.click.left; + this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; + this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; + + inst._trigger("toSortable", event); + inst.dropped = this.instance.element; //draggable revert needs that + //hack so receive/update callbacks work (mostly) + inst.currentItem = inst.element; + this.instance.fromOutside = inst; + + } + + //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable + if(this.instance.currentItem) { + this.instance._mouseDrag(event); + } + + } else { + + //If it doesn't intersect with the sortable, and it intersected before, + //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval + if(this.instance.isOver) { + + this.instance.isOver = 0; + this.instance.cancelHelperRemoval = true; + + //Prevent reverting on this forced stop + this.instance.options.revert = false; + + // The out event needs to be triggered independently + this.instance._trigger("out", event, this.instance._uiHash(this.instance)); + + this.instance._mouseStop(event, true); + this.instance.options.helper = this.instance.options._helper; + + //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size + this.instance.currentItem.remove(); + if(this.instance.placeholder) { + this.instance.placeholder.remove(); + } + + inst._trigger("fromSortable", event); + inst.dropped = false; //draggable revert needs that + } + + } + + }); + + } +}); + +$.ui.plugin.add("draggable", "cursor", { + start: function() { + var t = $("body"), o = $(this).data("ui-draggable").options; + if (t.css("cursor")) { + o._cursor = t.css("cursor"); + } + t.css("cursor", o.cursor); + }, + stop: function() { + var o = $(this).data("ui-draggable").options; + if (o._cursor) { + $("body").css("cursor", o._cursor); + } + } +}); + +$.ui.plugin.add("draggable", "opacity", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("opacity")) { + o._opacity = t.css("opacity"); + } + t.css("opacity", o.opacity); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._opacity) { + $(ui.helper).css("opacity", o._opacity); + } + } +}); + +$.ui.plugin.add("draggable", "scroll", { + start: function() { + var i = $(this).data("ui-draggable"); + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + i.overflowOffset = i.scrollParent.offset(); + } + }, + drag: function( event ) { + + var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; + + if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { + + if(!o.axis || o.axis !== "x") { + if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { + i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; + } + } + + if(!o.axis || o.axis !== "y") { + if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { + i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; + } + } + + } else { + + if(!o.axis || o.axis !== "x") { + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + } + + if(!o.axis || o.axis !== "y") { + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(i, event); + } + + } +}); + +$.ui.plugin.add("draggable", "snap", { + start: function() { + + var i = $(this).data("ui-draggable"), + o = i.options; + + i.snapElements = []; + + $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { + var $t = $(this), + $o = $t.offset(); + if(this !== i.element[0]) { + i.snapElements.push({ + item: this, + width: $t.outerWidth(), height: $t.outerHeight(), + top: $o.top, left: $o.left + }); + } + }); + + }, + drag: function(event, ui) { + + var ts, bs, ls, rs, l, r, t, b, i, first, + inst = $(this).data("ui-draggable"), + o = inst.options, + d = o.snapTolerance, + x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, + y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; + + for (i = inst.snapElements.length - 1; i >= 0; i--){ + + l = inst.snapElements[i].left; + r = l + inst.snapElements[i].width; + t = inst.snapElements[i].top; + b = t + inst.snapElements[i].height; + + //Yes, I know, this is insane ;) + if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { + if(inst.snapElements[i].snapping) { + (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = false; + continue; + } + + if(o.snapMode !== "inner") { + ts = Math.abs(t - y2) <= d; + bs = Math.abs(b - y1) <= d; + ls = Math.abs(l - x2) <= d; + rs = Math.abs(r - x1) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; + } + } + + first = (ts || bs || ls || rs); + + if(o.snapMode !== "outer") { + ts = Math.abs(t - y1) <= d; + bs = Math.abs(b - y2) <= d; + ls = Math.abs(l - x1) <= d; + rs = Math.abs(r - x2) <= d; + if(ts) { + ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; + } + if(bs) { + ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; + } + if(ls) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; + } + if(rs) { + ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; + } + } + + if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { + (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); + } + inst.snapElements[i].snapping = (ts || bs || ls || rs || first); + + } + + } +}); + +$.ui.plugin.add("draggable", "stack", { + start: function() { + + var min, + o = $(this).data("ui-draggable").options, + group = $.makeArray($(o.stack)).sort(function(a,b) { + return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); + }); + + if (!group.length) { return; } + + min = parseInt(group[0].style.zIndex, 10) || 0; + $(group).each(function(i) { + this.style.zIndex = min + i; + }); + + this[0].style.zIndex = min + group.length; + + } +}); + +$.ui.plugin.add("draggable", "zIndex", { + start: function(event, ui) { + var t = $(ui.helper), o = $(this).data("ui-draggable").options; + if(t.css("zIndex")) { + o._zIndex = t.css("zIndex"); + } + t.css("zIndex", o.zIndex); + }, + stop: function(event, ui) { + var o = $(this).data("ui-draggable").options; + if(o._zIndex) { + $(ui.helper).css("zIndex", o._zIndex); + } + } +}); + +})(jQuery); +(function( $, undefined ) { + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +$.widget("ui.droppable", { + version: "1.10.0", + widgetEventPrefix: "drop", + options: { + accept: "*", + activeClass: false, + addClasses: true, + greedy: false, + hoverClass: false, + scope: "default", + tolerance: "intersect", + + // callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = $.isFunction(accept) ? accept : function(d) { + return d.is(accept); + }; + + //Store the droppable's proportions + this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; + $.ui.ddmanager.droppables[o.scope].push(this); + + (o.addClasses && this.element.addClass("ui-droppable")); + + }, + + _destroy: function() { + var i = 0, + drop = $.ui.ddmanager.droppables[this.options.scope]; + + for ( ; i < drop.length; i++ ) { + if ( drop[i] === this ) { + drop.splice(i, 1); + } + } + + this.element.removeClass("ui-droppable ui-droppable-disabled"); + }, + + _setOption: function(key, value) { + + if(key === "accept") { + this.accept = $.isFunction(value) ? value : function(d) { + return d.is(value); + }; + } + $.Widget.prototype._setOption.apply(this, arguments); + }, + + _activate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.addClass(this.options.activeClass); + } + if(draggable){ + this._trigger("activate", event, this.ui(draggable)); + } + }, + + _deactivate: function(event) { + var draggable = $.ui.ddmanager.current; + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(draggable){ + this._trigger("deactivate", event, this.ui(draggable)); + } + }, + + _over: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.addClass(this.options.hoverClass); + } + this._trigger("over", event, this.ui(draggable)); + } + + }, + + _out: function(event) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return; + } + + if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("out", event, this.ui(draggable)); + } + + }, + + _drop: function(event,custom) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { + return false; + } + + this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { + var inst = $.data(this, "ui-droppable"); + if( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && + $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) + ) { childrenIntersection = true; return false; } + }); + if(childrenIntersection) { + return false; + } + + if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + if(this.options.activeClass) { + this.element.removeClass(this.options.activeClass); + } + if(this.options.hoverClass) { + this.element.removeClass(this.options.hoverClass); + } + this._trigger("drop", event, this.ui(draggable)); + return this.element; + } + + return false; + + }, + + ui: function(c) { + return { + draggable: (c.currentItem || c.element), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + } + +}); + +$.ui.intersect = function(draggable, droppable, toleranceMode) { + + if (!droppable.offset) { + return false; + } + + var draggableLeft, draggableTop, + x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, + y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, r = l + droppable.proportions.width, + t = droppable.offset.top, b = t + droppable.proportions.height; + + switch (toleranceMode) { + case "fit": + return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); + case "intersect": + return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half + x2 - (draggable.helperProportions.width / 2) < r && // Left Half + t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half + y2 - (draggable.helperProportions.height / 2) < b ); // Top Half + case "pointer": + draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); + draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); + return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); + case "touch": + return ( + (y1 >= t && y1 <= b) || // Top edge touching + (y2 >= t && y2 <= b) || // Bottom edge touching + (y1 < t && y2 > b) // Surrounded vertically + ) && ( + (x1 >= l && x1 <= r) || // Left edge touching + (x2 >= l && x2 <= r) || // Right edge touching + (x1 < l && x2 > r) // Surrounded horizontally + ); + default: + return false; + } + +}; + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function(t, event) { + + var i, j, + m = $.ui.ddmanager.droppables[t.options.scope] || [], + type = event ? event.type : null, // workaround for #2317 + list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); + + droppablesLoop: for (i = 0; i < m.length; i++) { + + //No disabled and non-accepted + if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { + continue; + } + + // Filter out elements in the current dragged item + for (j=0; j < list.length; j++) { + if(list[j] === m[i].element[0]) { + m[i].proportions.height = 0; + continue droppablesLoop; + } + } + + m[i].visible = m[i].element.css("display") !== "none"; + if(!m[i].visible) { + continue; + } + + //Activate the droppable if used directly from draggables + if(type === "mousedown") { + m[i]._activate.call(m[i], event); + } + + m[i].offset = m[i].element.offset(); + m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; + + } + + }, + drop: function(draggable, event) { + + var dropped = false; + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + + if(!this.options) { + return; + } + if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { + dropped = this._drop.call(this, event) || dropped; + } + + if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { + this.isout = true; + this.isover = false; + this._deactivate.call(this, event); + } + + }); + return dropped; + + }, + dragStart: function( draggable, event ) { + //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + }); + }, + drag: function(draggable, event) { + + //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. + if(draggable.options.refreshPositions) { + $.ui.ddmanager.prepareOffsets(draggable, event); + } + + //Run through all droppables and check their positions based on specific tolerance options + $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { + + if(this.options.disabled || this.greedyChild || !this.visible) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect(draggable, this, this.options.tolerance), + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + if(!c) { + return; + } + + if (this.options.greedy) { + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents(":data(ui-droppable)").filter(function () { + return $.data(this, "ui-droppable").options.scope === scope; + }); + + if (parent.length) { + parentInstance = $.data(parent[0], "ui-droppable"); + parentInstance.greedyChild = (c === "isover"); + } + } + + // we just moved into a greedy child + if (parentInstance && c === "isover") { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call(parentInstance, event); + } + + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + this[c === "isover" ? "_over" : "_out"].call(this, event); + + // we just moved out of a greedy child + if (parentInstance && c === "isout") { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call(parentInstance, event); + } + }); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); + //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) + if( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +})(jQuery); +(function( $, undefined ) { + +function num(v) { + return parseInt(v, 10) || 0; +} + +function isNumber(value) { + return !isNaN(parseInt(value, 10)); +} + +$.widget("ui.resizable", $.ui.mouse, { + version: "1.10.0", + widgetEventPrefix: "resize", + options: { + alsoResize: false, + animate: false, + animateDuration: "slow", + animateEasing: "swing", + aspectRatio: false, + autoHide: false, + containment: false, + ghost: false, + grid: false, + handles: "e,s,se", + helper: false, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + // See #7960 + zIndex: 90, + + // callbacks + resize: null, + start: null, + stop: null + }, + _create: function() { + + var n, i, handle, axis, hname, + that = this, + o = this.options; + this.element.addClass("ui-resizable"); + + $.extend(this, { + _aspectRatio: !!(o.aspectRatio), + aspectRatio: o.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null + }); + + //Wrap the element if it cannot hold child nodes + if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { + + //Create a wrapper element and set the wrapper to the new current internal element + this.element.wrap( + $("
").css({ + position: this.element.css("position"), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css("top"), + left: this.element.css("left") + }) + ); + + //Overwrite the original this.element + this.element = this.element.parent().data( + "ui-resizable", this.element.data("ui-resizable") + ); + + this.elementIsWrapper = true; + + //Move margins to the wrapper + this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); + this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); + + //Prevent Safari textarea resize + this.originalResizeStyle = this.originalElement.css("resize"); + this.originalElement.css("resize", "none"); + + //Push the actual element to our proportionallyResize internal array + this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); + + // avoid IE jump (hard set the margin) + this.originalElement.css({ margin: this.originalElement.css("margin") }); + + // fix handlers offset + this._proportionallyResize(); + + } + + this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); + if(this.handles.constructor === String) { + + if ( this.handles === "all") { + this.handles = "n,e,s,w,se,sw,ne,nw"; + } + + n = this.handles.split(","); + this.handles = {}; + + for(i = 0; i < n.length; i++) { + + handle = $.trim(n[i]); + hname = "ui-resizable-"+handle; + axis = $("
"); + + // Apply zIndex to all handles - see #7960 + axis.css({ zIndex: o.zIndex }); + + //TODO : What's going on here? + if ("se" === handle) { + axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); + } + + //Insert into internal handles object and append to element + this.handles[handle] = ".ui-resizable-"+handle; + this.element.append(axis); + } + + } + + this._renderAxis = function(target) { + + var i, axis, padPos, padWrapper; + + target = target || this.element; + + for(i in this.handles) { + + if(this.handles[i].constructor === String) { + this.handles[i] = $(this.handles[i], this.element).show(); + } + + //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) + if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { + + axis = $(this.handles[i], this.element); + + //Checking the correct pad and border + padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); + + //The padding type i have to apply... + padPos = [ "padding", + /ne|nw|n/.test(i) ? "Top" : + /se|sw|s/.test(i) ? "Bottom" : + /^e$/.test(i) ? "Right" : "Left" ].join(""); + + target.css(padPos, padWrapper); + + this._proportionallyResize(); + + } + + //TODO: What's that good for? There's not anything to be executed left + if(!$(this.handles[i]).length) { + continue; + } + } + }; + + //TODO: make renderAxis a prototype function + this._renderAxis(this.element); + + this._handles = $(".ui-resizable-handle", this.element) + .disableSelection(); + + //Matching axis name + this._handles.mouseover(function() { + if (!that.resizing) { + if (this.className) { + axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); + } + //Axis, default = se + that.axis = axis && axis[1] ? axis[1] : "se"; + } + }); + + //If we want to auto hide the elements + if (o.autoHide) { + this._handles.hide(); + $(this.element) + .addClass("ui-resizable-autohide") + .mouseenter(function() { + if (o.disabled) { + return; + } + $(this).removeClass("ui-resizable-autohide"); + that._handles.show(); + }) + .mouseleave(function(){ + if (o.disabled) { + return; + } + if (!that.resizing) { + $(this).addClass("ui-resizable-autohide"); + that._handles.hide(); + } + }); + } + + //Initialize the mouse interaction + this._mouseInit(); + + }, + + _destroy: function() { + + this._mouseDestroy(); + + var wrapper, + _destroy = function(exp) { + $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") + .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); + }; + + //TODO: Unwrap at same DOM position + if (this.elementIsWrapper) { + _destroy(this.element); + wrapper = this.element; + this.originalElement.css({ + position: wrapper.css("position"), + width: wrapper.outerWidth(), + height: wrapper.outerHeight(), + top: wrapper.css("top"), + left: wrapper.css("left") + }).insertAfter( wrapper ); + wrapper.remove(); + } + + this.originalElement.css("resize", this.originalResizeStyle); + _destroy(this.originalElement); + + return this; + }, + + _mouseCapture: function(event) { + var i, handle, + capture = false; + + for (i in this.handles) { + handle = $(this.handles[i])[0]; + if (handle === event.target || $.contains(handle, event.target)) { + capture = true; + } + } + + return !this.options.disabled && capture; + }, + + _mouseStart: function(event) { + + var curleft, curtop, cursor, + o = this.options, + iniPos = this.element.position(), + el = this.element; + + this.resizing = true; + + // bugfix for http://dev.jquery.com/ticket/1749 + if ( (/absolute/).test( el.css("position") ) ) { + el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); + } else if (el.is(".ui-draggable")) { + el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); + } + + this._renderProxy(); + + curleft = num(this.helper.css("left")); + curtop = num(this.helper.css("top")); + + if (o.containment) { + curleft += $(o.containment).scrollLeft() || 0; + curtop += $(o.containment).scrollTop() || 0; + } + + //Store needed variables + this.offset = this.helper.offset(); + this.position = { left: curleft, top: curtop }; + this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; + this.originalPosition = { left: curleft, top: curtop }; + this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; + this.originalMousePosition = { left: event.pageX, top: event.pageY }; + + //Aspect Ratio + this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); + + cursor = $(".ui-resizable-" + this.axis).css("cursor"); + $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); + + el.addClass("ui-resizable-resizing"); + this._propagate("start", event); + return true; + }, + + _mouseDrag: function(event) { + + //Increase performance, avoid regex + var data, + el = this.helper, props = {}, + smp = this.originalMousePosition, + a = this.axis, + prevTop = this.position.top, + prevLeft = this.position.left, + prevWidth = this.size.width, + prevHeight = this.size.height, + dx = (event.pageX-smp.left)||0, + dy = (event.pageY-smp.top)||0, + trigger = this._change[a]; + + if (!trigger) { + return false; + } + + // Calculate the attrs that will be change + data = trigger.apply(this, [event, dx, dy]); + + // Put this in the mouseDrag handler since the user can start pressing shift while resizing + this._updateVirtualBoundaries(event.shiftKey); + if (this._aspectRatio || event.shiftKey) { + data = this._updateRatio(data, event); + } + + data = this._respectSize(data, event); + + this._updateCache(data); + + // plugins callbacks need to be called first + this._propagate("resize", event); + + if (this.position.top !== prevTop) { + props.top = this.position.top + "px"; + } + if (this.position.left !== prevLeft) { + props.left = this.position.left + "px"; + } + if (this.size.width !== prevWidth) { + props.width = this.size.width + "px"; + } + if (this.size.height !== prevHeight) { + props.height = this.size.height + "px"; + } + el.css(props); + + if (!this._helper && this._proportionallyResizeElements.length) { + this._proportionallyResize(); + } + + // Call the user callback if the element was resized + if ( ! $.isEmptyObject(props) ) { + this._trigger("resize", event, this.ui()); + } + + return false; + }, + + _mouseStop: function(event) { + + this.resizing = false; + var pr, ista, soffseth, soffsetw, s, left, top, + o = this.options, that = this; + + if(this._helper) { + + pr = this._proportionallyResizeElements; + ista = pr.length && (/textarea/i).test(pr[0].nodeName); + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; + soffsetw = ista ? 0 : that.sizeDiff.width; + + s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + if (!o.animate) { + this.element.css($.extend(s, { top: top, left: left })); + } + + that.helper.height(that.size.height); + that.helper.width(that.size.width); + + if (this._helper && !o.animate) { + this._proportionallyResize(); + } + } + + $("body").css("cursor", "auto"); + + this.element.removeClass("ui-resizable-resizing"); + + this._propagate("stop", event); + + if (this._helper) { + this.helper.remove(); + } + + return false; + + }, + + _updateVirtualBoundaries: function(forceAspectRatio) { + var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, + o = this.options; + + b = { + minWidth: isNumber(o.minWidth) ? o.minWidth : 0, + maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, + minHeight: isNumber(o.minHeight) ? o.minHeight : 0, + maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity + }; + + if(this._aspectRatio || forceAspectRatio) { + // We want to create an enclosing box whose aspect ration is the requested one + // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension + pMinWidth = b.minHeight * this.aspectRatio; + pMinHeight = b.minWidth / this.aspectRatio; + pMaxWidth = b.maxHeight * this.aspectRatio; + pMaxHeight = b.maxWidth / this.aspectRatio; + + if(pMinWidth > b.minWidth) { + b.minWidth = pMinWidth; + } + if(pMinHeight > b.minHeight) { + b.minHeight = pMinHeight; + } + if(pMaxWidth < b.maxWidth) { + b.maxWidth = pMaxWidth; + } + if(pMaxHeight < b.maxHeight) { + b.maxHeight = pMaxHeight; + } + } + this._vBoundaries = b; + }, + + _updateCache: function(data) { + this.offset = this.helper.offset(); + if (isNumber(data.left)) { + this.position.left = data.left; + } + if (isNumber(data.top)) { + this.position.top = data.top; + } + if (isNumber(data.height)) { + this.size.height = data.height; + } + if (isNumber(data.width)) { + this.size.width = data.width; + } + }, + + _updateRatio: function( data ) { + + var cpos = this.position, + csize = this.size, + a = this.axis; + + if (isNumber(data.height)) { + data.width = (data.height * this.aspectRatio); + } else if (isNumber(data.width)) { + data.height = (data.width / this.aspectRatio); + } + + if (a === "sw") { + data.left = cpos.left + (csize.width - data.width); + data.top = null; + } + if (a === "nw") { + data.top = cpos.top + (csize.height - data.height); + data.left = cpos.left + (csize.width - data.width); + } + + return data; + }, + + _respectSize: function( data ) { + + var o = this._vBoundaries, + a = this.axis, + ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), + isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), + dw = this.originalPosition.left + this.originalSize.width, + dh = this.position.top + this.size.height, + cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); + if (isminw) { + data.width = o.minWidth; + } + if (isminh) { + data.height = o.minHeight; + } + if (ismaxw) { + data.width = o.maxWidth; + } + if (ismaxh) { + data.height = o.maxHeight; + } + + if (isminw && cw) { + data.left = dw - o.minWidth; + } + if (ismaxw && cw) { + data.left = dw - o.maxWidth; + } + if (isminh && ch) { + data.top = dh - o.minHeight; + } + if (ismaxh && ch) { + data.top = dh - o.maxHeight; + } + + // fixing jump error on top/left - bug #2330 + if (!data.width && !data.height && !data.left && data.top) { + data.top = null; + } else if (!data.width && !data.height && !data.top && data.left) { + data.left = null; + } + + return data; + }, + + _proportionallyResize: function() { + + if (!this._proportionallyResizeElements.length) { + return; + } + + var i, j, borders, paddings, prel, + element = this.helper || this.element; + + for ( i=0; i < this._proportionallyResizeElements.length; i++) { + + prel = this._proportionallyResizeElements[i]; + + if (!this.borderDif) { + this.borderDif = []; + borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; + paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; + + for ( j = 0; j < borders.length; j++ ) { + this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); + } + } + + prel.css({ + height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, + width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 + }); + + } + + }, + + _renderProxy: function() { + + var el = this.element, o = this.options; + this.elementOffset = el.offset(); + + if(this._helper) { + + this.helper = this.helper || $("
"); + + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: "absolute", + left: this.elementOffset.left +"px", + top: this.elementOffset.top +"px", + zIndex: ++o.zIndex //TODO: Don't modify option + }); + + this.helper + .appendTo("body") + .disableSelection(); + + } else { + this.helper = this.element; + } + + }, + + _change: { + e: function(event, dx) { + return { width: this.originalSize.width + dx }; + }, + w: function(event, dx) { + var cs = this.originalSize, sp = this.originalPosition; + return { left: sp.left + dx, width: cs.width - dx }; + }, + n: function(event, dx, dy) { + var cs = this.originalSize, sp = this.originalPosition; + return { top: sp.top + dy, height: cs.height - dy }; + }, + s: function(event, dx, dy) { + return { height: this.originalSize.height + dy }; + }, + se: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + sw: function(event, dx, dy) { + return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + }, + ne: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); + }, + nw: function(event, dx, dy) { + return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); + } + }, + + _propagate: function(n, event) { + $.ui.plugin.call(this, n, [event, this.ui()]); + (n !== "resize" && this._trigger(n, event, this.ui())); + }, + + plugins: {}, + + ui: function() { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition + }; + } + +}); + +/* + * Resizable Extensions + */ + +$.ui.plugin.add("resizable", "animate", { + + stop: function( event ) { + var that = $(this).data("ui-resizable"), + o = that.options, + pr = that._proportionallyResizeElements, + ista = pr.length && (/textarea/i).test(pr[0].nodeName), + soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, + soffsetw = ista ? 0 : that.sizeDiff.width, + style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, + left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, + top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; + + that.element.animate( + $.extend(style, top && left ? { top: top, left: left } : {}), { + duration: o.animateDuration, + easing: o.animateEasing, + step: function() { + + var data = { + width: parseInt(that.element.css("width"), 10), + height: parseInt(that.element.css("height"), 10), + top: parseInt(that.element.css("top"), 10), + left: parseInt(that.element.css("left"), 10) + }; + + if (pr && pr.length) { + $(pr[0]).css({ width: data.width, height: data.height }); + } + + // propagating resize, and updating values for each animation step + that._updateCache(data); + that._propagate("resize", event); + + } + } + ); + } + +}); + +$.ui.plugin.add("resizable", "containment", { + + start: function() { + var element, p, co, ch, cw, width, height, + that = $(this).data("ui-resizable"), + o = that.options, + el = that.element, + oc = o.containment, + ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; + + if (!ce) { + return; + } + + that.containerElement = $(ce); + + if (/document/.test(oc) || oc === document) { + that.containerOffset = { left: 0, top: 0 }; + that.containerPosition = { left: 0, top: 0 }; + + that.parentData = { + element: $(document), left: 0, top: 0, + width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight + }; + } + + // i'm a node, so compute top, left, right, bottom + else { + element = $(ce); + p = []; + $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); + + that.containerOffset = element.offset(); + that.containerPosition = element.position(); + that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; + + co = that.containerOffset; + ch = that.containerSize.height; + cw = that.containerSize.width; + width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); + height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); + + that.parentData = { + element: ce, left: co.left, top: co.top, width: width, height: height + }; + } + }, + + resize: function( event ) { + var woset, hoset, isParent, isOffsetRelative, + that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, cp = that.position, + pRatio = that._aspectRatio || event.shiftKey, + cop = { top:0, left:0 }, ce = that.containerElement; + + if (ce[0] !== document && (/static/).test(ce.css("position"))) { + cop = co; + } + + if (cp.left < (that._helper ? co.left : 0)) { + that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + that.position.left = o.helper ? co.left : 0; + } + + if (cp.top < (that._helper ? co.top : 0)) { + that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + that.position.top = that._helper ? co.top : 0; + } + + that.offset.left = that.parentData.left+that.position.left; + that.offset.top = that.parentData.top+that.position.top; + + woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); + hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); + + isParent = that.containerElement.get(0) === that.element.parent().get(0); + isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); + + if(isParent && isOffsetRelative) { + woset -= that.parentData.left; + } + + if (woset + that.size.width >= that.parentData.width) { + that.size.width = that.parentData.width - woset; + if (pRatio) { + that.size.height = that.size.width / that.aspectRatio; + } + } + + if (hoset + that.size.height >= that.parentData.height) { + that.size.height = that.parentData.height - hoset; + if (pRatio) { + that.size.width = that.size.height * that.aspectRatio; + } + } + }, + + stop: function(){ + var that = $(this).data("ui-resizable"), + o = that.options, + co = that.containerOffset, + cop = that.containerPosition, + ce = that.containerElement, + helper = $(that.helper), + ho = helper.offset(), + w = helper.outerWidth() - that.sizeDiff.width, + h = helper.outerHeight() - that.sizeDiff.height; + + if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { + $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); + } + + } +}); + +$.ui.plugin.add("resizable", "alsoResize", { + + start: function () { + var that = $(this).data("ui-resizable"), + o = that.options, + _store = function (exp) { + $(exp).each(function() { + var el = $(this); + el.data("ui-resizable-alsoresize", { + width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), + left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) + }); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { + if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } + else { $.each(o.alsoResize, function (exp) { _store(exp); }); } + }else{ + _store(o.alsoResize); + } + }, + + resize: function (event, ui) { + var that = $(this).data("ui-resizable"), + o = that.options, + os = that.originalSize, + op = that.originalPosition, + delta = { + height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, + top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 + }, + + _alsoResize = function (exp, c) { + $(exp).each(function() { + var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, + css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; + + $.each(css, function (i, prop) { + var sum = (start[prop]||0) + (delta[prop]||0); + if (sum && sum >= 0) { + style[prop] = sum || null; + } + }); + + el.css(style); + }); + }; + + if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { + $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); + }else{ + _alsoResize(o.alsoResize); + } + }, + + stop: function () { + $(this).removeData("resizable-alsoresize"); + } +}); + +$.ui.plugin.add("resizable", "ghost", { + + start: function() { + + var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; + + that.ghost = that.originalElement.clone(); + that.ghost + .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) + .addClass("ui-resizable-ghost") + .addClass(typeof o.ghost === "string" ? o.ghost : ""); + + that.ghost.appendTo(that.helper); + + }, + + resize: function(){ + var that = $(this).data("ui-resizable"); + if (that.ghost) { + that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); + } + }, + + stop: function() { + var that = $(this).data("ui-resizable"); + if (that.ghost && that.helper) { + that.helper.get(0).removeChild(that.ghost.get(0)); + } + } + +}); + +$.ui.plugin.add("resizable", "grid", { + + resize: function() { + var that = $(this).data("ui-resizable"), + o = that.options, + cs = that.size, + os = that.originalSize, + op = that.originalPosition, + a = that.axis, + grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, + gridX = (grid[0]||1), + gridY = (grid[1]||1), + ox = Math.round((cs.width - os.width) / gridX) * gridX, + oy = Math.round((cs.height - os.height) / gridY) * gridY, + newWidth = os.width + ox, + newHeight = os.height + oy, + isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), + isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), + isMinWidth = o.minWidth && (o.minWidth > newWidth), + isMinHeight = o.minHeight && (o.minHeight > newHeight); + + o.grid = grid; + + if (isMinWidth) { + newWidth = newWidth + gridX; + } + if (isMinHeight) { + newHeight = newHeight + gridY; + } + if (isMaxWidth) { + newWidth = newWidth - gridX; + } + if (isMaxHeight) { + newHeight = newHeight - gridY; + } + + if (/^(se|s|e)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + } else if (/^(ne)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + } else if (/^(sw)$/.test(a)) { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.left = op.left - ox; + } else { + that.size.width = newWidth; + that.size.height = newHeight; + that.position.top = op.top - oy; + that.position.left = op.left - ox; + } + } + +}); + +})(jQuery); +(function( $, undefined ) { + +$.widget("ui.selectable", $.ui.mouse, { + version: "1.10.0", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var selectees, + that = this; + + this.element.addClass("ui-selectable"); + + this.dragged = false; + + // cache selectee children based on filter + this.refresh = function() { + selectees = $(that.options.filter, that.element[0]); + selectees.addClass("ui-selectee"); + selectees.each(function() { + var $this = $(this), + pos = $this.offset(); + $.data(this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass("ui-selected"), + selecting: $this.hasClass("ui-selecting"), + unselecting: $this.hasClass("ui-unselecting") + }); + }); + }; + this.refresh(); + + this.selectees = selectees.addClass("ui-selectee"); + + this._mouseInit(); + + this.helper = $("
"); + }, + + _destroy: function() { + this.selectees + .removeClass("ui-selectee") + .removeData("selectable-item"); + this.element + .removeClass("ui-selectable ui-selectable-disabled"); + this._mouseDestroy(); + }, + + _mouseStart: function(event) { + var that = this, + options = this.options; + + this.opos = [event.pageX, event.pageY]; + + if (this.options.disabled) { + return; + } + + this.selectees = $(options.filter, this.element[0]); + + this._trigger("start", event); + + $(options.appendTo).append(this.helper); + // position helper (lasso) + this.helper.css({ + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + }); + + if (options.autoRefresh) { + this.refresh(); + } + + this.selectees.filter(".ui-selected").each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.startselected = true; + if (!event.metaKey && !event.ctrlKey) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + }); + + $(event.target).parents().addBack().each(function() { + var doSelect, + selectee = $.data(this, "selectable-item"); + if (selectee) { + doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); + selectee.$element + .removeClass(doSelect ? "ui-unselecting" : "ui-selected") + .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + // selectable (UN)SELECTING callback + if (doSelect) { + that._trigger("selecting", event, { + selecting: selectee.element + }); + } else { + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + return false; + } + }); + + }, + + _mouseDrag: function(event) { + + this.dragged = true; + + if (this.options.disabled) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[0], + y1 = this.opos[1], + x2 = event.pageX, + y2 = event.pageY; + + if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } + if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } + this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); + + this.selectees.each(function() { + var selectee = $.data(this, "selectable-item"), + hit = false; + + //prevent helper from being selected if appendTo: selectable + if (!selectee || selectee.element === that.element[0]) { + return; + } + + if (options.tolerance === "touch") { + hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); + } else if (options.tolerance === "fit") { + hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); + } + + if (hit) { + // SELECT + if (selectee.selected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + } + if (selectee.unselecting) { + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + } + if (!selectee.selecting) { + selectee.$element.addClass("ui-selecting"); + selectee.selecting = true; + // selectable SELECTING callback + that._trigger("selecting", event, { + selecting: selectee.element + }); + } + } else { + // UNSELECT + if (selectee.selecting) { + if ((event.metaKey || event.ctrlKey) && selectee.startselected) { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + selectee.$element.addClass("ui-selected"); + selectee.selected = true; + } else { + selectee.$element.removeClass("ui-selecting"); + selectee.selecting = false; + if (selectee.startselected) { + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + } + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + if (selectee.selected) { + if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { + selectee.$element.removeClass("ui-selected"); + selectee.selected = false; + + selectee.$element.addClass("ui-unselecting"); + selectee.unselecting = true; + // selectable UNSELECTING callback + that._trigger("unselecting", event, { + unselecting: selectee.element + }); + } + } + } + }); + + return false; + }, + + _mouseStop: function(event) { + var that = this; + + this.dragged = false; + + $(".ui-unselecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-unselecting"); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger("unselected", event, { + unselected: selectee.element + }); + }); + $(".ui-selecting", this.element[0]).each(function() { + var selectee = $.data(this, "selectable-item"); + selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger("selected", event, { + selected: selectee.element + }); + }); + this._trigger("stop", event); + + this.helper.remove(); + + return false; + } + +}); + +})(jQuery); +(function( $, undefined ) { + +/*jshint loopfunc: true */ + +function isOverAxis( x, reference, size ) { + return ( x > reference ) && ( x < ( reference + size ) ); +} + +$.widget("ui.sortable", $.ui.mouse, { + version: "1.10.0", + widgetEventPrefix: "sort", + ready: false, + options: { + appendTo: "parent", + axis: false, + connectWith: false, + containment: false, + cursor: "auto", + cursorAt: false, + dropOnEmpty: true, + forcePlaceholderSize: false, + forceHelperSize: false, + grid: false, + handle: false, + helper: "original", + items: "> *", + opacity: false, + placeholder: false, + revert: false, + scroll: true, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: "default", + tolerance: "intersect", + zIndex: 1000, + + // callbacks + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null + }, + _create: function() { + + var o = this.options; + this.containerCache = {}; + this.element.addClass("ui-sortable"); + + //Get the items + this.refresh(); + + //Let's determine if the items are being displayed horizontally + this.floating = this.items.length ? o.axis === "x" || (/left|right/).test(this.items[0].item.css("float")) || (/inline|table-cell/).test(this.items[0].item.css("display")) : false; + + //Let's determine the parent's offset + this.offset = this.element.offset(); + + //Initialize mouse events for interaction + this._mouseInit(); + + //We're ready to go + this.ready = true; + + }, + + _destroy: function() { + this.element + .removeClass("ui-sortable ui-sortable-disabled"); + this._mouseDestroy(); + + for ( var i = this.items.length - 1; i >= 0; i-- ) { + this.items[i].item.removeData(this.widgetName + "-item"); + } + + return this; + }, + + _setOption: function(key, value){ + if ( key === "disabled" ) { + this.options[ key ] = value; + + this.widget().toggleClass( "ui-sortable-disabled", !!value ); + } else { + // Don't call widget base _setOption for disable as it adds ui-state-disabled class + $.Widget.prototype._setOption.apply(this, arguments); + } + }, + + _mouseCapture: function(event, overrideHandle) { + var currentItem = null, + validHandle = false, + that = this; + + if (this.reverting) { + return false; + } + + if(this.options.disabled || this.options.type === "static") { + return false; + } + + //We have to refresh the items data once first + this._refreshItems(event); + + //Find out if the clicked node (or one of its parents) is a actual item in this.items + $(event.target).parents().each(function() { + if($.data(this, that.widgetName + "-item") === that) { + currentItem = $(this); + return false; + } + }); + if($.data(event.target, that.widgetName + "-item") === that) { + currentItem = $(event.target); + } + + if(!currentItem) { + return false; + } + if(this.options.handle && !overrideHandle) { + $(this.options.handle, currentItem).find("*").addBack().each(function() { + if(this === event.target) { + validHandle = true; + } + }); + if(!validHandle) { + return false; + } + } + + this.currentItem = currentItem; + this._removeCurrentsFromItems(); + return true; + + }, + + _mouseStart: function(event, overrideHandle, noActivation) { + + var i, + o = this.options; + + this.currentContainer = this; + + //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture + this.refreshPositions(); + + //Create and append the visible helper + this.helper = this._createHelper(event); + + //Cache the helper size + this._cacheHelperProportions(); + + /* + * - Position generation - + * This block generates everything position related - it's the core of draggables. + */ + + //Cache the margins of the original element + this._cacheMargins(); + + //Get the next scrolling parent + this.scrollParent = this.helper.scrollParent(); + + //The element's absolute position on the page minus margins + this.offset = this.currentItem.offset(); + this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left + }; + + $.extend(this.offset, { + click: { //Where the click happened, relative to the element + left: event.pageX - this.offset.left, + top: event.pageY - this.offset.top + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper + }); + + // Only after we got the offset, we can change the helper's position to absolute + // TODO: Still need to figure out a way to make relative sorting possible + this.helper.css("position", "absolute"); + this.cssPosition = this.helper.css("position"); + + //Generate the original position + this.originalPosition = this._generatePosition(event); + this.originalPageX = event.pageX; + this.originalPageY = event.pageY; + + //Adjust the mouse offset relative to the helper if "cursorAt" is supplied + (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); + + //Cache the former DOM position + this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; + + //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way + if(this.helper[0] !== this.currentItem[0]) { + this.currentItem.hide(); + } + + //Create the placeholder + this._createPlaceholder(); + + //Set a containment if given in the options + if(o.containment) { + this._setContainment(); + } + + if(o.cursor) { // cursor option + if ($("body").css("cursor")) { + this._storedCursor = $("body").css("cursor"); + } + $("body").css("cursor", o.cursor); + } + + if(o.opacity) { // opacity option + if (this.helper.css("opacity")) { + this._storedOpacity = this.helper.css("opacity"); + } + this.helper.css("opacity", o.opacity); + } + + if(o.zIndex) { // zIndex option + if (this.helper.css("zIndex")) { + this._storedZIndex = this.helper.css("zIndex"); + } + this.helper.css("zIndex", o.zIndex); + } + + //Prepare scrolling + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + this.overflowOffset = this.scrollParent.offset(); + } + + //Call callbacks + this._trigger("start", event, this._uiHash()); + + //Recache the helper size + if(!this._preserveHelperProportions) { + this._cacheHelperProportions(); + } + + + //Post "activate" events to possible containers + if( !noActivation ) { + for ( i = this.containers.length - 1; i >= 0; i-- ) { + this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); + } + } + + //Prepare possible droppables + if($.ui.ddmanager) { + $.ui.ddmanager.current = this; + } + + if ($.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + + this.dragging = true; + + this.helper.addClass("ui-sortable-helper"); + this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position + return true; + + }, + + _mouseDrag: function(event) { + var i, item, itemElement, intersection, + o = this.options, + scrolled = false; + + //Compute the helpers position + this.position = this._generatePosition(event); + this.positionAbs = this._convertPositionTo("absolute"); + + if (!this.lastPositionAbs) { + this.lastPositionAbs = this.positionAbs; + } + + //Do scrolling + if(this.options.scroll) { + if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { + + if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; + } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { + this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; + } + + if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; + } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { + this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; + } + + } else { + + if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); + } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { + scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); + } + + if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); + } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { + scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); + } + + } + + if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { + $.ui.ddmanager.prepareOffsets(this, event); + } + } + + //Regenerate the absolute position used for position checks + this.positionAbs = this._convertPositionTo("absolute"); + + //Set the helper position + if(!this.options.axis || this.options.axis !== "y") { + this.helper[0].style.left = this.position.left+"px"; + } + if(!this.options.axis || this.options.axis !== "x") { + this.helper[0].style.top = this.position.top+"px"; + } + + //Rearrange + for (i = this.items.length - 1; i >= 0; i--) { + + //Cache variables and intersection, continue if no intersection + item = this.items[i]; + itemElement = item.item[0]; + intersection = this._intersectsWithPointer(item); + if (!intersection) { + continue; + } + + // Only put the placeholder inside the current Container, skip all + // items form other containers. This works because when moving + // an item from one container to another the + // currentContainer is switched before the placeholder is moved. + // + // Without this moving items in "sub-sortables" can cause the placeholder to jitter + // beetween the outer and inner container. + if (item.instance !== this.currentContainer) { + continue; + } + + // cannot intersect with itself + // no useless actions that have been done before + // no action if the item moved is the parent of the item checked + if (itemElement !== this.currentItem[0] && + this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && + !$.contains(this.placeholder[0], itemElement) && + (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) + ) { + + this.direction = intersection === 1 ? "down" : "up"; + + if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { + this._rearrange(event, item); + } else { + break; + } + + this._trigger("change", event, this._uiHash()); + break; + } + } + + //Post events to containers + this._contactContainers(event); + + //Interconnect with droppables + if($.ui.ddmanager) { + $.ui.ddmanager.drag(this, event); + } + + //Call callbacks + this._trigger("sort", event, this._uiHash()); + + this.lastPositionAbs = this.positionAbs; + return false; + + }, + + _mouseStop: function(event, noPropagation) { + + if(!event) { + return; + } + + //If we are using droppables, inform the manager about the drop + if ($.ui.ddmanager && !this.options.dropBehaviour) { + $.ui.ddmanager.drop(this, event); + } + + if(this.options.revert) { + var that = this, + cur = this.placeholder.offset(); + + this.reverting = true; + + $(this.helper).animate({ + left: cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft), + top: cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop) + }, parseInt(this.options.revert, 10) || 500, function() { + that._clear(event); + }); + } else { + this._clear(event, noPropagation); + } + + return false; + + }, + + cancel: function() { + + if(this.dragging) { + + this._mouseUp({ target: null }); + + if(this.options.helper === "original") { + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + //Post deactivating events to containers + for (var i = this.containers.length - 1; i >= 0; i--){ + this.containers[i]._trigger("deactivate", null, this._uiHash(this)); + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", null, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + if (this.placeholder) { + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + if(this.placeholder[0].parentNode) { + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + } + if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { + this.helper.remove(); + } + + $.extend(this, { + helper: null, + dragging: false, + reverting: false, + _noFinalSort: null + }); + + if(this.domPosition.prev) { + $(this.domPosition.prev).after(this.currentItem); + } else { + $(this.domPosition.parent).prepend(this.currentItem); + } + } + + return this; + + }, + + serialize: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + str = []; + o = o || {}; + + $(items).each(function() { + var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); + if (res) { + str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); + } + }); + + if(!str.length && o.key) { + str.push(o.key + "="); + } + + return str.join("&"); + + }, + + toArray: function(o) { + + var items = this._getItemsAsjQuery(o && o.connected), + ret = []; + + o = o || {}; + + items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); + return ret; + + }, + + /* Be careful with the following core functions */ + _intersectsWith: function(item) { + + var x1 = this.positionAbs.left, + x2 = x1 + this.helperProportions.width, + y1 = this.positionAbs.top, + y2 = y1 + this.helperProportions.height, + l = item.left, + r = l + item.width, + t = item.top, + b = t + item.height, + dyClick = this.offset.click.top, + dxClick = this.offset.click.left, + isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; + + if ( this.options.tolerance === "pointer" || + this.options.forcePointerForContainers || + (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) + ) { + return isOverElement; + } else { + + return (l < x1 + (this.helperProportions.width / 2) && // Right Half + x2 - (this.helperProportions.width / 2) < r && // Left Half + t < y1 + (this.helperProportions.height / 2) && // Bottom Half + y2 - (this.helperProportions.height / 2) < b ); // Top Half + + } + }, + + _intersectsWithPointer: function(item) { + + var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), + isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), + isOverElement = isOverElementHeight && isOverElementWidth, + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (!isOverElement) { + return false; + } + + return this.floating ? + ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) + : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); + + }, + + _intersectsWithSides: function(item) { + + var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), + isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), + verticalDirection = this._getDragVerticalDirection(), + horizontalDirection = this._getDragHorizontalDirection(); + + if (this.floating && horizontalDirection) { + return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); + } else { + return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); + } + + }, + + _getDragVerticalDirection: function() { + var delta = this.positionAbs.top - this.lastPositionAbs.top; + return delta !== 0 && (delta > 0 ? "down" : "up"); + }, + + _getDragHorizontalDirection: function() { + var delta = this.positionAbs.left - this.lastPositionAbs.left; + return delta !== 0 && (delta > 0 ? "right" : "left"); + }, + + refresh: function(event) { + this._refreshItems(event); + this.refreshPositions(); + return this; + }, + + _connectWith: function() { + var options = this.options; + return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; + }, + + _getItemsAsjQuery: function(connected) { + + var i, j, cur, inst, + items = [], + queries = [], + connectWith = this._connectWith(); + + if(connectWith && connected) { + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for ( j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); + } + } + } + } + + queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); + + for (i = queries.length - 1; i >= 0; i--){ + queries[i][0].each(function() { + items.push(this); + }); + } + + return $(items); + + }, + + _removeCurrentsFromItems: function() { + + var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); + + this.items = $.grep(this.items, function (item) { + for (var j=0; j < list.length; j++) { + if(list[j] === item.item[0]) { + return false; + } + } + return true; + }); + + }, + + _refreshItems: function(event) { + + this.items = []; + this.containers = [this]; + + var i, j, cur, inst, targetData, _queries, item, queriesLength, + items = this.items, + queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], + connectWith = this._connectWith(); + + if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down + for (i = connectWith.length - 1; i >= 0; i--){ + cur = $(connectWith[i]); + for (j = cur.length - 1; j >= 0; j--){ + inst = $.data(cur[j], this.widgetFullName); + if(inst && inst !== this && !inst.options.disabled) { + queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); + this.containers.push(inst); + } + } + } + } + + for (i = queries.length - 1; i >= 0; i--) { + targetData = queries[i][1]; + _queries = queries[i][0]; + + for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { + item = $(_queries[j]); + + item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) + + items.push({ + item: item, + instance: targetData, + width: 0, height: 0, + left: 0, top: 0 + }); + } + } + + }, + + refreshPositions: function(fast) { + + //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change + if(this.offsetParent && this.helper) { + this.offset.parent = this._getParentOffset(); + } + + var i, item, t, p; + + for (i = this.items.length - 1; i >= 0; i--){ + item = this.items[i]; + + //We ignore calculating positions of all connected containers when we're not over them + if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { + continue; + } + + t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; + + if (!fast) { + item.width = t.outerWidth(); + item.height = t.outerHeight(); + } + + p = t.offset(); + item.left = p.left; + item.top = p.top; + } + + if(this.options.custom && this.options.custom.refreshContainers) { + this.options.custom.refreshContainers.call(this); + } else { + for (i = this.containers.length - 1; i >= 0; i--){ + p = this.containers[i].element.offset(); + this.containers[i].containerCache.left = p.left; + this.containers[i].containerCache.top = p.top; + this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); + this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); + } + } + + return this; + }, + + _createPlaceholder: function(that) { + that = that || this; + var className, + o = that.options; + + if(!o.placeholder || o.placeholder.constructor === String) { + className = o.placeholder; + o.placeholder = { + element: function() { + + var el = $(document.createElement(that.currentItem[0].nodeName)) + .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") + .removeClass("ui-sortable-helper")[0]; + + if(!className) { + el.style.visibility = "hidden"; + } + + return el; + }, + update: function(container, p) { + + // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that + // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified + if(className && !o.forcePlaceholderSize) { + return; + } + + //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item + if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } + if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } + } + }; + } + + //Create the placeholder + that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); + + //Append it after the actual current item + that.currentItem.after(that.placeholder); + + //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) + o.placeholder.update(that, that.placeholder); + + }, + + _contactContainers: function(event) { + var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, + innermostContainer = null, + innermostIndex = null; + + // get innermost container that intersects with item + for (i = this.containers.length - 1; i >= 0; i--) { + + // never consider a container that's located within the item itself + if($.contains(this.currentItem[0], this.containers[i].element[0])) { + continue; + } + + if(this._intersectsWith(this.containers[i].containerCache)) { + + // if we've already found a container and it's more "inner" than this, then continue + if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { + continue; + } + + innermostContainer = this.containers[i]; + innermostIndex = i; + + } else { + // container doesn't intersect. trigger "out" event if necessary + if(this.containers[i].containerCache.over) { + this.containers[i]._trigger("out", event, this._uiHash(this)); + this.containers[i].containerCache.over = 0; + } + } + + } + + // if no intersecting containers found, return + if(!innermostContainer) { + return; + } + + // move the item into the container if it's not there already + if(this.containers.length === 1) { + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } else { + + //When entering a new container, we will find the item with the least distance and append our item near it + dist = 10000; + itemWithLeastDistance = null; + posProperty = this.containers[innermostIndex].floating ? "left" : "top"; + sizeProperty = this.containers[innermostIndex].floating ? "width" : "height"; + base = this.positionAbs[posProperty] + this.offset.click[posProperty]; + for (j = this.items.length - 1; j >= 0; j--) { + if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { + continue; + } + if(this.items[j].item[0] === this.currentItem[0]) { + continue; + } + cur = this.items[j].item.offset()[posProperty]; + nearBottom = false; + if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ + nearBottom = true; + cur += this.items[j][sizeProperty]; + } + + if(Math.abs(cur - base) < dist) { + dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; + this.direction = nearBottom ? "up": "down"; + } + } + + //Check if dropOnEmpty is enabled + if(!itemWithLeastDistance && !this.options.dropOnEmpty) { + return; + } + + this.currentContainer = this.containers[innermostIndex]; + itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); + this._trigger("change", event, this._uiHash()); + this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); + + //Update the placeholder + this.options.placeholder.update(this.currentContainer, this.placeholder); + + this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); + this.containers[innermostIndex].containerCache.over = 1; + } + + + }, + + _createHelper: function(event) { + + var o = this.options, + helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); + + //Add the helper to the DOM if that didn't happen already + if(!helper.parents("body").length) { + $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); + } + + if(helper[0] === this.currentItem[0]) { + this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; + } + + if(!helper[0].style.width || o.forceHelperSize) { + helper.width(this.currentItem.width()); + } + if(!helper[0].style.height || o.forceHelperSize) { + helper.height(this.currentItem.height()); + } + + return helper; + + }, + + _adjustOffsetFromHelper: function(obj) { + if (typeof obj === "string") { + obj = obj.split(" "); + } + if ($.isArray(obj)) { + obj = {left: +obj[0], top: +obj[1] || 0}; + } + if ("left" in obj) { + this.offset.click.left = obj.left + this.margins.left; + } + if ("right" in obj) { + this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; + } + if ("top" in obj) { + this.offset.click.top = obj.top + this.margins.top; + } + if ("bottom" in obj) { + this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; + } + }, + + _getParentOffset: function() { + + + //Get the offsetParent and cache its position + this.offsetParent = this.helper.offsetParent(); + var po = this.offsetParent.offset(); + + // This is a special case where we need to modify a offset calculated on start, since the following happened: + // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent + // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that + // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag + if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { + po.left += this.scrollParent.scrollLeft(); + po.top += this.scrollParent.scrollTop(); + } + + // This needs to be actually done for all browsers, since pageX/pageY includes this information + // with an ugly IE fix + if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { + po = { top: 0, left: 0 }; + } + + return { + top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), + left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) + }; + + }, + + _getRelativeOffset: function() { + + if(this.cssPosition === "relative") { + var p = this.currentItem.position(); + return { + top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), + left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() + }; + } else { + return { top: 0, left: 0 }; + } + + }, + + _cacheMargins: function() { + this.margins = { + left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), + top: (parseInt(this.currentItem.css("marginTop"),10) || 0) + }; + }, + + _cacheHelperProportions: function() { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight() + }; + }, + + _setContainment: function() { + + var ce, co, over, + o = this.options; + if(o.containment === "parent") { + o.containment = this.helper[0].parentNode; + } + if(o.containment === "document" || o.containment === "window") { + this.containment = [ + 0 - this.offset.relative.left - this.offset.parent.left, + 0 - this.offset.relative.top - this.offset.parent.top, + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top + ]; + } + + if(!(/^(document|window|parent)$/).test(o.containment)) { + ce = $(o.containment)[0]; + co = $(o.containment).offset(); + over = ($(ce).css("overflow") !== "hidden"); + + this.containment = [ + co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, + co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, + co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, + co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top + ]; + } + + }, + + _convertPositionTo: function(d, pos) { + + if(!pos) { + pos = this.position; + } + var mod = d === "absolute" ? 1 : -1, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, + scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + return { + top: ( + pos.top + // The absolute mouse position + this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) + ), + left: ( + pos.left + // The absolute mouse position + this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) + ) + }; + + }, + + _generatePosition: function(event) { + + var top, left, + o = this.options, + pageX = event.pageX, + pageY = event.pageY, + scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); + + // This is another very weird special case that only happens for relative elements: + // 1. If the css position is relative + // 2. and the scroll parent is the document or similar to the offset parent + // we have to refresh the relative offset during the scroll so there are no jumps + if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { + this.offset.relative = this._getRelativeOffset(); + } + + /* + * - Position constraining - + * Constrain the position to a mix of grid, containment. + */ + + if(this.originalPosition) { //If we are not dragging yet, we won't check for options + + if(this.containment) { + if(event.pageX - this.offset.click.left < this.containment[0]) { + pageX = this.containment[0] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top < this.containment[1]) { + pageY = this.containment[1] + this.offset.click.top; + } + if(event.pageX - this.offset.click.left > this.containment[2]) { + pageX = this.containment[2] + this.offset.click.left; + } + if(event.pageY - this.offset.click.top > this.containment[3]) { + pageY = this.containment[3] + this.offset.click.top; + } + } + + if(o.grid) { + top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; + pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; + + left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; + pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; + } + + } + + return { + top: ( + pageY - // The absolute mouse position + this.offset.click.top - // Click offset (relative to the element) + this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.top + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) + ), + left: ( + pageX - // The absolute mouse position + this.offset.click.left - // Click offset (relative to the element) + this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent + this.offset.parent.left + // The offsetParent's offset without borders (offset + border) + ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) + ) + }; + + }, + + _rearrange: function(event, i, a, hardRefresh) { + + a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); + + //Various things done here to improve the performance: + // 1. we create a setTimeout, that calls refreshPositions + // 2. on the instance, we have a counter variable, that get's higher after every append + // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same + // 4. this lets only the last addition to the timeout stack through + this.counter = this.counter ? ++this.counter : 1; + var counter = this.counter; + + this._delay(function() { + if(counter === this.counter) { + this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove + } + }); + + }, + + _clear: function(event, noPropagation) { + + this.reverting = false; + // We delay all events that have to be triggered to after the point where the placeholder has been removed and + // everything else normalized again + var i, + delayedTriggers = []; + + // We first have to update the dom position of the actual currentItem + // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) + if(!this._noFinalSort && this.currentItem.parent().length) { + this.placeholder.before(this.currentItem); + } + this._noFinalSort = null; + + if(this.helper[0] === this.currentItem[0]) { + for(i in this._storedCSS) { + if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { + this._storedCSS[i] = ""; + } + } + this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); + } else { + this.currentItem.show(); + } + + if(this.fromOutside && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); + } + if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { + delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed + } + + // Check if the items Container has Changed and trigger appropriate + // events. + if (this !== this.currentContainer) { + if(!noPropagation) { + delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); + delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); + } + } + + + //Post events to containers + for (i = this.containers.length - 1; i >= 0; i--){ + if(!noPropagation) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + } + if(this.containers[i].containerCache.over) { + delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); + this.containers[i].containerCache.over = 0; + } + } + + //Do what was originally in plugins + if(this._storedCursor) { + $("body").css("cursor", this._storedCursor); + } + if(this._storedOpacity) { + this.helper.css("opacity", this._storedOpacity); + } + if(this._storedZIndex) { + this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); + } + + this.dragging = false; + if(this.cancelHelperRemoval) { + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return false; + } + + if(!noPropagation) { + this._trigger("beforeStop", event, this._uiHash()); + } + + //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! + this.placeholder[0].parentNode.removeChild(this.placeholder[0]); + + if(this.helper[0] !== this.currentItem[0]) { + this.helper.remove(); + } + this.helper = null; + + if(!noPropagation) { + for (i=0; i < delayedTriggers.length; i++) { + delayedTriggers[i].call(this, event); + } //Trigger all delayed events + this._trigger("stop", event, this._uiHash()); + } + + this.fromOutside = false; + return true; + + }, + + _trigger: function() { + if ($.Widget.prototype._trigger.apply(this, arguments) === false) { + this.cancel(); + } + }, + + _uiHash: function(_inst) { + var inst = _inst || this; + return { + helper: inst.helper, + placeholder: inst.placeholder || $([]), + position: inst.position, + originalPosition: inst.originalPosition, + offset: inst.positionAbs, + item: inst.currentItem, + sender: _inst ? _inst.element : null + }; + } + +}); + +})(jQuery); +(function( $, undefined ) { + +var uid = 0, + hideProps = {}, + showProps = {}; + +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; + +$.widget( "ui.accordion", { + version: "1.10.0", + options: { + active: 0, + animate: {}, + collapsible: false, + event: "click", + header: "> li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active" ) + .toggleClass( "ui-corner-all ui-corner-top" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + + this._trigger( "activate", null, data ); + } +}); + +})( jQuery ); +(function( $, undefined ) { + +// used to prevent race conditions with remote data sources +var requestIndex = 0; + +$.widget( "ui.autocomplete", { + version: "1.10.0", + defaultElement: "", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput; + + this.isMultiLine = this._isMultiLine(); + this.valueMethod = this.element[ this.element.is( "input,textarea" ) ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + event.preventDefault(); + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "
class="remove" style="visibility:hidden;" - ><?php echo $l->t('Delete'); ?>><?php echo $l->t('Delete'); ?>
" + + ""; + thead = (showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // days of the week + day = (dow + firstDay) % 7; + thead += "= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + + "" + dayNamesMin[day] + ""; + } + calender += thead + ""; + daysInMonth = this._getDaysInMonth(drawYear, drawMonth); + if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { + inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); + } + leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; + curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate + numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) + this.maxRows = numRows; + printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); + for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows + calender += ""; + tbody = (!showWeek ? "" : ""); + for (dow = 0; dow < 7; dow++) { // create date picker days + daySettings = (beforeShowDay ? + beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); + otherMonth = (printDate.getMonth() !== drawMonth); + unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || + (minDate && printDate < minDate) || (maxDate && printDate > maxDate); + tbody += ""; // display selectable date + printDate.setDate(printDate.getDate() + 1); + printDate = this._daylightSavingAdjust(printDate); + } + calender += tbody + ""; + } + drawMonth++; + if (drawMonth > 11) { + drawMonth = 0; + drawYear++; + } + calender += "
" + this._get(inst, "weekHeader") + "
" + + this._get(inst, "calculateWeek")(printDate) + "" + // actions + (otherMonth && !showOtherMonths ? " " : // display for other months + (unselectable ? "" + printDate.getDate() + "" : "" + printDate.getDate() + "")) + "
" + (isMultiMonth ? "
" + + ((numMonths[0] > 0 && col === numMonths[1]-1) ? "
" : "") : ""); + group += calender; + } + html += group; + } + html += buttonPanel; + inst._keyEvent = false; + return html; + }, + + /* Generate the month and year header. */ + _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, + secondary, monthNames, monthNamesShort) { + + var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, + changeMonth = this._get(inst, "changeMonth"), + changeYear = this._get(inst, "changeYear"), + showMonthAfterYear = this._get(inst, "showMonthAfterYear"), + html = "
", + monthHtml = ""; + + // month selection + if (secondary || !changeMonth) { + monthHtml += "" + monthNames[drawMonth] + ""; + } else { + inMinYear = (minDate && minDate.getFullYear() === drawYear); + inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); + monthHtml += ""; + } + + if (!showMonthAfterYear) { + html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); + } + + // year selection + if ( !inst.yearshtml ) { + inst.yearshtml = ""; + if (secondary || !changeYear) { + html += "" + drawYear + ""; + } else { + // determine range of years to display + years = this._get(inst, "yearRange").split(":"); + thisYear = new Date().getFullYear(); + determineYear = function(value) { + var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : + (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : + parseInt(value, 10))); + return (isNaN(year) ? thisYear : year); + }; + year = determineYear(years[0]); + endYear = Math.max(year, determineYear(years[1] || "")); + year = (minDate ? Math.max(year, minDate.getFullYear()) : year); + endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); + inst.yearshtml += ""; + + html += inst.yearshtml; + inst.yearshtml = null; + } + } + + html += this._get(inst, "yearSuffix"); + if (showMonthAfterYear) { + html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; + } + html += "
"; // Close datepicker_header + return html; + }, + + /* Adjust one of the date sub-fields. */ + _adjustInstDate: function(inst, offset, period) { + var year = inst.drawYear + (period === "Y" ? offset : 0), + month = inst.drawMonth + (period === "M" ? offset : 0), + day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), + date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); + + inst.selectedDay = date.getDate(); + inst.drawMonth = inst.selectedMonth = date.getMonth(); + inst.drawYear = inst.selectedYear = date.getFullYear(); + if (period === "M" || period === "Y") { + this._notifyChange(inst); + } + }, + + /* Ensure a date is within any min/max bounds. */ + _restrictMinMax: function(inst, date) { + var minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + newDate = (minDate && date < minDate ? minDate : date); + return (maxDate && newDate > maxDate ? maxDate : newDate); + }, + + /* Notify change of month/year. */ + _notifyChange: function(inst) { + var onChange = this._get(inst, "onChangeMonthYear"); + if (onChange) { + onChange.apply((inst.input ? inst.input[0] : null), + [inst.selectedYear, inst.selectedMonth + 1, inst]); + } + }, + + /* Determine the number of months to show. */ + _getNumberOfMonths: function(inst) { + var numMonths = this._get(inst, "numberOfMonths"); + return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); + }, + + /* Determine the current maximum date - ensure no time components are set. */ + _getMinMaxDate: function(inst, minMax) { + return this._determineDate(inst, this._get(inst, minMax + "Date"), null); + }, + + /* Find the number of days in a given month. */ + _getDaysInMonth: function(year, month) { + return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + /* Find the day of the week of the first of a month. */ + _getFirstDayOfMonth: function(year, month) { + return new Date(year, month, 1).getDay(); + }, + + /* Determines if we should allow a "next/prev" month display change. */ + _canAdjustMonth: function(inst, offset, curYear, curMonth) { + var numMonths = this._getNumberOfMonths(inst), + date = this._daylightSavingAdjust(new Date(curYear, + curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); + + if (offset < 0) { + date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); + } + return this._isInRange(inst, date); + }, + + /* Is the given date in the accepted range? */ + _isInRange: function(inst, date) { + var yearSplit, currentYear, + minDate = this._getMinMaxDate(inst, "min"), + maxDate = this._getMinMaxDate(inst, "max"), + minYear = null, + maxYear = null, + years = this._get(inst, "yearRange"); + if (years){ + yearSplit = years.split(":"); + currentYear = new Date().getFullYear(); + minYear = parseInt(yearSplit[0], 10) + currentYear; + maxYear = parseInt(yearSplit[1], 10) + currentYear; + } + + return ((!minDate || date.getTime() >= minDate.getTime()) && + (!maxDate || date.getTime() <= maxDate.getTime()) && + (!minYear || date.getFullYear() >= minYear) && + (!maxYear || date.getFullYear() <= maxYear)); + }, + + /* Provide the configuration settings for formatting/parsing. */ + _getFormatConfig: function(inst) { + var shortYearCutoff = this._get(inst, "shortYearCutoff"); + shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : + new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); + return {shortYearCutoff: shortYearCutoff, + dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), + monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; + }, + + /* Format the given date for display. */ + _formatDate: function(inst, day, month, year) { + if (!day) { + inst.currentDay = inst.selectedDay; + inst.currentMonth = inst.selectedMonth; + inst.currentYear = inst.selectedYear; + } + var date = (day ? (typeof day === "object" ? day : + this._daylightSavingAdjust(new Date(year, month, day))) : + this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); + return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); + } +}); + +/* + * Bind hover events for datepicker elements. + * Done via delegate so the binding only occurs once in the lifetime of the parent div. + * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. + */ +function bindHover(dpDiv) { + var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; + return dpDiv.delegate(selector, "mouseout", function() { + $(this).removeClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).removeClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).removeClass("ui-datepicker-next-hover"); + } + }) + .delegate(selector, "mouseover", function(){ + if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) { + $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); + $(this).addClass("ui-state-hover"); + if (this.className.indexOf("ui-datepicker-prev") !== -1) { + $(this).addClass("ui-datepicker-prev-hover"); + } + if (this.className.indexOf("ui-datepicker-next") !== -1) { + $(this).addClass("ui-datepicker-next-hover"); + } + } + }); +} + +/* jQuery extend now ignores nulls! */ +function extendRemove(target, props) { + $.extend(target, props); + for (var name in props) { + if (props[name] == null) { + target[name] = props[name]; + } + } + return target; +} + +/* Invoke the datepicker functionality. + @param options string - a command, optionally followed by additional parameters or + Object - settings for attaching new datepicker functionality + @return jQuery object */ +$.fn.datepicker = function(options){ + + /* Verify an empty collection wasn't passed - Fixes #6976 */ + if ( !this.length ) { + return this; + } + + /* Initialise the date picker. */ + if (!$.datepicker.initialized) { + $(document).mousedown($.datepicker._checkExternalClick); + $.datepicker.initialized = true; + } + + /* Append datepicker main container to body if not exist. */ + if ($("#"+$.datepicker._mainDivId).length === 0) { + $("body").append($.datepicker.dpDiv); + } + + var otherArgs = Array.prototype.slice.call(arguments, 1); + if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { + return $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this[0]].concat(otherArgs)); + } + return this.each(function() { + typeof options === "string" ? + $.datepicker["_" + options + "Datepicker"]. + apply($.datepicker, [this].concat(otherArgs)) : + $.datepicker._attachDatepicker(this, options); + }); +}; + +$.datepicker = new Datepicker(); // singleton instance +$.datepicker.initialized = false; +$.datepicker.uuid = new Date().getTime(); +$.datepicker.version = "1.10.0"; + +// Workaround for #4055 +// Add another global to avoid noConflict issues with inline event handlers +window["DP_jQuery_" + dpuuid] = $; + +})(jQuery); +(function( $, undefined ) { + +var sizeRelatedOptions = { + buttons: true, + height: true, + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true, + width: true + }, + resizableRelatedOptions = { + maxHeight: true, + maxWidth: true, + minHeight: true, + minWidth: true + }; + +$.widget( "ui.dialog", { + version: "1.10.0", + options: { + appendTo: "body", + autoOpen: true, + buttons: [], + closeOnEscape: true, + closeText: "close", + dialogClass: "", + draggable: true, + hide: null, + height: "auto", + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: false, + position: { + my: "center", + at: "center", + of: window, + collision: "fit", + // Ensure the titlebar is always visible + using: function( pos ) { + var topOffset = $( this ).css( pos ).offset().top; + if ( topOffset < 0 ) { + $( this ).css( "top", pos.top - topOffset ); + } + } + }, + resizable: true, + show: null, + title: null, + width: 300, + + // callbacks + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null + }, + + _create: function() { + this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height + }; + this.originalPosition = { + parent: this.element.parent(), + index: this.element.parent().children().index( this.element ) + }; + this.originalTitle = this.element.attr("title"); + this.options.title = this.options.title || this.originalTitle; + + this._createWrapper(); + + this.element + .show() + .removeAttr("title") + .addClass("ui-dialog-content ui-widget-content") + .appendTo( this.uiDialog ); + + this._createTitlebar(); + this._createButtonPane(); + + if ( this.options.draggable && $.fn.draggable ) { + this._makeDraggable(); + } + if ( this.options.resizable && $.fn.resizable ) { + this._makeResizable(); + } + + this._isOpen = false; + }, + + _init: function() { + if ( this.options.autoOpen ) { + this.open(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + if ( element && (element.jquery || element.nodeType) ) { + return $( element ); + } + return this.document.find( element || "body" ).eq( 0 ); + }, + + _destroy: function() { + var next, + originalPosition = this.originalPosition; + + this._destroyOverlay(); + + this.element + .removeUniqueId() + .removeClass("ui-dialog-content ui-widget-content") + .css( this.originalCss ) + // Without detaching first, the following becomes really slow + .detach(); + + this.uiDialog.stop( true, true ).remove(); + + if ( this.originalTitle ) { + this.element.attr( "title", this.originalTitle ); + } + + next = originalPosition.parent.children().eq( originalPosition.index ); + // Don't try to place the dialog next to itself (#8613) + if ( next.length && next[0] !== this.element[0] ) { + next.before( this.element ); + } else { + originalPosition.parent.append( this.element ); + } + }, + + widget: function() { + return this.uiDialog; + }, + + disable: $.noop, + enable: $.noop, + + close: function( event ) { + var that = this; + + if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { + return; + } + + this._isOpen = false; + this._destroyOverlay(); + + if ( !this.opener.filter(":focusable").focus().length ) { + // Hiding a focused element doesn't trigger blur in WebKit + // so in case we have nothing to focus on, explicitly blur the active element + // https://bugs.webkit.org/show_bug.cgi?id=47182 + $( this.document[0].activeElement ).blur(); + } + + this._hide( this.uiDialog, this.options.hide, function() { + that._trigger( "close", event ); + }); + }, + + isOpen: function() { + return this._isOpen; + }, + + moveToTop: function() { + this._moveToTop(); + }, + + _moveToTop: function( event, silent ) { + var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length; + if ( moved && !silent ) { + this._trigger( "focus", event ); + } + return moved; + }, + + open: function() { + if ( this._isOpen ) { + if ( this._moveToTop() ) { + this._focusTabbable(); + } + return; + } + + this.opener = $( this.document[0].activeElement ); + + this._size(); + this._position(); + this._createOverlay(); + this._moveToTop( null, true ); + this._show( this.uiDialog, this.options.show ); + + this._focusTabbable(); + + this._isOpen = true; + this._trigger("open"); + this._trigger("focus"); + }, + + _focusTabbable: function() { + // Set focus to the first match: + // 1. First element inside the dialog matching [autofocus] + // 2. Tabbable element inside the content element + // 3. Tabbable element inside the buttonpane + // 4. The close button + // 5. The dialog itself + var hasFocus = this.element.find("[autofocus]"); + if ( !hasFocus.length ) { + hasFocus = this.element.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogButtonPane.find(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialogTitlebarClose.filter(":tabbable"); + } + if ( !hasFocus.length ) { + hasFocus = this.uiDialog; + } + hasFocus.eq( 0 ).focus(); + }, + + _keepFocus: function( event ) { + function checkFocus() { + var activeElement = this.document[0].activeElement, + isActive = this.uiDialog[0] === activeElement || + $.contains( this.uiDialog[0], activeElement ); + if ( !isActive ) { + this._focusTabbable(); + } + } + event.preventDefault(); + checkFocus.call( this ); + // support: IE + // IE <= 8 doesn't prevent moving focus even with event.preventDefault() + // so we check again later + this._delay( checkFocus ); + }, + + _createWrapper: function() { + this.uiDialog = $("
") + .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + + this.options.dialogClass ) + .hide() + .attr({ + // Setting tabIndex makes the div focusable + tabIndex: -1, + role: "dialog" + }) + .appendTo( this._appendTo() ); + + this._on( this.uiDialog, { + keydown: function( event ) { + if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && + event.keyCode === $.ui.keyCode.ESCAPE ) { + event.preventDefault(); + this.close( event ); + return; + } + + // prevent tabbing out of dialogs + if ( event.keyCode !== $.ui.keyCode.TAB ) { + return; + } + var tabbables = this.uiDialog.find(":tabbable"), + first = tabbables.filter(":first"), + last = tabbables.filter(":last"); + + if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { + first.focus( 1 ); + event.preventDefault(); + } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { + last.focus( 1 ); + event.preventDefault(); + } + }, + mousedown: function( event ) { + if ( this._moveToTop( event ) ) { + this._focusTabbable(); + } + } + }); + + // We assume that any existing aria-describedby attribute means + // that the dialog content is marked up properly + // otherwise we brute force the content as the description + if ( !this.element.find("[aria-describedby]").length ) { + this.uiDialog.attr({ + "aria-describedby": this.element.uniqueId().attr("id") + }); + } + }, + + _createTitlebar: function() { + var uiDialogTitle; + + this.uiDialogTitlebar = $("
") + .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix") + .prependTo( this.uiDialog ); + this._on( this.uiDialogTitlebar, { + mousedown: function( event ) { + // Don't prevent click on close button (#8838) + // Focusing a dialog that is partially scrolled out of view + // causes the browser to scroll it into view, preventing the click event + if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) { + // Dialog isn't getting focus when dragging (#8063) + this.uiDialog.focus(); + } + } + }); + + this.uiDialogTitlebarClose = $("") + .button({ + label: this.options.closeText, + icons: { + primary: "ui-icon-closethick" + }, + text: false + }) + .addClass("ui-dialog-titlebar-close") + .appendTo( this.uiDialogTitlebar ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + }); + + uiDialogTitle = $("") + .uniqueId() + .addClass("ui-dialog-title") + .prependTo( this.uiDialogTitlebar ); + this._title( uiDialogTitle ); + + this.uiDialog.attr({ + "aria-labelledby": uiDialogTitle.attr("id") + }); + }, + + _title: function( title ) { + if ( !this.options.title ) { + title.html(" "); + } + title.text( this.options.title ); + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $("
") + .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"); + + this.uiButtonSet = $("
") + .addClass("ui-dialog-buttonset") + .appendTo( this.uiDialogButtonPane ); + + this._createButtons(); + }, + + _createButtons: function() { + var that = this, + buttons = this.options.buttons; + + // if we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( $.isEmptyObject( buttons ) ) { + this.uiDialog.removeClass("ui-dialog-buttons"); + return; + } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = $.isFunction( props ) ? + { click: props, text: name } : + props; + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + // Change the context for the click callback to be the main element + click = props.click; + props.click = function() { + click.apply( that.element[0], arguments ); + }; + buttonOptions = { + icons: props.icons, + text: props.showText + }; + delete props.icons; + delete props.showText; + $( "", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ); + }); + this.uiDialog.addClass("ui-dialog-buttons"); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + }, + + _makeDraggable: function() { + var that = this, + options = this.options; + + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } + + this.uiDialog.draggable({ + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + $( this ).addClass("ui-dialog-dragging"); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.position = [ + ui.position.left - that.document.scrollLeft(), + ui.position.top - that.document.scrollTop() + ]; + $( this ).removeClass("ui-dialog-dragging"); + that._trigger( "dragStop", event, filteredUi( ui ) ); + } + }); + }, + + _makeResizable: function() { + var that = this, + options = this.options, + handles = options.resizable, + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css("position"), + resizeHandles = typeof handles === "string" ? + handles : + "n,e,s,w,se,sw,ne,nw"; + + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable({ + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + $( this ).addClass("ui-dialog-resizing"); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + options.height = $( this ).height(); + options.width = $( this ).width(); + $( this ).removeClass("ui-dialog-resizing"); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + } + }) + .css( "position", position ); + }, + + _minHeight: function() { + var options = this.options; + + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); + }, + + _position: function() { + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( this.options.position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resize = false, + resizableOptions = {}; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in sizeRelatedOptions ) { + resize = true; + } + if ( key in resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + }); + + if ( resize ) { + this._size(); + this._position(); + } + if ( this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + /*jshint maxcomplexity:15*/ + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + if ( key === "dialogClass" ) { + uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } + + if ( key === "disabled" ) { + return; + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); + } + + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button({ + // Ensure that we always pass a string + label: "" + value + }); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is(":data(ui-draggable)"); + if ( isDraggable && !value ) { + uiDialog.draggable("destroy"); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + // currently resizable, becoming non-resizable + isResizable = uiDialog.is(":data(ui-resizable)"); + if ( isResizable && !value ) { + uiDialog.resizable("destroy"); + } + + // currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find(".ui-dialog-title") ); + } + }, + + _size: function() { + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; + + // Reset content sizing + this.element.show().css({ + width: "auto", + minHeight: 0, + maxHeight: "none", + height: 0 + }); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css({ + height: "auto", + width: options.width + }) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; + + if ( options.height === "auto" ) { + this.element.css({ + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + }); + } else { + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); + } + + if (this.uiDialog.is(":data(ui-resizable)") ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + if ( !$.ui.dialog.overlayInstances ) { + // Prevent use of anchors and inputs. + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling. (#2804) + this._delay(function() { + // Handle .dialog().dialog("close") (#4065) + if ( $.ui.dialog.overlayInstances ) { + this._on( this.document, { + focusin: function( event ) { + if ( !$( event.target ).closest(".ui-dialog").length ) { + event.preventDefault(); + $(".ui-dialog:visible:last .ui-dialog-content") + .data("ui-dialog")._focusTabbable(); + } + } + }); + } + }); + } + + this.overlay = $("
") + .addClass("ui-widget-overlay ui-front") + .appendTo( this.document[0].body ); + this._on( this.overlay, { + mousedown: "_keepFocus" + }); + $.ui.dialog.overlayInstances++; + }, + + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; + } + + $.ui.dialog.overlayInstances--; + if ( !$.ui.dialog.overlayInstances ) { + this._off( this.document, "focusin" ); + } + this.overlay.remove(); + } +}); + +$.ui.dialog.overlayInstances = 0; + +// DEPRECATED +if ( $.uiBackCompat !== false ) { + // position option with array notation + // just override with old implementation + $.widget( "ui.dialog", $.ui.dialog, { + _position: function() { + var position = this.options.position, + myAt = [], + offset = [ 0, 0 ], + isVisible; + + if ( position ) { + if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) { + myAt = position.split ? position.split(" ") : [ position[0], position[1] ]; + if ( myAt.length === 1 ) { + myAt[1] = myAt[0]; + } + + $.each( [ "left", "top" ], function( i, offsetPosition ) { + if ( +myAt[ i ] === myAt[ i ] ) { + offset[ i ] = myAt[ i ]; + myAt[ i ] = offsetPosition; + } + }); + + position = { + my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " + + myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]), + at: myAt.join(" ") + }; + } + + position = $.extend( {}, $.ui.dialog.prototype.options.position, position ); + } else { + position = $.ui.dialog.prototype.options.position; + } + + // need to show the dialog to get the actual offset in the position plugin + isVisible = this.uiDialog.is(":visible"); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + } + }); +} + +}( jQuery ) ); +(function( $, undefined ) { + +$.widget( "ui.menu", { + version: "1.10.0", + defaultElement: "").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&& -a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu"); -d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&& -b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source= -this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length").data("item.autocomplete",b).append(d("").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, -"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery); -(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex", --1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.scrollTop(),c=this.element.height();if(b<0)this.element.scrollTop(g+b);else b>=c&&this.element.scrollTop(g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id"); -this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b, -this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active|| -this.first()?":last":":first"))},hasScroll:function(){return this.element.height()").addClass("ui-button-text").html(this.options.label).appendTo(a.empty()).text(),e=this.options.icons,f=e.primary&&e.secondary,d=[];if(e.primary||e.secondary){if(this.options.text)d.push("ui-button-text-icon"+(f?"s":e.primary?"-primary":"-secondary"));e.primary&&a.prepend("");e.secondary&&a.append("");if(!this.options.text){d.push(f?"ui-button-icons-only": -"ui-button-icon-only");this.hasTitle||a.attr("title",c)}}else d.push("ui-button-text-only");a.addClass(d.join(" "))}}});b.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(a,c){a==="disabled"&&this.buttons.button("option",a,c);b.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){var a=this.element.css("direction")=== -"ltr";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(a?"ui-corner-left":"ui-corner-right").end().filter(":last").addClass(a?"ui-corner-right":"ui-corner-left").end().end()},destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return b(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy"); -b.Widget.prototype.destroy.call(this)}})})(jQuery); -;/* - * jQuery UI Dialog 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - * jquery.ui.button.js - * jquery.ui.draggable.js - * jquery.ui.mouse.js - * jquery.ui.position.js - * jquery.ui.resizable.js - */ -(function(c,l){var m={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},n={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true},o=c.attrFn||{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true,click:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false, -position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("
")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+ -b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&!i.isDefaultPrevented()&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("
")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g), -h=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("").addClass("ui-dialog-title").attr("id", -e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"); -a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!== -b.uiDialog[0]){e=c(this).css("z-index");isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()};c.ui.dialog.maxZ+=1; -d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target=== -f[0]&&e.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("
").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("
").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a, -function(){return!(d=true)});if(d){c.each(a,function(f,h){h=c.isFunction(h)?{click:h,text:f}:h;var i=c('').click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.each(h,function(j,k){if(j!=="click")j in o?i[j](k):i.attr(j,k)});c.fn.button&&i.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close", -handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition, -originalSize:f.originalSize,position:f.position,size:f.size}}a=a===l?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize", -f,b(h))},stop:function(f,h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "): -[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f); -if(g in m)e=true;if(g in n)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"): -e.removeClass("ui-dialog-disabled");break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a= -this.options,b,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height- -b,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.16",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "), -create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()
").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&& -c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a
").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(b.range==="min"||b.range==="max"?" ui-slider-range-"+b.range:""))}for(var j=c.length;j"); -this.handles=c.add(d(e.join("")).appendTo(a.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(g){g.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(g){d(this).data("index.ui-slider-handle", -g)});this.handles.keydown(function(g){var k=true,l=d(this).data("index.ui-slider-handle"),i,h,m;if(!a.options.disabled){switch(g.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:k=false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");i=a._start(g,l);if(i===false)return}break}m=a.options.step;i=a.options.values&&a.options.values.length? -(h=a.values(l)):(h=a.value());switch(g.keyCode){case d.ui.keyCode.HOME:h=a._valueMin();break;case d.ui.keyCode.END:h=a._valueMax();break;case d.ui.keyCode.PAGE_UP:h=a._trimAlignValue(i+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:h=a._trimAlignValue(i-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(i===a._valueMax())return;h=a._trimAlignValue(i+m);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(i===a._valueMin())return;h=a._trimAlignValue(i- -m);break}a._slide(g,l,h);return k}}).keyup(function(g){var k=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(g,k);a._change(g,k);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(a){var b=this.options,c,f,e,j,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});f=this._valueMax()-this._valueMin()+1;j=this;this.handles.each(function(k){var l=Math.abs(c-j.values(k));if(f>l){f=l;e=d(this);g=k}});if(b.range===true&&this.values(1)===b.min){g+=1;e=d(this.handles[g])}if(this._start(a,g)===false)return false; -this._mouseSliding=true;j._handleIndex=g;e.addClass("ui-state-active").focus();b=e.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-e.width()/2,top:a.pageY-b.top-e.height()/2-(parseInt(e.css("borderTopWidth"),10)||0)-(parseInt(e.css("borderBottomWidth"),10)||0)+(parseInt(e.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b= -this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b= -this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b); -c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var f;if(this.options.values&&this.options.values.length){f=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>f||b===1&&c1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}else if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;f=arguments[0];for(e=0;e=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a= -this.options.range,b=this.options,c=this,f=!this._animateOff?b.animate:false,e,j={},g,k,l,i;if(this.options.values&&this.options.values.length)this.handles.each(function(h){e=(c.values(h)-c._valueMin())/(c._valueMax()-c._valueMin())*100;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";d(this).stop(1,1)[f?"animate":"css"](j,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(h===0)c.range.stop(1,1)[f?"animate":"css"]({left:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({width:e- -g+"%"},{queue:false,duration:b.animate})}else{if(h===0)c.range.stop(1,1)[f?"animate":"css"]({bottom:e+"%"},b.animate);if(h===1)c.range[f?"animate":"css"]({height:e-g+"%"},{queue:false,duration:b.animate})}g=e});else{k=this.value();l=this._valueMin();i=this._valueMax();e=i!==l?(k-l)/(i-l)*100:0;j[c.orientation==="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[f?"animate":"css"](j,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[f?"animate":"css"]({width:e+"%"}, -b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[f?"animate":"css"]({width:100-e+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[f?"animate":"css"]({height:e+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[f?"animate":"css"]({height:100-e+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Tabs 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
  • #{label}
  • "},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&& -e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b= -d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]|| -(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"); -this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected= -this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active"); -if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")); -this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+ -g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal", -function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")}; -this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected= --1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier."; -d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e= -d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b, -e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]); -j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove(); -if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null, -this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this}, -load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c, -"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this}, -url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.16"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k
    '))}function N(a){return a.bind("mouseout", -function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");b.length&&b.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(b){b=d(b.target).closest("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a");if(!(d.datepicker._isDisabledDatepicker(J.inline?a.parent()[0]:J.input[0])||!b.length)){b.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); -b.addClass("ui-state-hover");b.hasClass("ui-datepicker-prev")&&b.addClass("ui-datepicker-prev-hover");b.hasClass("ui-datepicker-next")&&b.addClass("ui-datepicker-next-hover")}})}function H(a,b){d.extend(a,b);for(var c in b)if(b[c]==null||b[c]==C)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.16"}});var B=(new Date).getTime(),J;d.extend(M.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv}, -setDefaults:function(a){H(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g, -"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:N(d('
    '))}},_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker", -function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b);b.settings.disabled&&this._disableDatepicker(a)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&b.append.remove();if(c){b.append=d(''+c+"");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c== -"focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('').addClass(this._triggerClass).html(f==""?c:d("").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker(): -d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;gh){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a, -b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),true);this._updateDatepicker(b);this._updateAlternate(b);b.settings.disabled&&this._disableDatepicker(a);b.dpDiv.css("display","block")}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+= -1;this._dialogInput=d('');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}H(a.settings,e||{});b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/ -2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b= -d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e= -a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().removeClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a, -"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span"){b=b.children("."+this._inlineClass);b.children().addClass("ui-state-disabled");b.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=d.map(this._disabledInputs,function(f){return f== -a?null:f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input", -a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);if(d.datepicker._curInst&&d.datepicker._curInst!=b){d.datepicker._datepickerShowing&&d.datepicker._triggerOnClose(d.datepicker._curInst);d.datepicker._curInst.dpDiv.stop(true,true)}var c=d.datepicker._get(b,"beforeShow");c=c?c.apply(a,[a,b]):{};if(c!==false){H(b.settings,c);b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value= -"";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b); -c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.datepicker._datepickerShowing= -true;d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}}},_updateDatepicker:function(a){this.maxRows=4;var b=d.datepicker._getBorders(a.dpDiv);J=a;a.dpDiv.empty().append(this._generateHTML(a));var c=a.dpDiv.find("iframe.ui-datepicker-cover");c.length&&c.css({left:-b[0],top:-b[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}); -a.dpDiv.find("."+this._dayOverClass+" a").mouseover();b=this._getNumberOfMonths(a);c=b[1];a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");c>1&&a.dpDiv.addClass("ui-datepicker-multi-"+c).css("width",17*c+"em");a.dpDiv[(b[0]!=1||b[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&& -!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var e=a.yearshtml;setTimeout(function(){e===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);e=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(), -h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b= -this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_triggerOnClose:function(a){var b=this._get(a,"onClose");if(b)b.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a])},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b); -this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();d.datepicker._triggerOnClose(b);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")}, -_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"): -0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e["selected"+(c=="M"? -"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a); -this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField"); -if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"? -b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=A+1-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}v=this._daylightSavingAdjust(new Date(c,j-1,l));if(v.getFullYear()!=c||v.getMonth()+1!=j||v.getDate()!=l)throw"Invalid date";return v},ATOM:"yy-mm-dd", -COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames: -null)||this._defaults.monthNames;var i=function(o){(o=k+1 -12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&& -a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay? -new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&nn;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a)); -n=this._canAdjustMonth(a,-1,m,g)?''+n+"":f?"":''+n+"";var s=this._get(a,"nextText");s=!h?s:this.formatDate(s,this._daylightSavingAdjust(new Date(m, -g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?''+s+"":f?"":''+s+"";j=this._get(a,"currentText");s=this._get(a,"gotoCurrent")&& -a.currentDay?u:b;j=!h?j:this.formatDate(j,s,this._getFormatConfig(a));h=!a.inline?'":"";e=e?'
    '+(c?h:"")+(this._isInRange(a,s)?'":"")+(c?"":h)+"
    ":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");s=this._get(a,"dayNames");this._get(a,"dayNamesShort");var q=this._get(a,"dayNamesMin"),A=this._get(a,"monthNames"),v=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),D=this._get(a,"showOtherMonths"),K=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var E=this._getDefaultDate(a),w="",x=0;x1)switch(G){case 0:y+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-1:y+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:y+=" ui-datepicker-group-middle";t="";break}y+='">'}y+='
    '+(/all|left/.test(t)&& -x==0?c?f:n:"")+(/all|right/.test(t)&&x==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,x>0||G>0,A,v)+'
    ';var z=j?'":"";for(t=0;t<7;t++){var r=(t+h)%7;z+="=5?' class="ui-datepicker-week-end"':"")+'>'+q[r]+""}y+=z+"";z=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay, -z);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;z=Math.ceil((t+z)/7);this.maxRows=z=l?this.maxRows>z?this.maxRows:z:z;r=this._daylightSavingAdjust(new Date(m,g,1-t));for(var Q=0;Q";var R=!j?"":'";for(t=0;t<7;t++){var I=p?p.apply(a.input?a.input[0]:null,[r]):[true,""],F=r.getMonth()!=g,L=F&&!K||!I[0]||k&&ro;R+='";r.setDate(r.getDate()+1);r=this._daylightSavingAdjust(r)}y+=R+""}g++;if(g>11){g=0;m++}y+="
    '+this._get(a,"weekHeader")+"
    '+this._get(a,"calculateWeek")(r)+""+(F&&!D?" ":L?''+ -r.getDate()+"":''+r.getDate()+"")+"
    "+(l?"
    "+(i[0]>0&&G==i[1]-1?'
    ':""):"");O+=y}w+=O}w+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'': -"");a._keyEvent=false;return w},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='
    ',o="";if(h||!j)o+=''+i[b]+"";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='"}u||(k+=o+(h||!(j&&l)?" ":""));if(!a.yearshtml){a.yearshtml="";if(h||!l)k+=''+c+"";else{g=this._get(a,"yearRange").split(":");var s=(new Date).getFullYear();i=function(q){q=q.match(/c[+-].*/)?c+parseInt(q.substring(1),10):q.match(/[+-].*/)?s+parseInt(q,10):parseInt(q,10);return isNaN(q)?s:q};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b, -e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='";k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="
    ";return k},_adjustInstDate:function(a,b,c){var e=a.drawYear+(c=="Y"?b:0),f=a.drawMonth+ -(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&ba?a:b},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");if(b)b.apply(a.input? -a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);c=this._daylightSavingAdjust(new Date(c, -e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a, -"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=function(a){if(!this.length)return this; -if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));return this.each(function(){typeof a== -"string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new M;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.16";window["DP_jQuery_"+B]=d})(jQuery); -;/* - * jQuery UI Progressbar 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("
    ").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"); -this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100* -this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.16"})})(jQuery); -;/* - * jQuery UI Effects 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/ - */ -jQuery.effects||function(f,j){function m(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1], -16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return n.transparent;return n[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return m(b)}function o(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle, -a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function p(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d= -a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function l(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor", -"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=m(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var n={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0, -0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211, -211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},q=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b, -d){if(f.isFunction(b)){d=b;b=null}return this.queue(function(){var e=f(this),g=e.attr("style")||" ",h=p(o.call(this)),r,v=e.attr("class");f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});r=p(o.call(this));e.attr("class",v);e.animate(u(h,r),{queue:false,duration:a,easing:b,complete:function(){f.each(q,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments);f.dequeue(this)}})})}; -f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,a):f.effects.animateClass.apply(this, -[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.16",save:function(c,a){for(var b=0;b
    ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}), -d=document.activeElement;c.wrap(b);if(c[0]===d||f.contains(c[0],d))f(d).focus();b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(e,g){a[g]=c.css(g);if(isNaN(parseInt(a[g],10)))a[g]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){var a,b=document.activeElement; -if(c.parent().is(".ui-effects-wrapper")){a=c.parent().replaceWith(c);if(c[0]===b||f.contains(c[0],b))f(b).focus();return a}return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)}); -return d.call(this,b)},_show:f.fn.show,show:function(c){if(l(c))return this._show.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(l(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(l(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this, -arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/ -2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b, -d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c, -a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b, -d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top+ -e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery); -;/* - * jQuery UI Effects Fade 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fade - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Fold 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Fold - * - * Depends: - * jquery.effects.core.js - */ -(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1], -10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery); -;/* - * jQuery UI Effects Highlight 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Highlight - * - * Depends: - * jquery.effects.core.js - */ -(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&& -this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery); -;/* - * jQuery UI Effects Pulsate 1.8.16 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Effects/Pulsate - * - * Depends: - * jquery.effects.core.js - */ -(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments); -b.dequeue()})})}})(jQuery); -; \ No newline at end of file diff --git a/core/js/js.js b/core/js/js.js index 7d967321d93b97465f7abfb2a3b5bb4a1a79b46c..01e47edf2683876b0d1d37d5a0f99a39f96620e7 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -3,14 +3,15 @@ * Add * define('DEBUG', true); * To the end of config/config.php to enable debug mode. + * The undefined checks fix the broken ie8 console */ -if (oc_debug !== true) { +if (oc_debug !== true || typeof console === "undefined" || typeof console.log === "undefined") { if (!window.console) { window.console = {}; } var methods = ['log', 'debug', 'warn', 'info', 'error', 'assert']; for (var i = 0; i < methods.length; i++) { - console[methods[i]] = function () { }; + console[methods[i]] = function () { }; } } @@ -20,7 +21,6 @@ if (oc_debug !== true) { * @param text the string to translate * @return string */ - function t(app,text, vars){ if( !( t.cache[app] )){ $.ajax(OC.filePath('core','ajax','translations.php'),{ @@ -37,14 +37,14 @@ function t(app,text, vars){ t.cache[app] = []; } } - var _build = function(text, vars) { - return text.replace(/{([^{}]*)}/g, - function (a, b) { - var r = vars[b]; - return typeof r === 'string' || typeof r === 'number' ? r : a; - } - ); - } + var _build = function (text, vars) { + return text.replace(/{([^{}]*)}/g, + function (a, b) { + var r = vars[b]; + return typeof r === 'string' || typeof r === 'number' ? r : a; + } + ); + }; if( typeof( t.cache[app][text] ) !== 'undefined' ){ if(typeof vars === 'object') { return _build(t.cache[app][text], vars); @@ -88,7 +88,7 @@ var OC={ PERMISSION_DELETE:8, PERMISSION_SHARE:16, webroot:oc_webroot, - appswebroots:oc_appswebroots, + appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false, currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false, coreApps:['', 'admin','log','search','settings','core','3rdparty'], /** @@ -100,6 +100,27 @@ var OC={ linkTo:function(app,file){ return OC.filePath(app,'',file); }, + /** + * Creates an url for remote use + * @param string $service id + * @return string the url + * + * Returns a url to the given service. + */ + linkToRemoteBase:function(service) { + return OC.webroot + '/remote.php/' + service; + }, + /** + * @brief Creates an absolute url for remote use + * @param string $service id + * @param bool $add_slash + * @return string the url + * + * Returns a absolute url to the given service. + */ + linkToRemote:function(service) { + return window.location.protocol + '//' + window.location.host + OC.linkToRemoteBase(service); + }, /** * get the absolute url for a file in an app * @param app the id of the app @@ -247,7 +268,7 @@ var OC={ var popup = $('#appsettings_popup'); if(popup.length == 0) { $('body').prepend(''); - popup = $('#appsettings_popup'); + popup = $('#appsettings_popup'); popup.addClass(settings.hasClass('topright') ? 'topright' : 'bottomleft'); } if(popup.is(':visible')) { @@ -289,6 +310,41 @@ OC.search.lastResults={}; OC.addStyle.loaded=[]; OC.addScript.loaded=[]; +OC.Notification={ + getDefaultNotificationFunction: null, + setDefault: function(callback) { + OC.Notification.getDefaultNotificationFunction = callback; + }, + hide: function(callback) { + $("#notification").text(''); + $('#notification').fadeOut('400', function(){ + if (OC.Notification.isHidden()) { + if (OC.Notification.getDefaultNotificationFunction) { + OC.Notification.getDefaultNotificationFunction.call(); + } + } + if (callback) { + callback.call(); + } + }); + }, + showHtml: function(html) { + var notification = $('#notification'); + notification.hide(); + notification.html(html); + notification.fadeIn().css("display","inline"); + }, + show: function(text) { + var notification = $('#notification'); + notification.hide(); + notification.text(text); + notification.fadeIn().css("display","inline"); + }, + isHidden: function() { + return ($("#notification").text() === ''); + } +}; + OC.Breadcrumb={ container:null, crumbs:[], @@ -343,8 +399,15 @@ if(typeof localStorage !=='undefined' && localStorage !== null){ return localStorage.setItem(OC.localStorage.namespace+name,JSON.stringify(item)); }, getItem:function(name){ - if(localStorage.getItem(OC.localStorage.namespace+name)===null){return null;} - return JSON.parse(localStorage.getItem(OC.localStorage.namespace+name)); + var item = localStorage.getItem(OC.localStorage.namespace+name); + if(item===null) { + return null; + } else if (typeof JSON === 'undefined') { + //fallback to jquery for IE6/7/8 + return $.parseJSON(item); + } else { + return JSON.parse(item); + } } }; }else{ @@ -497,6 +560,7 @@ function fillHeight(selector) { if(selector.outerHeight() > selector.height()){ selector.css('height', height-(selector.outerHeight()-selector.height()) + 'px'); } + console.warn("This function is deprecated! Use CSS instead"); } /** @@ -512,17 +576,11 @@ function fillWindow(selector) { if(selector.outerWidth() > selector.width()){ selector.css('width', width-(selector.outerWidth()-selector.width()) + 'px'); } + console.warn("This function is deprecated! Use CSS instead"); } $(document).ready(function(){ - $(window).resize(function () { - fillHeight($('#leftcontent')); - fillWindow($('#content')); - fillWindow($('#rightcontent')); - }); - $(window).trigger('resize'); - if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg replaceSVG(); }else{ @@ -615,7 +673,7 @@ $(document).ready(function(){ $('.jp-controls .jp-previous').tipsy({gravity:'nw', fade:true, live:true}); $('.jp-controls .jp-next').tipsy({gravity:'n', fade:true, live:true}); $('.password .action').tipsy({gravity:'se', fade:true, live:true}); - $('#upload a').tipsy({gravity:'w', fade:true}); + $('#upload').tipsy({gravity:'w', fade:true}); $('.selectedActions a').tipsy({gravity:'s', fade:true, live:true}); $('a.delete').tipsy({gravity: 'e', fade:true, live:true}); $('a.action').tipsy({gravity:'s', fade:true, live:true}); diff --git a/core/js/multiselect.js b/core/js/multiselect.js index c4fd74b0475e746844b554f23d9b94f487de8b45..623c6e0f7e1c02a71a781bdf1341b426f5050f23 100644 --- a/core/js/multiselect.js +++ b/core/js/multiselect.js @@ -1,20 +1,44 @@ +/** + * @param 'createCallback' A function to be called when a new entry is created. Two arguments are supplied to this function: + * The select element used and the value of the option. If the function returns false addition will be cancelled. If it returns + * anything else it will be used as the value of the newly added option. + * @param 'createText' The placeholder text for the create action. + * @param 'title' The title to show if no options are selected. + * @param 'checked' An array containing values for options that should be checked. Any options which are already selected will be added to this array. + * @param 'labels' The corresponding labels to show for the checked items. + * @param 'oncheck' Callback function which will be called when a checkbox/radiobutton is selected. If the function returns false the input will be unchecked. + * @param 'onuncheck' @see 'oncheck'. + * @param 'singleSelect' If true radiobuttons will be used instead of checkboxes. + */ (function( $ ){ var multiSelectId=-1; - $.fn.multiSelect=function(options){ + $.fn.multiSelect=function(options) { multiSelectId++; var settings = { 'createCallback':false, 'createText':false, + 'singleSelect':false, + 'selectedFirst':false, + 'sort':true, 'title':this.attr('title'), 'checked':[], + 'labels':[], 'oncheck':false, 'onuncheck':false, 'minWidth': 'default;', }; + $(this).attr('data-msid', multiSelectId); $.extend(settings,options); - $.each(this.children(),function(i,option){ - if($(option).attr('selected') && settings.checked.indexOf($(option).val())==-1){ + $.each(this.children(),function(i,option) { + // If the option is selected, but not in the checked array, add it. + if($(option).attr('selected') && settings.checked.indexOf($(option).val()) === -1) { settings.checked.push($(option).val()); + settings.labels.push($(option).text().trim()); + } + // If the option is in the checked array but not selected, select it. + else if(settings.checked.indexOf($(option).val()) !== -1 && !$(option).attr('selected')) { + $(option).attr('selected', 'selected'); + settings.labels.push($(option).text().trim()); } }); var button=$('
    '+settings.title+'
    '); @@ -24,24 +48,36 @@ button.selectedItems=[]; this.hide(); this.before(span); - if(settings.minWidth=='default'){ + if(settings.minWidth=='default') { settings.minWidth=button.width(); } button.css('min-width',settings.minWidth); settings.minOuterWidth=button.outerWidth()-2; button.data('settings',settings); - if(settings.checked.length>0){ - button.children('span').first().text(settings.checked.join(', ')); + + if(!settings.singleSelect && settings.checked.length>0) { + button.children('span').first().text(settings.labels.join(', ')); + } else if(settings.singleSelect) { + button.children('span').first().text(this.find(':selected').text()); } + var self = this; + self.menuDirection = 'down'; button.click(function(event){ var button=$(this); - if(button.parent().children('ul').length>0){ - button.parent().children('ul').slideUp(400,function(){ - button.parent().children('ul').remove(); - button.removeClass('active'); - }); + if(button.parent().children('ul').length>0) { + if(self.menuDirection === 'down') { + button.parent().children('ul').slideUp(400,function() { + button.parent().children('ul').remove(); + button.removeClass('active down'); + }); + } else { + button.parent().children('ul').fadeOut(400,function() { + button.parent().children('ul').remove(); + button.removeClass('active up'); + }); + } return; } var lists=$('ul.multiselectoptions'); @@ -54,49 +90,69 @@ event.stopPropagation(); var options=$(this).parent().next().children(); var list=$('
      ').hide().appendTo($(this).parent()); - function createItem(element,checked){ + var inputType = settings.singleSelect ? 'radio' : 'checkbox'; + function createItem(element, checked){ element=$(element); var item=element.val(); var id='ms'+multiSelectId+'-option-'+item; - var input=$(''); + var input=$(''); input.attr('id',id); + if(settings.singleSelect) { + input.attr('name', 'ms'+multiSelectId+'-option'); + } var label=$('