Index: trunk/www/sites/www/applications/applicationpage.php =================================================================== --- trunk/www/sites/www/applications/applicationpage.php (revision 1512206) +++ trunk/www/sites/www/applications/applicationpage.php (revision 1512207) @@ -1,241 +1,241 @@ name(); if (!empty($app->genericName())) { $page_title = $page_title." - ".$app->genericName(); } if ($development) { $page_title=$app->name()." - Development Information"; } $page_title_extra_html = '
'.$app->name().' Icon
'; function printSidebar($app, $category, $backToOverview=false) { $content = ''; $content .= '
'; if ($backToOverview) { - $content .= 'Back to overview'; + $content .= 'Back to overview'; } else { $content .= << Back to $category BACK_LINK; } $content .= '
'; if ($app->hasHomepage() || $app->hasKDEApps()) { $content .= '
More about '.$app->name().''; if ($app->hasHomepage()) { $content .= '
'.$app->name().' Homepage'; } if ($app->hasKDEApps()) { $url = htmlspecialchars("http://kde-apps.org/content/show.php?content=".$app->KDEAppsId()); $content .= '
'.$app->name().' on KDE-Apps.org'; } $content .= '
'; } $content .= '
Get help'; if ($app->hasUserbase()) { $content .= '
'.$app->name().' on UserBase'; } $content .= '
KDE Community Forums'; if ($app->hasHandbook()) { $content .= '
'.$app->name().' Handbook'; } $content .= '
'; $content .= '
Contact the authors'; //Bug tracker links if ($app->hasBugTracker()) { if ($app->isBugTrackerExternal()) { $content .= '
Report a bug'; } else { //KDE Bugzilla $componentstring = ""; if ($app->bugzillaComponent()) { $componentstring = '&component='.$app->bugzillaComponent(); } $content .= '
Report a bug'; } } else { //Empty bugtracker, use default link $content .= '
Report a bug'; } foreach ($app->ircChannels() as $channel) { $content .= '
IRC: '.$channel.' on Freenode'; } foreach ($app->mailingLists() as $ml) { //KDE mailing lists if (substr($ml, -8, 8) == "@kde.org") { $base = substr($ml, 0, -8); $content .= '
Mailing List: ' .htmlspecialchars($base).''; $content .= '
(subscribe, list information)'; } else if (substr($ml, -22, 22) == "@lists.sourceforge.net") { //Sourceforge.net $base = substr($ml, 0, -22); $content .= '
Mailing List: '.htmlspecialchars($base).''; $content .= '
(subscribe, archive)'; } else if (substr($ml, 0, 31) == "http://groups.google.com/group/") { //Google Groups (web) $base = substr($ml, 31, strlen($ml)-31); $content .= '
Mailing List: '.htmlspecialchars($base).''; $content .= '
(subscribe, archive)'; } else if (substr($ml, -17, 17) == "@googlegroups.com") { //Google Groups (mail) $base = substr($ml, 0, -17); $content .= '
Mailing List: '.htmlspecialchars($base).''; $content .= '
(subscribe, archive)'; } else { //Default mail $content .= '
Mailing List: '.$app->name().''; } } $content .= '
'; if (!$backToOverview) { $content .= '
Development Information
'; } $content .= <<
Get {$app->name()}
EOT; return $content; } function printPage($app) { print '
'; //Print screenshot or dummy "no screenshot available" image $thumbUrl = $app->defaultScreenshotThumbnailUrl(); $screenshotUrl = $app->defaultScreenshotUrl(); if ($screenshotUrl) { print ''; ///TODO: image size } else { print '
No screenshot available
'; ///TODO: image size } print $app->descriptionHtml(); if ($app->hasVersions() || $app->hasAuthors() || $app->hasLicense()) { print '

'; print '
'; if ($app->hasAuthors()) { print '

Developed By

'; print $app->authorHtml(); } if ($app->hasVersions()) { ///TODO: Versions not yet implemented } if ($app->hasLicense()) { print '

License

'; print $app->licenseHtml(); } print '
'; } //If JS available, hide the application details (authors) and show a toggle link ?>
'; print ''; } function printDevelopmentPage($app) { print '
'; print '

Source code repository

'; print $app->browseSourcesHtml(); print $app->checkoutSourcesHtml(); //Show bugzilla related links only for applications hosted at bugs.kde.org if ($app->hasBugTracker() && !$app->isBugTrackerExternal()) { print '

Search for open bugs

'; $product = $app->bugzillaProduct(); $componentstring = ""; if ($app->bugzillaComponent()) { $componentstring = '&component='.$app->bugzillaComponent(); } $majorBugs = 'https://bugs.kde.org/buglist.cgi?short_desc_type=allwordssubstr&product='.$product.$componentstring.'&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=critical&bug_severity=grave&bug_severity=major&bug_severity=crash'; $minorBugs = 'https://bugs.kde.org/buglist.cgi?short_desc_type=allwordssubstr&product='.$product.$componentstring.'&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=normal&bug_severity=minor'; $wishes = 'https://bugs.kde.org/buglist.cgi?short_desc_type=allwordssubstr&product='.$product.$componentstring.'&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_severity=wishlist'; $juniorJobs = 'https://bugs.kde.org/buglist.cgi?keywords=junior-jobs&product='.$product.$componentstring.'&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&cmdtype=doit'; print ''; } if ($app->hasEbn()) { print '

Code checking

'; print '

Show results of automated code checking on the English Breakfast Network (EBN).

'; print ''; } print '
'; } $sidebar_content = printSidebar($app, $category, $development); include 'header.inc'; echo ''; ?> Index: trunk/www/sites/www/applications/includes/class_appdata2.inc =================================================================== --- trunk/www/sites/www/applications/includes/class_appdata2.inc (revision 1512206) +++ trunk/www/sites/www/applications/includes/class_appdata2.inc (revision 1512207) @@ -1,400 +1,406 @@ * Rebased on new backend data by Harald Sitter * * Usage: * */ class AppData2 { var $data; function AppData2($name, $path = "..") { $name = preg_replace('/[^a-z\-_0-9\.]/i','',$name); $file_path = $path.'/applications/appdata/'.$name.'.json'; // Make sure to resolve symlinks to their actual name. Specifically // symlinks may be used for backwards compatibility of old names, but // data resolution should happen on the current name. $link = readlink($file_path); if ($link != FALSE) { $file_path = $link; $name = basename($file_path, '.json'); } $this->data = json_decode(file_get_contents($path.'/applications/appdata/'.$name.'.json'), true); $extension_file = $path.'/applications/appdata-extensions/'.$name.'.json'; if (file_exists($extension_file)) { $this->data = array_merge_recursive($this->data, json_decode(file_get_contents($extension_file), true)); } + + $this->id = $name; + } + + # Same as AppStreamId but with .desktop stripped to force consistent naming. + function id() { + if (empty($this->id)) { + return $this->data['X-KDE-ID']; + } + return $this->id; } function name() { return $this->l10n($this->data['Name']); } function genericName() { // FIXME: summary is a bad fit for this as it can be rather long // return $this->l10n($this->data['Summary']); return $this->l10n($this->data['X-KDE-GenericName']); } // FIXME: in appdata things can be in more than one category, the sturcture of the site is kinda only expecting things once function category() { return $this->data['Categories'][0]; } function get_client_prefered_language($getSortedList = false, $acceptedLanguages = false) { if (empty($acceptedLanguages)) { $acceptedLanguages = $_SERVER["HTTP_ACCEPT_LANGUAGE"]; } // print_r($acceptedLanguages); print_r("
"); // regex inspired from @GabrielAnderson on http://stackoverflow.com/questions/6038236/http-accept-language preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})*)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $acceptedLanguages, $lang_parse); $langs = $lang_parse[1]; $ranks = $lang_parse[4]; // (create an associative array 'language' => 'preference') $lang2pref = array(); for($i=0; $i $lang2pref[$b]) return -1; elseif ($lang2pref[$a] < $lang2pref[$b]) return 1; elseif (strlen($a) > strlen($b)) return -1; elseif (strlen($a) < strlen($b)) return 1; else return 0; }; // sort the languages by prefered language and by the most specific region uksort($lang2pref, $cmpLangs); if ($getSortedList) { return array_keys($lang2pref); } // return the first value's key reset($lang2pref); return key($lang2pref); } function l10n($ary) { static $__c_alternates = array('en', 'en-US'); $ret = $ary['C']; foreach($this->get_client_prefered_language(True) as $lang) { // print_r($lang); print_r("
"); if (in_array($lang, $__c_alternates, true)) { return $ret; // Defaults to C already. } if (array_key_exists($lang, $ary)) { return $ary[$lang]; } } return $ret; } function descriptionHtml() { $description = $this->l10n($this->data['Description']); // Force paragraphing if the Description doesn't have it. if(substr($description, 0, 3) != '

') { $description = '

'.$description.'

'; } return $description; } function hasVersions() { return false; ///TODO: version information is not yet implemented } function hasAuthors() { return isset($this->data['authors']) && ($this->data['authors'] != false); } function authorHtml() { $html = '

'.i18n_var( "Authors:" ).'

'; $html .= ''; if (count($this->data['credits'])) { $html .= '

'.i18n_var( "Thanks To:" ).'

'; $html .= ''; } return $html; } function hasLicense() { return isset($this->data['ProjectLicense']) && ($this->data['ProjectLicense'] != false); } function licenseHtml() { // TODO: we should really render SPDX properly. There are some databases // of licenses and their texts. Or we could send URLs to spdx.org. $license = $this->data['ProjectLicense']; $text = '

'; // $stripped_license = str_replace("+", "", $license); // $text = i18n_var('%1 is distributed under the terms of the .', // $this->name(), $stripped_license, $license); switch($license) { case 'GPL-2.0+': case 'GPL-2.0': $text .= i18n_var('%1 is distributed under the terms of the GNU General Public License (GPL), Version 2.', $this->name()); break; case 'GPL-3.0+': case 'GPL-3.0': $text .= i18n_var('%1 is distributed under the terms of the GNU General Public License (GPL), Version 3.', $this->name()); break; case 'LGPL': $text .= i18n_var('%1 is distributed under the terms of the GNU Library General Public License, version 2.', $this->name()); break; default: $text .= $license.'.'; } $text .= '

'; return $text; } function hasHomepage() { return isset($this->data['Url']['homepage']) && ($this->data['Url']['homepage'] != false); } function homepage() { return $this->data['Url']['homepage']; } function hasAppStream() { return true; } function AppStreamId() { return $this->data['ID']; } - function id() { - return $this->AppStreamId(); - } - function icon() { return $this->data['Icon']['local'][0]['name']; } // TODO: not in appdata function hasKDEApps() { return $this->data['kde-apps.org'] != false; } // FIXME: not in appdata function KDEAppsId() { return $this->data['kde-apps.org']; } // FIXME: not in appdata function hasUserbase() { return $this->data['userbase'] != false; } // FIXME: not in appdata function userbase() { return "http://userbase.kde.org/".$this->data['userbase']; } function hasHandbook() { return isset($this->data['Url']['help']) && ($this->data['Url']['help'] != false); } function handbook() { return $this->data['Url']['help']; } // AppData extension X-KDE-Forum: function forumUrl() { if ($this->data['X-KDE-Forum'] != false) { return 'http://forum.kde.org/viewforum.php?f='.$this->data['X-KDE-Forum']; } else { return 'http://forum.kde.org/'; } } // AppData extension X-KDE-IRC: function ircChannels() { if ($this->data['X-KDE-IRC'] != false) { $irc = $this->data['X-KDE-IRC']; if (is_array($irc)) { return $irc; } else { return array($irc); } } else { return array("#kde"); } } // AppData extension X-KDE-MailingLists: function mailingLists() { if ($this->data['X-KDE-MailingLists'] != false) { $ml = $this->data['X-KDE-MailingLists']; if (is_array($ml)) { return $ml; } else { return array($ml); } } else { return array("kde@kde.org"); } } // AppData extension X-KDE-Repository: function repository() { return $this->data['X-KDE-Repository']; } function browseSourcesHtml() { $path = '

'.i18n_var("Browse %1 source code online", $this->name()).'

'; return $path; } function checkoutSourcesHtml() { return '

'.i18n_var("Clone %1 source code:", $this->name()).'

git clone https://anongit.kde.org/'.$this->repository().'

'; } //Returns true if the application has a bugtracker (external or KDE bugzilla) function hasBugTracker() { return isset($this->data['Url']['bugtracker']) && ($this->data['Url']['bugtracker'] != false); } function bugTracker() { return $this->data['Url']['bugtracker']; } // FIXME: not implemented url types in frontend: // faq // donation // translate // TODO: appstream bts are always complete URLs so this code is pointless // Returns true if the application has an external bugtracker (!bugs.k.o) function isBugTrackerExternal() { return (substr($this->bugTracker(), 0, 7) == "http://" || substr($this->bugTracker(), 0, 8) == "https://"); } function bugzillaProduct() { if (is_array($this->bugTracker())) { return $this->bugTracker()[0]; } return $this->bugTracker(); } function bugzillaComponent() { if (is_array($this->bugTracker())) { return $this->bugTracker()[1]; } return false; } // TODO: ebn is broken for now function hasEbn() { return false; } function ebnUrlBase() { // examples: // KDE/kdeedu/parley: http://englishbreakfastnetwork.org/krazy/reports/kde-4.x/kdeedu/parley/index.html // KDE/kdebase/apps/dolphin: http://englishbreakfastnetwork.org/krazy/reports/kde-4.x/kdebase-apps/dolphin/index.html // extragear/graphics/digikam: http://englishbreakfastnetwork.org/krazy/reports/extragear/graphics/digikam/index.html // koffice/kword: http://englishbreakfastnetwork.org/krazy/reports/bundled-apps/koffice/kword/index.html // amarok (gitorious): http://englishbreakfastnetwork.org/krazy/reports/extragear/multimedia/amarok-git/index.html $ebn = ''; // extract path segments from module parent $parts = explode('/', $this->data['parent']); // replace path segment by "kde-4.x" for "kde" if ($parts[0] == 'kde') { $ebn = "kde-4.x/" . $parts[1] . "/" . strtolower($this->data['repository'][1]); } else { $ebn = $parts[0] . "/" . $parts[1] . "/" . strtolower($this->name()); } return $ebn; } function ebnCodeCheckingUrl() { return 'http://ebn.kde.org/krazy/reports/'.$this->ebnUrlBase().'/index.html'; } function ebnDocCheckingUrl() { return 'http://ebn.kde.org/sanitizer/reports/'.$this->ebnUrlBase().'/index.html'; } function defaultScreenshotUrl() { // TODO: implement l10n foreach($this->data['Screenshots'] as $screenshot) { if ($screenshot['default'] == true && $screenshot['source-image']['lang'] == 'C') { return $screenshot['source-image']['url']; } } // No default found, use first available screenshot. foreach($this->data['Screenshots'] as $screenshot) { if ($screenshot['source-image']['lang'] == 'C') { return $screenshot['source-image']['url']; } } return NULL; } function defaultScreenshotThumbnailUrl() { // TODO: implement l10n foreach($this->data['Screenshots'] as $screenshot) { if ($screenshot['default'] == true && $screenshot['source-image']['lang'] == 'C') { return '/applications'.$screenshot['thumbnails'][0]['url']; } } // No default found, use first available screenshot. foreach($this->data['Screenshots'] as $screenshot) { if ($screenshot['source-image']['lang'] == 'C') { return '/applications'.$screenshot['thumbnails'][0]['url']; } } // If we can't find a thumb, simply use the off-site real image and let // the browser scale it. return $this->defaultScreenshotUrl(); } }