diff --git a/build.xml b/build.xml index a173a660..7ba32af3 100644 --- a/build.xml +++ b/build.xml @@ -106,7 +106,7 @@ minimum_version="0.4.0" /> - diff --git a/data/config.default.php b/data/config.default.php index 8af04ba9..2562cb4e 100644 --- a/data/config.default.php +++ b/data/config.default.php @@ -612,7 +612,12 @@ 'menu2', 'tags', 'configurable', 'in', 'data/config.php' ); - +/** + * Automatic tag extraction + * + * @var boolean + */ +$tagExtraction = true; /**************************** * Search @@ -655,7 +660,7 @@ * a simple value "xxx" (like "author") automatically associates xxx with * [xxx][/xxx]. * A complex value "xxx"=>"yyy" (like "address") directly - * associates xxx with yyy. + * associates xxx with yyy. * * @var array */ diff --git a/data/templates/default/dynamictags.inc.php b/data/templates/default/dynamictags.inc.php index c2ab6d4e..eb2f7e4a 100644 --- a/data/templates/default/dynamictags.inc.php +++ b/data/templates/default/dynamictags.inc.php @@ -34,6 +34,8 @@ $allPopularTagsCloud = $b2tservice->tagCloud($allPopularTags, 5, 90, 175); $allPopularTagsCount = count($allPopularTags); +$suggestedTagsCloud = $b2tservice->tagCloud($row['extractedTags'], 5, 90, 175); +$suggestedTagsCount = count($row['extractedTags']); // function printing the cloud function writeTagsProposition($tagsCloud, $title) @@ -49,7 +51,7 @@ function writeTagsProposition($tagsCloud, $title) + '

' + ''); JS; - + $taglist = ''; foreach (array_keys($tagsCloud) as $key) { $row = $tagsCloud[$key]; @@ -101,6 +103,9 @@ function addonload(addition) { jQuery(function($) { 0) { + writeTagsProposition($suggestedTagsCloud, 'Suggested Tags'); +} if ($userPopularTagsCount > 0) { writeTagsProposition($userPopularTagsCloud, T_('Popular Tags')); } @@ -110,9 +115,9 @@ function addonload(addition) { ?> var taglist = $('#tags'); var tags = taglist.val().split(', '); - + var populartags = $('.edit-tagclouds span'); - + for (var i = 0; i < populartags.length; i++) { if (tags.contains(populartags[i].innerHTML)) { populartags[i].className = 'selected'; @@ -124,20 +129,20 @@ function addTag(ele) { var thisTag = ele.innerHTML; var taglist = document.getElementById('tags'); var tags = taglist.value.split(', '); - + // If tag is already listed, remove it if (tags.contains(thisTag)) { tags = tags.remove(thisTag); ele.className = 'unselected'; - + // Otherwise add it } else { tags.splice(0, 0, thisTag); ele.className = 'selected'; } - + taglist.value = tags.join(', '); - + document.getElementById('tags').focus(); } //]]> diff --git a/data/templates/default/editbookmark.tpl.php b/data/templates/default/editbookmark.tpl.php index 8b71230f..62a67308 100644 --- a/data/templates/default/editbookmark.tpl.php +++ b/data/templates/default/editbookmark.tpl.php @@ -59,11 +59,11 @@ function fixOperaButtonName($name) { - 0): ?> + 0): ?>

$anchorValue): ?> - @@ -72,7 +72,7 @@ function fixOperaButtonName($name) { -style="display:none"> +style="display:none"> diff --git a/src/SemanticScuttle/Service/AuthUser.php b/src/SemanticScuttle/Service/AuthUser.php index 9447ee4b..1c43776a 100644 --- a/src/SemanticScuttle/Service/AuthUser.php +++ b/src/SemanticScuttle/Service/AuthUser.php @@ -53,7 +53,7 @@ class SemanticScuttle_Service_AuthUser extends SemanticScuttle_Service_User * @link http://pear.php.net/manual/en/package.authentication.auth.intro-storage.php */ var $authtype = null; - + /** * Authentication options * @@ -86,7 +86,7 @@ public static function getInstance($db) /** * Create new instance * - * @var sql_db $db Database object + * @param sql_db $db Database object */ protected function __construct($db) { @@ -100,11 +100,11 @@ protected function __construct($db) if (!$this->authtype) { return; } - require_once 'Auth.php'; + include_once 'Auth.php'; $this->auth = new Auth($this->authtype, $this->authoptions); //FIXME: check if it worked (i.e. db connection) if ($this->authdebug) { - require_once 'Log.php'; + include_once 'Log.php'; $this->auth->logger = Log::singleton( 'display', '', '', array(), PEAR_LOG_DEBUG ); @@ -208,7 +208,7 @@ public function loginAuth($username, $password) } return true; - } + } @@ -229,4 +229,4 @@ public function logout() } } -?> \ No newline at end of file +?> diff --git a/src/SemanticScuttle/Service/Bookmark2Tag.php b/src/SemanticScuttle/Service/Bookmark2Tag.php index a01b5d70..a14bad30 100644 --- a/src/SemanticScuttle/Service/Bookmark2Tag.php +++ b/src/SemanticScuttle/Service/Bookmark2Tag.php @@ -135,7 +135,7 @@ public function attachTags( $this->db->sql_transaction('begin'); if ($replace) { - if (!$this->deleteTagsForBookmark($bookmarkid)){ + if (!$this->deleteTagsForBookmark($bookmarkid)) { $this->db->sql_transaction('rollback'); message_die(GENERAL_ERROR, 'Could not attach tags (deleting old ones failed)', '', __LINE__, __FILE__, $sql, $this->db); return false; @@ -379,6 +379,51 @@ function &getTags($userid = NULL) { return $output; } + /** + * Given an array of named tags, return an array containing them and the + * count of occurrences of them. Much the same as what getTags returns but + * a subset of it. + * + * @param array $tags + * @param null|id $userid + * + * @return array + */ + function getChoiceTags($tags, $userid = NULL) { + $userservice =SemanticScuttle_Service_Factory::get('User'); + $logged_on_user = $userservice->getCurrentUserId(); + + $ftags = array(); + foreach($tags as $tag) { + $ftags[] = $this->db->sql_escape(trim($tag)); + } + + $imp = implode('\',\'', $ftags); + $imp = '\'' . $imp . '\''; + + $query = 'SELECT T.tag, COUNT(B.bId) AS bCount FROM '. $GLOBALS['tableprefix'] .'bookmarks AS B INNER JOIN '. $userservice->getTableName() .' AS U ON B.uId = U.'. $userservice->getFieldName('primary') .' INNER JOIN '. $GLOBALS['tableprefix'] .'bookmarks2tags AS T ON B.bId = T.bId'; + + $conditions = array(); + if (!is_null($userid)) { + $conditions['U.'. $userservice->getFieldName('primary')] = intval($userid); + if ($logged_on_user != $userid) + $conditions['B.bStatus'] = 0; + } else { + $conditions['B.bStatus'] = 0; + } + + $query .= ' WHERE '. $this->db->sql_build_array('SELECT', $conditions) .' AND T.tag in ('. $imp .') GROUP BY T.tag ORDER BY bCount DESC, tag'; + + if (!($dbresult = $this->db->sql_query($query))) { + message_die(GENERAL_ERROR, 'Could not get tags', '', __LINE__, __FILE__, $query, $this->db); + return false; + } + + $output = $this->db->sql_fetchrowset($dbresult); + $this->db->sql_freeresult($dbresult); + return $output; + } + // Returns the tags related to the specified tags; i.e. attached to the same bookmarks function &getRelatedTags($tags, $for_user = NULL, $logged_on_user = NULL, $limit = 10) { @@ -417,7 +462,7 @@ function &getRelatedTags($tags, $for_user = NULL, $logged_on_user = NULL, $limit $query_5 = ' AND LEFT(T0.tag, 7) <> "system:" GROUP BY T0.tag ORDER BY bCount DESC, T0.tag'; $query = $query_1 . $query_2 . $query_3 . $query_4 . $query_5; - if (! ($dbresult = $this->db->sql_query_limit($query, $limit)) ){ + if (! ($dbresult = $this->db->sql_query_limit($query, $limit)) ) { message_die(GENERAL_ERROR, 'Could not get related tags', '', __LINE__, __FILE__, $query, $this->db); return false; } diff --git a/src/SemanticScuttle/Service/TagExtractor.php b/src/SemanticScuttle/Service/TagExtractor.php new file mode 100644 index 00000000..d5743c1f --- /dev/null +++ b/src/SemanticScuttle/Service/TagExtractor.php @@ -0,0 +1,167 @@ + + * @author Christian Weiske + * @author Eric Dane + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * Extract recommended tags for new URL not yet saved as a bookmark. + * + * @category Bookmarking + * @package SemanticScuttle + * @author Ken Guest + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +class SemanticScuttle_Service_TagExtractor +{ + + /** + * Client used for making HTTP requests + * + * @var HTTP_Request2 + */ + protected $httpClient; + + /** + * Create simple HTTP_Request2 client/instance + * + * @return HTTP_Request2 + */ + private function _createClient() + { + include "HTTP/Request2.php"; + $client = new HTTP_Request2(); + return $client; + } + + /** + * Get content from some URL + * + * @param string $url URL to retrieve content from. + * + * @return string + */ + private function _getContent($url) + { + if (is_file($url)) { + return file_get_contents($url); + } + $content = null; + if ($this->httpClient === null) { + $client = $this->_createClient(); + $this->httpClient = $client; + } else { + $client = $this->httpClient; + } + $client->setUrl($url); + $res = $client->send(); + $code = $res->getStatus(); + if ($code == 200) { + $content = $res->getBody(); + } + return $content; + } + + private function _getExtractor($metaTags) + { + $class = "TagExtractor_Basic"; + if (!empty ($metaTags)) { + if (isset($metaTags['generator'])) { + if (stripos($metaTags['generator'], 'MediaWiki') !== false) { + $class = "TagExtractor_MediaWiki"; + } elseif (stripos($metaTags['generator'], 'WordPress') !== false) { + $class = "TagExtractor_WordPress"; + } + } + } + $class = "SemanticScuttle_Service_" . $class; + ini_set('display_errors', 1); + error_reporting(E_ALL); + $file = str_replace('_', '/', $class) . '.php'; + include_once "SemanticScuttle/Service/TagExtractor/Basic.php"; + include_once $file; + return new $class(); + } + + /** + * getInstance + * + * @param mixed $db ... + * + * @return SemanticScuttle_Service_TagExtractor + */ + public static function getInstance($db) + { + static $instance; + if (!isset($instance)) { + $instance = new self($db); + } + return $instance; + } + + /** + * Extract/return tags based on passed URL. + * + * @param string $url URL being saved/bookmarked. + * + * @return array + */ + public function extractFromUrl($url) + { + $tags = array(); + $parsed = parse_url($url); + $mUrl = $url; + if ($parsed['scheme'] === 'file') { + $mUrl = $parsed['path']; + } + $metaTags = get_meta_tags($mUrl); + + $extractor = null; + if ($metaTags !== false) { + $extractor = $this->_getExtractor($metaTags); + } else { + $extractor = $this->_getExtractor(''); + } + + try { + $content = $this->_getContent($mUrl); + } catch(Exception $ex) { + $content = null; + } + + $extractor->setUrl($mUrl)->setContent($content)->setMetaTags($metaTags); + $extracted = $extractor->getTags(); + $tags = array_merge($extracted, $tags); + + // Also check + // + + return array_unique($tags); + } + + /** + * set HttpClient + * + * @param HTTP_Request2 $client Custom HTTP_Request2 instance + * + * @return SemanticScuttle_Service_TagExtractor Provide Fluent interface + */ + public function setHttpClient(HTTP_Request2 $client) + { + $this->httpClient = $client; + return $this; + } + +} +?> diff --git a/src/SemanticScuttle/Service/TagExtractor/Basic.php b/src/SemanticScuttle/Service/TagExtractor/Basic.php new file mode 100644 index 00000000..5554fb36 --- /dev/null +++ b/src/SemanticScuttle/Service/TagExtractor/Basic.php @@ -0,0 +1,149 @@ + + * @author Christian Weiske + * @author Eric Dane + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * SemanticScuttle_Service_TagExtractor_Basic + * + * @category Bookmarking + * @package SemanticScuttle + * @author Ken Guest + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ +class SemanticScuttle_Service_TagExtractor_Basic +{ + /** + * @var content string content retrieved + */ + protected $content = null; + /** + * @var metaTags Associated meta tags. + */ + protected $metaTags = null; + /** + * @var url string URL to work with + */ + protected $url = null; + + /** + * Set the content of this resource. + * + * @param string $content Content of this resource. + * + * @return SemanticScuttle_Service_TagExtractor_Basic + */ + public function setContent($content) + { + $this->content = $content; + return $this; + } + + /** + * setMetaTags + * + * @param mixed $metaTags Metatags for this resource + * + * @return SemanticScuttle_Service_TagExtractor_Basic + */ + public function setMetaTags($metaTags) + { + $this->metaTags = $metaTags; + return $this; + } + + + /** + * Set the URL/Resource to work with. + * + * @param string $url URL + * + * @return SemanticScuttle_Service_TagExtractor_Basic + */ + public function setUrl($url) + { + $this->url = $url; + return $this; + } + + /** + * Determine tags associated with given resource + * + * @return array + */ + public function getTags() + { + + $url = $this->url; + $metaTags = $this->metaTags; + $content = $this->content; + + $tags = array(); + + $parsed = parse_url($url); + /* + // stackexchange sites... + if (isset($parsed['host'])) { + if (stripos($parsed['host'], 'stackexchange.com') !== false) { + $tags[] = str_replace('.stackexchange.com', '', $parsed['host']); + } + + $hostArray = explode('.', $parsed['host']); + $sub = strtolower($hostArray[0]); + if (($sub == 'help') || ($sub == 'hilfe')) { + $tags[] = $hostArray[1]; + } + } + + if (strpos($parsed['path'], "/questions/tagged/") === 0) { + $tags[] = str_replace('+', ', ', substr($parsed['path'], 18)); + } + if (strpos($parsed['path'], "/unanswered/tagged/") === 0) { + $tags[] = str_replace('+', ', ', substr($parsed['path'], 19)); + } + + // common/favourite keywords. + if (stripos($url, "ubuntu") !== false) { + $tags[] = "ubuntu"; + } elseif (stripos($url, "voip") !== false) { + $tags[] = "voip"; + } elseif (stripos($url, "magento") !== false) { + $tags[] = "magento"; + } + */ + + if ($metaTags !== false && !empty($metaTags)) { + if (isset($metaTags['keywords'])) { + $w = explode(",", $metaTags['keywords']); + $tags = array_merge($w, $tags); + } + } + if ($content !== null) { + include 'php-mf2/Mf2/Parser.php'; + $mf2Parsed = Mf2\parse($content, $url); + $rels = $mf2Parsed['rels']; + if (is_array($rels) && isset($rels['tag'])) { + foreach ($rels['tag'] as $tag) { + $tag = trim($tag, '/'); + $temp = explode('/', $tag); + $tags[] = urldecode(array_pop($temp)); + } + } + } + + return $tags; + } +} + +?> diff --git a/src/SemanticScuttle/Service/TagExtractor/MediaWiki.php b/src/SemanticScuttle/Service/TagExtractor/MediaWiki.php new file mode 100644 index 00000000..bfa90fdd --- /dev/null +++ b/src/SemanticScuttle/Service/TagExtractor/MediaWiki.php @@ -0,0 +1,63 @@ + + * @author Christian Weiske + * @author Eric Dane + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * SemanticScuttle_Service_TagExtractor_MediaWiki + * + * @category Bookmarking + * @package SemanticScuttle + * @author Ken Guest + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ +class SemanticScuttle_Service_TagExtractor_MediaWiki +extends SemanticScuttle_Service_TagExtractor_Basic +{ + const MAX_WORDS = 2; + + /** + * getTags + * + * @return array + */ + public function getTags() + { + $content = $this->content; + $tags = parent::getTags(); + $start = 0; + $categories = array(); + do { + if ($sPos = strpos($content, '"Category:', $start)) { + $ePos = strpos($content, '"', $sPos + 1); + $cat = substr($content, $sPos + 1, $ePos - $sPos - 1); + $temp = explode(':', $cat); + $category = strtolower($temp[1]); + $para = strpos($category, ' ('); + if ($para !== false) { + $category = substr($category, 0, $para - 1); + } + $category = trim($category); + // Ignore category if there are too many words in its name. + if (substr_count($category, ' ') <= (self::MAX_WORDS - 1)) { + $categories[] = $category; + } + $start = $ePos; + } + } while ($sPos !== false); + return array_merge($tags, $categories); + } +} + +?> diff --git a/src/SemanticScuttle/Service/TagExtractor/WordPress.php b/src/SemanticScuttle/Service/TagExtractor/WordPress.php new file mode 100644 index 00000000..2119439b --- /dev/null +++ b/src/SemanticScuttle/Service/TagExtractor/WordPress.php @@ -0,0 +1,52 @@ + + * @author Christian Weiske + * @author Eric Dane + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * SemanticScuttle_Service_TagExtractor_WordPress + * + * @category Bookmarking + * @package SemanticScuttle + * @author Ken Guest + * @license GPL http://www.gnu.org/licenses/gpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ +class SemanticScuttle_Service_TagExtractor_WordPress +extends SemanticScuttle_Service_TagExtractor_Basic +{ + /** + * getTags + * + * @return array + */ + public function getTags() + { + $content = $this->content; + $tags = parent::getTags(); + + $meta = $this->metaTags; + if (isset($meta['wp-parsely_version']) + && $meta['wp-parsely_version'] === "1.5" + && isset($meta['parsely-page']) + ) { + $parsely = json_decode($meta['parsely-page']); + if (isset($parsely->tags)) { + $tags = array_merge($tags, $parsely->tags); + } + } + return $tags; + } +} + +?> diff --git a/src/php-mf2 b/src/php-mf2 new file mode 160000 index 00000000..ab3ea1b3 --- /dev/null +++ b/src/php-mf2 @@ -0,0 +1 @@ +Subproject commit ab3ea1b30c3bf1e1d9f50d2580cb79b7e80c37a4 diff --git a/www/bookmarks.php b/www/bookmarks.php index bf06fb6a..91c071a7 100644 --- a/www/bookmarks.php +++ b/www/bookmarks.php @@ -21,33 +21,84 @@ require_once 'www-header.php'; -/* Service creation: only useful services are created */ -$bookmarkservice =SemanticScuttle_Service_Factory::get('Bookmark'); -$cacheservice =SemanticScuttle_Service_Factory::get('Cache'); - -/* Managing all possible inputs */ -isset($_GET['action']) ? define('GET_ACTION', $_GET['action']): define('GET_ACTION', ''); -isset($_POST['submitted']) ? define('POST_SUBMITTED', $_POST['submitted']): define('POST_SUBMITTED', ''); +/** + * Define a constant to a key/value if present in associative array + * or to a default value. + * + * @param string $name Name of constant. + * @param array $array Typically $_GET or $_POST. + * @param string $key Associated key. + * @param mixed $default Default value, optional. Defaults to empty string. + * @param bool $case Whether to define constant as case-insensitive. + * + * @access public + * + * @return void + */ +function defineWithDefault($name, $array, $key, $default = '', $case = false) +{ + if (isset($array[$key])) { + return define($name, $array[$key], (bool) $case); + } else { + return define($name, $default, (bool) $case); + } +} -isset($_GET['title']) ? define('GET_TITLE', $_GET['title']): define('GET_TITLE', ''); -isset($_GET['address']) ? define('GET_ADDRESS', $_GET['address']): define('GET_ADDRESS', ''); -isset($_GET['description']) ? define('GET_DESCRIPTION', $_GET['description']): define('GET_DESCRIPTION', ''); -isset($_GET['privateNote']) ? define('GET_PRIVATENOTE', $_GET['privateNote']): define('GET_PRIVATENOTE', ''); -isset($_GET['tags']) ? define('GET_TAGS', $_GET['tags']): define('GET_TAGS', ''); -isset($_GET['copyOf']) ? define('GET_COPYOF', $_GET['copyOf']): define('GET_COPYOF', ''); +/** + * Filter tags based on whether they are already used by the current user. + * + * @param array $tags Array of tags + * @param boolean $includeAll Whether to exclude tags not present in db, or + * adjust resultset. + * + * @return array + */ +function filterTags($tags, $includeAll = false) +{ + $b2tservice = SemanticScuttle_Service_Factory::get('Bookmark2Tag'); + $rTags = $b2tservice->getChoiceTags($tags); + /** proof of concept - later just return rTags for a tag cloud representation */ + $ret = array(); + $found = array(); + foreach ($rTags as $rTag) { + $rTag['bCount']++; + $ret[] = $rTag; + $found[] = $rTag['tag']; + } -isset($_POST['title']) ? define('POST_TITLE', $_POST['title']): define('POST_TITLE', ''); -isset($_POST['address']) ? define('POST_ADDRESS', $_POST['address']): define('POST_ADDRESS', ''); -isset($_POST['description']) ? define('POST_DESCRIPTION', $_POST['description']): define('POST_DESCRIPTION', ''); -isset($_POST['privateNote']) ? define('POST_PRIVATENOTE', $_POST['privateNote']): define('POST_PRIVATENOTE', ''); -isset($_POST['status']) ? define('POST_STATUS', $_POST['status']): define('POST_STATUS', ''); -isset($_POST['referrer']) ? define('POST_REFERRER', $_POST['referrer']): define('POST_REFERRER', ''); + if ($includeAll) { + $not_found = array_diff($tags, $found); + foreach ($not_found as $element) { + $ret[] = array('bCount' => 0, 'tag' => $element); + } + } + return $ret; +} -isset($_GET['popup']) ? define('GET_POPUP', $_GET['popup']): define('GET_POPUP', ''); -isset($_POST['popup']) ? define('POST_POPUP', $_POST['popup']): define('POST_POPUP', ''); +/* Service creation: only useful services are created */ +$bookmarkservice = SemanticScuttle_Service_Factory::get('Bookmark'); +$cacheservice = SemanticScuttle_Service_Factory::get('Cache'); +$tagextractorservice = SemanticScuttle_Service_Factory::get('TagExtractor'); -isset($_GET['page']) ? define('GET_PAGE', $_GET['page']): define('GET_PAGE', 0); -isset($_GET['sort']) ? define('GET_SORT', $_GET['sort']): define('GET_SORT', ''); +/* Managing all possible inputs */ +defineWithDefault('GET_ACTION', $_GET, 'action'); +defineWithDefault('GET_ADDRESS', $_GET, 'address'); +defineWithDefault('GET_COPYOF', $_GET, 'copyOf'); +defineWithDefault('GET_DESCRIPTION', $_GET, 'description'); +defineWithDefault('GET_PAGE', $_GET, 'page', 0); +defineWithDefault('GET_POPUP', $_GET, 'popup'); +defineWithDefault('GET_PRIVATENOTE', $_GET, 'privateNote'); +defineWithDefault('GET_SORT', $_GET, 'sort'); +defineWithDefault('GET_TAGS', $_GET, 'tags'); +defineWithDefault('GET_TITLE', $_GET, 'title'); +defineWithDefault('POST_ADDRESS', $_POST, 'address'); +defineWithDefault('POST_DESCRIPTION', $_POST, 'description'); +defineWithDefault('POST_POPUP', $_POST, 'popup'); +defineWithDefault('POST_PRIVATENOTE', $_POST, 'privateNote'); +defineWithDefault('POST_REFERRER', $_POST, 'referrer'); +defineWithDefault('POST_STATUS', $_POST, 'status'); +defineWithDefault('POST_SUBMITTED', $_POST, 'submitted'); +defineWithDefault('POST_TITLE', $_POST, 'title'); if (!isset($_POST['tags'])) { $_POST['tags'] = array(); @@ -56,70 +107,82 @@ if ((GET_ACTION == "add") && !$userservice->isLoggedOn()) { - $loginqry = str_replace("'", '%27', stripslashes($_SERVER['QUERY_STRING'])); - header('Location: '. createURL('login', '?'. $loginqry)); - exit(); + $loginqry = str_replace("'", '%27', stripslashes($_SERVER['QUERY_STRING'])); + header('Location: '. createURL('login', '?'. $loginqry)); + exit(); } if ($userservice->isLoggedOn()) { - $currentUser = $userservice->getCurrentObjectUser(); - $currentUserID = $currentUser->getId(); - $currentUsername = $currentUser->getUsername(); + $currentUser = $userservice->getCurrentObjectUser(); + $currentUserID = $currentUser->getId(); + $currentUsername = $currentUser->getUsername(); } -@list($url, $user, $cat) = isset($_SERVER['PATH_INFO']) ? explode('/', $_SERVER['PATH_INFO']) : NULL; +@list($url, $user, $cat) = isset($_SERVER['PATH_INFO']) ? + explode('/', $_SERVER['PATH_INFO']) : null; $endcache = false; if ($usecache) { - // Generate hash for caching on - $hash = md5($_SERVER['REQUEST_URI'] . $user); - - // Don't cache if its users' own bookmarks - if ($userservice->isLoggedOn()) { - if ($currentUsername != $user) { - // Cache for 5 minutes - $cacheservice->Start($hash); - $endcache = true; - } - } else { - // Cache for 30 minutes - $cacheservice->Start($hash, 1800); - $endcache = true; - } + // Generate hash for caching on + $hash = md5($_SERVER['REQUEST_URI'] . $user); + + // Don't cache if its users' own bookmarks + if ($userservice->isLoggedOn()) { + if ($currentUsername != $user) { + // Cache for 5 minutes + $cacheservice->Start($hash); + $endcache = true; + } + } else { + // Cache for 30 minutes + $cacheservice->Start($hash, 1800); + $endcache = true; + } } $pagetitle = $rssCat = $catTitle = ''; if ($user) { - if (is_int($user)) { - $userid = intval($user); - } else { - if (!($userinfo = $userservice->getUserByUsername($user))) { - $tplVars['error'] = sprintf(T_('User with username %s was not found'), $user); - $templateservice->loadTemplate('error.404.tpl', $tplVars); - exit(); - } else { - $userid = $userinfo['uId']; - } - } - $pagetitle .= ': '. $user; + if (is_int($user)) { + $userid = intval($user); + } else { + if (!($userinfo = $userservice->getUserByUsername($user))) { + $tplVars['error'] = sprintf( + T_('User with username %s was not found'), + $user + ); + $templateservice->loadTemplate('error.404.tpl', $tplVars); + exit(); + } else { + $userid = $userinfo['uId']; + } + } + $pagetitle .= ': '. $user; } if ($cat) { - $catTitle = ': '. str_replace('+', ' + ', $cat); - - $catTitleWithUrls = ': '; - $titleTags = explode('+', filter($cat)); - for($i = 0; $i* + '; - } - $catTitleWithUrls = substr($catTitleWithUrls, 0, strlen($catTitleWithUrls) - strlen(' + ')); - - $pagetitle .= $catTitleWithUrls; -} -else -{ - $catTitleWithUrls = ''; + $catTitle = ': '. str_replace('+', ' + ', $cat); + + $catTitleWithUrls = ': '; + $titleTags = explode('+', filter($cat)); + $title = T_('Remove the tag from the selection'); + for ($i = 0; $i* + "; + } + $catTitleWithUrls = substr( + $catTitleWithUrls, + 0, + strlen($catTitleWithUrls) - strlen(' + ') + ); + + $pagetitle .= $catTitleWithUrls; +} else { + $catTitleWithUrls = ''; } $pagetitle = substr($pagetitle, 2); @@ -130,148 +193,195 @@ $saved = false; $templatename = 'bookmarks.tpl'; if ($userservice->isLoggedOn() && POST_SUBMITTED != '') { - if (!POST_TITLE || !POST_ADDRESS) { - $tplVars['error'] = T_('Your bookmark must have a title and an address'); - $templatename = 'editbookmark.tpl'; - } else { - $address = trim(POST_ADDRESS); + if (!POST_TITLE || !POST_ADDRESS) { + $tplVars['error'] = T_('Your bookmark must have a title and an address'); + $templatename = 'editbookmark.tpl'; + } else { + $address = trim(POST_ADDRESS); if (!SemanticScuttle_Model_Bookmark::isValidUrl($address)) { $tplVars['error'] = T_('This bookmark URL may not be added'); $templatename = 'editbookmark.tpl'; } else if ($bookmarkservice->bookmarkExists($address, $currentUserID)) { // If the bookmark exists already, edit the original - $bookmark = $bookmarkservice->getBookmarkByAddress($address); - header('Location: '. createURL('edit', $bookmark['bId'])); - exit(); - // If it's new, save it - } else { - $title = trim(POST_TITLE); - $description = trim(POST_DESCRIPTION); - $privateNote = trim(POST_PRIVATENOTE); - $status = intval(POST_STATUS); - $categories = explode(',', $_POST['tags']); - $saved = true; - if ($bookmarkservice->addBookmark($address, $title, $description, $privateNote, $status, $categories)) { - if (POST_POPUP != '') { - $tplVars['msg'] = ''; - } else { - $tplVars['msg'] = T_('Bookmark saved') . ' '.T_('(Come back to previous page.)').''; - // Redirection option - if ($GLOBALS['useredir']) { - $address = $GLOBALS['url_redir'] . $address; - } - } - } else { - $tplVars['error'] = T_('There was an error saving your bookmark. Please try again or contact the administrator.'); - $templatename = 'editbookmark.tpl'; - $saved = false; - } - } - } + $bookmark = $bookmarkservice->getBookmarkByAddress($address); + header('Location: '. createURL('edit', $bookmark['bId'])); + exit(); + // If it's new, save it + } else { + $title = trim(POST_TITLE); + $description = trim(POST_DESCRIPTION); + $privateNote = trim(POST_PRIVATENOTE); + $status = intval(POST_STATUS); + $categories = explode(',', $_POST['tags']); + $saved = true; + if ($bookmarkservice->addBookmark( + $address, + $title, + $description, + $privateNote, + $status, + $categories + )) { + if (POST_POPUP != '') { + $tplVars['msg'] = ''; + } else { + $tplVars['msg'] = T_('Bookmark saved') + . ' ' + . T_('(Come back to previous page.)') + . ''; + // Redirection option + if ($GLOBALS['useredir']) { + $address = $GLOBALS['url_redir'] . $address; + } + } + } else { + $tplVars['error'] = T_( + 'There was an error saving your bookmark. ' . + 'Please try again or contact the administrator.' + ); + $templatename = 'editbookmark.tpl'; + $saved = false; + } + } + } } if (GET_ACTION == "add") { - // If the bookmark exists already, edit the original - if ($bookmarkservice->bookmarkExists(stripslashes(GET_ADDRESS), $currentUserID)) { - $bookmark = $bookmarkservice->getBookmarks(0, NULL, $currentUserID, NULL, NULL, NULL, NULL, NULL, NULL, $bookmarkservice->getHash(stripslashes(GET_ADDRESS))); - $popup = (GET_POPUP!='') ? '?popup=1' : ''; - header('Location: '. createURL('edit', $bookmark['bookmarks'][0]['bId'] . $popup)); - exit(); - } - $templatename = 'editbookmark.tpl'; + // If the bookmark exists already, edit the original + if ($bookmarkservice->bookmarkExists( + stripslashes(GET_ADDRESS), + $currentUserID + )) { + $bookmark = $bookmarkservice->getBookmarks( + 0, + null, + $currentUserID, + null, + null, + null, + null, + null, + null, + $bookmarkservice->getHash(stripslashes(GET_ADDRESS)) + ); + $popup = (GET_POPUP!='') ? '?popup=1' : ''; + $url = createURL('edit', $bookmark['bookmarks'][0]['bId'] . $popup); + header('Location: '. $url); + exit(); + } + $templatename = 'editbookmark.tpl'; } if ($templatename == 'editbookmark.tpl') { - if ($userservice->isLoggedOn()) { - $tplVars['formaction'] = createURL('bookmarks', $currentUsername); - if (POST_SUBMITTED != '') { - $tplVars['row'] = array( + if ($userservice->isLoggedOn()) { + $tplVars['formaction'] = createURL('bookmarks', $currentUsername); + if (POST_SUBMITTED != '') { + $tplVars['row'] = array( 'bTitle' => stripslashes(POST_TITLE), 'bAddress' => stripslashes(POST_ADDRESS), 'bDescription' => stripslashes(POST_DESCRIPTION), - 'bPrivateNote' => stripslashes(POST_PRIVATENOTE), + 'bPrivateNote' => stripslashes(POST_PRIVATENOTE), 'tags' => ($_POST['tags'] ? $_POST['tags'] : array()), - 'bStatus' => $GLOBALS['defaults']['privacy'], - ); - $tplVars['tags'] = $_POST['tags']; - } else { - if(GET_COPYOF != '') { //copy from bookmarks page - $tplVars['row'] = $bookmarkservice->getBookmark(intval(GET_COPYOF), true); - if(!$currentUser->isAdmin()) { - $tplVars['row']['bPrivateNote'] = ''; //only admin can copy private note - } - }else { //copy from pop-up bookmarklet - $tplVars['row'] = array( - 'bTitle' => stripslashes(GET_TITLE), - 'bAddress' => stripslashes(GET_ADDRESS), - 'bDescription' => stripslashes(GET_DESCRIPTION), - 'bPrivateNote' => stripslashes(GET_PRIVATENOTE), - 'tags' => (GET_TAGS ? explode(',', stripslashes(GET_TAGS)) : array()), - 'bStatus' => $GLOBALS['defaults']['privacy'] - ); - } - - } - $title = T_('Add a Bookmark'); - $tplVars['referrer'] = '';; - if (isset($_SERVER['HTTP_REFERER'])) { - $tplVars['referrer'] = $_SERVER['HTTP_REFERER']; - } - $tplVars['pagetitle'] = $title; - $tplVars['subtitle'] = $title; - $tplVars['btnsubmit'] = T_('Add Bookmark'); - $tplVars['popup'] = (GET_POPUP!='') ? GET_POPUP : null; - } else { - $tplVars['error'] = T_('You must be logged in before you can add bookmarks.'); - } + 'bStatus' => $GLOBALS['defaults']['privacy'], + ); + $tplVars['tags'] = $_POST['tags']; + } else { + if (GET_COPYOF != '') { //copy from bookmarks page + $tplVars['row'] = $bookmarkservice->getBookmark( + intval(GET_COPYOF), true + ); + if (!$currentUser->isAdmin()) { + //only admin can copy private note + $tplVars['row']['bPrivateNote'] = ''; + } + } else { + //copy from pop-up bookmarklet + $extractedTags = array(); + if ($GLOBALS['tagExtraction']) { + $extractedTags = $tagextractorservice->extractFromUrl( + stripslashes(GET_ADDRESS) + ); + $filteredTags = filterTags($extractedTags, $bIncludeAll = true); + $extractedTags = $filteredTags; + } + $tplVars['row'] = array( + 'bTitle' => stripslashes(GET_TITLE), + 'bAddress' => stripslashes(GET_ADDRESS), + 'bDescription' => stripslashes(GET_DESCRIPTION), + 'bPrivateNote' => stripslashes(GET_PRIVATENOTE), + 'tags' => ( + GET_TAGS ? + explode(',', stripslashes(GET_TAGS)) : array() + ), + 'extractedTags' => $extractedTags, + 'bStatus' => $GLOBALS['defaults']['privacy'] + ); + } + + } + $title = T_('Add a Bookmark'); + $tplVars['referrer'] = '';; + if (isset($_SERVER['HTTP_REFERER'])) { + $tplVars['referrer'] = $_SERVER['HTTP_REFERER']; + } + $tplVars['pagetitle'] = $title; + $tplVars['subtitle'] = $title; + $tplVars['btnsubmit'] = T_('Add Bookmark'); + $tplVars['popup'] = (GET_POPUP!='') ? GET_POPUP : null; + } else { + $tplVars['error'] = T_( + 'You must be logged in before you can add bookmarks.' + ); + } } else if ($user && GET_POPUP == '') { - $tplVars['sidebar_blocks'] = array('watchstatus'); + $tplVars['sidebar_blocks'] = array('watchstatus'); - if (!$cat) { //user page without tags + if (!$cat) { //user page without tags $rssTitle = "My Bookmarks"; - $cat = NULL; - $tplVars['currenttag'] = NULL; - //$tplVars['sidebar_blocks'][] = 'menu2'; - $tplVars['sidebar_blocks'][] = 'linked'; - $tplVars['sidebar_blocks'][] = 'popular'; - } else { //pages with tags + $cat = null; + $tplVars['currenttag'] = null; + //$tplVars['sidebar_blocks'][] = 'menu2'; + $tplVars['sidebar_blocks'][] = 'linked'; + $tplVars['sidebar_blocks'][] = 'popular'; + } else { //pages with tags $rssTitle = "Tags" . $catTitle; - $rssCat = '/'. filter($cat, 'url'); - $tplVars['currenttag'] = $cat; - $tplVars['sidebar_blocks'][] = 'tagactions'; - //$tplVars['sidebar_blocks'][] = 'menu2'; - $tplVars['sidebar_blocks'][] = 'linked'; - $tplVars['sidebar_blocks'][] = 'related'; - /*$tplVars['sidebar_blocks'][] = 'menu';*/ - } - $tplVars['sidebar_blocks'][] = 'menu2'; - $tplVars['popCount'] = 30; - //$tplVars['sidebar_blocks'][] = 'popular'; - - $tplVars['userid'] = $userid; - $tplVars['userinfo'] = $userinfo; - $tplVars['user'] = $user; - $tplVars['range'] = 'user'; - - // Pagination - $perpage = getPerPageCount($currentUser); - if (intval(GET_PAGE) > 1) { - $page = intval(GET_PAGE); - $start = ($page - 1) * $perpage; - } else { - $page = 0; - $start = 0; - } - - // Set template vars - $tplVars['rsschannels'] = array( + $rssCat = '/'. filter($cat, 'url'); + $tplVars['currenttag'] = $cat; + $tplVars['sidebar_blocks'][] = 'tagactions'; + //$tplVars['sidebar_blocks'][] = 'menu2'; + $tplVars['sidebar_blocks'][] = 'linked'; + $tplVars['sidebar_blocks'][] = 'related'; + /*$tplVars['sidebar_blocks'][] = 'menu';*/ + } + $tplVars['sidebar_blocks'][] = 'menu2'; + $tplVars['popCount'] = 30; + //$tplVars['sidebar_blocks'][] = 'popular'; + + $tplVars['userid'] = $userid; + $tplVars['userinfo'] = $userinfo; + $tplVars['user'] = $user; + $tplVars['range'] = 'user'; + + // Pagination + $perpage = getPerPageCount($currentUser); + if (intval(GET_PAGE) > 1) { + $page = intval(GET_PAGE); + $start = ($page - 1) * $perpage; + } else { + $page = 0; + $start = 0; + } + + // Set template vars + $tplVars['rsschannels'] = array( array( sprintf(T_('%s: %s'), $sitename, $rssTitle), createURL('rss', filter($user, 'url')) . $rssCat . '?sort='.getSortOrder() ) - ); + ); if ($userservice->isLoggedOn()) { $currentUsername = $currentUser->getUsername(); @@ -292,32 +402,38 @@ } } - $tplVars['page'] = $page; - $tplVars['start'] = $start; - $tplVars['bookmarkCount'] = $start + 1; - - $bookmarks = $bookmarkservice->getBookmarks($start, $perpage, $userid, $cat, null, getSortOrder()); - $tplVars['total'] = $bookmarks['total']; - $tplVars['bookmarks'] = $bookmarks['bookmarks']; - $tplVars['cat_url'] = createURL('bookmarks', '%s/%s'); - $tplVars['nav_url'] = createURL('bookmarks', '%s/%s%s'); - if ($userservice->isLoggedOn() && $user == $currentUsername) { - $tplVars['pagetitle'] = T_('My Bookmarks') . $catTitle; - $tplVars['subtitlehtml'] = T_('My Bookmarks') . $catTitleWithUrls; - } else { - $tplVars['pagetitle'] = $user.': '.$cat; - $tplVars['subtitlehtml'] = $user . $catTitleWithUrls; - } + $tplVars['page'] = $page; + $tplVars['start'] = $start; + $tplVars['bookmarkCount'] = $start + 1; + + $bookmarks = $bookmarkservice->getBookmarks( + $start, + $perpage, + $userid, + $cat, + null, + getSortOrder() + ); + $tplVars['total'] = $bookmarks['total']; + $tplVars['bookmarks'] = $bookmarks['bookmarks']; + $tplVars['cat_url'] = createURL('bookmarks', '%s/%s'); + $tplVars['nav_url'] = createURL('bookmarks', '%s/%s%s'); + if ($userservice->isLoggedOn() && $user == $currentUsername) { + $tplVars['pagetitle'] = T_('My Bookmarks') . $catTitle; + $tplVars['subtitlehtml'] = T_('My Bookmarks') . $catTitleWithUrls; + } else { + $tplVars['pagetitle'] = $user.': '.$cat; + $tplVars['subtitlehtml'] = $user . $catTitleWithUrls; + } } $tplVars['summarizeLinkedTags'] = true; $tplVars['pageName'] = PAGE_BOOKMARKS; - $templateservice->loadTemplate($templatename, $tplVars); if ($usecache && $endcache) { - // Cache output if existing copy has expired - $cacheservice->End($hash); + // Cache output if existing copy has expired + $cacheservice->End($hash); } ?> diff --git a/www/jsScuttle.php b/www/jsScuttle.php index de97fd2b..41d47cac 100644 --- a/www/jsScuttle.php +++ b/www/jsScuttle.php @@ -20,9 +20,9 @@ function _playerAdd(anchor) { }; var deleted = false; -function deleteBookmark(ele, input){ +function deleteBookmark(ele, input) { var confirmDelete = " - "; - ele.style.display = 'none'; + ele.style.display = 'none'; ele.parentNode.innerHTML = ele.parentNode.innerHTML + confirmDelete; } @@ -36,15 +36,15 @@ function deleteCancelled(ele) { function deleteConfirmed(ele, input, response) { //if (deleted == false) { deleted = ele.parentNode.parentNode.parentNode.parentNode; - //} + //} var post = deleted; - post.className = 'xfolkentry deleted'; + post.className = 'xfolkentry deleted'; if (response != '') { post.style.display = 'none'; deleted = false; } else { - loadXMLDocProc('ajaxDelete.php?id=' + input); - post.style.display = 'none'; + loadXMLDocProc('ajaxDelete.php?id=' + input); + post.style.display = 'none'; } } @@ -56,7 +56,7 @@ function previousElement(ele) { return ele; } -function isAvailable(input, response){ +function isAvailable(input, response) { var usernameField = document.getElementById("username"); var username = usernameField.value; username = username.toLowerCase(); @@ -87,6 +87,7 @@ function useAddress(ele) { } getTitle(address, null); ele.value = address; + suggestTags(address); } } @@ -98,7 +99,7 @@ function useAddress(ele) { * * @return boolean Returns false to halt execution after call */ -function getNewPrivateKey(input, response){ +function getNewPrivateKey(input, response) { var pk = document.getElementById('pPrivateKey'); if (response != null) { pk.value = response.trim(); @@ -108,7 +109,25 @@ function getNewPrivateKey(input, response){ return false; } -function getTitle(input, response){ +function suggestTags(url) { + // only prepend the div if there is not an h3 tag w Suggested Tags as the content. + var h3s = $('h3'); + var suggest = 1; + var tags = null; + + for (var ih = 0; ih < h3s.length; ih++) { + if (h3s[ih].innerHTML == 'Suggested Tags') { + suggest = 0; + ih = h3s.length; + } + } + if (suggest == 0) { + return; + } + $('.edit-tagclouds').prepend('

Suggested Tags

'); +} + +function getTitle(input, response) { var title = document.getElementById('titleField'); if (title.value == '') { title.style.backgroundImage = 'url(resource('images/loading.gif');?>)'; @@ -193,7 +212,7 @@ function playerLoad() { } function addAnchor(anchorForm, where) { - var whereZone = document.getElementById(where); - whereZone.value = whereZone.value + anchorForm; + var whereZone = document.getElementById(where); + whereZone.value = whereZone.value + anchorForm; document.getElementById(where).focus(); }