diff --git a/apps/files_encryption/img/app.svg b/apps/files_encryption/img/app.svg new file mode 100644 index 0000000000..1157c71c66 --- /dev/null +++ b/apps/files_encryption/img/app.svg @@ -0,0 +1,51 @@ + +image/svg+xml \ No newline at end of file diff --git a/apps/files_external/img/app.svg b/apps/files_external/img/app.svg new file mode 100644 index 0000000000..df1bfd163f --- /dev/null +++ b/apps/files_external/img/app.svg @@ -0,0 +1,212 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/files_sharing/img/app.svg b/apps/files_sharing/img/app.svg new file mode 100644 index 0000000000..d64e44b70b --- /dev/null +++ b/apps/files_sharing/img/app.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/apps/files_trashbin/img/app.svg b/apps/files_trashbin/img/app.svg new file mode 100644 index 0000000000..b749f9879e --- /dev/null +++ b/apps/files_trashbin/img/app.svg @@ -0,0 +1,54 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/apps/files_versions/img/app.svg b/apps/files_versions/img/app.svg new file mode 100644 index 0000000000..862b0a6885 --- /dev/null +++ b/apps/files_versions/img/app.svg @@ -0,0 +1,103 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/apps/user_ldap/img/app.svg b/apps/user_ldap/img/app.svg new file mode 100644 index 0000000000..63a065afdc --- /dev/null +++ b/apps/user_ldap/img/app.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/apps/user_webdavauth/img/app.svg b/apps/user_webdavauth/img/app.svg new file mode 100644 index 0000000000..63a065afdc --- /dev/null +++ b/apps/user_webdavauth/img/app.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/core/img/rating/s0.png b/core/img/rating/s0.png new file mode 100644 index 0000000000..9d5014106e Binary files /dev/null and b/core/img/rating/s0.png differ diff --git a/core/img/rating/s1.png b/core/img/rating/s1.png index 9d5014106e..6846c8771f 100644 Binary files a/core/img/rating/s1.png and b/core/img/rating/s1.png differ diff --git a/core/img/rating/s10.png b/core/img/rating/s10.png index b9c190f8ce..c674569c38 100644 Binary files a/core/img/rating/s10.png and b/core/img/rating/s10.png differ diff --git a/core/img/rating/s11.png b/core/img/rating/s11.png deleted file mode 100644 index c674569c38..0000000000 Binary files a/core/img/rating/s11.png and /dev/null differ diff --git a/core/img/rating/s2.png b/core/img/rating/s2.png index 6846c8771f..2f132cc5fa 100644 Binary files a/core/img/rating/s2.png and b/core/img/rating/s2.png differ diff --git a/core/img/rating/s3.png b/core/img/rating/s3.png index 2f132cc5fa..55e917f92e 100644 Binary files a/core/img/rating/s3.png and b/core/img/rating/s3.png differ diff --git a/core/img/rating/s4.png b/core/img/rating/s4.png index 55e917f92e..fa76c311c6 100644 Binary files a/core/img/rating/s4.png and b/core/img/rating/s4.png differ diff --git a/core/img/rating/s5.png b/core/img/rating/s5.png index fa76c311c6..8856309f83 100644 Binary files a/core/img/rating/s5.png and b/core/img/rating/s5.png differ diff --git a/core/img/rating/s6.png b/core/img/rating/s6.png index 8856309f83..4112e14fde 100644 Binary files a/core/img/rating/s6.png and b/core/img/rating/s6.png differ diff --git a/core/img/rating/s7.png b/core/img/rating/s7.png index 4112e14fde..ce25cf58df 100644 Binary files a/core/img/rating/s7.png and b/core/img/rating/s7.png differ diff --git a/core/img/rating/s8.png b/core/img/rating/s8.png index ce25cf58df..3197f23785 100644 Binary files a/core/img/rating/s8.png and b/core/img/rating/s8.png differ diff --git a/core/img/rating/s9.png b/core/img/rating/s9.png index 3197f23785..b9c190f8ce 100644 Binary files a/core/img/rating/s9.png and b/core/img/rating/s9.png differ diff --git a/core/templates/layout.user.php b/core/templates/layout.user.php index 04cb6eb9de..9445175efc 100644 --- a/core/templates/layout.user.php +++ b/core/templates/layout.user.php @@ -119,7 +119,7 @@
  • - class="active"> diff --git a/lib/private/app.php b/lib/private/app.php index a356139044..95a8a7302d 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -815,7 +815,7 @@ class OC_App { * Lists all apps, this is used in apps.php * @return array */ - public static function listAllApps() { + public static function listAllApps($onlyLocal = false) { $installedApps = OC_App::getAllApps(); //TODO which apps do we want to blacklist and how do we integrate @@ -823,6 +823,7 @@ class OC_App { $blacklist = array('files'); //we don't want to show configuration for these $appList = array(); + $l = \OC::$server->getL10N('core'); foreach ($installedApps as $app) { if (array_search($app, $blacklist) === false) { @@ -849,24 +850,36 @@ class OC_App { if(isset($info['shipped']) and ($info['shipped'] == 'true')) { $info['internal'] = true; - $info['internallabel'] = 'Internal App'; - $info['internalclass'] = ''; + $info['internallabel'] = $l->t('Recommended'); + $info['internalclass'] = 'recommendedapp'; $info['removable'] = false; } else { $info['internal'] = false; - $info['internallabel'] = '3rd Party'; - $info['internalclass'] = 'externalapp'; $info['removable'] = true; } $info['update'] = OC_Installer::isUpdateAvailable($app); - $info['preview'] = OC_Helper::imagePath('settings', 'trans.png'); + $appIcon = self::getAppPath($app) . '/img/' . $app.'.svg'; + if (file_exists($appIcon)) { + $info['preview'] = OC_Helper::imagePath($app, $app.'.svg'); + $info['previewAsIcon'] = true; + } else { + $appIcon = self::getAppPath($app) . '/img/app.svg'; + if (file_exists($appIcon)) { + $info['preview'] = OC_Helper::imagePath($app, 'app.svg'); + $info['previewAsIcon'] = true; + } + } $info['version'] = OC_App::getAppVersion($app); $appList[] = $info; } } - $remoteApps = OC_App::getAppstoreApps(); + if ($onlyLocal) { + $remoteApps = array(); + } else { + $remoteApps = OC_App::getAppstoreApps(); + } if ($remoteApps) { // Remove duplicates foreach ($appList as $app) { @@ -898,9 +911,11 @@ class OC_App { } // priority 3: recommended - if ($a['internalclass'] != $b['internalclass']) { - $aTemp = ($a['internalclass'] == 'recommendedapp' ? 1 : 0); - $bTemp = ($b['internalclass'] == 'recommendedapp' ? 1 : 0); + $internalClassA = isset($a['internalclass']) ? $a['internalclass'] : ''; + $internalClassB = isset($b['internalclass']) ? $b['internalclass'] : ''; + if ($internalClassA != $internalClassB) { + $aTemp = ($internalClassA == 'recommendedapp' ? 1 : 0); + $bTemp = ($internalClassB == 'recommendedapp' ? 1 : 0); return ($bTemp - $aTemp); } @@ -917,63 +932,40 @@ class OC_App { * @return array, multi-dimensional array of apps. * Keys: id, name, type, typename, personid, license, detailpage, preview, changed, description */ - public static function getAppstoreApps($filter = 'approved') { - $categoryNames = OC_OCSClient::getCategories(); - if (is_array($categoryNames)) { - // Check that categories of apps were retrieved correctly - if (!$categories = array_keys($categoryNames)) { + public static function getAppstoreApps($filter = 'approved', $category = null) { + $categories = array($category); + if (is_null($category)) { + $categoryNames = OC_OCSClient::getCategories(); + if (is_array($categoryNames)) { + // Check that categories of apps were retrieved correctly + if (!$categories = array_keys($categoryNames)) { + return false; + } + } else { return false; } + } - $page = 0; - $remoteApps = OC_OCSClient::getApplications($categories, $page, $filter); - $app1 = array(); - $i = 0; - foreach ($remoteApps as $app) { - $app1[$i] = $app; - $app1[$i]['author'] = $app['personid']; - $app1[$i]['ocs_id'] = $app['id']; - $app1[$i]['internal'] = $app1[$i]['active'] = 0; - $app1[$i]['update'] = false; - $app1[$i]['groups'] = false; - $app1[$i]['removable'] = false; - if ($app['label'] == 'recommended') { - $app1[$i]['internallabel'] = 'Recommended'; - $app1[$i]['internalclass'] = 'recommendedapp'; - } else { - $app1[$i]['internallabel'] = '3rd Party'; - $app1[$i]['internalclass'] = 'externalapp'; - } - - - // rating img - if ($app['score'] < 5) { - $img = OC_Helper::imagePath( "core", "rating/s1.png" ); - } elseif ($app['score'] < 15) { - $img = OC_Helper::imagePath( "core", "rating/s2.png" ); - } elseif($app['score'] < 25) { - $img = OC_Helper::imagePath( "core", "rating/s3.png" ); - } elseif($app['score'] < 35) { - $img = OC_Helper::imagePath( "core", "rating/s4.png" ); - } elseif($app['score'] < 45) { - $img = OC_Helper::imagePath( "core", "rating/s5.png" ); - } elseif($app['score'] < 55) { - $img = OC_Helper::imagePath( "core", "rating/s6.png" ); - } elseif($app['score'] < 65) { - $img = OC_Helper::imagePath( "core", "rating/s7.png" ); - } elseif($app['score'] < 75) { - $img = OC_Helper::imagePath( "core", "rating/s8.png" ); - } elseif($app['score'] < 85) { - $img = OC_Helper::imagePath( "core", "rating/s9.png" ); - } elseif($app['score'] < 95) { - $img = OC_Helper::imagePath( "core", "rating/s10.png" ); - } elseif($app['score'] < 100) { - $img = OC_Helper::imagePath( "core", "rating/s11.png" ); - } - - $app1[$i]['score'] = ' Score: ' . $app['score'] . '%'; - $i++; + $page = 0; + $remoteApps = OC_OCSClient::getApplications($categories, $page, $filter); + $app1 = array(); + $i = 0; + $l = \OC::$server->getL10N('core'); + foreach ($remoteApps as $app) { + $app1[$i] = $app; + $app1[$i]['author'] = $app['personid']; + $app1[$i]['ocs_id'] = $app['id']; + $app1[$i]['internal'] = $app1[$i]['active'] = 0; + $app1[$i]['update'] = false; + $app1[$i]['groups'] = false; + $app1[$i]['score'] = $app['score']; + $app1[$i]['removable'] = false; + if ($app['label'] == 'recommended') { + $app1[$i]['internallabel'] = $l->t('Recommended'); + $app1[$i]['internalclass'] = 'recommendedapp'; } + + $i++; } if (empty($app1)) { diff --git a/lib/private/installer.php b/lib/private/installer.php index 02e2190aaf..cd1d8ce392 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -201,11 +201,10 @@ class OC_Installer{ /** * update an app by it's id * @param integer $ocsid - * @param bool $isShipped * @return bool * @throws Exception */ - public static function updateAppByOCSId($ocsid, $isShipped=false) { + public static function updateAppByOCSId($ocsid) { $appdata = OC_OCSClient::getApplication($ocsid); $download = OC_OCSClient::getApplicationDownload($ocsid, 1); diff --git a/lib/private/ocsclient.php b/lib/private/ocsclient.php index dc147dea0c..8ceb43f4c1 100644 --- a/lib/private/ocsclient.php +++ b/lib/private/ocsclient.php @@ -142,9 +142,11 @@ class OC_OCSClient{ $app['license']=(string)$tmp[$i]->license; $app['detailpage']=(string)$tmp[$i]->detailpage; $app['preview']=(string)$tmp[$i]->smallpreviewpic1; + $app['preview-full']=(string)$tmp[$i]->previewpic1; $app['changed']=strtotime($tmp[$i]->changed); $app['description']=(string)$tmp[$i]->description; $app['score']=(string)$tmp[$i]->score; + $app['downloads'] = $tmp[$i]->downloads; $apps[]=$app; } diff --git a/settings/ajax/apps/categories.php b/settings/ajax/apps/categories.php new file mode 100644 index 0000000000..3bde28be99 --- /dev/null +++ b/settings/ajax/apps/categories.php @@ -0,0 +1,30 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC_JSON::checkAdminUser(); + +$l = OC_L10N::get('settings'); + +$categories = array( + array('id' => 0, 'displayName' => (string)$l->t('Enabled') ), + array('id' => 1, 'displayName' => (string)$l->t('Not enabled') ), +); + +if(OC_Config::getValue('appstoreenabled', true)) { + $categories[] = array('id' => 2, 'displayName' => (string)$l->t('Recommended') ); + // apps from external repo via OCS + $ocs = OC_OCSClient::getCategories(); + foreach($ocs as $k => $v) { + $categories[] = array( + 'id' => $k, + 'displayName' => str_replace('ownCloud ', '', $v) + ); + } +} + +OCP\JSON::success($categories); diff --git a/settings/ajax/apps/index.php b/settings/ajax/apps/index.php new file mode 100644 index 0000000000..24fba8be31 --- /dev/null +++ b/settings/ajax/apps/index.php @@ -0,0 +1,65 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +OC_JSON::checkAdminUser(); + +$l = OC_L10N::get('settings'); + +$category = intval($_GET['category']); +$apps = array(); + +switch($category) { + // installed apps + case 0: + $apps = \OC_App::listAllApps(true); + $apps = array_filter($apps, function($app) { + return $app['active']; + }); + break; + // not-installed apps + case 1: + $apps = \OC_App::listAllApps(true); + $apps = array_filter($apps, function($app) { + return !$app['active']; + }); + break; + default: + if ($category === 2) { + $apps = \OC_App::getAppstoreApps('approved'); + $apps = array_filter($apps, function($app) { + return isset($app['internalclass']) && $app['internalclass'] === 'recommendedapp'; + }); + } else { + $apps = \OC_App::getAppstoreApps('approved', $category); + } + if (!$apps) { + $apps = array(); + } + usort($apps, function ($a, $b) { + $a = (int)$a['score']; + $b = (int)$b['score']; + if ($a === $b) { + return 0; + } + return ($a > $b) ? -1 : 1; + }); + break; +} + +// fix groups to be an array +$apps = array_map(function($app){ + $groups = array(); + if (is_string($app['groups'])) { + $groups = json_decode($app['groups']); + } + $app['groups'] = $groups; + $app['canUnInstall'] = !$app['active'] && $app['removable']; + return $app; +}, $apps); + +OCP\JSON::success(array("apps" => $apps)); diff --git a/settings/ajax/apps/ocs.php b/settings/ajax/apps/ocs.php deleted file mode 100644 index aad0690e01..0000000000 --- a/settings/ajax/apps/ocs.php +++ /dev/null @@ -1,68 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -OC_JSON::checkAdminUser(); - -$l = \OC::$server->getL10N('settings'); - -if(OC_Config::getValue('appstoreenabled', true)==false) { - OCP\JSON::success(array('type' => 'external', 'data' => array())); -} - -$enabledApps=OC_App::getEnabledApps(); - -if(is_null($enabledApps)) { - OCP\JSON::error(array('data' => array('message' => $l->t('Unable to load list from App Store')))); -} - -$apps=array(); - -// apps from external repo via OCS -$categoryNames=OC_OCSClient::getCategories(); -if(is_array($categoryNames)) { - $categories=array_keys($categoryNames); - $page=0; - $filter='approved'; - $externalApps=OC_OCSClient::getApplications($categories, $page, $filter); - foreach($externalApps as $app) { - // show only external apps that aren't enabled yet - $local=false; - foreach($enabledApps as $a) { - if($a === $app['name']) { - $local=true; - } - } - - if(!$local) { - if($app['preview'] === '') { - $pre=OC_Helper::imagePath('settings', 'trans.png'); - } else { - $pre=$app['preview']; - } - if($app['label'] === 'recommended') { - $label='3rd Party'; - } else { - $label='Recommended'; - } - $apps[]=array( - 'name'=>$app['name'], - 'id'=>$app['id'], - 'active'=>false, - 'description'=>$app['description'], - 'author'=>$app['personid'], - 'license'=>$app['license'], - 'preview'=>$pre, - 'internal'=>false, - 'internallabel'=>$label, - 'update'=>false, - ); - } - } -} - -OCP\JSON::success(array('type' => 'external', 'data' => $apps)); diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php index 6375a41024..3e28c65285 100644 --- a/settings/ajax/updateapp.php +++ b/settings/ajax/updateapp.php @@ -12,30 +12,33 @@ if (!array_key_exists('appid', $_POST)) { OCP\JSON::error(array( 'message' => 'No AppId given!' )); - exit; + return; } $appId = $_POST['appid']; if (!is_numeric($appId)) { - $appId = OC_Appconfig::getValue($appId, 'ocsid', null); - $isShipped = OC_App::isShipped($appId); - + $appId = \OC::$server->getAppConfig()->getValue($appId, 'ocsid', null); if ($appId === null) { OCP\JSON::error(array( 'message' => 'No OCS-ID found for app!' )); exit; } -} else { - $isShipped = false; } $appId = OC_App::cleanAppId($appId); -\OC_Config::setValue('maintenance', true); -$result = OC_Installer::updateAppByOCSId($appId, $isShipped); -\OC_Config::setValue('maintenance', false); +$config = \OC::$server->getConfig(); +$config->setSystemValue('maintenance', true); +try { + $result = OC_Installer::updateAppByOCSId($appId); + $config->setSystemValue('maintenance', false); +} catch(Exception $ex) { + $config->setSystemValue('maintenance', false); + OC_JSON::error(array("data" => array( "message" => $ex->getMessage() ))); + return; +} if($result !== false) { OC_JSON::success(array('data' => array('appid' => $appId))); diff --git a/settings/apps.php b/settings/apps.php index b725c87b0a..2d6f3c4c69 100644 --- a/settings/apps.php +++ b/settings/apps.php @@ -25,21 +25,14 @@ OC_Util::checkAdminUser(); \OC::$server->getSession()->close(); // Load the files we need -OCP\Util::addStyle('settings', 'settings' ); -OCP\Util::addScript('settings', 'settings'); -OCP\Util::addScript('core', 'select2/select2'); -OCP\Util::addStyle('core', 'select2/select2'); -OC_App::setActiveNavigationEntry( "core_apps" ); - -$combinedApps = OC_App::listAllApps(); +\OCP\Util::addScript('handlebars-v1.3.0'); +\OCP\Util::addScript("settings", "settings"); +\OCP\Util::addStyle("settings", "settings"); +\OCP\Util::addScript('core', 'select2/select2'); +\OCP\Util::addStyle('core', 'select2/select2'); +\OCP\Util::addScript("settings", "apps"); +\OC_App::setActiveNavigationEntry( "core_apps" ); $tmpl = new OC_Template( "settings", "apps", "user" ); - -$tmpl->assign('apps', $combinedApps); - -$appid = (isset($_GET['appid'])?strip_tags($_GET['appid']):''); - -$tmpl->assign('appid', $appid); - $tmpl->printPage(); diff --git a/settings/css/settings.css b/settings/css/settings.css index 581904591d..bc6001ddf8 100644 --- a/settings/css/settings.css +++ b/settings/css/settings.css @@ -128,7 +128,11 @@ input.userFilter {width: 200px;} .ie8 table.hascontrols{border-collapse:collapse;width: 100%;} .ie8 table.hascontrols tbody tr{border-collapse:collapse;border: 1px solid #ddd !important;} + + + /* APPS */ + .appinfo { margin: 1em 40px; } #app-navigation { padding-bottom: 0px; @@ -139,11 +143,62 @@ input.userFilter {width: 200px;} #app-navigation.appwarning:hover { background: #fbb; } -small.externalapp { color:#FFF; background-color:#BBB; font-weight:bold; font-size: 0.6em; margin: 0; padding: 0.1em 0.2em; border-radius: 3px;} -small.recommendedapp { color:#FFF; background-color:#888; font-weight:bold; font-size: 0.6em; margin: 0; padding: 0.1em 0.2em; border-radius: 3px;} -small.externalapp.list, small.recommendedapp.list { position: absolute; right: 10px; top: 12px; } + +.recommendedapp { + font-size: 11px; + background-position: left center; + padding-left: 18px; + vertical-align: top; +} span.version { margin-left:1em; margin-right:1em; color:#555; } +#app-navigation .app-external, +.app-version, +.recommendedapp { + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; + filter: alpha(opacity=50); + opacity: .5; +} + +#apps-list { + position: relative; + height: 100%; +} +.section { + position: relative; +} +.app-image { + float: left; + padding-right: 10px; + width: 80px; + height: 80px; +} +.app-image img { + max-width: 80px; + max-height: 80px; +} +.app-image-icon img { + background-color: #ccc; + width: 60px; + padding: 10px; + border-radius: 3px; +} +.app-name, +.app-version, +.app-score, +.recommendedapp { + display: inline-block; +} +.app-description { + clear: both; +} +.app-description pre { + white-space: pre-line; +} + +#app-category-2 { + border-bottom: 1px solid #e8e8e8; +} /* Transition to complete width! */ .app:hover, .app:active { max-width: inherit; } diff --git a/settings/js/apps-custom.php b/settings/js/apps-custom.php deleted file mode 100644 index 2b2f256b39..0000000000 --- a/settings/js/apps-custom.php +++ /dev/null @@ -1,26 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -// Check if admin user -OC_Util::checkAdminUser(); - -// Set the content type to JS -header('Content-type: application/javascript'); - -// Disallow caching -header("Cache-Control: no-cache, must-revalidate"); -header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); - -$combinedApps = OC_App::listAllApps(); - -foreach($combinedApps as $app) { - echo("appData_".$app['id']."=".json_encode($app)); - echo("\n"); -} - -echo ("var appid =".json_encode($_GET['appid']).";"); diff --git a/settings/js/apps.js b/settings/js/apps.js index 22bac1eaf3..328c57db8e 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -1,225 +1,235 @@ -/** - * Copyright (c) 2011, Robin Appelman - * Copyright (c) 2012, Thomas Tanghus - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */ +/* global Handlebars */ + +Handlebars.registerHelper('score', function() { + if(this.score) { + var score = Math.round( this.score / 10 ); + var imageName = 'rating/s' + score + '.png'; + + return new Handlebars.SafeString(''); + } + return new Handlebars.SafeString(''); +}); OC.Settings = OC.Settings || {}; OC.Settings.Apps = OC.Settings.Apps || { - setupGroupsSelect: function() { - OC.Settings.setupGroupsSelect($('#group_select'), { + setupGroupsSelect: function($elements) { + OC.Settings.setupGroupsSelect($elements, { placeholder: t('core', 'All') }); }, - loadApp:function(app) { - var page = $('#app-content'); - page.find('p.license').show(); - page.find('span.name').text(app.name); - page.find('small.externalapp').text(app.internallabel); - if (app.version) { - page.find('span.version').text(app.version); - } else { - page.find('span.version').text(''); - } - page.find('span.score').html(app.score); - page.find('p.description').text(app.description); - page.find('img.preview').attr('src', app.preview); - if (app.preview && app.preview.length) { - page.find('img.preview').show(); - } else { - page.find('img.preview').hide(); - } - page.find('small.externalapp').attr('style', 'visibility:visible'); - page.find('span.author').text(app.author); - // FIXME licenses of downloaded apps go into app.licence, licenses of not-downloaded apps into app.license - var appLicense = ''; - if (typeof(app.licence) !== 'undefined') { - appLicense = app.licence; - } else if (typeof(app.license) !== 'undefined') { - appLicense = app.license; - } - page.find('span.licence').text(appLicense); + State: { + currentCategory: null, + apps: null + }, - var userDocumentation = false; - var adminDocumentation = false; - if (typeof(app.documentation) !== 'undefined') { - if (typeof(app.documentation.user) !== 'undefined') { - userDocumentation = true; - page.find('span.userDocumentation').html("" + t('settings', 'User Documentation') + ""); - page.find('p.documentation').show(); - } - else { - page.find('span.userDocumentation').empty(); - userDocumentation = false; - } - if (typeof(app.documentation.admin) !== 'undefined') { - adminDocumentation = true; - page.find('span.adminDocumentation').html("" + t('settings', 'Admin Documentation') + ""); - page.find('p.documentation').show(); - } - else { - page.find('span.adminDocumentation').empty(); - adminDocumentation = false; + loadCategories: function() { + var categories = [ + {displayName: 'Enabled', id: '0'} + ]; + + var source = $("#categories-template").html(); + var template = Handlebars.compile(source); + var html = template(categories); + $('#apps-categories').html(html); + + OC.Settings.Apps.loadCategory(0); + + $.ajax(OC.generateUrl('settings/apps/categories'), { + data:{}, + type:'GET', + success:function (jsondata) { + var html = template(jsondata); + $('#apps-categories').html(html); + $('#app-category-' + OC.Settings.Apps.State.currentCategory).addClass('active'); + }, + complete: function() { + $('#app-navigation').removeClass('icon-loading'); } + }); - if(userDocumentation && adminDocumentation) { - page.find('span.comma').remove(); - page.find('span.userDocumentation').after(', '); - } - else { - page.find('span.comma').remove(); - } + }, + + loadCategory: function(categoryId) { + if (OC.Settings.Apps.State.currentCategory === categoryId) { + return; } - else { - page.find('p.documentation').hide(); + $('#apps-list') + .addClass('icon-loading') + .html(''); + $('#app-category-' + OC.Settings.Apps.State.currentCategory).removeClass('active'); + $('#app-category-' + categoryId).addClass('active'); + OC.Settings.Apps.State.currentCategory = categoryId; + + $.ajax(OC.generateUrl('settings/apps/list?category={categoryId}', { + categoryId: categoryId + }), { + data:{}, + type:'GET', + success:function (apps) { + OC.Settings.Apps.State.apps = _.indexBy(apps.apps, 'id'); + var source = $("#app-template").html(); + var template = Handlebars.compile(source); + + _.each(apps.apps, function(app) { + OC.Settings.Apps.renderApp(app, template, null); + }); + }, + complete: function() { + $('#apps-list').removeClass('icon-loading'); + } + }); + }, + + renderApp: function(app, template, selector) { + if (!template) { + var source = $("#app-template").html(); + template = Handlebars.compile(source); + } + if (typeof app === 'string') { + app = OC.Settings.Apps.State.apps[app]; } - if (typeof(app.website) !== 'undefined') { - page.find('p.website').show(); - page.find('a#websitelink').attr('href', app.website); - } - - if (app.update !== false) { - page.find('input.update').show(); - page.find('input.update').data('appid', app.id); - page.find('input.update').attr('value',t('settings', 'Update to {appversion}', {appversion:app.update})); + var html = template(app); + if (selector) { + selector.html(html); } else { - page.find('input.update').hide(); + $('#apps-list').append(html); } - if (app.removable !== false && app.active === false) { - page.find('a.uninstall').show(); - page.find('a.uninstall').data('appid', app.id); - page.find('a.uninstall').attr('value', t('settings', 'Uninstall App')); - } else { - page.find('a.uninstall').hide(); - } - - page.find('input.enable').show(); - page.find('input.enable').val((app.active) ? t('settings', 'Disable') : t('settings', 'Enable')); - page.find('input.enable').data('appid', app.id); - page.find('input.enable').data('active', app.active); - if (app.internal === false) { - page.find('span.score').show(); - page.find('p.appstore').show(); - page.find('a#appstorelink').attr('href', 'http://apps.owncloud.com/content/show.php?content=' + app.id); - page.find('small.externalapp').hide(); - } else { - page.find('p.appslink').hide(); - page.find('span.score').hide(); - } - if (typeof($('#app-navigation ul li[data-id="'+app.id+'"]').data('errormsg')) !== "undefined") { - page.find(".warning").show(); - page.find(".warning").text($('#app-navigation ul li[data-id="'+app.id+'"]').data('errormsg')); - } else { - page.find(".warning").hide(); + var page = $('#app-' + app.id); + + // image loading kung-fu + if (app.preview) { + var currentImage = new Image(); + currentImage.src = app.preview; + + currentImage.onload = function() { + page.find('.app-image') + .append(this) + .fadeIn(); + }; } + // set group select properly if(OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') || OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) { - page.find("#groups_enable").hide(); - page.find("label[for='groups_enable']").hide(); - page.find("#groups_enable").attr('checked', null); + page.find(".groups-enable").hide(); + page.find("label[for='groups_enable-"+app.id+"']").hide(); + page.find(".groups-enable").attr('checked', null); } else { + page.find('#group_select').val((app.groups || []).join(',')); if (app.active) { if (app.groups.length) { - OC.Settings.Apps.setupGroupsSelect(); - $('#group_select').select2('val', app.groups || []); - page.find("#groups_enable").attr('checked','checked'); + OC.Settings.Apps.setupGroupsSelect(page.find('#group_select')); + page.find(".groups-enable").attr('checked','checked'); } else { - page.find("#groups_enable").attr('checked', null); + page.find(".groups-enable").attr('checked', null); } - page.find("#groups_enable").show(); - page.find("label[for='groups_enable']").show(); + page.find(".groups-enable").show(); + page.find("label[for='groups_enable-"+app.id+"']").show(); } else { - page.find("#groups_enable").hide(); - page.find("label[for='groups_enable']").hide(); + page.find(".groups-enable").hide(); + page.find("label[for='groups_enable-"+app.id+"']").hide(); } } }, - enableApp:function(appid, active, element, groups) { + + isType: function(app, type){ + return app.types && app.types.indexOf(type) !== -1; + }, + + enableApp:function(appId, active, element, groups) { + OC.Settings.Apps.hideErrorMessage(appId); groups = groups || []; - var appitem=$('#app-navigation ul li[data-id="'+appid+'"]'); + var appItem = $('div#app-'+appId+''); element.val(t('settings','Please wait....')); if(active && !groups.length) { - $.post(OC.filePath('settings','ajax','disableapp.php'),{appid:appid},function(result) { + $.post(OC.filePath('settings','ajax','disableapp.php'),{appid:appId},function(result) { if(!result || result.status !== 'success') { if (result.data && result.data.message) { - OC.Settings.Apps.showErrorMessage(result.data.message); - appitem.data('errormsg', result.data.message); + OC.Settings.Apps.showErrorMessage(appId, result.data.message); + appItem.data('errormsg', result.data.message); } else { - OC.Settings.Apps.showErrorMessage(t('settings', 'Error while disabling app')); - appitem.data('errormsg', t('settings', 'Error while disabling app')); + OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while disabling app')); + appItem.data('errormsg', t('settings', 'Error while disabling app')); } element.val(t('settings','Disable')); - appitem.addClass('appwarning'); - } - else { - appitem.data('active',false); - appitem.data('groups', ''); + appItem.addClass('appwarning'); + } else { + appItem.data('active',false); + appItem.data('groups', ''); element.data('active',false); - OC.Settings.Apps.removeNavigation(appid); - appitem.removeClass('active'); + OC.Settings.Apps.removeNavigation(appId); + appItem.removeClass('active'); element.val(t('settings','Enable')); - element.parent().find("#groups_enable").hide(); - element.parent().find("label[for='groups_enable']").hide(); - var app = OC.get('appData_' + appid); - app.active = false; + element.parent().find(".groups-enable").hide(); + element.parent().find("#groups_enable-"+appId).hide(); + element.parent().find("label[for='groups_enable-"+appId+"']").hide(); + element.parent().find('#group_select').hide().val(null); + OC.Settings.Apps.State.apps[appId].active = false; } },'json'); } else { - $.post(OC.filePath('settings','ajax','enableapp.php'),{appid: appid, groups: groups},function(result) { + $.post(OC.filePath('settings','ajax','enableapp.php'),{appid: appId, groups: groups},function(result) { if(!result || result.status !== 'success') { if (result.data && result.data.message) { - OC.Settings.Apps.showErrorMessage(result.data.message); - appitem.data('errormsg', result.data.message); + OC.Settings.Apps.showErrorMessage(appId, result.data.message); + appItem.data('errormsg', result.data.message); } else { - OC.Settings.Apps.showErrorMessage(t('settings', 'Error while enabling app')); - appitem.data('errormsg', t('settings', 'Error while disabling app')); + OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while enabling app')); + appItem.data('errormsg', t('settings', 'Error while disabling app')); } element.val(t('settings','Enable')); - appitem.addClass('appwarning'); + appItem.addClass('appwarning'); } else { - OC.Settings.Apps.addNavigation(appid); - appitem.data('active',true); + OC.Settings.Apps.addNavigation(appId); + appItem.data('active',true); element.data('active',true); - appitem.addClass('active'); + appItem.addClass('active'); element.val(t('settings','Disable')); - var app = OC.get('appData_' + appid); + var app = OC.Settings.Apps.State.apps[appId]; app.active = true; + if (OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') || OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) { - element.parent().find("#groups_enable").hide(); - element.parent().find("label[for='groups_enable']").hide(); + element.parent().find(".groups-enable").attr('checked', null); + element.parent().find("#groups_enable-"+appId).hide(); + element.parent().find("label[for='groups_enable-"+appId+"']").hide(); + element.parent().find(".groups-enable").hide(); + element.parent().find("#groups_enable-"+appId).hide(); + element.parent().find("label[for='groups_enable-"+appId+"']").hide(); + element.parent().find('#group_select').hide().val(null); } else { - element.parent().find("#groups_enable").show(); - element.parent().find("label[for='groups_enable']").show(); + element.parent().find("#groups_enable-"+appId).show(); + element.parent().find("label[for='groups_enable-"+appId+"']").show(); if (groups) { - appitem.data('groups', JSON.stringify(groups)); + appItem.data('groups', JSON.stringify(groups)); } else { - appitem.data('groups', ''); + appItem.data('groups', ''); } } } },'json') - .fail(function() { - OC.Settings.Apps.showErrorMessage(t('settings', 'Error while enabling app')); - appitem.data('errormsg', t('settings', 'Error while enabling app')); - appitem.data('active',false); - appitem.addClass('appwarning'); - OC.Settings.Apps.removeNavigation(appid); - element.val(t('settings','Enable')); - }); + .fail(function() { + OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while enabling app')); + appItem.data('errormsg', t('settings', 'Error while enabling app')); + appItem.data('active',false); + appItem.addClass('appwarning'); + OC.Settings.Apps.removeNavigation(appId); + element.val(t('settings','Enable')); + }); } }, - updateApp:function(appid, element) { + + updateApp:function(appId, element) { + var oldButtonText = element.val(); element.val(t('settings','Updating....')); - $.post(OC.filePath('settings','ajax','updateapp.php'),{appid:appid},function(result) { + OC.Settings.Apps.hideErrorMessage(appId); + $.post(OC.filePath('settings','ajax','updateapp.php'),{appid:appId},function(result) { if(!result || result.status !== 'success') { - OC.Settings.Apps.showErrorMessage(t('settings','Error while updating app'),t('settings','Error')); - element.val(t('settings','Update')); + OC.Settings.Apps.showErrorMessage(appId, t('settings','Error while updating app')); + element.val(oldButtonText); } else { element.val(t('settings','Updated')); @@ -227,42 +237,25 @@ OC.Settings.Apps = OC.Settings.Apps || { } },'json'); }, - uninstallApp:function(appid, element) { + + uninstallApp:function(appId, element) { + OC.Settings.Apps.hideErrorMessage(appId); element.val(t('settings','Uninstalling ....')); - $.post(OC.filePath('settings','ajax','uninstallapp.php'),{appid:appid},function(result) { + $.post(OC.filePath('settings','ajax','uninstallapp.php'),{appid:appId},function(result) { if(!result || result.status !== 'success') { - OC.Settings.Apps.showErrorMessage(t('settings','Error while uninstalling app'),t('settings','Error')); + OC.Settings.Apps.showErrorMessage(appId, t('settings','Error while uninstalling app')); element.val(t('settings','Uninstall')); } else { - OC.Settings.Apps.removeNavigation(appid); - var appItem = $('#app-navigation li').filterAttr('data-id', appid); - appItem.removeClass('active'); + OC.Settings.Apps.removeNavigation(appId); + element.parent().fadeOut(function() { + element.remove(); + }); } },'json'); }, - insertApp:function(appdata) { - var applist = $('#app-navigation ul li'); - var app = - $('
  • ' - + '' - + appdata.name+'3rd party
  • '); - app.data('app', appdata); - var added = false; - applist.each(function() { - if(!parseInt($(this).data('installed')) && $(this).find('a').text().toLowerCase() > appdata.name.toLowerCase()) { - $(this).before(app); - added = true; - return false; // dang, remember this to get out of loop - } - }); - if(!added) { - applist.last().after(app); - } - return app; - }, - removeNavigation: function(appid){ - $.getJSON(OC.filePath('settings', 'ajax', 'navigationdetect.php'), {app: appid}).done(function(response){ + removeNavigation: function(appId){ + $.getJSON(OC.filePath('settings', 'ajax', 'navigationdetect.php'), {app: appId}).done(function(response){ if(response.status === 'success'){ var navIds=response.nav_ids; for(var i=0; i< navIds.length; i++){ @@ -310,107 +303,87 @@ OC.Settings.Apps = OC.Settings.Apps || { .animate({opacity: 1}) .animate({opacity: 0.75}); - if (!SVGSupport() && entry.icon.match(/\.svg$/i)) { + if (!OC.Util.hasSVGSupport() && entry.icon.match(/\.svg$/i)) { $(img).addClass('svg'); - replaceSVG(); + OC.Util.replaceSVG(); } } } } }); }, - showErrorMessage: function(message) { - $('.appinfo .warning').show(); - $('.appinfo .warning').text(message); + + showErrorMessage: function(appId, message) { + $('div#app-'+appId+' .warning') + .show() + .text(message); }, - isType: function(app, type){ - return app.types && app.types.indexOf(type) !== -1; + + hideErrorMessage: function(appId) { + $('div#app-'+appId+' .warning') + .hide() + .text(''); } + }; -$(document).ready(function(){ - $('#app-navigation ul li').each(function(index,li){ - var app = OC.get('appData_'+$(li).data('id')); - if (app) { - app.groups= $(li).data('groups') || []; - } - $(li).data('app',app); - $(this).find('span.hidden').remove(); - }); - $('#app-navigation ul li').keydown(function(event) { - if (event.which === 13 || event.which === 32) { - $(event.target).click(); - } - return false; +$(document).ready(function () { + OC.Settings.Apps.loadCategories(); + + $(document).on('click', 'ul#apps-categories li', function () { + var categoryId = $(this).data('categoryId'); + OC.Settings.Apps.loadCategory(categoryId); }); - $(document).on('click', '#app-navigation', function(event){ - var tgt = $(event.target); - if (tgt.is('li') || tgt.is('a')) { - var item = tgt.is('li') ? $(tgt) : $(tgt).parent(); - var app = item.data('app'); - OC.Settings.Apps.loadApp(app); - $('#app-navigation .selected').removeClass('selected'); - item.addClass('selected'); - } - return false; - }); - $('#app-content input.enable').click(function(){ + $(document).on('click', '#apps-list input.enable', function () { + var appId = $(this).data('appid'); var element = $(this); - var appid=$(this).data('appid'); - var active=$(this).data('active'); - if(appid) { - OC.Settings.Apps.enableApp(appid, active, element); - } + var active = $(this).data('active'); + + OC.Settings.Apps.enableApp(appId, active, element); }); - $('#app-content input.update').click(function(){ + + $(document).on('click', '#apps-list input.uninstall', function () { + var appId = $(this).data('appid'); var element = $(this); - var appid=$(this).data('appid'); - if(appid) { - OC.Settings.Apps.updateApp(appid, element); - } + + OC.Settings.Apps.uninstallApp(appId, element); }); - $('#app-content a.uninstall').click(function(){ + + $(document).on('click', '#apps-list input.update', function () { + var appId = $(this).data('appid'); var element = $(this); - var appid=$(this).data('appid'); - if(appid) { - OC.Settings.Apps.uninstallApp(appid, element); + + OC.Settings.Apps.updateApp(appId, element); + }); + + $(document).on('change', '#group_select', function() { + var element = $(this).parent().find('input.enable'); + var groups = $(this).val(); + if (groups && groups !== '') { + groups = groups.split(','); + } else { + groups = []; + } + + var appId = element.data('appid'); + if (appId) { + OC.Settings.Apps.enableApp(appId, false, element, groups); + OC.Settings.Apps.State.apps[appId].groups = groups; } }); - $('#group_select').change(function(ev) { - var element = $('#app-content input.enable'); - // getting an array of values from select2 - var groups = ev.val || []; - var appid = element.data('appid'); - if (appid) { - OC.Settings.Apps.enableApp(appid, false, element, groups); - var li = $('[data-id="'+appid+'"]'); - var app = OC.get('appData_' + $(li).data('id')); - app.groups = groups; - li.data('groups', groups); - li.attr('data-groups', JSON.stringify(groups)); - } - }); - - if(appid) { - var item = $('#app-navigation ul li[data-id="'+appid+'"]'); - if(item) { - item.trigger('click'); - item.addClass('active'); - $('#app-navigation').animate({scrollTop: item.offset().top-70}, 'slow','swing'); - } - } - - $("#groups_enable").change(function() { - var $select = $('#group_select'); + $(document).on('change', ".groups-enable", function() { + var $select = $(this).parent().find('#group_select'); $select.val(''); + if (this.checked) { - OC.Settings.Apps.setupGroupsSelect(); - } - else { + OC.Settings.Apps.setupGroupsSelect($select); + } else { $select.select2('destroy'); } + $select.change(); }); + }); diff --git a/settings/js/old-apps.js b/settings/js/old-apps.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/settings/routes.php b/settings/routes.php index 25a8b1da7e..d942e54036 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -69,10 +69,12 @@ $this->create('settings_cert_post', '/settings/ajax/addRootCertificate') $this->create('settings_cert_remove', '/settings/ajax/removeRootCertificate') ->actionInclude('settings/ajax/removeRootCertificate.php'); // apps -$this->create('settings_ajax_apps_ocs', '/settings/ajax/apps/ocs.php') - ->actionInclude('settings/ajax/apps/ocs.php'); $this->create('settings_ajax_enableapp', '/settings/ajax/enableapp.php') ->actionInclude('settings/ajax/enableapp.php'); +$this->create('settings_ajax_load_app_categories', '/settings/apps/categories') + ->actionInclude('settings/ajax/apps/categories.php'); +$this->create('settings_ajax_load_apps', '/settings/apps/list') + ->actionInclude('settings/ajax/apps/index.php'); $this->create('settings_ajax_disableapp', '/settings/ajax/disableapp.php') ->actionInclude('settings/ajax/disableapp.php'); $this->create('settings_ajax_updateapp', '/settings/ajax/updateapp.php') @@ -81,8 +83,6 @@ $this->create('settings_ajax_uninstallapp', '/settings/ajax/uninstallapp.php') ->actionInclude('settings/ajax/uninstallapp.php'); $this->create('settings_ajax_navigationdetect', '/settings/ajax/navigationdetect.php') ->actionInclude('settings/ajax/navigationdetect.php'); -$this->create('apps_custom', '/settings/js/apps-custom.js') - ->actionInclude('settings/js/apps-custom.php'); // admin $this->create('settings_ajax_getlog', '/settings/ajax/getlog.php') ->actionInclude('settings/ajax/getlog.php'); diff --git a/settings/templates/apps.php b/settings/templates/apps.php index 5199d3fd7c..1ad37000f3 100644 --- a/settings/templates/apps.php +++ b/settings/templates/apps.php @@ -1,65 +1,82 @@ - - * This file is licensed under the Affero General Public License version 3 or later. - * See the COPYING-README file. - */?> - - + - -
  • data-id="" data-groups="" - - data-type="" data-installed="1"> - - '.OC_Util::sanitizeHTML($app['internallabel']).'') ?> -
  • - + + +
    +
    -
    -

    t('Select an App'));?>

    - -

    - - - - - - - - -
    - - -
    - - - -
    +